Bug 6308 – Destruction of temporaries on exception causes unhandled access violation
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2011-07-13T17:52:00Z
Last change time
2011-09-08T09:16:03Z
Keywords
wrong-code
Assigned to
nobody
Creator
dlang-bugzilla
Comments
Comment #0 by dlang-bugzilla — 2011-07-13T17:52:12Z
My reply about this issue on dmd-beta is pending moderation, but a bug about this should probably be filed anyway.
import std.stdio;
void main()
{
foreach (i; 0..100)
foreach (line; File("test.d").byLine)
{}
}
On Windows, when the above program is compiled with DMD from current git and ran, it crashes with an unhandled exception (Windows displays two standard "has stopped working" dialogs in succession).
Comment #1 by bugzilla — 2011-07-15T10:27:29Z
More by Vladimir:
I did a bit of research on this a few days ago. Using a certain debugger
and the map file, I found that the crash occurred in the autogenerated
scope(exit) for getDependencies - the block of code that calls the File
destructor. I didn't look too closely, but it looked like a bad "this"
pointer is passed to the File dtor. I tried a full DMD/Phobos regression
test, but didn't really get anywhere.
Comment #2 by dlang-bugzilla — 2011-07-15T21:48:28Z
Minimized testcase:
struct C
{
this(int)
{
throw new Exception("Oops!");
}
~this()
{
}
int bar() { return 1; }
}
void foo(int) {}
void main()
{
foo(C(1).bar());
}
The key finding is that the exception is thrown in the constructor.
Comment #3 by dlang-bugzilla — 2011-07-21T16:29:13Z
*** Issue 6329 has been marked as a duplicate of this issue. ***
Comment #4 by dlang-bugzilla — 2011-07-21T16:32:01Z
Issue 6329 is an example where the the exception isn't thrown in the constructor, but in the body of a delegate (dirEntries uses opApply). I'll try to minimize it.
Comment #5 by dlang-bugzilla — 2011-07-25T23:26:22Z
(In reply to comment #4)
> I'll try to minimize it.
Reduced it to a small variation of the above.
struct C
{
void oops()
{
throw new Exception("Oops!");
}
~this()
{
}
}
void main()
{
C().oops();
}
I think DustMite may have taken some shortcuts while reducing Andrej's test case, though - but this test case definitely does show that it's not about throwing in a constructor.
Comment #6 by dlang-bugzilla — 2011-07-25T23:28:29Z
By the way, I should probably clearly mention that this is Windows-only.
Comment #7 by r.sagitario — 2011-08-13T13:55:58Z
I had a quick look at the disassembly generated for the code in comment 5, and it turns out that the frame handler pointer is zero, instead of identical code "C c; c.oops();" that generates something like
mov edx,dword ptr fs:[0]
push offset __Dmain+77h // this is 0 for "C().oops();"
push edx
mov dword ptr fs:[0],esp
Comment #8 by r.sagitario — 2011-08-13T14:13:28Z
dmd 2.053 does not crash, but also does not create any exception handling code at all, while dmd 2.054+ seems to generate setup code for the exception frame, but no exception code.
*** Issue 6363 has been marked as a duplicate of this issue. ***
Comment #11 by andrej.mitrovich — 2011-08-26T09:25:16Z
This code:
import std.file;
void main()
{
string[] dirs;
foreach (string dir; dirEntries(r"C:\", SpanMode.shallow))
{
if (dir.isDir)
dirs ~= dir;
}
}
Compiled via DMD 2.055 commit cfab198ee186f6e69c364aaf4206434220d83204 (Aug 15), enters an infinite loop at runtime where exceptions are kept throwing:
=== Bypassed ===
std.file.FileException@std\file.d(1156): C:\pagefile.sys: The process cannot access the file because it is being used by
another process.
----------------
42A540
42A3B7
402A7D
40206D
402950
40298F
40258B
45B855
45B7AC
----------------
object.Error: Access Violation
----------------
42A540
42A3B7
402950
40298F
40258B
45B855
45B7AC
----------------
Bypasses std.file.FileException@std\file.d(1156)
object.Error: Access Violation
----------------
42A540
42A3B7
402950
40298F
40258B
45B855
45B7AC
----------------
object.Error: Access Violation
----------------
42A540
42A3B7
402950
40298F
40258B
45B855
45B7AC
It seems after it tries to open the protected pagefile.sys it keeps rethrowing exceptions and not exiting the foreach loop. It doesn't stop at all, just keeps rethrowing.
Comment #12 by dlang-bugzilla — 2011-09-08T03:22:49Z
(In reply to comment #11)
> It seems after it tries to open the protected pagefile.sys it keeps rethrowing
> exceptions and not exiting the foreach loop. It doesn't stop at all, just keeps
> rethrowing.
I can't reproduce this, it throws a single exception for me. Was this fixed in the meantime?
The fact that you can't list C:\ because Phobos can't read a file's attributes is worth a separate bug report, though.
Comment #13 by andrej.mitrovich — 2011-09-08T07:48:16Z
(In reply to comment #12)
> (In reply to comment #11)
> > It seems after it tries to open the protected pagefile.sys it keeps rethrowing
> > exceptions and not exiting the foreach loop. It doesn't stop at all, just keeps
> > rethrowing.
>
> I can't reproduce this, it throws a single exception for me. Was this fixed in
> the meantime?
The final 2.055 release still has this issue, just checked.
Comment #14 by andrej.mitrovich — 2011-09-08T09:16:03Z
(In reply to comment #13)
> (In reply to comment #12)
> > (In reply to comment #11)
> > > It seems after it tries to open the protected pagefile.sys it keeps rethrowing
> > > exceptions and not exiting the foreach loop. It doesn't stop at all, just keeps
> > > rethrowing.
> >
> > I can't reproduce this, it throws a single exception for me. Was this fixed in
> > the meantime?
>
> The final 2.055 release still has this issue, just checked.
Note that my bug6329 which was labeled as duplicate of this has a similar issue. First I get a range violation, then `object.Error: Access Violation` is printed many times before the app exits.