debug delphi application / DLL called inside a thread - delphi

problem description :
..... ( this code is executed inside a thread.execute
...
if fileexists(myFile) then
begin
// call functions inside a DLL
...
dll_process_data ( .....) ;
....
end;
..... (clean up )
write_clean_data_fct(...)
..... //
... // AV happens here inside kernel.dll , no further information
If the file is not found the complete routine / multithreaded algos is executed without any problem; If i add the additional files some data is processed inside a dll, this is also done without trouble.
Somewhere after the write_clean_data_fct the AV happens now. INside the dll I open a file read data and do data processing with these data.
Q: what might be the reasin and how to debugg this issue ??
Can#t post more lines of code because the complete code sequence is ~ 15.000 LOC.

You can debug the DLL like this:
Open the DLL project in your IDE.
Make sure the host is going to load the DLL from the same path as your DLL project's output directory.
Set a break point on the function you wish to debug.
From the menu select Run | Host application and specify the host executable.
Run.
You should now be able to debug code in the DLL. In modern versions of Delphi, you should also be able to step into the DLL code when debugging the host executable. This requires you to have built the DLL with debug information, and for the host executable to load the DLL from the DLL project's output path.
Your actual problem sounds a little tricky. The access violation perhaps occurs long after the erroneous code executes. To debug that, you might first identify the code that raises the exception. Which part of that code has a pointer that could be invalid? Then track back to anything in the DLL that could have modified that pointer.
If static analysis does not help then you can add debugging tools. You'll want:
Range checking enabled to detect obvious buffer overruns.
Full FastMM debug to detect heap corruptions, access after free etc.
madExcept to give detailed diagnostics and stack traces for the actual exception.
You'll want these tools in all modules.

Related

can't debug datamodule in DLL at application server delphi

I wanted to debug a data module that I've created and which is a part of a DLL, but for some reasons, I can't debug it. The debugger doesn't seems to be hitting the break point, is there a way i can debug my Dll/ data module.
Check list:
be sure your DLL have included debug info
if it's COM DLL - be sure it is registered on same place where you build it
try to rebuild the DLL, rebuild the App if you have changed the interface
check in EventLog when debugger loads the DLL does it says it have or dont have debug info.
To debug the DLL, the project loaded in Delphi must be the DLL itself. You enter a host application (Your application server executable), the one which will load the DLL. Make sure the host application load the DLL exactly where you have built it. You cannot move the DLL once constructed.
If the DLL must be in some fixed place, be sure to set the DLL's project options so that the DLL is produced at the right place.
And of course you must activate the debug build configuration for the DLL.
Using a tool such as ProcessExplorer (https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer), you can see if the DLL you built was actually the one loaded by your application server.

Memory management issues between InnoSetup and Delphi DLL

Situation:
a DLL that:
is written and compiled with Delphi XE3 32bit
exports a function that displays a modal VCL-form:
function EditOptions(AIniFileName: PAnsiChar; ALCID: Integer): Boolean; stdcall;
is also a COM-server
an installer created with InnoSetup 5.5.4:
imports said DLL function via external 'EditOptions#files:mydll.dll stdcall'-directive and calls it when needed
explicitly unloads the DLL before registering the COM server via the Inno utility function UnloadDLL
Problem:
When...
Windows is using a theme other than Classic
the modal dialog from the DLL is displayed during installation
the installer hangs upon unloading the DLL
no error messages are shown
logs indicate no runtime exceptions
Please note that to keep this brief, I deliberately left out the explanations for some of the more idiosyncratic details, e.g. why I'm explicitly unloading the DLL or why a COM server needs to have custom exports. Let me know if you think these details would be relevant and should be added.
To further analyse this I created a dummy host EXE that calls the DLL function so I can easier run the whole thing in the debugger. Doing so leads to an AV being raised in TUxThemeStyle.UnloadThemeData on the line that calls CloseThemeData(). When placing a breakpoint directly on that line and stepping forward from the stop, I actually get a "too many consecutive exceptions" error eventually. I can only reproduce the error when I enable runtime themes for the host EXE.
Going back through our git history it appears that this issue exists ever since we switched from Delphi 2010 to XE3 (unfortunately, the installer was not part of our regular test suite so this only cropped up now as work on the actual release comes to a close as the DLL exports exist exclusively for the benefit of the installer).
Any ideas what might be causing this? Could this really be theme-related (I have no custom theme-related code in this project) or is that maybe just a symptom of memory corruption caused somewhere else entirely? E.g. I once had an error that manifested in the form of AVs in the theme tear-down code before but in that case it actually turned out to be caused by the leaking of anonymous method references from initialization sections...
Update: I've worked hard trying to produce a dumbed-down sample project to demonstrate the issue in isolation but so far without luck. I have managed to narrow down a few more things, though. First, here are some more facts about the code:
The dialog I'm showing is a third-degree descendant of TForm. The ancestors accomplish several things:
TAppModalDialog implements a special constructor CreateOnTop that ensures it appears as the topmost window in the current process (the project is a plugin that loads into multi-windowed third-party hosts that do unfortunately not communicate their window handles for use as modal parents) - it accomplishes this by manipulating the global Application.Handle.
TTabbedDialog is part of an interface-based framework that allows registration of "pages" (actually TFrame-descendants) via a factory pattern - at runtime the form will dynamically create TTabSheets in a TPageControl and instantiate and parent the registered page frames to them
I've replaced the call to the actual dialog with a dummy, gradually working myself through the inheritance chain from a blank TForm up to my TAppModalDialog and eventually to my TTabbedDialog class. The problem only starts to occur at that last level. I also commented out all page registrations around the project so that the dialog comes up with an empty page control (this rules out code in any of the pages as the cause for the problem). I then commented out all code and data members in the routines of the TTabbedDialog class itself, leaving only empty method bodies to fulfill the interface implementation requirement and the TPageControl component (along with two empty TImageLists and a TBalloonHint component) -> the error still occurs.
I then copied the call to the dummy dialog into a new DLL project that contains nothing else but this and the tabbed dialog framework. If I load that DLL into my dummy host EXE, the problem does not occur anymore... sigh
So, my suspicion is still that there must be some sort of memory corruption occuring somewhere else entirely and the error I see is only a symptom of that. So the real question is how can I finally get to the bottom of this?
I will now continue by commenting out / removing bits from the production DLL...

how to debug a 64 bit dll registration process made with regsvr32.exe?

i have
Run time Error 216 at ADDRESS
when registering a 64 bit dll built with Delphi XE2 (I have Update 3).
from command prompt I do (note: system32 folder contains the 64bit exe!)
c:\windows\system32\regsvr32.exe My64bitdll.dll
and after a "dll succesfully installed message"
i have the runtime error.
I would like to debug the registering process, somehow using Run/Parameters/host.
Could anyone post the correct procedure? In some other questions like this one a bug is mentioned, but it seems fixed now, i have a delphi build older than this one.
Update:
Also any comment on the RunTime error is welcome.
Load the DLL project.
Modify run parameters (Run | Parameters) to specify host app as regsvr32. Note that you may need to use C:\Windows\sysnative path to defeat the 32 bit file system redirector.
Include path to DLL as command line arguments.
Perhaps enable Debug DCUs, in case the error is raised in the Delphi COM self-registration code.
Then debug the DLL like any other DLL.
Runtime error 216 is an access violation.
1) this runtime error may be just program exit. For example would you debug internals of DllMain, you can easily get past exit point and try to trace ended DLL, which would through RE. Process exit is not looking just like return from subroutine - but rather as a call to special system API function. But debugger does not understand it and continues to trace now dead project.
2) i see not point in using RegSvr32.exe or TRegSvr.exe for debuging. All RegSvr32 does is calling predefined function from DLL. Do you debug your DLL or RegSvr32 itself ?
2.1) If latter - i heard there are sources of RegSvr32, and probably there are debug symbols, but some Microsoft debugger to be used.
2.2) If former, then there should be now difference how to call those functions and you only have to debug those functions. Just take any code from File not found when registering DLL with TFileRun and regsvr32 and use it as host.

External exception is thrown in function when using DLL's from not application folder

I have a problem which I do not understand. I am using a DLL in my application. This DLL requires other DLL's and I have all of them. If I put the libraries in my appliction folder everything works fine.
However, having a bunch of DLLs in application folder looks quite ugly so I wanted to move them to application\lib subfolder.
After this change now I am getting External Exception when I try to use some of its functions.
I've only changed one line of code:
The original code
DLLHandle := LoadLibrary(Pchar(ExtractFilePath(ParamStr(0)) + 'External.dll'))
The code after change
DLLHandle := LoadLibrary(Pchar(ExtractFilePath(ParamStr(0)) + 'lib\External.dll'))
In both cases DLLHandle have a handle after loading the library. I am also not getting any error after calling GetProcAddress( DLLHandle, '_SomeFunction#8')
No exceptions, and return value of GetLastError is always 0.
Do you have any idea what could be wrong?
Thanks.
Life is far easier if you keep the DLLs in the same folder as the executable. That's the first folder searched when libraries are loaded. To move all the DLLs into a sub folder of the executable directory requires cooperation from all DLLs.
Most likely you have secondary DLL dependencies that are not cooperating. So exe loads A fine, but then A fails to load B. You can debug this further with Dependency Walker running in profile mode. It's quite possible that a secondary DLL is being loaded with implicit linking and that this throws and exception. Whatever the cause, Depenency Walker will lead you to the problem.
Whilst you can modify the PATH variable this is generally not advisable. If you do choose to go down this route then don't modify system wide, just modify the executable process environment at runtime before the first LoadLibrary. This is tenable so long as all your DLL linking is explicit using GetProcAddress.
All accepted wisdom recommends that you put your DLLs in the same folder as your executable. I would echo this recommendation. If you did this then you would be able to use implicit linking which would greatly simplify your code.
Yet another option may be to abandon DLLs and link everything straight into your executable. Unless you have a plugin type architecture, a single big exe is by far the simplest approach.
The other DLL's that need to be loaded must be on the system path for Windows to find them. Your application can find the External.dll as you explicitly define the path. Try adding the lib folder to your system path.

External exception C0000006

I've wrote some program in Delphi and when I am running it from a disk on key. At some point I'm required to unplug the disk on key while the application is running. If I do this on a computer with at least 1gb of ram everything is okay. When I do this on a machine with 512mb I get an external exception C0000006. If I'm not mistaken, this is because the OS is trying to read the next line of code but cannot find the resource for it (meaning, the application wasn't loaded to the ram) which is absurd because it's a 500kb application.
How can I solve this? or at least handle this exception in a more elegant way? (Since I can't catch it since it's an external exception).
Oh, and my Delphi application is a console application under windows xp.
What you need to do is tell windows to load your whole program into memory, rather than allowing it to demand load pages when it needs to. I have done this successfully for applications running off a CD. I don't have the code with me right now, but I recall that I found hints on how to do it in source for the fantastic open source install program Inno Setup.
Edit: Actually, after doing a little research, you can use a Delphi compiler directive to tell windows to load the full executable. This works if you have Delphi > 2006. This will have the effect that you will never get the external exception.
Put this line in your applications project file:
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
This tells windows that the executable is going to be used from removable media, so load the the executable into memory (or the swap file). Then you don't need to worry about things like copying the file to the machine first, etc.
Edit 2: I currently have access to Delphi 7 and I can confirm, as noted by others, that this also works with Delphi 7 (and likely Delphi 6) with the following code:
const
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
For Delphi < 6, you can go down the path of forcing the executable to be paged in. There is an example of how to do it in C++ here (unless you find a way to modify the PE header flags after link time, which looks to be complicated)
N#
That's EXCEPTION_IN_PAGE_ERROR. It means that the OS loader failed to page in some data required for the application to run, probably due to an I/O error or other error. Since you're removing the disk, that would make sense.
Perhaps the working set (the set of often-used memory pages) for the application was allowed to grow large enough on 1GB machines such that recourse to the disk to reload pages wasn't necessary, but that wasn't the case on 512MB machines?
I would suggest trying to copy the executable to a temporary location and starting it from there, possibly with delayed deletion; or use some other mechanism to guarantee on-disk backing for all memory pages touched by the application in normal use, and prevent this error in cases of memory pressure, where the OS will trim the working set of running processes.
Like #Barry, I would recommend checking the drive type of the volume that your executable is running from; if it is a removeable drive (and missing a "already in temp" command line parameter) copy the executable (and any of its dependencies) to the user's %TEMP% folder and then re-launch it from there with an extra command line parameter to indicate "already in temp".
Create each temporary file using File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose) (or one of the FileStream constructors that takes a FileOptions parameter), but make sure to hang onto the returned File instance until after the second copy is launched (e.g. in a List<File>).
Copy the contents of each file.
Launch the executable from the temp folder.
Call Close() on each of the File instances saved above.
Exit the original executable.
This way the files get closed regardless of which process finishes first, and the source volume can be removed earlier.
The solution
uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}
is available for Delphi since version 6.
There's a Delphi working version of RunImageLocally from MSJ which forces the executable/dll to be paged in. This can prevent C0000006 errors when running from network or removable media...
Check it out at https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr
This exception C0000006 also often occurs if your software is run from a network drive. To prevent that problem you can combine the flag
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
with the following flag:
IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;
{$SetPEFlags $0C00}

Resources