Application crashes when generating leak reports

delphi package - automated exception handling
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Application crashes when generating leak reports

Post by TByte »

Hiya, I've recently migrated a large application from Delphi 6 to Delphi 7. As my trusty tool over many years, I've put madExcept in and it helped me track down a few exceptions accurately. I noticed, after going into a certain area of the application, on shutdown, FastMM4 was complaining about GetMem being called after FastMM was uninstalled: "FastMM has detected a GetMem call after FastMM was uninstalled." and was followed by a lovely runtime error message "Runtime error 203 at 00402F00". So I've turned on madExcept's leak reporting and found that the application crashes during leak report generation. It looks like it's happening right at the end of the process, when it says "creating leak report..." and the progress bar is full. It then disappears and nothing else happens. I've noticed the Event Viewer is immediately populated with 2 entries:

Faulting application name: FM.exe, version: 3.35.10.6, time stamp: 0x2a425e19
Faulting module name: FM.exe, version: 3.35.10.6, time stamp: 0x2a425e19
Exception code: 0xc000041d
Fault offset: 0x000fa2b5
Faulting process id: 0x220c
Faulting application start time: 0x01da3f108d420d83
Faulting application path: C:\Delphi7\Main\Projects\FM.exe
Faulting module path: C:\Delphi7\Main\Projects\FM.exe

Faulting application name: FM.exe, version: 3.35.10.6, time stamp: 0x2a425e19
Faulting module name: FM.exe, version: 3.35.10.6, time stamp: 0x2a425e19
Exception code: 0xc0000005
Fault offset: 0x000fa2b5
Faulting process id: 0x220c
Faulting application start time: 0x01da3f108d420d83
Faulting application path: C:\Delphi7\Main\Projects\FM.exe
Faulting module path: C:\Delphi7\Main\Projects\FM.exe

--

madExcept didn't kick in unfortunately :)

If I go into the leaky area of the program only once, I do get a few leaks being reported, but if entering that area more than once, madExcept takes noticeably longer to generate the leak report before it crashes. I thought I'll try and disable child leak filtering as well as write the report to file, and the crash still occurs (if number of leaks if small, and there is no crash, I do get the report file instead).

I don't know if it's the size of the report or some other bug lurking in there. I've noticed that when just using FastMM to get informed of leaks, it works to a point - if I don't go into the really leaky area. madExcept gets a little further.

madCollection version: 2.8.13.0. madExcept 4.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

Just a quick update that I've reinstalled the collection and tried madExcept 5 instead of 4, and there's no change in behavior.

I don't want to muddy the waters regarding 1 point which I am now not 100% sure about: I am not sure I ever got a successful leak report after visiting a certain area of the application. So it may not be the amount of leaks in that area, but something about the kind of leaks themselves. I can't seem to get a successful leak report after using that area of the application after having tried a few more times.
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

Is it a 32bit or 64bit application? In 32bit, it's very easy to run out of RAM, especially when using leak reporting.

Anyway, your original problem does not really indicate a leak, I think instead it indicates that you probably have a secondary thread that is still running while your application is shutting down. So in this situation, the main thread already finalized the memory manager, but the secondary thread is still running, doing work, and trying to allocate memory.

So I'd suggest this: In the finalization of your project, raise a dummy exception. Then look at the crash report to see if there are any secondary threads listed. If there are, that's bad. Your application should first close down all threads before it shuts down.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

Sorry for the delay in responding. I've only just recently got back to take a look at this again and have tried stuff out and your suggestions, thank you.

It's a 32bit application. As much as I'd like to think it has something to do with RAM - due to recent VM crash caused by running out of virtual memory after leaving Process Monitor running for 2~ hours - I am pretty sure it's not that. I've since consistently reproduced the issue with a fair bit of RAM remaining (and having increased the page file size from 12GB~ to 24GB; the measly 8GB of RAM I have on this VM wasn't the main culprit in the crash but certainly didn't help). It may seem that due to going into a specific leaky or troublesome area in the application, madExcept finds more leaks on shutdown and is clearly showing a delay in producing the report, but I don't think it's that many more leaks that it would exceed the 32bit process RAM limit which, incidentally, I believe is set to 3GB for this application with PE flags in the project file (in one of the tests I commented those out but it didn't help). So I don't think it's due to number/size of leaks but something else unsavory.

I've taken your useful suggestion and tested for running threads on shutdown using a dummy exception in a finalization section. I've checked those in madExcept's exception and within the Delphi 7 IDE (in events, it's showing that there are a fair few threads being started and stopped, and a heck of a lot more modules being loaded, especially when I close the application a lot of modules first get loaded which seems unnecessary and kind of costly, which was followed by a mass unloading of modules -- something to investigate, but certainly the machine looks to be very busy! - in fact, having just checked the modules again, spotted a large third-party mapping library loading about 40 DLLs when going into one area of the application :/).

I've checked for breakpoint hits on CreateThread and there were none during my minimal attempts to reproduce the issue. So the remaining threads appear to be created by the OS (and whatever is installed and gets loaded into every application etc), or by something external/third-party that this application uses/calls that I've not yet come across. There is one particular thread that's left running that madExcept reports was started by main thread, but it's not a thread created by this application directly, the application is not aware of any threading in third-party components (to my knowledge). So can this thing be called "thread leak"? and should madExcept catch those :) Anyway, this particular thread is showing early enough for me to get a leak report from madExcept, so I don't think it's this thread that's causing the crash when I go further into the leaky areas of the application.

Perhaps worth noting, this dev VM is in a cloud, in a corporate environment, under constant Windows Defender checks, and everything is definitely on the slower side. I've had madExcept related errors in the IDE that I've never seen before such as:

"[madExcept Warning] Mapping binary file failed (8)." and "[madExcept Warning] The binary couldn't be patched, because it's currently in use." I've also had madExcept's exception dialog taking quite a long time to produce a stack trace for some of the threads, and when it eventually loads, it shows a very long stack for one of the threads, containing meaningful units and method names, but in a seemingly random order. I think it's because I managed to run the application before madExcept has done its thing to the executable. Not sure how that's happened exactly, whether it was a compile or build or run without debugging (a non-standard option in D7 IIRC), but it happened a few times. But that's by the by.

I finally progressed this a little more, while debugging the application and having IDE set to stop on exceptions, madExcept exception handling and leak detecting on, when shutting down the application, the IDE breaks on a line either in Menus.TPopupList.MainWndProc (shows line in editor) or Classes.StdWndProc (shows CPU window) and says:
---------------------------
Debugger Fault Notification
---------------------------
Project xxxx.exe faulted with message: 'application-defined exception (code 0xc000041d) at 0x2e412020'. Process Stopped. Use Step or Run to continue.

The code is the same as was previously reported in Event Viewer. It apparently means STATUS_FATAL_USER_CALLBACK_EXCEPTION (or "An unhandled exception was encountered during a user callback"). Presumably no exception handler exists at that point and the OS just brings the process down/it crashes. But according the Event Viewer, the other exception just before that has code 0xc0000005 which means Access Denied.

We can pretty much rule out that it's due to another thread that's still running because the exception the IDE stops at is in the main thread. During this time, madExcept's leak-check form is showing "Creating leak report..." and progress bar full. I wonder if madExcept could somehow save the report before resuming any other threads? I know it's not madExcept's fault that other threads are not shut down properly, but it might be better not to resume them until the report is saved anyway, especially if they interfere with madExcept's functionality, e.g. crash the application before a leak report is saved? I think in this case something is interfering with both madExcept's exception handling and leak reporting. It causes madExcept to miss the exception that the IDE catches in the end - presumably because it's unloaded by that point by leak reporter? or it unloads itself at that point during the process shutdown (original function in callstack showing as @Halt0); and it somehow causes the application to crash when leak reporting is on. With leak reporting off, there is no exception caught by madExcept nor the IDE.

I'll be migrating the project over to Delphi 12 shortly, will be interesting to see how things behave then, but I would really like to get to the bottom of this unsavory and leaky shutdown situation while on Delphi 7.
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

I don't think activating leak reporting is a good idea in your specific situation. Leak reporting almost never helps tracking down the cause of exceptions. Leak reporting is for finding issues with high memory consumption, or your application running into "out of memory" exceptions. For other types of exceptions, activating leak reporting will not help. The original issue occurred without leak reporting, right? So adding leak reporting on top will just add more possible causes for trouble.

In addition to secondary threads still running, I'd suggest to check for:

1) Forms being freed twice.
2) Buffer overruns.

You can test 2) by activating madExcept's "instantly crash on buffer overrun" feature. However, this will once more eat tons of additional RAM, so this could cause issues on its own.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

I wrote all that stuff below over several hours as I was testing stuff, and I've since found the root cause. So here's a <TLDR>:

This almost ties everything together.
The short version is that there was a form that was not being freed.

But it's a little more nuanced. It's to do with AllocateHwnd/DeallocateHwnd routines and components that depend on them such as TTimer and TPopupMenu. The TPopupMenu area is what kept falling over. In TPopupList.Add, the first time it's called, AllocateHwnd is called (creating window "TPUtilWindow"). There is a counter being maintained, and TPopupList.Remove calls DeallocateHwnd if the counter is 0. The application creates a bunch of TPopupMenus when it starts, in various forms. The form that is being leaked also creates a bunch of those. So when the application was shutting down, the counter only got reduced to 18~ (popup menus remaining somewhere), never getting to 0 and never calling DeallocateHwnd (complete application shut down follows). I think it doesn't matter if the form that is being leaked didn't free those TPopupMenus or they were leaked by the application earlier on, the key thing is that DeallocateHwnd did not get called, leaving the handle for Windows to put messages in. And the way AllocateHwnd works (which I've read about earlier today), it does some sort of patching (in MakeObjectInstance) so the WndProc that Windows would call for the TPopupList, would have the matching method/object. For some reason, the AV happens is when madExcept is preparing the leak report and calls a GetWindowText on one of these window handles. This ends up in Delphi around here:

Code: Select all

procedure TPopupList.MainWndProc(var Message: TMessage);
begin
  try
    WndProc(Message); <<<<
  except
    Application.HandleException(Self);
  end;
end;
So it appears the intended WndProc is called back, but it stops here and can't call the real TPopupList.WndProc().

Sometimes it also lands here:

Code: Select all

function StdWndProc(Window: HWND; Message, WParam: Longint;
  LParam: Longint): Longint; stdcall; assembler;
asm
        XOR     EAX,EAX
        PUSH    EAX
        PUSH    LParam
        PUSH    WParam
        PUSH    Message
        MOV     EDX,ESP
        MOV     EAX,[ECX].Longint[4]
        CALL    [ECX].Pointer <<<<<<<<<<<<<<<<<<<<<
        ADD     ESP,12
        POP     EAX
end;
Not sure if this is the correct/patched WndProc, nor am I sure as to why it jumps between these 2 randomly. I think the CALL above would end up in TPopupList.MainWndProc(), but something appears to be corrupt at this point to proceed. I guess it's half corrupt when it gets into TPopupList, to explain it failing there. That's me guessing, trying to make sense of it. I checked that TPopupList doesn't get freed until Classes's finalization.

So it's a mixed bag: messages shouldn't be firing into that window handle; if they are, they shouldn't cause the AV (Delphi's special code should still be in place); messages only sent when madExcept's leak reporting is enabled. Perhaps madExcept could avoid using API's that would send a message to existing windows? Just tossing ideas around. Apparently AllocateHwnd is not thread safe (see https://www.thedelphigeek.com/2007/06/a ... -safe.html).


In conclusion (for now :D), I will see how things behave in Delphi 12, but for now, the form that leaked 70000 bits of memory is freed. Now madExcept leak report is showing me some 260 leaks to check out - back to where I was a few days ago :) I wonder how things would behave if I did manually controlled runtime leak testing with madExcept (this was going to be one of my next steps). Unfortunately I've spent too long on this today, but I will set a little time aside to test that scenario out (and again, I'll come back to this thread to post if all of this would have worked in Delphi 12 and I would have seen the big form leak to begin with).

If any info is needed or anything to try out, it would be my pleasure.

Thank you Mathias for your attention here. Sorry I have subjected you to these really long posts :)

</TLDR>

>The original issue occurred without leak reporting, right? So adding leak reporting on top will just add more possible causes for trouble.

Before I started leak testing, there were no exceptions caught in the IDE (i.e. when "Stop on Delphi Exceptions is on"), nor any exceptions were caught by madExcept when enabled only for exception handling, not leak reporting. But when leak reporting is turned on in madExcept, the application crashes at the stage when the report appears to have finished generating but the little window is still showing in the bottom-right corner of the screen.

So it's an odd one because on one hand, the application is most certainly leaving something unfreed that manages to cause a crash when madExcept's leak reporting is turned on (and who knows, if it's indeed an issue on its own, it may well manifest in other circumstances without madExcept+leak reporting). But on the other hand, madExcept could perhaps be dealing with this a little better. After all, I am using it to find leaks, and instead, an exception is introduced that shows up in the IDE, but missed by madExcept, whose primary purpose is to catch unhandled exceptions, no?

I am sure there is a problem in the application's code, and I will find what it is soon enough and post my findings. My bet is that even though the problem will be something leaking in the application, madExcept leak report generation process (right toward the end of it) could be slightly improved to deal with this case (whatever it turns out to be) and make madExcept just that bit better :) You'll be the judge of that; I have to find the source of the problem :)

---

Because the exception is in Classes.StdWndProc(), I suspect some form/window is not freed and this form somehow ends up receiving messages when madExcept finishes producing the leak report. Something either manually pumps the messages, does something like an Application.ProcessMessages, does a SendMessage; or the message pump shouldn't be running by this point. If it comes to it, I should be able to find out to which window the message belongs to when StdWndProc fires (might use hooks to trace creation/destruction of HWNDs or try something like Winspector Spy to see if it can find the handle + name and class). Starting to suspect this 40 DLLs third-party library isn't squeaky clean either. We will see.

Well I started looking into it a little bit more, just to draw a line for the time being.....


I've attached 2 screenshots from x32dbg when debugging this issue. madExcept is enabled, leak reporting enabled, crash on buffer overrun/underrun disabled.
"1a - madexcept32.dll is about to call GetWindowTextW (insta crash on buffer overflow or underrun is disabled).png"
"1b - GetWindowTextW appears to lead to a crash in StdWndProc.png"

Indeed it's madExcept's call to GetWindowTextW is what's resulting in the message WM_GETTEXT arriving in StdWndProc and lead to a crash with error code 0xc000041d. And it does look like there are a lot of leaks - bits of strings in the debugger are showing leak count in the range of 70000 :)

>In addition to secondary threads still running, I'd suggest to check for:
>1) Forms being freed twice.

I wonder how to do that? It's rare that this happens and one hopes for an exception when it does.

>2) Buffer overruns.
>You can test 2) by activating madExcept's "instantly crash on buffer overrun" feature. However, this will once more eat tons of additional RAM, so this could cause issues on its own.

This doesn't appear to have made a difference, but see point 3 below.

3) I've also tested the other option, to crash on buffer underrun.

The report generation window's progress bar reached about 40% before a crash - but this time, madExcept popped up, showing that exception has occurred in madExcept32.dll. So this is something new.

Screenshot "2 - crash in madExcept32.dll.png" attached.

Noticed it says compiled with "Delphi 12" for madExcept32.dll - this is probably a coincidence, but I've installed Delphi 12 a couple of days ago. Also, some leaks are being shown by madExcept if I don't go into the trouble area, so this DLL works with Delphi 7 just fine, but thought I'll mention, just in case.


---

Other unrelated bits I've noticed - just some feedback/question. When doing a couple of these tests (buffer overrun and underrun) when expecting a crash, I didn't see madExcept popup, so I thought the settings didn't have any effect. I repeated the tests to be sure, and indeed madExcept popped up. I must've got distracted or something before, having not noticed madExcept's dialog? A bit later I noticed that madExcept appears to hide its exception dialog after a while. Is that so? I was taking screenshots of it for this post, and a couple of times the form just disappeared while I was print-screening/pasting. UPDATE: indeed when testing point 3 above, madExcept's dialog got closed after a few minutes - the application crashed with the same 2 Event Viewer entries as reported previously. Thought I'll mention this.

The other minor thing to consider: I use laptop for 2nd display which has 150% DPI settings (Win10). Moving madExcept's exception dialog to this laptop's screen makes it look a little odd: large non-client area (as per 150% DPI), while everything else looks teeny. I suspect adding some DPI awareness to madExcept's dialog would help those with super high res display and Windows set to increase text size.

Final nit from me: unimportant but maybe you feel like fixing: I managed to mess up the scrollbar in one of the madExcept dialogs (barely seen in one of the screenshots). I tried to make the window tall enough to screenshot all the listed threads, and tried to resize the window beyond the desktop's workspace area (under taskbar). Windows forced the form back into view, but madExcept dialog's scrollbars didn't adjust back.
Attachments
1a - madexcept32.dll is about to call GetWindowTextW (instant crash on buffer overflow or underrun is disabled).png
1a - madexcept32.dll is about to call GetWindowTextW (instant crash on buffer overflow or underrun is disabled).png (247.87 KiB) Viewed 19425 times
1b - GetWindowTextW appears to lead to a crash in StdWndProc.png
1b - GetWindowTextW appears to lead to a crash in StdWndProc.png (217.13 KiB) Viewed 19425 times
2 - crash in madExcept32.dll.png
2 - crash in madExcept32.dll.png (163.71 KiB) Viewed 19425 times
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

Ok, I thought it would be a thread still being active, and now it seems to have been some window instead, maybe. In any case, usually madExcept's leak reporting only starts when the application is already nearly shutdown. So if any code still crashes afterwards, that would point to probably some code still being executed although it shouldn't have.

It would be hard for madExcept to avoid calling any APIs that might cause messages to be sent/handled. Maybe it would be possible, but I don't think it's worth the effort, to be honest.

Generally, madExcept is tweaked a ton to be ultra stable and very lightweight during runtime when used in the normal way. The extra features like leak reporting and "instantly crash" are features that are not intended to be used on a customer's PC, they're additional debugging tools for a developer's need. As such, although I tried to make them stable and working well, they're not as polished as the normal runtime code. These extra features are always a bit risky to use, due to how deep they modify the memory manager behavior and how much extra RAM they consume etc. As such, I'm not overly enthusiastic about spending a ton of time to make them "perfect". Of course I'm happy to fix clear bugs, though.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

I understand and it's pretty much how I used madExcept over the years. But I very much welcomed the leak reporting functionality in madExcept - I remember trying it out very early on and you've made changes to make it awesome :) I have used it over AQ Time since (mind, I'll be needing the latter soon enough to do some code coverage testing and profiling - you're not planning to whip out one of these features any time soon? :D ); and I remember not being enamored with FastMM's equivalent either.

At first, I would have acquiesced with your last response, i.e. nothing to do even though maybe something could be done. But having thought about it some more, I changed my mind and was confident that I've found an issue that you'd consider worth fixing. I suppose it's how you look at it. How about this repro code:

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
begin
  TPopupMenu.Create(nil);
end;
Same symptoms as in the main application - a crash + 2 event viewer entries.

In Delphi 12, now with madExcept 5, no issue. Screenshot attached. In the top row, madExcept succeeded in GetWindowText on the leaked handle, but in Delphi 7 with madExcept 4, this crashes. Retested with madExcept 5 on Delphi 7, same issue. Who knows up to which version this goes? I am willing to bet, Delphi 2007 also exhibits this based on the article linked in the previous post that details the implementation of AllocateHwnd and its runtime code patching technique.

Well, moving over to Delphi 12 so won't be relevant to me, but fixing it might still be useful for those who are not migrating just yet but would like to do some of these house-keeping/health-check tasks on a big legacy system to snatch some quick wins.
Attachments
madExcept reporting a TPopupMenu leak correctly in Delphi 12
madExcept reporting a TPopupMenu leak correctly in Delphi 12
3.png (35.59 KiB) Viewed 19372 times
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

I can reproduce the issue with Delphi 7, but there's really not much I can do about it.

The tricky thing is that we want leak reporting to be done at the *VERY LAST* thing in your process. If we do it too early, e.g. let's say we do it just before the "finalization" section of all units has run through, there will be tons and tons of leak reports about leaks that aren't really leaks because the allocated things are freed in the "finalization" section of their unit.

What this practically means is that madExcept's leak reporting is doing something very tricky and clever: It basically does all its work not in your EXE file, but in the separate madExcept32.dll, which is loaded in your process. This DLL then hooks into your EXE file. Basically in the moment when your EXE file calls "ExitProcess(0)", leak reporting is finally started. Delphi projects call "ExitProcess(0)" as the very last thing, after all units have been finalized etc. By doing this tricky thing, madExcept32.dll is able to report leaks *after* all unit finalization sections have run through.

Please understand that after all units have been finalized in your project, nothing works, anymore, because the unit finalization closes down *everything*, including (but not limited to) the memory manager. So in this state, if there's any code running which tries to allocate some memory using your EXE's Delphi memory manager, an exception will occur, because the memory manager was already finalized/freed. This is also why I've moved leak reporting to the separate madExcept32.dll, because although the memory manager in your EXE file is already freed, it hasn't been freed yet in the madExcept32.dll. That's how leak reporting can still be performed, although your EXE is already "paralyzed".

But what this practically means is that anything that result in your EXE still running some code while leak reporting is running will likely crash. Usually, this is a secondary thread still running. In your case, it's some window still being alive and listening to messages and doing some fancy processing on the messages.

There's simply no way I can think of to fix this. Of course I could try to avoid using any APIs that might induce message handling in your EXE file. But really, that would be a TON of work, and it would only workaround a bug in your code. So I'm sorry to say, but not going to happen.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

Hello,

I am having a few minor issues, some of which are related to the issue in this thread, so I thought I'll just add more here, hope that's okay.

Issue 1) I seem to be unable to stop madExcept from hooking into my application during debugging, even though I've turned madExcept off. Following that, I've removed madExcept from the IDE (deleted the BPLs from the registry), and still somehow it hooks into the app. I've deleted .MAP and .MES files as a final step to no avail.

I have been trying to use FastMM4 in Delphi 7 to check for a specific type of leak (to check if I introduced it as part of Delphi 12 migration), and remembering that madExcept leak reporter doesn't work in my case (as per this thread), I resorted to using the full build of FastMM4. Each time I run my application within the IDE, I get a big FastMM4 message box (and a text file) to tell me there was a call against a free object (basically the issue discussed here ad nauseum).

Here is a snippet of FastMM's output:

---------------------------
FM.exe: Memory Error Detected
---------------------------
FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.

Freed object class: TPopupList

Virtual method: Offset +16

Virtual method address: 4A0680

The allocation number was: 190

The object was allocated by thread 0x2C18, and the stack trace (return addresses) at the time was:
402EF0 [madCrypt][madCrypt][@LGetDir][3205]
4048E3 [madExcept][madExcept][HandleExceptionWP][8914]
404CBE [VarUtils][VarUtils][CVarTypeToElementInfo][9893]
404918 [madExcept][madExcept][RaiseExceptionProc2][8948]
4A1216 [ToolWin.pas][ToolWin][TToolDockForm.WMNCHitTest][331]
4054E3 [ExtCtrls][ExtCtrls][BeginThread][11577]
40554B [ExtCtrls][ExtCtrls][@LStrArrayClr][11693]
4080D7 [Types.pas][Types][Bounds][531]

-- There is more in the message and the log, showing madExcept related threads/units all over the place.

Why is madExcept showing here at all? How is it possible if I removed it from the IDE!? What am I missing here?

Issue 2) As mentioned somewhere in this thread, I am having an intermittent issue with madExcept and Delphi 12. Sometimes madExcept reports that it's failed to patch the EXE due to it being in use. It's obviously the antivirus taking a while to scan the file (EXE size more than doubles with all the needed settings for madExcept to function, so the extra time the AV takes on a 70~MB EXE is okay...well, it sucks to be honest, but not much I can do about it). I think madExcept should wait as long as Delphi does when it builds an EXE and begins to debug it.

Issue 3) When having D7 and D12 open, double-clicking a leak in the report opens the wrong Delphi version (leak report was generated by D12, but madExcept viewer picks D7; picks D12 after I shut D7 down). It's very minor, sure, but the minor issues I've been encountering lately are accumulating to, shall we say, less than great experience with madExcept, and sadly, my impression of madExcept as a rock solid product has been shaken somewhat, can't "swear by it" as it stands. As it stands, I can't be recommending it wholeheartedly to my prospective employers or colleagues.

Issue 4) The issue regarding report leak generation crashing on shutdown in D7 has also occurred on D12, albeit less frequently. I've been not focused on it to dig deeper (and you've said you won't be fixing it, so I don't want to waste my time on that), but it's likely to be the same issue based on Event Viewer. I only noticed by chance as I thought this issue was not present in D12 based on minimal repro I posted in this thread. But when my app closed without a leak report a couple of times (as nice as it might have been if it were genuine), I knew something was up - thanks Event Viewer.

Thanks
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

1) Maybe you still have madExcept in your uses clause in some unit(s)? Removing the BPLs from the IDE doesn't stop the compiler from linking the madExcept DCU into your EXE file if your uses clause still references it. You can put your madExcept "uses" and custom code into "{$ifdef madExcept}" blocks, that should solve the issue, I would assume (?), because this define is automatically set and removed by madExcept when you activate/deactivate madExcept.

2) The debugger doesn't need to open the file for write access, which is why it doesn't collide with the AV product. madExcept does need to open the file for write access, and seemingly, your AV blocks that. In the last 25 years I've had maybe half a dozen reports about that, but none in the last 3 years, I think (?). Honestly, I think you should use a better AV product. There's no excuse for an AV product to block write access to a file just because it wants to scan it. I dare claim that a good AV product probably (?) doesn't do that.

3) Leak reports are displayed by the external madExceptViewer tool. Leak reports don't contain information about which Delphi version compiled the EXE file.
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

Thank you for responding so quickly!

1) That's the thing - the only place madExcept's units would have been placed is in the DPR file, and only by using the madExcept UI from within the IDE. I've searched all the files anyway, no madExcept anywhere in vicinity of the project - but the search isn't 100%. I did check in the Modules window with the IDE paused on the error and it shows all the units, but no madExcept there. Okay, so this is really odd then. Here I was hoping you'll reveal some secret madExcept IDE hooking or something :)

Just to add, I thought without the .MES file, even if madExcept got included in the binary, it wouldn't hook into the exception handling by default (I've used it manually like that before, just to get a stack trace on exception and having the .MAP file together with the EXE).

Useful tips regarding using IFDEF - will keep in mind - thank you.

Minor suggestion/nice to have: Whenever turning off madExcept, I typically do one more step of turning off the map file (and IIRC on D12, Debug information, in the linker options). I understand why madExcept doesn't turn that off by itself even though madExcept turned it on in the first place, but maybe the settings for Linker (whatever madExcept sets in the project when enabled) should be also settable in madExcept's UI in the IDE - it should then be more transparent and save an extra few clicks.

I realise I am in this temporary territory of migration, and have raised a few things that just relate to that scenario, but it has been pretty tense (2-4 instances of D7/D12 regularly, leak reports, exception reports, lots going on and pesky little bugs things keep cropping up for me - don't get me started on Delphi 12, what a bugfest), so every little helps :)

2) I agree that a better AV product should be used (if there is such a thing as a good AV :D) - it's Windows Defender, enforced by company policy. I've found Defender to be getting heavier and heavier, it cripples my system and I just have to live with it (including it picking up an empty Delphi 7 project as some sort of malware!!!). BUT - I find myself in a corporate environment with hyped up IT security (the laptop I am working on is draconically restricted; I actually do all the work in a VM in Azure - at least it's RDP, and not Citrix or worse). I suspect I am far from alone working like this in this day and age - perhaps there'll be more cases like mine. This is actually a minor thing - I can just recompile, but I don't always notice madExcept's message about this in the Messages window and have found myself wasting a few minutes here and there because of this; it's still not a big deal - but it's worth adding some weight to the issue, in case someone else starts moaning then we're sure onto a fix :)

3) I believe the info is in the binary - every DCU has the version so I imagine the EXE will as well. With lots of other stuff madExcept rolls into the binary, I am sure it can accommodate an extra byte :) Again, a minor issue but like I said it's a cumulative effect. Currently, I'll have to either shut D7 down or manually locate the error in D12, or vice versa (hopefully won't be doing this for long, but surely there's lots of software houses out there with products on multiple Delphi versions that will have been bit by this, and worked around it like I have).

--

The first issue is a mystery. I will post here if/when I find out what it is (which will probably be a PEBCAK error given how ridiculous the problem looks and you've not mentioned any secret IDE hooking which was what I was hoping for heh).


Well, another day in paradise.


P.S. I nearly lost this wall of text - I didn't have "Remember me" ticked so pressing Submit took me to a login page, then back to an empty post! Browser saved it when I went back :)
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

1) It seems to be 2 things at once: The madExcept DCUs are linked into your EXE (otherwise there would be no way for madExcept to be active), plus madExcept seems to be active. Which should both not be the case. I think this is both unlikely to be madExcept's fault, but it's hard to be 100% sure. One thought: It's not madExcept_.bpl that is getting loaded into your EXE file, is it? Or maybe it's because madExcept32.dll is loaded for leak reporting? I'd suggest that you double check if the map file lists madExcept after compilation. If so, the compiler seems to still believe that madExcept needs to be linked in. Which means that some unit somewhere that is directly or indirectly "uses"ed by your application must still reference madExcept somehow. I can't think of any other explanation. The other part is why madExcept appears to be active. You can check if there's an "RCData\TMADEXCEPT" resource in your exe file after compilation. It shouldn't be there. But if it is, somebody must have added it. That is always madExceptPatch.exe, which may be called in a post-build event or by the madExceptWizard_.bpl that is loaded in the IDE. If the resources is there, you can check if says "Enabled = True" or "Enabled = False".

2) I've double checked my code. madExceptPatch.exe already waits 2 full seconds for the AV software to complete its work. It only fails if the AV software doesn't unlock the EXE file within 2 seconds. Of course it would be possible to increase the timeout, but it seems pretty outrageous that we would have to do that. How long do we have to wait? 5 seconds? 20 seconds? 10 minutes?? You can workaround this yourself by recompiling madExceptPatch. You can edit the "Sleep()" call in madExceptPatcher.pas to increase the waiting time.

3) Which binary file? madExceptViewer.exe doesn't have that information. Well, ok, I guess it could parse the leak callstacks to check if it finds an EXE file referenced there, and then open the EXE file to figure out which Delphi version compiled it, but that seems pretty "wild".
TByte
Posts: 10
Joined: Thu Jan 04, 2024 1:05 pm

Re: Application crashes when generating leak reports

Post by TByte »

1) Yup - a PEBCAK error. Fresh pair of eyes and all that. After checking to see what DLLs/BPLs the IDE has loaded while running, checking in RCData as suggested, I found no madExcept. Baffled, I went to sleep having put the PC to search *.* that contain madExcept :) Found it in the map file which was out of date and the setting to generate it was turned off (could have sworn I turned it on!). I blame FastMM for not telling me. Just kidding :)

Sorry about that - hate to waste your time.

2) I see, so it's doing a simple Sleep() - I thought it might have hooked in somewhere a bit too early or something . Thank you for the suggestion to recompile the patcher! I'll have a play. I immediately thought to use CreateFile() with flags to wait with a larger timeout (or more crudely, a retry loop), so it might improve slightly on the current 2s delay, even for me (sometimes Defender takes very little time, sometimes it really churns away). I'll probably put an obnoxious MessageBox if it times out because it's rare when it happens.

3) My bad. It's in the EXE/DLL, but it's not super straight forward (or reliable) to retrieve, as you've explained. On the other hand, the patcher could embed this easily enough I think.
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Re: Application crashes when generating leak reports

Post by madshi »

The 2 second delay is not a fixed delay, it already is a loop. So there's no delay unless it's needed.
Post Reply