Mega Search
23.2 Million


Sign Up

Make a donation  
Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock

I am using a TIdHTTPServer in my IDE plugin (a DLL).

The DLL is linked to DesignIDE so all Indy stuff is compiled into the DLL.

Everything works fine except on some installations (XE and XE6 occured so far) when the DLL is unloaded (closing the IDE) an AV happens (windows dialog with error message - not on a machine right now where this is reproducable).

This happens when the TIdHTTPServer is set to inactive and I found the line that seems to cause it (at least changing it makes the error go away).
I am just not sure why.

The line is in TIdListenerThread.Run - I marked it below

{code}procedure TIdListenerThread.Run;
var
  LContext: TIdServerContext;
  LIOHandler: TIdIOHandler;
  LPeer: TIdTCPConnection;
  LYarn: TIdYarn;
begin
  Assert(Server<>nil);
  Assert(Server.IOHandler<>nil);

  LContext := nil;
  LPeer := nil;
  LYarn := nil;
  try
    LYarn := Server.Scheduler.AcquireYarn;

    LIOHandler := Server.IOHandler.Accept(Binding, Self, LYarn);
    if LIOHandler = nil then begin
      Stop;
      Abort; // !!!  >>> Changing this line to Exit makes everything work <<< !!!
    end else begin
      LPeer := TIdTCPConnection.Create(nil);
      {$IFDEF USE_OBJECT_ARC}
      LPeer.InsertComponent(LIOHandler);
      {$ENDIF}
      LPeer.IOHandler := LIOHandler;
      LPeer.ManagedIOHandler := True;
    end;

    if (Server.MaxConnections > 0) and (not Server.Contexts.IsCountLessThan(Server.MaxConnections)) then begin
      FServer.DoMaxConnectionsExceeded(LIOHandler);
      LPeer.Disconnect;
      Abort;
    end;

    LContext := Server.FContextClass.Create(LPeer, LYarn, Server.Contexts);
    LContext.FServer := Server;
    LContext.OnBeforeRun := Server.ContextConnected;
    LContext.OnRun := Server.DoExecute;
    LContext.OnAfterRun := Server.ContextDisconnected;
    LContext.OnException := Server.DoException;

    Server.ContextCreated(LContext);
    Server.Scheduler.StartYarn(LYarn, LContext);
  except
    on E: Exception do begin
      if LContext <> nil then begin
        TIdServerContextAccess(LContext).FOwnsConnection := False;
      end;
      FreeAndNil(LContext);
      FreeAndNil(LPeer);
      if LYarn <> nil then begin
        Server.Scheduler.TerminateYarn(LYarn);
      end;
      if not (E is EAbort) then begin
        Server.DoListenException(Self, E);
      end;
    end;
  end;
end;{code}

Edit: removed original code comments to make it clearer.

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 2:12 AM EST
From: Stefan Glienke
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit] [E  
News Group: embarcadero.public.delphi.internet.winsock
> {quote:title=Remy Lebeau (TeamB) wrote:}{quote}
> You are writing an OpenTools wizard, which should be implement as a Package, 
> not as a plain DLL.

This isn't correct. You can implement an IDE plugin as either a BPL or DLL, but because the package loading system prevents units with the same name, what Stefan wrote is correct.  It's very risky to use any third-party components at all, because:

a) If the units are compiled into the BPL, you get errors about duplicate unit names, preventing one of the packages (the plugin, or the component package) being loaded
b) If you rely on runtime linking, you have an implicit but not enforced dependency on a specific version of the component etc.  It's not uncommon for interfaces to change. You can't handle that linking to a package you don't have control over.  That is, suppose you use Virtual Treeview, but link at runtime - what if the user doesn't have it installed at all? What if they have a different version with a different interface somewhere? Etc.

Some simple plugins are BPLs, using inbuilt VCL code only (known packages, known versions and interfaces, guaranteed to be safe to refer to them.) But once you start using other components, or even if your own unit names might potentially clash with others, you *must* use a DLL for your plugin.  But that DLL should runtime link to designide, rtl, vcl.

Cheers,

David

Edited by: David Millington on Jan 20, 2015 1:13 AM

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 19-Jan-2015, at 6:15 AM EST
From: David Millington
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:
> you do know how to debug a running instance of the IDE, right?

Yes I do.

> You are writing an OpenTools wizard, which should be implement as a Package, 
> not as a plain DLL.  Any plugins that the IDE itself loads must share the 
> IDE's copy of the RTL, thus requires the use of Runtime Packages.

For the last time: I use runtime packages which makes the DLL use the same RTL and VCL.

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 5:20 PM EST
From: Stefan Glienke
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Stefan wrote:

> An AV is exactly what I get.

SysUtils.Abort() does not cause AVs.  Evenif it did, TIdThread catches all 
exceptions, including EAccessViolation.  Unless the RTL's exception handling 
subsystem is messed up to begin with (ie, memory corrupted, etc).

> I just said that changing the Abort to an Exit removed the problem and
> was asking why that might be.

Removing Abort() would "fix" the problem if the RTL's exception handling 
subsystem were indeed messed up, since an exeption is not being raised anymore.

> When I don't activate (and thus not shutdown) the TIdHTTPServer
> everything runs fine. It even happens without any event attached.

It still sounds like something in memory is being corrupted, and the RTL 
is a victim of it.  You will just have to debug your plugin while it is running 
(you do know how to debug a running instance of the IDE, right?) and see 
what is really happening when SysUtils.Abort() is called and where the AV 
is actually occuring.

> Activating is happening in the WizardInitProc and deactivating is
> happening when the IOTAWizard is released.

You are writing an OpenTools wizard, which should be implement as a Package, 
not as a plain DLL.  Any plugins that the IDE itself loads must share the 
IDE's copy of the RTL, thus requires the use of Runtime Packages.

-- 
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 5:10 PM EST
From: Remy Lebeau (TeamB)
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:

> I have never heard of this issue before.  And the discussion to linked to 
> does not point out Abort() as the culprit.  It talkes about an AV instead, 
> which is a very different beast than SysUtils.Abort().  RemObjects themselves 
> stated in that same discussion that they could not reproduce the problem. 
>  AFAIK, the fact that an AV originated in TIdListerThread.Run() could be 
> purely coincidental and a completely different situation than what you are 
> experiencing.

An AV is exactly what I get. I just said that changing the Abort to an Exit removed the problem and was asking why that might be.
When I don't activate (and thus not shutdown) the TIdHTTPServer everything runs fine. It even happens without any event attached.
Drop a new one on the form, setting DefaultPort, Active := True, boom on shutdown.

> You are not trying to activate/deactivate TIdHTTPServer from within the DllEntryPoint 
> itself, are you?  That would be a big no-no.  Microsoft is very restrictive 
> in what a DLL is allowed to do in its DllEntryPoint.

Activating is happening in the WizardInitProc and deactivating is happening when the IOTAWizard is released.
But it also happens when I do that in the TWizardTerminateProc but haven't found any earlier place to destroy it.

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 3:43 PM EST
From: Stefan Glienke
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Stefan wrote:

> And with linking to I actually meant runtime packages... Since
> DesignIDE itself requires rtl, vcl and some other packages.

But not Indy.

> A package is not an option because a package prevents using any
> 3rd party components in it.

No, it does not.

> Why? Because the user of the IDE plugin might have installed another
> version of these components.

So?  By using Runtime Packages, the plugin can utilize the components that 
are already installed in the IDE.  If the plugin needs to use a specific 
version of the components, regardless of what is installed, then you can 
separate the needed components into a separate Pacakge/DLL for its internal 
use.  This is exactly the approach that Embarcadero took for their own technologies, 
like DataSnap, to use a private copy of Indy so users can use a different 
version in their projects.

> Two different packages cannot contain the same unit.

Yes, they can.  The two packages simply cannot be loaded at the same time, 
that's all.

> So I would have to rename every 3rd party component unit

That is the approach AToZed took with their private copy of Indy used by 
IntraWeb.

> Anyway this is not for discussion but the Indy AV - which seems to
> be pretty old as it has already been mentioned years ago.
> 
> Like here:
> http://talk.remobjects.com/t/indy-tidlistenerthread-run-throws-av-on-exit/1122

I have never heard of this issue before.  And the discussion to linked to 
does not point out Abort() as the culprit.  It talkes about an AV instead, 
which is a very different beast than SysUtils.Abort().  RemObjects themselves 
stated in that same discussion that they could not reproduce the problem. 
 AFAIK, the fact that an AV originated in TIdListerThread.Run() could be 
purely coincidental and a completely different situation than what you are 
experiencing.

> I don't see that either but it is the case. I sat down there with my
> coworker a couple hours debugging the plugin and it always raised the
> "application has stopped working" dialog when the TIdHTTPServer was
> destroyed (or when I explicitly set Active to False).

There is no possible way that SysUtils.Abort() by itself can be affecting 
the IDE like you have described.  And a "stopped working" dialog would mean 
that the IDE process crashed and terminated abnormally, which simply deactivating 
TIdHTTPServer cannot do.  Had the IDE simply frozen instead of crashed, I 
would think that you had an event handler attached to TIdHTTPServer that 
was synchronizing with the same thread that was trying to shutdown TIdHTTPServer, 
as that would be a guaranteed deadlock.  But not a process-wide crash.  Something 
else is going on, and it is not related to deactivating TIdHTTPServer.  You 
are merely looking at a symptom, not the root cause.

> I have another tester who can reproduce that error almost all the time
> on an XE6 installation.
> I was not able to reproduce it at work nor at home with XE, XE5, XE6
> or XE7.
> But I was able in to reproduce it sometimes when loading the plugin in
> a simple VCL application using LoadLibrary and FreeLibrary.

You are not trying to activate/deactivate TIdHTTPServer from within the DllEntryPoint 
itself, are you?  That would be a big no-no.  Microsoft is very restrictive 
in what a DLL is allowed to do in its DllEntryPoint.

-- 
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 3:22 PM EST
From: Remy Lebeau (TeamB)
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:
> > The DLL is linked to DesignIDE so all Indy stuff is compiled into the DLL.
> 
> Linking to the DesignIDE package does not force Indy to be compiled into 
> the DLL.  Compiling the DLL with Runtime Packages disabled forces Indy to 
> be compiled into the DLL.  IDE plugins should not have Runtime Packages disabled, 
> though.  It should be enabled, so the DLL shares the same RTL that the IDE 
> uses.  In fact, when writing an IDE plugin, you should be creating a Package, 
> not a plain DLL.

And with linking to I actually meant runtime packages...
Since DesignIDE itself requires rtl, vcl and some other packages.

A package is not an option because a package prevents using any 3rd party components in it.
Why? Because the user of the IDE plugin might have installed another version of these components.
Two different packages cannot contain the same unit. So I would have to rename every 3rd party component unit 
I use to compile it into my plugin and make sure there is no RegisterClass call or other code blowing up things.

Anyway this is not for discussion but the Indy AV - which seems to be pretty old as it has already been mentioned years ago.
Like here: http://talk.remobjects.com/t/indy-tidlistenerthread-run-throws-av-on-exit/1122

> I see no reason for calling SysUtils.Abort() to cause any problems in the 
> IDE, especially since everything is contained within a single thread context. 
> If it is causing problems, something else unrelated to Indy is going on 
> inside your plugin, such as memory corruption or the like.

I don't see that either but it is the case. I sat down there with my coworker a couple hours 
debugging the plugin and it always raised the "application has stopped working" dialog when 
the TIdHTTPServer was destroyed (or when I explicitly set Active to False).
I have another tester who can reproduce that error almost all the time on an XE6 installation.
I was not able to reproduce it at work nor at home with XE, XE5, XE6 or XE7.

But I was able in to reproduce it sometimes when loading the plugin in a simple VCL application using LoadLibrary and FreeLibrary.
And as well only on the machine that had the problem in the IDE.

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 12:40 PM EST
From: Stefan Glienke
 
Re: Indy causing AV on IDE shutdown when in Plugin [Edit]  
News Group: embarcadero.public.delphi.internet.winsock
Stefan wrote::

> The DLL is linked to DesignIDE so all Indy stuff is compiled into the DLL.

Linking to the DesignIDE package does not force Indy to be compiled into 
the DLL.  Compiling the DLL with Runtime Packages disabled forces Indy to 
be compiled into the DLL.  IDE plugins should not have Runtime Packages disabled, 
though.  It should be enabled, so the DLL shares the same RTL that the IDE 
uses.  In fact, when writing an IDE plugin, you should be creating a Package, 
not a plain DLL.

> This happens when the TIdHTTPServer is set to inactive and I found
> the line that seems to cause it (at least changing it makes the error
> go away).
> 
> I am just not sure why.

The code you quoted is calling SysUtils.Abort(), which simply raises an EAbort 
exception.  TIdListenerThread is a worker thread.  Abort() is used to raise 
an exception that terminates the thread (exceptions are caught in TIdThread.Execute()). 
 The reason Exit is not being used is because it does not force the thread 
to terminate.  If Run() exits without raising an exception, the thread's 
Stopped state could be overridden by user code, thus allowing Run() to be 
called again.  On the other hand, I suppose Run() could call Terminate() 
and then Exit.  But Abort() was easier and more explicit, and allows more 
centralized code to be written in TIdThread.Execute() for all Indy worker 
threads.

I see no reason for calling SysUtils.Abort() to cause any problems in the 
IDE, especially since everything is contained within a single thread context. 
 If it is causing problems, something else unrelated to Indy is going on 
inside your plugin, such as memory corruption or the like.

-- 
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2015, at 11:15 AM EST
From: Remy Lebeau (TeamB)