I have a strange problem with an IDE plugin (DLL). On some PCs it causes an "application has stopped working" dialog when the IDE is being closed (and the plugin is being unloaded). After hunting that error for quite some time now I was able to reduce it to the code below.
I have a strange problem with an IDE plugin (DLL). On some PCs it causes an "application has stopped working" dialog when the IDE is being closed (and the plugin is being unloaded). After hunting that error for quite some time now I was able to reduce it to the code below.
I have not been able to reproduce it on some of my PCs so far but it happens on some other machines all the time (I already tried disabling any other plugin and any third party component package). I did not have the time yet to do some IDE debugging. Maybe someone of you has a clue what is going on. The DLL is built with runtime packages (designide which itself requires the rtl and some other packages).
library CrashPlugin;
uses
SysUtils,
ToolsAPI;
procedure FreePlugin;
begin
try
Abort; // boom!
except
end;
end;
function InitPlugin(const BorlandIDEServices: IBorlandIDEServices;
RegisterProc: TWizardRegisterProc;
var Terminate: TWizardTerminateProc): Boolean; stdcall;
begin
Terminate := FreePlugin;
Result := True;
end;
exports
InitPlugin name WizardEntryPoint;
end.
I can also explicitly raise an exception, no difference. It does not even arrive in the except part (I put logging there which was not executed).
I have not been able to reproduce it on some of my PCs so far but it happens on some other machines all the time (I already tried disabling any other plugin and any third party component package). I did not have the time yet to do some IDE debugging. Maybe someone of you has a clue what is going on. The DLL is built with runtime packages (designide which itself requires the rtl and some other packages).
library CrashPlugin;
uses
SysUtils,
ToolsAPI;
procedure FreePlugin;
begin
try
Abort; // boom!
except
end;
end;
function InitPlugin(const BorlandIDEServices: IBorlandIDEServices;
RegisterProc: TWizardRegisterProc;
var Terminate: TWizardTerminateProc): Boolean; stdcall;
begin
Terminate := FreePlugin;
Result := True;
end;
exports
InitPlugin name WizardEntryPoint;
end.
I can also explicitly raise an exception, no difference. It does not even arrive in the except part (I put logging there which was not executed).
That dialog is due to an unhandled exception no? If so, is it the exception you raise or a different one?
ReplyDeleteSince the dialog does not say "Hey I got an EAbortException here" but does not appear when I don't call Abort - it is related.
ReplyDeleteOriginally found this when destroying a TIdHTTPServer component and tracked it down to TIdListenerThread.Run where an Abort is called inside a try/except block.
It did not happen when I called HTTPServer.Active := False at some earlier point in the plugin. I modified the code and finally came to the conclusion that it was not indy related but that something with either exception raising or catching is wrong at that point.
Stefan Glienke My brain is fried here right now but doesn't the windows event log have more details, like the exception type?
ReplyDeleteMy guess is that the runtime exception support has been removed by the time your plugin is removed
ReplyDeleteThe PCs that do freeze, do they have some IDE exception logging plugin installed? The reason I ask is because I have had issues with dialogues/windows trying to be displayed upon application being terminated but since the application was being terminated, the dialogues/windows weren't being displayed (a Windows OS thing). I can't remember the exact issue, just something rough.
ReplyDeleteWhat I am trying to say, is there a third-party plug-in (madExcept, EurekaLog, etc) that is trying to show a modal window and waiting for the user to do something, for a window that isn't being displayed to the user...
Asbjørn Heid I checked some while ago but there was not an entry in the event log. I will check again tomorrow. I remember the name exceptiondiag150.bpl_unloaded was in the module name (also will be able to provide a more detailed information tomorrow)
ReplyDeleteDavid Heffernan That would be f'ed up because the host application (bds.exe) is still normally running by that time - well it depends when the plugin is unloaded, it must be some code executed in the IDE because that TerminateProc is something from the OTAPI.
Nicholas Ring They do not freeze. IDE closes, twentyone, twentytwo, boom error dialog. As I said I disabled all plugins (removed all entries from the known packages and experts key).
Stefan Glienke Apologies - I misunderstood the issue. :(
ReplyDeletehave you tried doing your cleanup in a finalization section of a unit? For my Plugin (which is quite minimalistic compared to yours) i do all of the setup in an initialization-section and the cleanup in a finalization-section of a unit. However, mine is still a package so that might behave differently
ReplyDeleteFinalization is even later than this one and crashes as well (and making a package based plugin is not up for debate)
ReplyDeleteI'm interested in what you find.
ReplyDeleteLooks like I found the issue. There is a Delphi bpl called exceptiondiag.bpl which hooks the windows kernel function RaiseException but does not restore it properly when being unloaded leaving it to point into nirvana. This package gets unloaded before the dll plugins and thus any raise after that will cause a crash. -.-
ReplyDeleteMy idea of solving that: calling loadlibrary on that bpl causing its ref count to get increased preventing it from being unloaded before my DLL ;p
Stefan Glienke Nice find and that (it doesn't restore it correctly) is down right nasty!
ReplyDeleteThe finalization section of ExceptionDiagReg contains calls to JclStopExceptionTracking, but does that call JclUnhookExceptions?
ReplyDeleteUwe Schuster No clue, I did not look into it. With trial and error I identified this bpl as the one hooking the RaiseException and obviously not resetting it because my Abort (the RaiseException) ended at some address that did not contain any code. Funny enough I did not get the "has stopped working" dialog and I don't have it disabled in the registry - I found this by debugging.
ReplyDeleteSounds like something to be posted to QC. Maybe it'll get fixed within 6 or 7 releases. I encountered the TidHTTPServer issue myself, but setting active := false was sufficient for me at that point. I'm glad you found the real reason.
ReplyDeleteGiovanni Van Geel Issues go into QP (quality.embarcadero.com) nowadays. Unless there is a reason that JclStopExceptionTracking doesn't call JclUnhookExceptions we can fix this in the JCL. Since I don't know who nowadays maintains the Quality Insight package it may take ages till they pickup the fix.
ReplyDeleteNice find, nasty issue.
ReplyDeleteUwe Schuster QP isn't indexed Google Search. BTW: welcome back. Any plans to resurrect http://bitcommander.de/?
ReplyDeleteThe JCL issue http://issuetracker.delphi-jedi.org/view.php?id=6381 is now fixed in latest git. I can't repeat the crash on IDE shutdown at this point of time. As soon as I can I'll check if it doesn't crash when exceptdiag would have the patch as well.
ReplyDeleteStefan Glienke Consider filing a QP.
Uwe Schuster It seems to crash on some machines and on some it does not. But when it does, it does so in all Delphi versions from XE to XE7.
ReplyDelete