Program hangs when unloading a DLL making use of GdiPlus - delphi

I have an application which load a DLL that makes use of Delphi GDI+ Library. This application hangs when it unload the DLL (Calling FreeLibrary).
I tracked the issue down to GdiPlus.pas unit finalization section which calls GdiPlusShutdown which never returns.
How to avoid this deadlock?

The documentation for the GdiplusStartup function says this:
Do not call GdiplusStartup or GdiplusShutdown in DllMain or in any
function that is called by DllMain. If you want to create a DLL that
uses GDI+, you should use one of the following techniques to
initialize GDI+:
Require your clients to call GdiplusStartup before they call the functions in your DLL and to call GdiplusShutdown when they have
finished using your DLL.
Export your own startup function that calls GdiplusStartup and your own shutdown function that calls GdiplusShutdown. Require your clients
to call your startup function before they call other functions in your
DLL and to call your shutdown function when they have finished using
your DLL.
Call GdiplusStartup and GdiplusShutdown in each of your functions that make GDI+ calls.
By compiling this Delphi GdiPlus library into a DLL you are breaking this rule for both GdiplusStartup and GdiplusShutdown. These functions are called in unit initialization and finalization sections, respectively. And for library projects, code in the initialization and finalization sections of a unit is executed from DllMain.
It seems that the GdiPlus library that you use was never intended to be used from a library. But as a general rule, when writing library code, you should be aware of the restrictions around DllMain and make sure that code that you place in initialization and finalization sections respects that. I think that this GdiPlus library fails in that regard.
By way of contrast, have a look at the code in the Delphi RTL's WinApi.GDIPOBJ unit:
initialization
if not IsLibrary then
begin
// Initialize StartupInput structure
StartupInput.DebugEventCallback := nil;
StartupInput.SuppressBackgroundThread := False;
StartupInput.SuppressExternalCodecs := False;
StartupInput.GdiplusVersion := 1;
GdiplusStartup(gdiplusToken, #StartupInput, nil);
end;
finalization
if not IsLibrary then
begin
if Assigned(GenericSansSerifFontFamily) then
GenericSansSerifFontFamily.Free;
if Assigned(GenericSerifFontFamily) then
GenericSerifFontFamily.Free;
if Assigned(GenericMonospaceFontFamily) then
GenericMonospaceFontFamily.Free;
if Assigned(GenericTypographicStringFormatBuffer) then
GenericTypographicStringFormatBuffer.free;
if Assigned(GenericDefaultStringFormatBuffer) then
GenericDefaultStringFormatBuffer.Free;
GdiplusShutdown(gdiplusToken);
end;
This code respects the rules by making sure that it does not call GdiplusStartup and GdiplusShutdown from DllMain. Instead it leaves the onus on the author of any library that uses WinApi.GDIPOBJ to make sure that GdiplusStartup and GdiplusShutdown are called at appropriate times.
If I were you I would pick one of the three bullet point options listed above. The third of these options is not very practical, but the first two are good choices. Were it me, I would opt for the first option and modify the initialization and finalization code in your GdiPlus library to look more like that found in WinApi.GDIPOBJ.

GdiPlusShutdown (and GdiPlusStartup btw) cannot be called from DllMain but DllMain is called by Windows and Delphi runtime when FreeLibrary is called: Delphi call the finalization section of all units used by the DLL and GdiPlus finalization section calls GdiPlusShutdown (This is perfectly OK when used from an executable). Similar behavior with initialization section.
I have fixed the issue by adding a test for IsLibrary in both initialization and finalization sections to avoid calling the offending functions, also added two public procedures InitializeForDll and FinalizeForDll. With those little changes, the DLL is able to export functions calling InitializeForDll and FinalizeForDll. Those exported function have to be called by the hosting application right after loading the DLL and just before unloading the DLL.
Here are the changes I made to GdiPlus.pas:
In the interface section:
var
procedure InitializeForDll;
procedure FinalizeForDll;
In the implementation section:
procedure InitializeForDll;
begin
Initialize;
end;
procedure FinalizeForDll;
begin
Finalize;
end;
Also updated the initialization and finalization sections like this:
Initialization
if not IsLibrary then
Initialize;
Finalization
if not IsLibrary then
Finalize;
In the DLL, I exported those functions:
procedure Initialize; stdcall;
begin
GdiPlus.InitializeForDll;
end;
procedure Finalize; stdcall;
begin
GdiPlus.FinalizeForDll;
end;
Initialize and Finalize are called by the hosting application right after calling LoadLibrary and just before calling FreeLibrary (Or whatever will load/unload the DLL).
I hope this will help others.
btw: Thanks to Eric Bilsen for providing Delphi GdiPlus Library

Related

Dynamicly handle not defined functions in a dll in dlephi

I have a dll which defines a simple functions to show a message:
library testdll;
uses SysUtils, Classes, Dialogs;
{$R *res}
procedure ShowDll;stdcall;
begin
ShowMessage('ShowDLL testdll.dll');
end;
exports ShowDLL;
begin
end.
And my main file call this dll dynamicly using this procedure:
i defined a new type:
type
testdll = procedure;stdcall;
Then on my button click event:
procedure TForm1.Button1Click(Sender:TObject);
var
dllHandle: THandle; //Don't use Cardinal; it's limited to 32-bits
test : testdll;
begin
dllHandle := LoadLibrary('testdll.dll');
if dllHandle <> 0 then
begin
#test := GetProcAddress(dllHandle,'ShowDLL');
if Assigned(test) then
ShowDLL
else
ShowMessage('Func not found');
end
else
ShowMessage('dll not found');
end;
This works. But I don't know if it's possible to handle not defined functions with my dll. My purpose here is to call a function without knowing if it will be defined in my dll. So i would like the dll to tell me if the functions exists or not.
For example here i only have a ShowDLL procedure. If i call another method which does not exists it will show 'Func not found' from my main application. But i would my dll to tell me this. Is this possible? If yes, how could i achieve this pls?
EDIT: I can't modify the main function this is only a test. In my final version there will be only the dll. So exporting all functions into my main application is not possible here. That's why i want to know id the dll alone can handle it rather than doing this in my main application which i can't do.
I don't have acces to the main application to modify any code in it. I only know what are functions that will be used in this application that i will later export in my dll using exports statement. So what i try to achieve is to catch a not defined function with the dll if it's possible.
Your code already demonstrates how to detect the presence of an export. Namely to call GetProcAddress and compare the result with nil.
You can reduce the amount of boiler plate code by using delay loading. This essentially lets the compiler generate the code the performs the checks. This relies on the delayed keyword.
procedure testdll; stdcall;
external 'testdll.dll` delayed;
When you call this function, if it cannot be found, an exception is raised. Indeed this behaviour can be customised, as described in the documentation: http://docwiki.embarcadero.com/RADStudio/en/Libraries_and_Packages#Delayed_Loading
Update
In a comment to this answer you state that the executable cannot be changed. In which case, the message that you wish to avoid will be shown if the function is missing. You ask if the missing export can be handled by the DLL but that is not possible. When you call GetProcAddress, no code inside the DLL is executed. All the processing is done external to the DLL by reading its PE metadata.
The obvious conclusion is that the DLL must export the function. If the true DLL does not, put another DLL in its place. Use an interposer DLL that exports the function. Implement the function by delegating to the true DLL, if the true DLL exports the function. Otherwise do something else, whatever you please.

Finalization of a log unit called too early

I am running a ISAPI service which runs with IdHTTPWebBrokerBridge (for debugging as standalone EXE) as well as in Apache with mod_isapi (in productive enviroment).
While logging some stuff at the destruction of the web module, I found following problem:
unit LogFactory;
...
initialization
GlobalLogFactory := TMyLogFactory.Create;
finalization
FreeAndNil(GlobalLogFactory);
end.
-
unit MyWebModuleUnit;
...
uses LogFactory;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
Assert(Assigned(GlobalLogFactory)); // <-- failure
GlobalLogFactory.GetLogger('D:\test.txt').LogLine('test'); // <-- Nullpointer Exception
end;
LogFactory.pas creates the object GlobalLogFactory on its initialization and destroys it on its finalization.
But LogFactory.pas:finalization gets called BEFORE TMyWebModule.WebModuleDestroy , since it was included by this unit only, and so the finalization will be done in reverse order.
How can I ensure that my GlobalLogFactory will be correctly freed (i.e. FastMM will not warn about a memory leak), but at the same time, I want to give all destruction/finalization-procedures the chance to log something?
One Workaround would be to include LogFactory.pas explicitely in the DPR file as the first unit. But I don't like that very much, since this Log-Unit should be used in many projects and it should be useable by simply including it in the unit where you need to log something. Putting this log unit in every DPR which might want to log something in future, is a big effort and forgetting it might cause problems for the developers who are not knowing what I did/require.
Instad of using a class instance in a global variable use an interface and a function to get that.
unit LogFactory;
interface
type
ILogFactory = interface
[{GUID}]
function GetLogger(...) : TLogger;
...
end;
TLogFactory = class( TInterfacedObject, ILogFactory )
function GetLogger(...) : TLogger;
end;
function GlobalLogFactory : ILogFactory;
implementation
var
_LogFactory : ILogFactory;
function GlobalLogFactory : ILogFactory;
begin
if not Assigned( _LogFactory ) then
_LogFactory := TLogFactory.Create;
Result := _LogFactory;
end;
{ TLogFactory Implementation }
initialization
// nothing needed
finalization
// nothing needed
end.
There is no need for any initialization or finalization at all.
If you want
Any unit in your program to be able to log, and
Logging to be available during finalization, and
The logging code to require tidy up,
then you don't have many options. One option is to include the log unit very early in the .dpr file. I don't know why you regard that to be a problem. It's the standard way to achieve your goals. It's the technique used by external memory managers for example. Delphi developers are familiar with the concept. You tell the developers what they need to do, and if they don't follow your instructions, the program does not work. That is their problem.
If you still cannot face doing it this way then I see one alternative. Arrange for the logger initialization to happen before any other initialization in your code. And the finalization after all other finalization. You can do that by putting the logger implementation into an external module that is linked with load time linking.

How can i tell if i'm being called during DLL_PROCESS_DETACH after ExitProcess has been called?

i have a unit in Delphi that (has the option) to provide a single global object:
var
InternalThemeParkServices: TThemeParkServices;
function ThemeParkServices: TThemeParkServices;
begin
if InternalThemeParkServices= nil then
InternalThemeParkServices := TThemeParkServices.Create();
Result := InternalThemeParkServices ;
end;
...
initialization
finalization
FreeAndNil(InternalThemeServices);
end.
And i destroy myself during process shutdown.
Note: Another code variant is:
var
InternalThemeParkServices: IThemeParkServices;
function ThemeParkServices: TThemeParkServices;
begin
if InternalThemeParkServices= nil then
InternalThemeParkServices := TThemeParkServices.Create();
Result := InternalThemeParkServices ;
end;
Where the interface variable is implicitly destroyed when it's
reference count goes to zero during program shutdown
When my object is no longer used (i.e. during its destructor), i call call various WinAPI functions.
The problem is that if someone uses my class from a DLL (something which i cannot control), then anything being called during:
finalization
is the Delphi moral equivalent of DLL_PROCESS_DETACH. There are all kinds of things i should not be doing during DLL_PROCESS_DETACH when the process is terminating (e.g. CoCreateInstance).
i know Embarcadero uses:
initialization
if not IsLibrary then
begin
...
Which i perhaps i could adapt, changing my code from:
var
InternalThemeParkServices: IThemeParkServices;
(using implicit cleanup), to:
var
InternalThemeParkServices: IThemeParkServices;
...
finalization
if IsLibrary then
Pointer(InternalThemeParkServices) := nil; //defeat reference counting and let the object leak
end;
and let it leak.
But is this the best resolution? i assume it means that if the dll running my code is unloaded (but not during process shutdown) that i'll leak memory. If the dll is attached and detached, i'll leak each time.
What i really want is Delphi to run its finalization blocks before ExitProcess/DllMain(DLL_PROCESS_DETACH). Is this possible?
Bonus Chatter
#pa deciphered the Delphi application shutdown scheme:
The hierarchy of shutdown is as follows
Application.Terminate()
performs some unidentified housekeeping of application
calls Halt()
Halt()
calls ExitProc if set
alerts the user in case of runtime error
get rid of PackageLoad call contexts that might be pending
finalize all units
clear all exception handlers
call ExitprocessProc if set
and finally, call ExitProcess() from 'kernel32.dll'
ExitProcess()
unloads all DLLs
uses TerminateProcess() to kill the process
With DLLs being unloaded after a call to ExitProcess - because Windows is the one who does it.
To tell if you're being called during DLL_PROCESS_DETACH after ExitProcess has been called, you can write initialization code for your library so that your code is executed when FreeLibrary is called from the main program. The 'lpReserved' parameter will be '1' if ExitProcess have already been called, '0' otherwise:
..
var
SaveDllProcEx: TDllProcEx;
procedure DllMainEx(Reason: Integer; Reserved: Integer);
begin
if (Reason = DLL_PROCESS_DETACH) and (Reserved = 0) then
// Main app is still running, cleanup.
if Assigned(SaveDllProcEx) then
SaveDllProcEx(Reason, Reserved);
end;
initialization
if IsLibrary then begin
SaveDllProcEx := DllProcEx;
DllProcEx := #DllMainEx;
end;
From DllMain entry point:
The lpReserved parameter indicates whether the DLL is being unloaded
as a result of a FreeLibrary call, a failure to load, or process
termination.
What I really want is Delphi to run its finalization blocks before DllMain(DLL_PROCESS_DETACH). Is this possible?
No it is not possible.
If you need to perform shutdown actions that cannot be done during DllMain(DLL_PROCESS_DETACH) then you will need to add an exported function to your DLL that peforms the finalization. You should then require your DLL's clients to call this function before unloading the DLL. This is the same pattern as CoInitialize/CoUninitialize.

Conversion of a delphi win32 application to a library and FreeLibrary freeze

I have an application which Should be converted to a library. I' ve only copied the project dpr and changed the source file:
library aLibrary;
uses
FastMM4,
Forms,
SysUtils,
Windows,
Mainfrm in 'Mainfrm.pas' {Mainform};
{$R *.res}
Procedure DllMain(Reason: Integer);
Begin
If Reason = DLL_PROCESS_ATTACH Then
Begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
ExitCode := 0;
End;
If Reason = DLL_PROCESS_DETACH Then
Begin
Application.Terminate;
MainForm.Free;
End;
End;
Begin
DllProc := #DllMain;
DllProc(DLL_PROCESS_ATTACH);
End.
As you can see, I've simply removed the usually auto-generated code lines related to the app initialization and put them in the DllMain procedure, changed the 'program' keyword to 'library'.
The dll loads well, the embedded program runs well too, but I can't manage to free it (FreeLibrary) in the host process. The dll freezes, whatever the DLL_PROCESS_DETACH code is (even when nothing is put for this case).
What would be the proper way to free all the application stuffs ?
You're doing way too much in your DLL procedure.
While loading a DLL, the OS acquires the loader lock. That prevents any other libraries from being loaded at the same time. If you call a function that's in a library that hasn't already been loaded, then that will trigger an attempt to load that library. Since you're still inside the loader lock, that other library blocks while attempting to acquire the lock itself, and you get deadlock. Similar rules apply for unloading.
You should do the absolute minimum in the DllMain function to get your library loaded or unloaded. Leave everything else to a separate function that the DLL host can call after loading is complete or just before unloading begins. In your case, the minimum is probably nothing at all.
Ok, I've well understood your summary about dll locks and I've put the embedded application constructor/destructor in some standard exported dll routines, so there 's no more DllMain. However calling freelibrary still reveals a deadlock. My dll is instantiated by another dll, which is itself instantiated in an executable. Maybe the lock is introduced at a lower level in the processes hierarchy.

Unit finalization order for application, compiled with run-time packages?

I need to execute my code after finalization of SysUtils unit.
I've placed my code in separate unit and included it first in uses clause of dpr-file, like this:
project Project1;
uses
MyUnit, // <- my separate unit
SysUtils,
Classes,
SomeOtherUnits;
procedure Test;
begin
//
end;
begin
SetProc(Test);
end.
MyUnit looks like this:
unit MyUnit;
interface
procedure SetProc(AProc: TProcedure);
implementation
var
Test: TProcedure;
procedure SetProc(AProc: TProcedure);
begin
Test := AProc;
end;
initialization
finalization
Test;
end.
Note that MyUnit doesn't have any uses.
This is usual Windows exe, no console, without forms and compiled with default run-time packages. MyUnit is not part of any package (but I've tried to use it from package too).
I expect that finalization section of MyUnit will be executed after finalization section of SysUtils. This is what Delphi's help tells me.
However, this is not always the case.
I have 2 test apps, which differs a bit by code in Test routine/dpr-file and units, listed in uses. MyUnit, however, is listed first in all cases.
One application is run as expected: Halt0 -> FinalizeUnits -> ...other units... -> SysUtils's finalization -> MyUnit's finalization -> ...other units...
But the second is not. MyUnit's finalization is invoked before SysUtils's finalization. The actual call chain looks like this: Halt0 -> FinalizeUnits -> ...other units... -> SysUtils's finalization (skipped) -> MyUnit's finalization -> ...other units... -> SysUtils's finalization (executed)
Both projects have very similar settings. I tried a lot to remove/minimize their differences, but I still do not see a reason for this behaviour.
I've tried to debug this and found out that: it seems that every unit have some kind of reference counting. And it seems that InitTable contains multiply references to the same unit. When SysUtils's finalization section is called first time - it change reference counter and do nothing. Then MyUnit's finalization is executed. And then SysUtils is called again, but this time ref-count reaches zero and finalization section is executed:
Finalization: // SysUtils' finalization
5003B3F0 55 push ebp // here and below is some form of stub
5003B3F1 8BEC mov ebp,esp
5003B3F3 33C0 xor eax,eax
5003B3F5 55 push ebp
5003B3F6 688EB50350 push $5003b58e
5003B3FB 64FF30 push dword ptr fs:[eax]
5003B3FE 648920 mov fs:[eax],esp
5003B401 FF05DCAD1150 inc dword ptr [$5011addc] // here: some sort of reference counter
5003B407 0F8573010000 jnz $5003b580 // <- this jump skips execution of finalization for first call
5003B40D B8CC4D0350 mov eax,$50034dcc // here and below is actual SysUtils' finalization section
...
Can anyone can shred light on this issue? Am I missing something?
Units are finalized in reverse order of initialization. The order of initialization is determined by a non-cyclic (i.e. never descends into an already-visited unit) post-order traversal of the unit uses graph, starting with the main uses clause (in the program or library). SysInit is normally the first unit to be initialized, followed by System.
Dynamic loading of packages complicates things, because the main EXE or DLL gets to specify the order of initialization of the units used by the main image. So when a package is dynamically loaded, it will run what it thinks should be the initialization order, but units already initialized will be skipped; when the package is dynamically unloaded, this happens in reverse.
The general rules:
lower-level things should be initialized before higher-level things
finalization should be in reverse order of initialization
These rules almost always make sense. Higher-level units' initializations often rely on services provided by lower-level units. For example, without SysUtils, there is no exception support in Delphi. Reverse order finalization makes sense for the same reason: high-level finalizations rely on services provided by lower-level units, so they must run before the lower-level units' finalizations.
All that said, with respect to your problem, it sounds like there may be a bug somewhere in the compiler or RTL, if what you say is true: that the main EXE uses MyUnit first, and MyUnit uses no other units in its interface or implementation, and there's no funny business going on with dynamically loaded packages. All I can suggest is to keep paring down the project with the odd behaviour until you have a minimal reproducing sample; at that point, it should be clear exactly what is causing the problem.
I was able to find a reason and I feel myself a bit stupid now :)
My second test application have a static reference to DLL, which was compiled with RTL.bpl (it's empty, except for references to SysUtils and having 1 simple routine). So, since DLL is statically linked, it is initialized before any code from exe have chances to run.
That's it:
DLL's System -> DLL's SysUtils -> exe's System (skipped) -> MyUnit -> exe's SysUtils (skipped) -> etc
Finalizations are in reverse order, leading to execution of MyUnit before SysUtils.
Solution: require to include MyUnit first in all projects.
(oh, how I wish to have a time-machine to travel back in time and force somebody to add OnBeforeMMShutdown event :D )
You're not missing anything. That's exactly what's happening.
When your program loads a package, it will initialize all the units used in that package. When it unloads the package, it has to finalize all the units. But finalization often involves freeing variables. Remember that double-frees are a Bad Thing, especially if they happen during finalization when certain exception-handling features might have been unloaded, making debugging very difficult. So it puts a reference counter on the unit initializations so that they don't get finalized until everything that was using them is done with them.
Is there any particular reason why your MyUnit needs to finalize after SysUtils?
I am not sure but isn't there still the good old ExitProc global variable of Turbo/BorlandPascal fame? If yes, this could solve your problem.

Resources