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
(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