Bug 8563 – Exception segfault

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
All
Creation time
2012-08-20T03:12:00Z
Last change time
2014-08-15T18:15:57Z
Assigned to
nobody
Creator
daniel350
Blocks
10463

Comments

Comment #0 by daniel350 — 2012-08-20T03:12:35Z
http://dpaste.dzfl.pl/08d60e83 import std.exception : assertThrown; import std.file : dirEntries, SpanMode; // segfault does not occur with -O command line argument (exception is thrown as expected with -O) void main() { assertThrown(dirEntries("test", SpanMode.breadth)); // assert does not fail, as expected (ie, exception was thrown) func("test"); } void func(string suicide_variable) { // must be in a seperate function auto ax = suicide_variable; // uncomment this for a segfault in the following statement // not clear as to why, can't yet reproduce with other unpredictable exceptions (AFAIK) foreach(s; dirEntries("test", SpanMode.breadth)) {} // exception is expected, not a segfault } ---------- I tried to produce this behaviour for other functions (ie, without the dirEntries call), but I could not get at it; but this is all still very much undefined behaviour.
Comment #1 by maxim — 2013-02-18T09:06:35Z
Reduced struct DirEntry { string name; } struct DirIteratorImpl { DirEntry _cur; @property bool empty(){ return true; } @property DirEntry front(){ return _cur; } void popFront() { } } struct RefCounted { struct RefCountedStore { private struct Impl { DirIteratorImpl _payload; size_t _count; } private Impl* _store; } RefCountedStore _refCounted; ~this() { if (_refCounted._store) _refCounted._store._count = 0; } ref inout(DirIteratorImpl) refCountedPayload() inout { if (_refCounted._store) return _refCounted._store._payload; else throw new Exception("absent"); } alias refCountedPayload this; } struct DirIterator { RefCounted impl; this(string pathname) { throw new Exception(""); } @property bool empty(){ return impl.empty; } @property DirEntry front(){ return impl.front; } void popFront(){ impl.popFront(); } } auto dirEntries(string path) { return DirIterator(path); } void main() { foreach(s; dirEntries("test")) {} }
Comment #2 by maxim — 2013-02-18T11:03:57Z
Further reduced: struct Foo { int[100] i; } struct DirIterator { Foo* _store ; ~this() { if (_store) { _store.i = 0; // to segfault for sure _store = null; } } this(string pathname) { throw new Exception(""); } void popFront() { } bool empty() { return true; } Foo front() { return *_store; } } auto dirEntries() { return DirIterator("path"); } void main() { foreach(s; dirEntries()) {} } This looks like issue 9438 (struct with pointer field and dtor) but now temporaries from function return values are involved.
Comment #3 by maxim — 2013-02-18T11:26:46Z
The reason of the issue seems to be in that struct temporary inside main() is not initialized. If, line foreach(s; dirEntries()) {} is replaced to directly accessing object foreach(s; DirIterator("path")) {} dmd emits some code to clear the stack before assigning $rdi.
Comment #4 by nilsbossung — 2013-06-26T19:07:23Z
*** Issue 10475 has been marked as a duplicate of this issue. ***
Comment #5 by nilsbossung — 2013-06-26T19:09:12Z
Some observations (includes the stuff form issue 10475): struct DirIterator { int _store = 42; this(string dummy) {throw new Exception("constructor");} ~this() { assert(_store == 42, "destructing garbage"); assert(false, "destructor"); } } DirIterator dirEntries() {return DirIterator("");} void main() { /* This triggers only "constructor". The destructor is not called. */ version(A) DirIterator a = dirEntries(); /* This triggers "constructor" and "destructing garbage". I.e. destructor is called on uninitialized data. Probably fine in this case because of explicit void initialization. */ else version(B) { DirIterator b = void; b = dirEntries(); } /* This triggers "constructor" and "destructor". Arguably, the destructor should not be called, since construction has failed. */ else version(C) for(DirIterator c = DirIterator(""); true; ) {} /* Just like B, this triggers "constructor" and "destructing garbage". No explicit void initialization here, so that should not happen. */ else version(D) for(DirIterator c = dirEntries(); true;) {} else static assert(false); }
Comment #6 by k.hara.pg — 2013-07-02T07:05:14Z
I posted bug 10475 fix and now it's merged in git head. Could you please confirm the actual case by using git head?
Comment #7 by maxim — 2013-07-02T10:12:24Z
(In reply to comment #6) > I posted bug 10475 fix and now it's merged in git head. > Could you please confirm the actual case by using git head? This issue is also fixed. Thank you.
Comment #8 by dlang-bugzilla — 2014-08-15T18:15:57Z
*** Issue 6329 has been marked as a duplicate of this issue. ***