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
精彩评论