AV when releasing a form after compressing and sending TFDDataset data

I have AV when releasing Form, it appears when I compress and send Dataset FireDAC data to a remote server.

This is the code I use to compress TFDDataset data:

function CompressDataset(Dataset: TFDDataset): TMemoryStream; var Data: TMemoryStream; Compress: TZCompressionStream; begin Result := TMemoryStream.Create; Data := TMemoryStream.Create; try Compress := TZCompressionStream.Create(Result); Dataset.SaveToStream(Data, TFDStorageFormat.sfBinary); Data.Position := 0; Compress.CopyFrom(Data, Data.Size); finally Data.Free; Compress.Free; end; Result.Position := 0; end; 

And this is the code for sending compressed data to a remote call (Datasnap).

 procedure TfrmRentFacturacion_Facturar.btnSendDesgloseClick(Sender: TObject); var Stream: TMemoryStream; begin if qryFacturacion_Desglose.State = dsEdit then qryFacturacion_Desglose.Post; Stream := CompressDataset(qryFacturacion_Desglose); try spActualizaDesglose.ParamByName('AStream').AsStream := Stream; spActualizaDesglose.ExecProc; finally Stream.Free; end; end; 

This code leaves something unstable, most likely TFDDataset qryFacturacion_Desglose, and raises AV when the form is released. But I do not understand what might be wrong.

PS: Thanks @J ... suggestion to check call stack. I found the source of the problem. This is the call stack:

 :000000000040E735 TObject.Free + $15 :00000000007F1123 TParamObject.Destroy + $43 :000000000041A155 TInterfacedObject._Release + $55 :000007FEFF2211CE ; C:\Windows\system32\oleaut32.dll :0000000000459DAB VarClearDeep + $1B :0000000000459E6B @VarClear + $1B :0000000000459E7D @VarClr + $D :00000000004149F4 @VarClr + $14 :0000000000414ACC @FinalizeArray + $BC :00000000004162F1 @DynArrayClear + $61 :0000000000414B58 @FinalizeArray + $148 :0000000000414985 @FinalizeRecord + $75 :000000000040E82E TObject.CleanupInstance + $4E :000000000040E450 TObject.FreeInstance + $10 :000000000040F1C1 @ClassDestroy + $11 :000000000051ED43 TCollectionItem.Destroy + $43 :000000000040E738 TObject.Free + $18 :000000000051F40A TCollection.Clear + $5A :000000000051F1CD TCollection.Destroy + $2D :000000000084A858 TFDParams.Destroy + $88 :0000000000838FD8 FDFree + $18 :000000000084A8BB TFDParams.RemRef + $2B :0000000000B8C907 TFDCustomCommand.Destroy + $57 :000000000040E738 TObject.Free + $18 :00000000005419F3 TComponent.DestroyComponents + $93 :000000000054117F TComponent.Destroy + $2F :0000000000B92A66 TFDCustomTableAdapter.Destroy + $86 :0000000000B9BE02 TFDRdbmsDataSet.Destroy + $C2 :000000000040E738 TObject.Free + $18 :00000000005419F3 TComponent.DestroyComponents + $93 :000000000054117F TComponent.Destroy + $2F :00000000006039C2 TControl.Destroy + $192 :000000000060AA91 TWinControl.Destroy + $1B1 :0000000000797273 TScrollingWinControl.Destroy + $73 :0000000000798EB7 TCustomForm.Destroy + $1E7 :000000000040E738 TObject.Free + $18 :00000000007A1389 TCustomForm.CMRelease + $9 :000000000040EE81 TObject.Dispatch + $41 :0000000000607D56 TControl.WndProc + $386 :000000000060EC07 TWinControl.WndProc + $8E7 :000000000079ADB0 TCustomForm.WndProc + $910 :000000000060DE4C TWinControl.MainWndProc + $2C :0000000000545056 StdWndProc + $26 :00000000777D9BBD ; C:\Windows\system32\USER32.dll :00000000777D98C2 ; C:\Windows\system32\USER32.dll :00000000007A8E84 TApplication.ProcessMessage + $134 :00000000007A8EF8 TApplication.HandleMessage + $18 :00000000007A9364 TApplication.Run + $F4 Impuestos.Impuestos :00000000776B59CD ; C:\Windows\system32\kernel32.dll :00000000778EA561 ; ntdll.dll 

AV occurs when you try to release the AStream parameter of the spActualizaDesglose TFDStoredProc parameter, which makes a remote call to the Datasnap server.

I changed the call, so it does not release the original data stream after making the remote call.

  procedure TfrmRentFacturacion_Facturar.btnSendDesgloseClick(Sender: TObject); var Stream: TMemoryStream; begin if qryFacturacion_Desglose.State = dsEdit then qryFacturacion_Desglose.Post; Stream := CompressDataset(qryFacturacion_Desglose); spActualizaDesglose.ParamByName('AStream').AsStream := Stream; spActualizaDesglose.ExecProc; end; 

Now the form is issued without problems, but is it true? Will I have no memory leak?

Thanks.

+5
source share
1 answer

From the manual page :

Setting the AsStream property sets the DataType property for ftStream if it is not one of the character string / byte / BLOB data types. The assigned TStream object will belong to this TFDParam. To explicitly manage property, use the SetStream method.

The emphasis is mine. Therefore, yes, assigning a stream to a parameter gives ownership of this stream, and it becomes responsible for releasing it when it is freed (which makes the data set when it is freed by the form that owns the data set component).

When you free the thread here:

 Stream := CompressDataset(qryFacturacion_Desglose); try spActualizaDesglose.ParamByName('AStream').AsStream := Stream; spActualizaDesglose.ExecProc; finally Stream.Free; end; 

you destroy the object in which the parameter holds the link, and it calls AV when the parameter object tries to free it a second time.

+7
source

Source: https://habr.com/ru/post/1265833/


All Articles