Bug 10664 – Win64: exception handling does not work with COMDAT folding
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2013-07-18T00:17:26Z
Last change time
2020-09-15T10:43:05Z
Keywords
backend, pull, wrong-code
Assigned to
No Owner
Creator
Rainer Schuetze
Comments
Comment #0 by r.sagitario — 2013-07-18T00:17:26Z
Another excerpt from the phobos unittests:
import core.exception;
T collectException(T = Exception, E)(lazy E expression, ref E result)
{
try
{
result = expression();
}
catch (T e)
{
return e;
}
return null;
}
void main()
{
int b;
int foo() { throw new Exception("blah"); }
assert(collectException(foo(), b));
int[] a = new int[3];
collectException!RangeError(a[4], b);
}
compile with "dmd -m64 test.d" and run:
core.exception.RangeError@test(23): Range violation
----------------
0x000007F627E337DF in rt.lifetime.__setArrayAllocLength at M:\s\d\rainers\drunti
me\src\rt\lifetime.d(283)
0x000007F627E31508 in rt.lifetime._d_newarrayT at M:\s\d\rainers\druntime\src\rt
\lifetime.d(781)
0x000007F627E31237 in test.main.__dgliteral12
0x000007F627E31197 in test.main.foo at M:\s\d\rainers\bugs\rs144\test.d(19)
0x000007F627E311E8 in test.main.foo
0x000007F627E310AA in D main at M:\s\d\rainers\bugs\rs144\test.d(20)
0x000007F627E32FDE in rt.dmain2._d_run_main.tryExec.printInfoBlock at M:\s\d\rai
ners\druntime\src\rt\dmain2.d(556)
0x000007F627E3222E in rt.dmain2._d_run_main at M:\s\d\rainers\druntime\src\rt\dm
ain2.d(469)
0x000007F627E330D6 in rt.dmain2._d_run_main.tryExec.print at M:\s\d\rainers\drun
time\src\rt\dmain2.d(567)
0x000007F627E3222E in rt.dmain2._d_run_main at M:\s\d\rainers\druntime\src\rt\dm
ain2.d(469)
0x000007F627E321CE in rt.dmain2._d_run_main at M:\s\d\rainers\druntime\src\rt\dm
ain2.d(463)
0x000007F627E31276 in test.main.__dgliteral13 at M:\s\d\rainers\bugs\rs144\test.
d(23)
0x000007F627E4AD0B in core.demangle.Demangle.parseType at M:\s\d\rainers\druntim
e\src\core\demangle.d(862)
0x000007FB2EDF1832 in BaseThreadInitThunk
0x000007FB2EF8D609 in RtlUserThreadStart
----------------
It works with -g or more specifically with
dmd -m64 -L/OPT:NOICF test.d
So it seems exception information for the two collectException instantiations are merged.
Comment #1 by temtaime — 2015-03-19T10:53:25Z
Is there any fix not workaround ?
It increases .exe's size significantly.
Comment #2 by bugzilla — 2020-08-09T09:24:18Z
It would be easier to understand without the templates, lambdas, lazy parameters, etc. :-/
Comment #3 by r.sagitario — 2020-08-09T19:45:24Z
Here's a version without lazy and templates:
import core.exception;
Exception collectExceptionE(int delegate () expression, ref int result)
{
try
{
result = expression();
}
catch (Exception e)
{
return e;
}
return null;
}
RangeError collectExceptionR(int delegate () expression, ref int result)
{
try
{
result = expression();
}
catch (RangeError e)
{
return e;
}
return null;
}
void main()
{
int b;
int foo() { throw new Exception("blah"); }
assert(collectExceptionE(&foo, b));
int[] a = new int[3];
int goo() { return a[4]; }
collectExceptionR(&goo, b);
}
I suspect that the functions need to be the exact same code, and only the associated exception data differs. That's also why you cannot easily eliminate the delegate call.
Please note that you have to remove /OPT:NOICF from sc.ini to reproduce, as it was added as a workaround.
Comment #4 by bugzilla — 2020-09-15T08:43:29Z
You're right, it's the handler table that is different. The handler table is all based on offsets from the start of the function, so that works. The only pointer in it is the pointer to the catch type (the `*__ClassZ` symbols), and hence the only actual difference in the handler table.
The best fix I can think of for this is to embed in the catch blocks a reference to the catch type. Then functions that differ only in catch type won't be merged, and /OPT:NOICF will no longer be needed.
Comment #5 by bugzilla — 2020-09-15T09:33:00Z
I.e. this works:
import core.exception;
import core.bitop;
Exception collectExceptionE(int delegate () expression, ref int result)
{
try
{
result = expression();
}
catch (Exception e)
{
core.bitop.volatileLoad(cast(size_t*)Exception.classinfo); <*****
return e;
}
return null;
}
RangeError collectExceptionR(int delegate () expression, ref int result)
{
try
{
result = expression();
}
catch (RangeError e)
{
core.bitop.volatileLoad(cast(size_t*)RangeError.classinfo); <*****
return e;
}
return null;
}
void main()
{
int b;
int foo() { throw new Exception("blah"); }
assert(collectExceptionE(&foo, b));
int[] a = new int[3];
int goo() { return a[4]; }
collectExceptionR(&goo, b);
}
Comment #6 by dlang-bot — 2020-09-15T10:00:16Z
@WalterBright created dlang/dmd pull request #11736 "fix Issue 10664 - Win64: exception handling does not work with COMDAT…" fixing this issue:
- fix Issue 10664 - Win64: exception handling does not work with COMDAT folding
https://github.com/dlang/dmd/pull/11736
Comment #7 by dlang-bot — 2020-09-15T10:43:05Z
dlang/dmd pull request #11736 "fix Issue 10664 - Win64: exception handling does not work with COMDAT…" was merged into master:
- f3d96a38deee69fdfaabe49cd1a6c5a2b53563ce by Walter Bright:
fix Issue 10664 - Win64: exception handling does not work with COMDAT folding
https://github.com/dlang/dmd/pull/11736