Thread Handle leak (gdiplus related) when tms unit used with a pdf library

Hi,
Windows 10x64
Delphi 10.4.2
Vcl UI Pack 10.5.3.0

Other 3rd party components required to reproduce:
PdfiumLib (source code at https://github.com/ahausladen/PdfiumLib)
pdfium.dll (pre-compiled version at https://github.com/bblanchon/pdfium-binaries)

I have a hard to understand thread handle leak in AdvGDIPlusClasses.pas InitializeGdiPlus.
I get this leak report using madExcept.

I will start by saying that
- if I use tms without the pdf stuff it doesn't leak.
- if I use the pdf stuff without tms it doesn't leak.

To reproduce:
Create a new win32 vcl project
Add the unit PdfiumCtrl to the uses clause.

Add a button with code:

	var
	  p: TPdfControl;
	begin
	  p := TPdfControl.Create(nil);
	  p.Free;
	end;

Scenarios:

  • Start the project, click the button and close it --> no leak
  • Add the unit AdvToolBar to the uses clause, start the project and close it (do not click button) --> no leak
  • Add the unit AdvToolBar to the uses clause, start the project, click the button and close it --> leak
  • AdvToolBar could be replaced with AdvGlowButton and give the same results.

I will include the madExcept leak report at the end. The last Delphi code before going into gdiplus.dll is AdvGDIPlusClasses / InitializeGdiPlus / GdiplusStartup(gdiplusToken, @StartupInput, nil);

Is there something you can do on your end to avoid this leak?

Thanks

Leak report:

allocation number: 3040
program up time: 260 ms
type: Thread Handle
handle: $a74
access rights: $1fffff
threadId: $4d4
processId: $36f0
process exe: C:\TFS\Embarcadero\Studio\Projects\TestLeakTmsPdf\Win32\Debug\Project1.exe

thread $2a08:
671aaa76 madExcept32.dll madExceptDbg       4055 CreateThreadCallback
004b0f73 Project1.exe    madExcept               HookedCreateThread
6cb542fd gdiplus.dll                             GdiplusStartup
0073a28b Project1.exe    AdvGDIPlusClasses  7759 InitializeGdiPlus
007dde92 Project1.exe    AdvGDIPlusClasses  7772 initialization
0040a5e6 Project1.exe    System            23832 InitUnits
0040a64f Project1.exe    System            23907 @StartExe
004126a2 Project1.exe    SysInit            1535 @InitExe
007e0f33 Project1.exe    Project1             14 initialization
75c46357 KERNEL32.DLL                            BaseThreadInitThunk

Is this PdfiumCtrl doing anything with GDI+?

Hi,
PdfiumLib itself doesn't seem to use gdi+. I have the same leak if I use another pdfium wrapper.
The pdfium dll itself uses gdi (pretty sure it's not gdi+).

If I had to take a rough guess, I would say that something invalidates the gdiplusToken obtained in the initialization section of AdvGDIPlusClasses.pas so the finalization section is unable to free the resource properly.

Is this leak report from Delphi, i.e. with ReportMemoryLeaksOnShutdown = true?

The leak report is from Delphi using madExcept.

ReportMemoryLeaksOnShutdown doesn't report anything because I think it doesn't doesn't monitor resource leaks but only memory leaks.

Good morning,
I was just writing a piece to report something very similar when I read this comment.
I get a similar message in EurekaLog.

Piece of code:
Var
Image: TUIImage;
ImgProps: IImageProperties;
Scalefactor: real;
hImageWidth: Integer;
hImageHeight: Integer;
tmpStream: TMemoryStream;
bm: TBitmap;

//Create a new Excel file with 3 sheets.

With xls do
begin
…….

bm := TBitmap.Create;
tmpStream := TMemoryStream.Create;

{Zet TGraphic uit container om naar TBitmap}
bm.Width := PictureContainer1.Items[9].Picture.Width;
bm.Height := PictureContainer1.Items[9].Picture.Height;
bm.Canvas.Draw(0, 0, PictureContainer1.Items[9].Picture);

bm.SaveToStream(tmpStream);
tmpStream.Position := 0;
Image := TUIImage.FromStream(tmpStream);

try
  Image := TUIImage.FromStream(tmpStream);

  ImgProps := TImageProperties_Create();
  ImgProps.ShapeName := 'JBT';
  ImgProps.PreferRelativeSize := false;
  ImgProps.LockAspectRatio := true;

  hImageWidth := 300;
  Scalefactor := hImageWidth / Image.WidthInPoints;
  hImageHeight := Round(Image.HeightInPoints * Scalefactor);

  ImgProps.Anchor := TClientAnchor.Create(TFlxAnchorType.MoveAndDontResize,
    2, // row 2
    1, // 1 pcx lager !
    2, // col 2    => B3
    0, // Linker bovenhoek op B3 en 1 pcx lager
    hImageHeight, hImageWidth, dmflExcel.Xls);

  AddImage(Image, ImgProps);
finally
  TClientAnchor.Null;  //??
  tmpStream.Free;
  bm.Free;
  ImgProps := nil;
  Image.Free;
end;

When closing my program Eurekalog pops up with a memory leak message.

Pointing to unit _GDIPlusGraphicsFactory;
{$INCLUDE _GDIPlusGraphicsFactory.inc}

image

With kind regards,
Frans

Delphi 10.4.1
TMS VCL UI Pack 10.5.3.0
TMS Flexcel v7.8.0.0
Eurekalog 7.9.2.0 Enterprise

Hi Frans,
in your code sample you have Image := TUIImage.FromStream(tmpStream); twice back to back.
Maybe this could explain the TGdipUIImage leak?

Oh, no .... I'm so ashamed.
I've been looking for the leak for a week and have been looking over it all this time. The problem has been solved and of course I am very happy with your comment!
Thank you very much.

With kind regards,
Frans

Hi,
any news on a possible fix for the reported issue?

Thanks

Based on the previous post, I thought this issue was found & solved...?

It is not solved. The previous post was from another user with an unrelated issue.

We would appreciate if there was a reproducible case where only standard VCL + TMS components is involved, so there is a certainty this is really an issue in our code.

I am not able to reproduce with only VCL + TMS components.
All I can say is that I do not get this issue if I use the pdf component without TMS.

I only get the leak when TMS and the pdf controls are involved together.

Hi,
Just to be sure we are not in a stalemate, can you please tell me if you are going to investigate or not?

Let's say the author of the pdf library asks for an example without TMS before investigating this would create a catch-22 because I only get the issue when both are used together.

Also, the pdf library source is freely available. TMS source is not so the pdf library author would have no way to investigate and me providing him the source code would be illegal.

I tried to provide the simplest reproductible example to show the issue while keeping the source code of both products in their own respective black box.

Looking at the TMS source code, I can see that gdi+ is loaded and unloaded in the initialization and finalization of AdvGDIPlusClasses.pas

This would point me at investigating TMS first since the lifetime scope is larger. The leak only happens once so it would make sense to be related to the initialization and finalization that is invoked only once.
If the leak was multiplied for each invocation of the pdf library I would look the other way but this isn't the case.

I understand this could be a complex issue to resolve but I want to avoid, or at least know, if we are in a stalemate.

Thanks for your time

If this proves to be a problem outside our code, who will pay the cost for our investigation?

If you do not want to investigate please just say so and I will move on.

I will only say this toxic sentence because you asked, but to answer your question, your licensing faq says "Free priority support through email and forum" and I don't think we have abused your support enough to deserve this reply.

Now to be constructive, I noticed that if I comment out the following lines in AdvGDIPlusClasses.pas I do not get the leak anymore and did not notice any kind of crash (only did a quick test).

initialization part:

  if not IsLibrary then
	InitializeGdiPlus;

and

finalization part:

  if not IsLibrary then
	FinalizeGdiPlus;

So maybe this gdi+ initialization / finalization is OS related and not needed anymore, at least in windows 10 x64?. Surely you can help confirming this and make the required changes if this proves to be true?

Do you remember your own blog post about qq => qa? I would suggest you have a look at it again.

one of the pillars of what we want to offer as a company is first-class technical support for our products

Every time I post an issue I try my best to make it as clear and simple as possible.
It may not be perfect but I believe it was still a qq and I sadly do not have the feeling I got a qa. Actually, the last answer made me QQ.

This post is about the concepts of gdi+ and gdi+ tokens that I am clearly not familiar with.
Investigating this also requires knowledge of the TMS code base and I tried to give a few hints where the problem could originate.

Thanks for your time

We do offer free priority support and we have been doing this for the past 26 years, for the code that we write. We have to draw a line somewhere. And this line is : our own code + standard Delphi/C++Builder.
Even when drawing this line, we have over the past 26 years spent thousands of hours in investigating issues that eventually came down to issues in the IDE, the VCL, FMX library, Windows operating system and have not directly something to do with our code.
We do offer a QA for every QQ within this territory. If something cannot be reproduced using our code + standard Delphi IDE and standard libraries, it is impossible to investigate this for free.