Bug 22365 – Compiler crash: tcs.body_ null in StatementSemanticVisitor.visit(TryCatchStatement) in semantic3 pass (dmd/statementsem.d:3956)

Status
RESOLVED
Resolution
FIXED
Severity
blocker
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-10-08T13:12:00Z
Last change time
2022-01-14T10:13:07Z
Keywords
pull
Assigned to
No Owner
Creator
evilrat666

Comments

Comment #0 by evilrat666 — 2021-10-08T13:12:00Z
Crashes when building one specific project: https://github.com/buggins/dlangui Related issue: https://github.com/buggins/dlangui/issues/616 Happens in class constructor with debug statement, however using minimal repro-case doesn't expose this behavior, also no other project I tried had this. Note that it is possible that it is only happens doing -release/optimization builds. (this code won't trigger it) ------------ import std.stdio; class Test { this() { debug writeln("hello"); } } void main() { auto test = new Test(); } ----------- CALL STACK for dmd as a library running semantic3 for dlangui issue ---------------------- dmdlib.exe!_D2rt15deh_win64_posix9terminateFZv() (Unknown Source:0) dmdlib.exe!_d_assertp() (Unknown Source:0) dmdlib.exe!dmd.statementsem.StatementSemanticVisitor.visit(dmd.statement.TryCatchStatement * tcs) Line 3956 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\statementsem.d:3956) dmdlib.exe!dmd.statement.TryCatchStatement.accept(dmd.visitor.Visitor * v) Line 1582 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\statement.d:1582) dmdlib.exe!dmd.statementsem.statementSemantic(dmd.statement.Statement * s, dmd.dscope.Scope * sc) Line 143 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\statementsem.d:143) dmdlib.exe!dmd.semantic3.Semantic3Visitor.visit(dmd.func.FuncDeclaration * funcdecl) Line 581 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:581) dmdlib.exe!dmd.semantic3.Semantic3Visitor.visit(dmd.func.CtorDeclaration * ctor) Line 1445 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:1445) dmdlib.exe!dmd.func.CtorDeclaration.accept(dmd.visitor.Visitor * v) Line 3660 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\func.d:3660) dmdlib.exe!dmd.semantic3.semantic3(dmd.dsymbol.Dsymbol * dsym, dmd.dscope.Scope * sc) Line 82 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:82) dmdlib.exe!dmd.semantic3.Semantic3Visitor.visit(dmd.aggregate.AggregateDeclaration * ad) Line 1505 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:1505) dmdlib.exe!dmd.parsetimevisitor.ParseTimeVisitor!(dmd.astcodegen.ASTCodegen).ParseTimeVisitor.visit(dmd.dclass.ClassDeclaration * s) Line 90 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\parsetimevisitor.d:90) dmdlib.exe!dmd.dclass.ClassDeclaration.accept(dmd.visitor.Visitor * v) Line 999 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\dclass.d:999) dmdlib.exe!dmd.semantic3.semantic3(dmd.dsymbol.Dsymbol * dsym, dmd.dscope.Scope * sc) Line 82 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:82) dmdlib.exe!dmd.semantic3.Semantic3Visitor.visit(dmd.dmodule.Module * mod) Line 195 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:195) dmdlib.exe!dmd.dmodule.Module.accept(dmd.visitor.Visitor * v) Line 1542 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\dmodule.d:1542) dmdlib.exe!dmd.semantic3.semantic3(dmd.dsymbol.Dsymbol * dsym, dmd.dscope.Scope * sc) Line 82 (c:\Users\devr\AppData\Local\dub\packages\dmd-master\dmd\src\dmd\semantic3.d:82) dmdlib.exe!app.processDecls.__foreachbody17(string * __capture, dmd.dmodule.Module * * __applyArg1) Line 288 (d:\prog\dmdlib\source\app.d:288) dmdlib.exe!_aaApply2() (Unknown Source:0) dmdlib.exe!app.processDecls(app.RunParams params) Line 286 (d:\prog\dmdlib\source\app.d:286) dmdlib.exe!D main(string[] args) Line 69 (d:\prog\dmdlib\source\app.d:69) ----------------------
Comment #1 by razvan.nitu1305 — 2021-10-12T09:16:47Z
The chances of this bug getting fixed without a minimal reproducible test case are small. Maybe you can use DustMite [1] to reduce it? [1] https://dlang.org/blog/2020/04/13/dustmite-the-general-purpose-data-reduction-tool/
Comment #2 by evilrat666 — 2021-10-19T11:02:27Z
(In reply to RazvanN from comment #1) > The chances of this bug getting fixed without a minimal reproducible test > case are small. Maybe you can use DustMite [1] to reduce it? > > [1] > https://dlang.org/blog/2020/04/13/dustmite-the-general-purpose-data- > reduction-tool/ nope, unfortunately I wasn't able to reduce it yet, this is a complex library with tons of dependencies and it is happily reduces it down to 'import ;'. I'll try again later, meanwhile I traced down the issue and ready to submit possible fix (I hope that's a real fix and not just symptoms mending) PR after I double check everything. Here is an overview ----------------------------------------- dmd issue 22365 calls: [1] semantic3.d:1369 Semantic3Visitor.visit(CtorDeclaration) at 1446 TryCatchStatemt generation [2] semantic3.d:208 Semantic3Visitor.visit(FuncDeclaration) at 595 statementSemantic(funcdecl.fbody, sc2) call [3] statementsem.d:148 statementSemantic(Statement, Scope*) at 145 StatementSemanticVisitor.accept() [4] statement.d:1580 TryCatchStatemt.accept (just in case) [5] statementsem.d:3936 StatementSemanticVisitor.visit(TryCatchStatemt) at 3957 semanticScope() <--- here, returns wrong scope [6] statementsem.d:4486 semanticScope(Statement, Scope*, Statement, Statement, Statement) <--- push & pop the same scope? [7] statementsem.d:4473 semanticNoScope(Statement, Scope*) at 4468 statementSemantic() returns null which triggers assert above [8] statementsem.d:236 StatementSemanticVisitor.visit(CompoundStatent) at 257-264 flatten() and then statementSemantic() [9] statementsem.d:4631 flatten(Statement, Scope*) probably at 4720 if condition specifically look: [5] https://github.com/dlang/dmd/blob/96b959e27c690f5e3abf411f8032c60f4728c1c1/src/dmd/statementsem.d#L3936 [6] https://github.com/dlang/dmd/blob/96b959e27c690f5e3abf411f8032c60f4728c1c1/src/dmd/statementsem.d#L4497 so, at step 6 when using debbuger after semanticNoScope() restore s (null at this moment) back to original s (from function argument), now it works as expected > s = s.semanticNoScope(scd); // <- null > /* restore s */ > scd.pop(); > return s; tracing it further... [8] https://github.com/dlang/dmd/blob/96b959e27c690f5e3abf411f8032c60f4728c1c1/src/dmd/statementsem.d#L255 calling flatten() produces Statements[] array with single null element which is then returned as valid result here around line 420 > if (cs.statements.length == 1) > { > result = (*cs.statements)[0]; > return; > } [9] https://github.com/dlang/dmd/blob/96b959e27c690f5e3abf411f8032c60f4728c1c1/src/dmd/statementsem.d#L4726 debug condition doesn't get picked up and returns that Statements[] array with single null element afterwards > if (cs.condition.include(sc)) can be fixed with adding else if check for null and else return 0 here https://github.com/dlang/dmd/blob/96b959e27c690f5e3abf411f8032c60f4728c1c1/src/dmd/statementsem.d#L4737 this doesn't happens when adding debug else condition to original problem source, or replacing debug with version (all/none) or anything else, so there is a logic issue related to debug ConditionStatement somewhere
Comment #3 by moonlightsentinel — 2022-01-12T20:38:48Z
Reduction: alias DrawableRef = Ref!int; class DrawableCache { DrawableRef _nullDrawable; this() { debug Log; } } struct Ref(T) { ~this() { } } Requires -preview=dtorfields with older compilers.
Comment #4 by moonlightsentinel — 2022-01-12T20:49:50Z
Even smaller: class DrawableCache { Ref _nullDrawable; this() { debug Log; } } struct Ref { ~this() {} }
Comment #5 by dlang-bot — 2022-01-12T22:25:10Z
@MoonlightSentinel updated dlang/dmd pull request #13516 "Don't crash for conditionally empty body of TryStatement" fixing this issue: - Fix 22365 - Don't crash for conditionally empty body of a TryStatement The body may end up empty / null after `statementSemantic` if it only contains conditionally compiled statements (`version`, `debug`, ...) whose conditions are not met. This only triggered for the `-preview=dtorfields` rewrite because it didn't wrap the empty body into an additional `ScopeStatement`. But it should be sufficient to check during `TryStatement` semantic instead of unconditionally allocating an additional node for this rare case. https://github.com/dlang/dmd/pull/13516
Comment #6 by dlang-bot — 2022-01-14T10:13:07Z
dlang/dmd pull request #13516 "Fix 22365 - Don't crash for conditionally empty body of a TryStatement" was merged into stable: - 4b2b2af5c276f64334a8eb9daf0c00db83cb93d2 by MoonlightSentinel: Fix 22365 - Don't crash for conditionally empty body of a TryStatement The body may end up empty / null after `statementSemantic` if it only contains conditionally compiled statements (`version`, `debug`, ...) whose conditions are not met. This only triggered for the `-preview=dtorfields` rewrite because it didn't wrap the empty body into an additional `ScopeStatement`. But it should be sufficient to check during `TryStatement` semantic instead of unconditionally allocating an additional node for this rare case. https://github.com/dlang/dmd/pull/13516