From 97add4d57a496170732e2f4f49fc9cb7ca57cde0 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Thu, 6 Oct 2022 15:38:59 +0200 Subject: [PATCH] Fix null access on optimized-out fork statements (#3658) `V3SchedTiming` currently assumes that if a fork still exists, it must have statements within it (otherwise it would have been deleted by `V3Timing`). However, in a case like this: ``` module t; reg a; initial fork a = 1; join endmodule ``` the assignment in the fork is optimized out by `V3Dead` after `V3Timing`. This leads to `V3SchedTiming` accessing fork's `stmtsp` pointer, which at this point is null. This patch addresses that issue. Signed-off-by: Krzysztof Bieganski --- src/V3SchedTiming.cpp | 6 ++++-- test_regress/t/t_timing_debug2.out | 2 ++ test_regress/t/t_timing_fork_join.v | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 5423ec629..6fc2e0656 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -323,8 +323,10 @@ void transformForks(AstNetlist* const netlistp) { iterateChildrenConst(nodep); // Const, so we don't iterate the calls twice // Replace self with the function calls (no co_await, as we don't want the main // process to suspend whenever any of the children do) - nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + // V3Dead could have removed all statements from the fork, so guard against it + AstNode* const stmtsp = nodep->stmtsp(); + if (stmtsp) nodep->addNextHere(stmtsp->unlinkFrBackWithNext()); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } void visit(AstBegin* nodep) override { UASSERT_OBJ(m_forkp, nodep, "Begin outside of a fork"); diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index 0972ba27c..0e3f6d873 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -15,6 +15,8 @@ -V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__5 -V{t#,#} Awaiting join of fork at: t/t_timing_fork_join.v:13 -V{t#,#}+ Vt_timing_debug2___024root___eval_initial__TOP__1 +-V{t#,#}+ Vt_timing_debug2___024root___eval_initial__TOP__2 +-V{t#,#} Awaiting join of fork at: t/t_timing_fork_join.v:83 -V{t#,#}+ Vt_timing_debug2___024root___eval_settle -V{t#,#}+ Eval -V{t#,#}+ Vt_timing_debug2___024root___eval diff --git a/test_regress/t/t_timing_fork_join.v b/test_regress/t/t_timing_fork_join.v index fb5b6c60d..12ec14ef6 100644 --- a/test_regress/t/t_timing_fork_join.v +++ b/test_regress/t/t_timing_fork_join.v @@ -77,4 +77,8 @@ module t; $finish; end initial #100 $stop; // timeout + + // Test optimized-out fork statements: + reg a; + initial fork a = 1; join endmodule