Recent

Author Topic: [SOLVED] Strange mem leaks when passing obj from procedure to an other procedure  (Read 1792 times)

Kepsz

  • New Member
  • *
  • Posts: 37
Hi!

I have a communication debugger program for RS485 bus. It works, but with heaptrace i got a bunch of memory leak.

It have two records, one for virtualstringtree (to display comm packets) and one for transporting data from the reciever / transmitter to the virtualtree.

Code: Pascal  [Select][+][-]
  1. type
  2.   PLogTreeData = ^TLogTreeData;
  3.   TLogTreeData = record
  4.     time: TDateTime;
  5.     Sender: string;
  6.     Address: string;
  7.     Len: string;
  8.     Rnd: string;
  9.     Msn: string;
  10.     CmdCode: string;
  11.     Direction: string;
  12.     CRC_readed: string;
  13.     CRC_calced: string;
  14.     Message: array of byte;
  15.   end;
  16.  
  17.  PLogLineData = ^TLogLineData;
  18.  TLogLineData = record
  19.     Time: TDateTime;
  20.     Sender: string;
  21.     Address: string;
  22.     Len: string;
  23.     Rnd: string;
  24.     Msn: string;
  25.     CmdCode: string;
  26.     Direction: string;
  27.     CRC_readed: string;
  28.     CRC_calced: string;
  29.     Message: array of byte;
  30.  end;

The transmitter and the receiver procedures are mostly the same, so i just post the transmitter procedure.

Code: Pascal  [Select][+][-]
  1. procedure FillTxbuff(CMD_H: integer; CMD_L: integer; LEN: integer; Data: array of byte; Broadcast: boolean);
  2. var
  3.   tbytes: array[0..BYTEMAX] of byte;
  4.   LogMsg: TLogLineData;
  5.   LogMsgPtr: PLogLineData;
  6. begin
  7. ...
  8.   LogMsgPtr := @LogMsg;
  9.   SetLength(LogMsgPtr^.Message, tbytes[3]);
  10.   for i:=0 to tbytes[3] - 1 do begin
  11.      LogMsgPtr^.Message[i] := tbytes[i];
  12.   end;
  13.  
  14.   LogMsgPtr^.Time := Now;
  15.   LogMsgPtr^.Direction:='out';
  16.   LogMsgPtr^.Address:= 'L: '+IntToStr(tbytes[1])+' H: '+IntToStr(tbytes[2]);
  17.  
  18.   if tbytes[2] > 127 then begin
  19.      LogMsgPtr^.Sender := 'master';
  20.   end else begin
  21.      LogMsgPtr^.Sender := 'slave';
  22.   end;
  23.  
  24.   LogMsgPtr^.Len := IntToStr(tbytes[3]);
  25.   LogMsgPtr^.Rnd := IntToStr(tbytes[4]);
  26.   LogMsgPtr^.Msn := IntToStr(tbytes[5]);
  27.  
  28.   //////////////////////////////////////////////
  29.   RS485EncryptData(tbytes[3] - 5, 4, tbytes);
  30.   tbytes[tbytes[3] - 1] := ArrayCRC08Calc(tbytes, tbytes[3]-1);
  31.  
  32.   LogMsgPtr^.CRC_readed := '';
  33.   LogMsgPtr^.CRC_calced := tbytes[tbytes[3] - 1].ToHexString();
  34.   if (tbytes[3] = 7) and (ShowVoid = true) then begin
  35.        MainForm.AddNewLineToLogTree(LogMsgPtr);
  36.   end else if tbytes[3] > 7 then begin
  37.        LogMsgPtr^.CmdCode := '0x'+IntToHex(tbytes[7], 2) + IntToHex(tbytes[6], 2);
  38.        MainForm.AddNewLineToLogTree(LogMsgPtr);
  39.   end;
  40.   Move(tbytes, txbuff, tbytes[3]);
  41.   MainForm.TxLed.Color:=clRed;
  42.   MainForm.TxClear.Enabled:=true;
  43.   SbFlag := true;
  44. end;
So i'm passing a pointer of a local variable here to an other procedure.

This is the procedure what puts the data to the gui:
Quote
procedure TMainForm.AddNewLineToLogTree(MessageLine: PLogLineData);
var
  xnode: PVirtualNode;
  data: PLogTreeData;
begin
  LogTree.BeginUpdate;

  xnode:=LogTree.AddChild(nil);
  data:=LogTree.GetNodeData(xnode);
  data^.time:=MessageLine^.Time;
  data^.Sender:=MessageLine^.Sender;
  data^.Direction:=MessageLine^.Direction;
  data^.Address:=MessageLine^.Address;
  data^.Len:=MessageLine^.Len;
  data^.Rnd:=MessageLine^.Rnd;
  data^.Msn:=MessageLine^.Msn;
  data^.CRC_calced:=MessageLine^.CRC_calced;
  data^.CRC_readed:=MessageLine^.CRC_readed;
  data^.CmdCode:=MessageLine^.CmdCode;
  SetLength(data^.Message, data^.Len.ToInteger);
  data^.Message:=MessageLine^.Message;

  LogTree.EndUpdate;
And that's all. Whit these code, i'm getting many memory leaks in heaptrace output.

Code: Pascal  [Select][+][-]
  1. Call trace for block $000000000BA248F0 size 36
  2.   $0000000100012672
  3.   $0000000100009FE3
  4.   $000000010000B23C
  5.   $000000010000A82F
  6.   $000000010004B65A line 194 of rs485_utils.pas
  7.   $000000010004BA48 line 235 of rs485_utils.pas
  8.   $0000000100051CED line 1218 of main.pas
  9.   $00000001001DE896 line 175 of customtimer.pas
  10. Call trace for block $000000000BA24D70 size 23
  11.   $0000000100012672
  12.   $000000010000EE32
  13.   $000000010004B56C line 187 of rs485_utils.pas
  14.   $000000010004BA48 line 235 of rs485_utils.pas
  15.   $0000000100051CED line 1218 of main.pas
  16.   $00000001001DE896 line 175 of customtimer.pas
  17.   $00000001001DE7D9 line 150 of customtimer.pas
  18.   $000000010013F47D line 2843 of win32callback.inc
  19. ...
And so on. These lines are various LogMsgPtr^... lines of the FillTxbuff procedure. What I'm doing wrong?


« Last Edit: February 08, 2019, 11:17:33 am by Kepsz »

wp

  • Hero Member
  • *****
  • Posts: 13645
Do you provide a handler also for the OnFreeNode event of the VirtualTree? Here you must "free" the strings of the TLogLineData record:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree;
  2.   Node: PVirtualNode);
  3. var
  4.   data: PLogLineData;
  5. begin
  6.   data := LogTree.GetNodeData(Node);
  7.   data^.Sender := '';
  8.   data^.Address := '';
  9.   // etc
 

PascalDragon

  • Hero Member
  • *****
  • Posts: 6418
  • Compiler Developer
Not related to your problem (I think wp's answer might be correct here, though a Finalize(data) should do it as well), but why are you passing a PLogLineData at all when you don't keep the pointer around? You could just as well declare your AddNewLineToLogTree as AddNewLineToLogTree(constref MessageLine: TLogLineData). This way you don't need to play around with pointers in FillTxbuff, but get the same advantage as constref is essentially a pointer.

Kepsz

  • New Member
  • *
  • Posts: 37
Not related to your problem (I think wp's answer might be correct here, though a Finalize(data) should do it as well), but why are you passing a PLogLineData at all when you don't keep the pointer around? You could just as well declare your AddNewLineToLogTree as AddNewLineToLogTree(constref MessageLine: TLogLineData). This way you don't need to play around with pointers in FillTxbuff, but get the same advantage as constref is essentially a pointer.

Hmm, i was unfamiliar with the constref option, but that's awsome. Thank you, it works great!

Do you provide a handler also for the OnFreeNode event of the VirtualTree? Here you must "free" the strings of the TLogLineData record:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree;
  2.   Node: PVirtualNode);
  3. var
  4.   data: PLogLineData;
  5. begin
  6.   data := LogTree.GetNodeData(Node);
  7.   data^.Sender := '';
  8.   data^.Address := '';
  9.   // etc
 

That was the problem! By implementing this procedure:
Code: Pascal  [Select][+][-]
  1. procedure TMainForm.LogTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
  2. var
  3.   data: PLogTreeData;
  4. begin
  5.   data := LogTree.GetNodeData(Node);
  6.   data^.time := 0;
  7.   data^.Sender := '';
  8.   data^.Direction := '';
  9.   data^.Address := '';
  10.   data^.Len := '';
  11.   data^.Rnd := '';
  12.   data^.Msn := '';
  13.   data^.CRC_calced := '';
  14.   data^.CRC_readed := '';
  15.   data^.CmdCode := '';
  16.   SetLength(data^.Message, 0);
  17. end;
the memory leaks are gone now. Than you!

Btw, I also tried finalize(data); here instead of all the ... := ''; lines, but that did nothing. It may not work with complicated records.

 

TinyPortal © 2005-2018