Bug 15272 – [2.069-rc2,inline] nothing written to output when -inline is set

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-11-01T18:10:00Z
Last change time
2015-12-01T13:22:31Z
Assigned to
nobody
Creator
b2.temp

Attachments

IDFilenameSummaryContent-TypeSize
1560file_15272.txtinvoled projecttext/plain11037

Comments

Comment #0 by b2.temp — 2015-11-01T18:10:31Z
Created attachment 1560 involed project I have this project that compiles fine with 2.069-rc2 but doesn't work anymore. So far I didn't manage to reduce the issue because several factors are mixed: What happens now: ================= nothing is written to stdout. what should happens: ==================== stdout filled. when does this work anyway: =========================== 1/ if I use the 'new' operator instead of my custom 'construct' template. 2/ if I disable the inline switch. 3/ if I create a File with "w" flag before writing stdout. with the 3rd workaround being totally WTF. So maybe something in File __ctor fix the issue ?!. code: ===== see attachment shell commands: =============== dmd /home/basile/Dev/pasproj/Coedit/cesyms/cesyms.d /home/basile/Dev/metad/libs/libdparse.a -I/home/basile/Dev/metad/repos/libdparse/src -w -inline -O -release -boundscheck=off -of../lazproj/cesyms Attempt to reduce: ================== So far I'm here but it doesn't capture the essence of the problem. --- //#!runnable-flags: -O -inline module runnable; import core.memory; import std.stdio, std.array, std.conv; import std.experimental.allocator.mallocator; ST* construct(ST, Allocator = Mallocator, A...)(A a) if(is(ST==struct)) { auto memory = Allocator.instance.allocate(ST.sizeof)[0 .. ST.sizeof]; //GC.addRange(memory.ptr, ST.sizeof); return emplace!(ST, A)(memory, a); } struct Foo { Foo*[] children; void get(ref Appender!string app) { app.put("whatever"); foreach(child; children) child.get(app); } } void main(string[] args) { Appender!string app; Foo* foo = construct!Foo; foreach(i; 0..100) { foo.children ~= construct!Foo; foreach(j; 0..100) foo.children[i].children ~= construct!Foo; } foo.get(app); auto s = app.data; assert(0, s); } --- the assertion failure doesn't happen at all when GC.addRange() is commented. Then in the real project project I've added GC.addRange() too to the struct/class allocators but the bug still happens (empty stdout). It looks like actually there's a crash before reaching 'write(stuff.serialize)'.
Comment #1 by ag0aep6g — 2015-11-01T18:46:34Z
(In reply to bb.temp from comment #0) > So far I'm here but it doesn't capture the essence of the problem. > > --- [...] > --- That code segfaults for me. Is that what you see, too?
Comment #2 by ag0aep6g — 2015-11-01T19:16:21Z
(In reply to bb.temp from comment #0) > So far I'm here but it doesn't capture the essence of the problem. > > --- [...] > --- As far as I can tell, everything works as expected in that code. The different `children` arrays are GC allocated (via ~=), but the `Foo`s themselves are not. So a parent `Foo` doesn't keep its `children` alive, and at some point the GC collects the seemingly dead arrays.
Comment #3 by b2.temp — 2015-11-01T20:05:29Z
(In reply to ag0aep6g from comment #2) > (In reply to bb.temp from comment #0) > > So far I'm here but it doesn't capture the essence of the problem. > > > > --- > [...] > > --- > > As far as I can tell, everything works as expected in that code. > > The different `children` arrays are GC allocated (via ~=), but the `Foo`s > themselves are not. So a parent `Foo` doesn't keep its `children` alive, and > at some point the GC collects the seemingly dead arrays. Take care with the small sample. I've written that <<it does not reproduce the problem>>, it was just an attempt. So far it just helped to show that it's necessary to add the ranges to the GC, which I've done to the real program. Despite of this in the real program it's still the same, if I call 'write(slb.serialize)': - with '-inline': stdout is empty. - without: stdout is filled When you consider those two facts it really looks that the inliner does something wrong.
Comment #4 by ag0aep6g — 2015-11-01T21:03:43Z
I think this is a bug in libdparse. Its `StringCache` allocates space for `buckets`, but doesn't null the pointers. On destruction it then tries to `free` the garbage pointers in there. https://github.com/Hackerpilot/libdparse/blob/8230f207912b40a46e5eae84e50ee59215b7c67f/src/dparse/lexer.d#L2009 Could you try adding `buckets[] = null;` after that line, then rebuild libdparse, and see if your project still crashes?
Comment #5 by ag0aep6g — 2015-11-01T21:11:50Z
(In reply to ag0aep6g from comment #4) > I think this is a bug in libdparse. > > Its `StringCache` allocates space for `buckets`, but doesn't null the > pointers. On destruction it then tries to `free` the garbage pointers in > there. Forget that. It's using calloc, not malloc, so it should be all zeros already.
Comment #6 by b2.temp — 2015-11-01T21:56:37Z
(In reply to ag0aep6g from comment #4) > I think this is a bug in libdparse. > > Its `StringCache` allocates space for `buckets`, but doesn't null the > pointers. On destruction it then tries to `free` the garbage pointers in > there. > > https://github.com/Hackerpilot/libdparse/blob/ > 8230f207912b40a46e5eae84e50ee59215b7c67f/src/dparse/lexer.d#L2009 > > Could you try adding `buckets[] = null;` after that line, then rebuild > libdparse, and see if your project still crashes? Yes. I confirm that the fix you suggested in libdparse works. But now I don't know whom the bug belongs to... Was it accidental that the program worked without -inline and without the libdparse fix ?!
Comment #7 by ag0aep6g — 2015-11-01T22:26:46Z
Here's a reduction that segfaults reliably for me with -release -O -inline: ---- extern(C) void* calloc(size_t, size_t) nothrow pure; void main() { { File file_; nop(); } auto scache = StringCache(1); foreach (nodePointer; scache.buckets) { if (nodePointer !is null) new Object; } } struct File { ~this() {} } void nop() {} struct StringCache { this(size_t bucketCount) { buckets = (cast(void**) calloc(8, bucketCount))[0 .. bucketCount]; } void*[] buckets; } ---- (In reply to bb.temp from comment #6) > Yes. I confirm that the fix you suggested in libdparse works. > > But now I don't know whom the bug belongs to... > Was it accidental that the program worked without -inline and without the > libdparse fix ?! I was mistaken. The bug I saw in libdparse is not there. My "fix" probably just masks the issue somehow.
Comment #8 by b2.temp — 2015-11-01T22:41:55Z
(In reply to ag0aep6g from comment #7) > Here's a reduction that segfaults reliably for me with -release -O -inline: > ---- > extern(C) void* calloc(size_t, size_t) nothrow pure; > > void main() > { > { > File file_; > nop(); > } > > auto scache = StringCache(1); > foreach (nodePointer; scache.buckets) > { > if (nodePointer !is null) new Object; > } > } > > struct File > { > ~this() {} > } > > void nop() {} > > struct StringCache > { > this(size_t bucketCount) > { > buckets = (cast(void**) calloc(8, bucketCount))[0 .. bucketCount]; > } > > void*[] buckets; > } > ---- Yes that's it. Thx much for your patience.
Comment #9 by schuetzm — 2015-11-02T09:47:22Z
Digger blames this PR for me: https://github.com/D-Programming-Language/dmd/pull/5060 ... but this looks very unlikely to be the culprit.
Comment #10 by ag0aep6g — 2015-11-02T11:42:37Z
(In reply to ag0aep6g from comment #7) > Here's a reduction that segfaults reliably for me with -release -O -inline: > ---- [...] > ---- Reduced a little further, showing that bucketCount gets corrupted: ---- import core.stdc.stdio: printf; pragma(inline, false) void[] calloc_(size_t bc) nothrow pure { debug printf("%x\n", bc); /* prints "ffffffff", should print "1" */ return []; } void main() { { File file_; nop(); } auto scache = StringCache(1); } struct File { ~this() {} } void nop() {} struct StringCache { this(size_t bucketCount) { buckets = calloc_(bucketCount)[0 .. bucketCount]; printf(""); } void[] buckets; } ----
Comment #11 by ag0aep6g — 2015-11-02T12:47:06Z
(In reply to ag0aep6g from comment #10) > Reduced a little further, showing that bucketCount gets corrupted: > ---- [...] > ---- And further, removing -inline from the equation (still needs -release -O): ---- import core.stdc.stdio: printf; void[] calloc_(size_t bc) nothrow pure { debug printf("%x\n", bc); /* prints "ffffffff", should print "1" */ return []; } void main() { try nop(); finally {} StringCache scache; size_t bucketCount = 1; void[]* buckets = &scache.buckets; *buckets = calloc_(bucketCount)[0 .. bucketCount]; printf(""); } void nop() {} struct StringCache { void[] buckets; } ----
Comment #12 by code — 2015-11-02T17:30:02Z
I diggered and found https://github.com/D-Programming-Language/dmd/pull/4909 to be the culprit.
Comment #13 by safety0ff.bugz — 2015-11-02T20:11:23Z
(In reply to Martin Nowak from comment #12) > I diggered and found https://github.com/D-Programming-Language/dmd/pull/4909 > to be the culprit. FWIW, the following patch fixes it for me: --- a/src/backend/cgelem.c +++ b/src/backend/cgelem.c @@ -3545,8 +3545,8 @@ STATIC elem * eleq(elem *e, goal_t goal) { e->E2 = e2->E1; eb = el_bin(OPeq,ty,eb,e2->E2); - e2->E1 = eb; - e2->E2 = e; + e2->E1 = e; + e2->E2 = eb; } else {
Comment #14 by bugzilla — 2015-11-02T23:38:32Z
(In reply to safety0ff.bugz from comment #13) > FWIW, the following patch fixes it for me: > > --- a/src/backend/cgelem.c > +++ b/src/backend/cgelem.c > @@ -3545,8 +3545,8 @@ STATIC elem * eleq(elem *e, goal_t goal) > { > e->E2 = e2->E1; > eb = el_bin(OPeq,ty,eb,e2->E2); > - e2->E1 = eb; > - e2->E2 = e; > + e2->E1 = e; > + e2->E2 = eb; > } > else > { https://github.com/D-Programming-Language/dmd/pull/5253
Comment #15 by bugzilla — 2015-11-03T07:45:00Z
BTW, this is a critical bug.
Comment #16 by github-bugzilla — 2015-11-03T19:24:10Z
Commits pushed to stable at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/633c50a4ffd3980502eaacecf7c743e7051925a3 fix Issue 15272 - [2.069-rc2,inline] nothing written to output when -inline is set https://github.com/D-Programming-Language/dmd/commit/90433ba633c85ce784e971077b2af8aef389ed47 Merge pull request #5258 from MartinNowak/fix15272 fix Issue 15272 - [2.069-rc2,inline] nothing written to output when -inline is set
Comment #17 by github-bugzilla — 2015-12-01T13:22:31Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/633c50a4ffd3980502eaacecf7c743e7051925a3 fix Issue 15272 - [2.069-rc2,inline] nothing written to output when -inline is set https://github.com/D-Programming-Language/dmd/commit/90433ba633c85ce784e971077b2af8aef389ed47 Merge pull request #5258 from MartinNowak/fix15272