开发者

Wrong exception after calling .net4.0 com server from delphi application

We are migrating our codebase from BDS2006 to Rad Studio XE, and we found some very strange behavior: if we make invalid floating point operation (ie. division by zero) after creating some object from COM server implemented in .Net4.0, we don't get normal exception (ie. EDivisionByZero), but EStackOverflow.

We managed to prepare very simple example: ComErrorExample

There is an .net 4.0 assembly, with com interface (one function returning string) and simple delphi application:

var
  a, b: Double;
  Stored8087CW: Word;

begin
  CoInitialize(nil);

  try
    b := 0;
    a := 1 / b;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message, ' (Expected type of exception)');
  end;

  Stored8087CW := Get8087CW;
  Writeln('Code from .NET COM: ', CoExampleOfCOM.Create.DoSomething);
  Set8087CW(Stored8087CW); //it's only to show that 8087 control word doesn't change

  try
    b := 0;
    a := 1 / b;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message, ' (Unexpected type of exception! Why stack overflow?)');
  end;

  Readln;

  CoUninitialize;

end.

As you can see, we make two divisions by zero - first one, before com object creation, throws EDivisionByZero, second one throws EStackOverflow.

We tested this on win7 x64, and winXP x32 - no difference. But when we switched com server from .net4.0 to .net3.5 - everything works fine.

Question: are we doing something wrong? Can we do something to fix this problem?

Switching to .net3.5, or dumping Delphi isn't an option for us.

UPDATE: We checked the floating point configuration ( Set8087CW() ) before but without any luck. UPDATE2: I've expanded example 开发者_StackOverflow社区with restoring floating point configuration.


It looks like something in the COM DLL is changing the floating point processor configuration. See Default8087CW and Set8087CW in the Delphi help.

You can save it before doing anything with the COM DLL and restore it afterwards.

var
  Saved8087CW: Word;
begin
  Saved8087CW := Default8087CW;
  // If you want, disable all fpu exceptions 
  // with the next line.
  Set8087CW($133F);
  DoYourComOperationHere;
  Set8087CW(Saved8087CW);
end;


I can't seem to comment on the origional question, so excuse this answer which is more a set of questions. Did you ever find an acceptable work around to the issue? Did you log the Delphi issue with Quality Central, and if so do you have the incident number?

I'm seeing what I think is a related issue, where on the Delphi side I am setting the FPU CW to $133f, and then on the C# side I had

    try
    {
        Double.IsNaN(Double.NaN);
    }
    catch (ArithmeticException)
    {
        /* Intentionally empty. .NET will initialise the FPU at this point. */
    }

Which used to work fine in the 2.0 Framework, but now I am getting massive amounts of 0xC0000092: Floating-point stack check. and then the StackOverflow exceptions.

Adding the above code into COM exposed methods causes a call stack of

clr.dll!CLRVectoredExceptionHandlerShim()  + 0xa3 bytes 
ntdll.dll!_RtlpCallVectoredHandlers@12()  - 0xef1c bytes    
ntdll.dll!_RtlCallVectoredExceptionHandlers@8()  + 0x12 bytes   
ntdll.dll!_RtlDispatchException@8()  + 0x19 bytes   
ntdll.dll!_KiUserExceptionDispatcher@8()  + 0xf bytes   
clr.dll!CLRVectoredExceptionHandler()  + 0x9a bytes 
clr.dll!CLRVectoredExceptionHandlerShim()  + 0xa3 bytes 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜