Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2011-05

Buffer dealocating between program and C++ library

8 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Leonardo M. Ramé

Hi, I'm using a C++ library created by me, with a function that let me get an image buffer. I use that buffer to do some processing, then I can tell the library to delete the buffer.

In Linux, I never had an issue between my Lazarus program and that library, but yesterday I decided to port it to Windows, and found the buffer is never deleted, causing a "Microsoft Visual C++ Runtime library, runtime error....". The library is compiled with Mingw32.

After having found the error, I created a C++ program that calls the problematic method 1000 times, and noted the memory is handled correctly, then I made a simple FPC program that does the same thing, and found the same behavior as in Lazarus.

Here are the signatures for the functions exported by the library:

  TgetDicomImage = function(const ADicomImage: Pointer; out buffer: Pointer;
    out bufSize: longint; ALeft, ATop: double; var AWidth, AHeight: double): integer; cdecl;
  TdeleteBuffer = procedure(ABuffer: PByte); cdecl;

And here is a snippet of the code I use to test the function:

  Pointer(lGetDicomImage) := GetProcAddress(lLibHandle, 'getDicomImageBufferEx');
  Pointer(lDeleteBuffer) := GetProcAddress(lLibHandle, 'deleteBuffer');
  for I := 0 to 1000 do
  begin
    if @lGetDicomImage  nil then
    begin
      lWidth := 900;
      lHeight := 400;
      lBuffer := nil;
      lBufSize:= 0;
      if lGetDicomImage(lDicomImage, lBuffer, lBufSize, lLeft, lTop, lWidth, lHeight) = 1 then
      begin
        // ---   buffer processing  --
        // ...
        // --- end buffer processing --
        if @lDeleteBuffer  nil then
          lDeleteBuffer(lBuffer); // <----- memory keeps increasing here.
      end;
    end;
  end;

For those interested in the C++ functions:

  int getImageBufferEx(void * imagen, void * &buffer, unsigned long&
  bufSize, double left, double top, double &width, double &height)
  {
     DicomImageHandler * imgHandler = (DicomImageHandler *)imagen;
     int lResult = -1;
     if(imgHandler->getDicomImage()->getStatus() == EIS_Normal)
     {
       double lZoom = imgHandler->getZoomFactor();
       DicomImage * lOrigImage = imgHandler->getDicomImage()->createClippedImage(left, top, width, height, 65535);
       DicomImage * clippedImage = lOrigImage->createScaledImage(lZoom);
       width = clippedImage->getWidth();
       height = clippedImage->getHeight();
       bufSize = clippedImage->getOutputDataSize();
       buffer = new Uint16[bufSize];
       if(clippedImage->getOutputData((void *)(buffer), bufSize, 8))
         lResult = 1;
       delete clippedImage;
       delete lOrigImage;
     }
     return lResult;
  }
  void deleteBuffer(void * &buffer)
  {
    delete [] (Uint16 *)buffer;
    buffer = NULL;
  }

Please, tell me if you find something that can be causing the memory leaks.

Thanks in advance,

Reply by email

Mattias Gaertner
to Leonardo M. Ramé
Show quoted text 30 lines
Hi, I'm using a C++ library created by me, with a function that let me get an image buffer. I use that buffer to do some processing, then I can tell the library to delete the buffer. In Linux, I never had an issue between my Lazarus program and that library, but yesterday I decided to port it to Windows, and found the buffer is never deleted, causing a "Microsoft Visual C++ Runtime library, runtime error....". The library is compiled with Mingw32. After having found the error, I created a C++ program that calls the problematic method 1000 times, and noted the memory is handled correctly, then I made a simple FPC program that does the same thing, and found the same behavior as in Lazarus. Here are the signatures for the functions exported by the library: TgetDicomImage = function(const ADicomImage: Pointer; out buffer: Pointer; out bufSize: longint; ALeft, ATop: double; var AWidth, AHeight: double): integer; cdecl; TdeleteBuffer = procedure(ABuffer: PByte); cdecl; And here is a snippet of the code I use to test the function: Pointer(lGetDicomImage) := GetProcAddress(lLibHandle, 'getDicomImageBufferEx'); Pointer(lDeleteBuffer) := GetProcAddress(lLibHandle, 'deleteBuffer'); for I := 0 to 1000 do begin if @lGetDicomImage nil then
if lGetDicomImage  nil then

What mode are you using? Delphi?

Show quoted text 15 lines
begin lWidth := 900; lHeight := 400; lBuffer := nil; lBufSize:= 0; if lGetDicomImage(lDicomImage, lBuffer, lBufSize, lLeft, lTop, lWidth, lHeight) = 1 then begin // --- buffer processing -- // ... // --- end buffer processing -- if @lDeleteBuffer nil then lDeleteBuffer(lBuffer); // <----- memory keeps increasing here. end;
end;
if lBuffernil then
  lDeleteBuffer(lBuffer);
Show quoted text 37 lines
end; end; For those interested in the C++ functions: int getImageBufferEx(void * imagen, void * &buffer, unsigned long& bufSize, double left, double top, double &width, double &height) { DicomImageHandler * imgHandler = (DicomImageHandler *)imagen; int lResult = -1; if(imgHandler->getDicomImage()->getStatus() == EIS_Normal) { double lZoom = imgHandler->getZoomFactor(); DicomImage * lOrigImage = imgHandler->getDicomImage()->createClippedImage(left, top, width, height, 65535); DicomImage * clippedImage = lOrigImage->createScaledImage(lZoom); width = clippedImage->getWidth(); height = clippedImage->getHeight(); bufSize = clippedImage->getOutputDataSize(); buffer = new Uint16[bufSize]; if(clippedImage->getOutputData((void *)(buffer), bufSize, 8)) lResult = 1; delete clippedImage; delete lOrigImage; } return lResult; } void deleteBuffer(void * &buffer) { delete [] (Uint16 *)buffer; buffer = NULL; } Please, tell me if you find something that can be causing the memory leaks.

Mattias

Reply by email

Leonardo M. Ramé
to Mattias Gaertner
Mattias Gaertner wrote 37 lines
On Wed, 11 May 2011 15:35:40 -0300 Leonardo M. Ram? wrote: > Hi, I'm using a C++ library created by me, with a function that let me get an image buffer. > I use that buffer to do some processing, then I can tell the library to delete the buffer. > > In Linux, I never had an issue between my Lazarus program and that > library, but yesterday I decided to port it to Windows, and found the > buffer is never deleted, causing a "Microsoft Visual C++ Runtime > library, runtime error....". The library is compiled with Mingw32. > > After having found the error, I created a C++ program that calls the > problematic method 1000 times, and noted the memory is handled > correctly, then I made a simple FPC program that does the same thing, > and found the same behavior as in Lazarus. > > Here are the signatures for the functions exported by the library: > > TgetDicomImage = function(const ADicomImage: Pointer; out buffer: Pointer; > out bufSize: longint; ALeft, ATop: double; var AWidth, AHeight: double): integer; cdecl; > > TdeleteBuffer = procedure(ABuffer: PByte); cdecl; > > > And here is a snippet of the code I use to test the function: > > > Pointer(lGetDicomImage) := GetProcAddress(lLibHandle, 'getDicomImageBufferEx'); > Pointer(lDeleteBuffer) := GetProcAddress(lLibHandle, 'deleteBuffer'); > > for I := 0 to 1000 do > begin > if @lGetDicomImage nil then if lGetDicomImage nil then What mode are you using? Delphi?

No, I'm using objfpc.

Show quoted text 8 lines
> if @lDeleteBuffer nil then > lDeleteBuffer(lBuffer); // <----- memory keeps increasing here. > end; end; if lBuffernil then lDeleteBuffer(lBuffer);

I don't understand this. Do you mean, I should call lDeleteBuffer aftert the "end;" that closes the loop?.

Reply by email

Kostas Michalopoulos
to Leonardo M. Ramé: Hi, I'm using a C++ library created by me, with a function that let me get an image…

I think that using a "@" before the function pointer variable returns the variable's address not the function's and that the "@" is needed only for functions, ie.

function Foo: TBar;

...

;

will assign to FooRef the address of Foo, but

;

will try to assign to OtherFooRef the address of the FooRef variable (not the address stored in the FooRef variable - that is, the address of Foo) but fail at compilation time since OtherFooRef is supposed to be of type of whatever Foo is, not a pointer to that type.

However if you just check for nil this won't be noticed since by typing

if @FooRef nil ...

is like saying "if FooRef's address is not nil" instead of "if the address stored in FooRef is not nil". So basically you need to get rid of those "@"s.

Also personally i prefer to use the Assigned built-in function like

if Assigned(FooRef) ...

instead of

if FooRef nil ...

Kostas "Bad Sector" Michalopoulos

Reply by email

Mattias Gaertner
to Leonardo M. Ramé: No, I'm using objfpc. I don't understand this. Do you mean, I should call lDeleteBuffer…
Show quoted text 8 lines
[...] > > if @lGetDicomImage nil then > > if lGetDicomImage nil then > > What mode are you using? Delphi? No, I'm using objfpc.

Then the "if @lGetDicomImage nil then" is a tautology.

Show quoted text 10 lines
> > if @lDeleteBuffer nil then > > lDeleteBuffer(lBuffer); // <----- memory keeps increasing here. > > end; > > end; > if lBuffernil then > lDeleteBuffer(lBuffer); I don't understand this. Do you mean, I should call lDeleteBuffer aftert the "end;" that closes the loop?.

Yes. The C code was not enough to be sure about the state of lBuffer.

BTW, I'm not sure about the "out" in cdecl. Better use the real equivalent "var".

Mattias

Reply by email

Leonardo M. Ramé
to Mattias Gaertner
Mattias Gaertner wrote 13 lines
On Wed, 11 May 2011 19:49:15 -0300 Leonardo M. Ram? wrote: >[...] > > > if @lGetDicomImage nil then > > > > if lGetDicomImage nil then > > > > What mode are you using? Delphi? > > No, I'm using objfpc. Then the "if @lGetDicomImage nil then" is a tautology.

Then, how should I check if the function is part of the library?.

Show quoted text 18 lines
> > > if @lDeleteBuffer nil then > > > lDeleteBuffer(lBuffer); // <----- memory keeps increasing here. > > > end; > > > > end; > > if lBuffernil then > > lDeleteBuffer(lBuffer); > > I don't understand this. Do you mean, I should call lDeleteBuffer aftert > the "end;" that closes the loop?. Yes. The C code was not enough to be sure about the state of lBuffer. BTW, I'm not sure about the "out" in cdecl. Better use the real equivalent "var".

Thanks.

Reply by email

Leonardo M. Ramé
to Kostas Michalopoulos: I think that using a "@" before the function pointer variable returns the variable's…
Kostas Michalopoulos wrote 35 lines
I think that using a "@" before the function pointer variable returns the variable's address not the function's and that the "@" is needed only for functions, ie. function Foo: TBar; ... ; will assign to FooRef the address of Foo, but ; will try to assign to OtherFooRef the address of the FooRef variable (not the address stored in the FooRef variable - that is, the address of Foo) but fail at compilation time since OtherFooRef is supposed to be of type of whatever Foo is, not a pointer to that type. However if you just check for nil this won't be noticed since by typing if @FooRef nil ... is like saying "if FooRef's address is not nil" instead of "if the address stored in FooRef is not nil". So basically you need to get rid of those "@"s. Also personally i prefer to use the Assigned built-in function like if Assigned(FooRef) ... instead of if FooRef nil ...

Thanks. Fixed.

Reply by email