From 826e5b08266273af70b2be9b0da2f41c6352a379 Mon Sep 17 00:00:00 2001 From: Igor Zaworski Date: Wed, 16 Jul 2025 18:07:34 +0200 Subject: [PATCH] Fix `--coverage-expr` null pointer dereference (#6181) --- src/V3Coverage.cpp | 20 ++++++++++---- test_regress/t/t_cover_expr_array_class.py | 18 +++++++++++++ test_regress/t/t_cover_expr_array_class.v | 26 +++++++++++++++++++ .../t/t_cover_expr_associative_array_class.py | 18 +++++++++++++ .../t/t_cover_expr_associative_array_class.v | 26 +++++++++++++++++++ .../t/t_cover_expr_dyn_array_class.py | 18 +++++++++++++ test_regress/t/t_cover_expr_dyn_array_class.v | 26 +++++++++++++++++++ test_regress/t/t_cover_expr_queue_class.py | 18 +++++++++++++ test_regress/t/t_cover_expr_queue_class.v | 26 +++++++++++++++++++ 9 files changed, 191 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_cover_expr_array_class.py create mode 100644 test_regress/t/t_cover_expr_array_class.v create mode 100755 test_regress/t/t_cover_expr_associative_array_class.py create mode 100644 test_regress/t/t_cover_expr_associative_array_class.v create mode 100755 test_regress/t/t_cover_expr_dyn_array_class.py create mode 100644 test_regress/t/t_cover_expr_dyn_array_class.v create mode 100755 test_regress/t/t_cover_expr_queue_class.py create mode 100644 test_regress/t/t_cover_expr_queue_class.v diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 3ec67eb85..68e98835c 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -39,17 +39,28 @@ class ExprCoverageEligibleVisitor final : public VNVisitor { // STATE bool m_eligible = true; + static bool elemDTypeEligible(const AstNodeDType* dtypep) { + dtypep = dtypep->skipRefp(); + if (AstNodeDType* const dtp = dtypep->virtRefDTypep()) { + if (!elemDTypeEligible(dtp)) return false; + } + if (AstNodeDType* const dtp = dtypep->virtRefDType2p()) { + if (!elemDTypeEligible(dtp)) return false; + } + return !VN_IS(dtypep, ClassRefDType); + } + void visit(AstNodeVarRef* nodep) override { AstNodeDType* dtypep = nodep->varp()->dtypep(); - // Class objecs and references not supported for expression coverage + // Class objects and references not supported for expression coverage // because the object may not persist until the point at which // coverage data is gathered // This could be resolved in the future by protecting against dereferrencing // null pointers when cloning the expression for expression coverage - if (VN_CAST(dtypep, ClassRefDType)) { - m_eligible = false; - } else { + if (dtypep && elemDTypeEligible(dtypep)) { iterateChildren(nodep); + } else { + m_eligible = false; } } @@ -858,7 +869,6 @@ class CoverageVisitor final : public VNVisitor { != strs[!term.m_objective].end()) impossible = true; } - if (!redundant) expr.push_back(term); } if (!impossible) m_exprs.push_back(std::move(expr)); diff --git a/test_regress/t/t_cover_expr_array_class.py b/test_regress/t/t_cover_expr_array_class.py new file mode 100755 index 000000000..27aec629f --- /dev/null +++ b/test_regress/t/t_cover_expr_array_class.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--coverage-expr']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cover_expr_array_class.v b/test_regress/t/t_cover_expr_array_class.v new file mode 100644 index 000000000..1c82e6a45 --- /dev/null +++ b/test_regress/t/t_cover_expr_array_class.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class Class1; + int value0 = 7; +endclass + +module t; + initial begin + int i = 0; + Class1 q[15]; + for (int j = 0; j < 15; j = j + 1) begin + Class1 x = new; + q[j] = x; + end + while (i < 15) begin + if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop; + i += 1; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_cover_expr_associative_array_class.py b/test_regress/t/t_cover_expr_associative_array_class.py new file mode 100755 index 000000000..27aec629f --- /dev/null +++ b/test_regress/t/t_cover_expr_associative_array_class.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--coverage-expr']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cover_expr_associative_array_class.v b/test_regress/t/t_cover_expr_associative_array_class.v new file mode 100644 index 000000000..2c1057a3b --- /dev/null +++ b/test_regress/t/t_cover_expr_associative_array_class.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class Class1; + int value0 = 7; +endclass + +module t; + initial begin + int i = 0; + Class1 q[int] = '{}; + for (int j = 0; j < 15; j = j + 1) begin + Class1 x = new; + q[j] = x; + end + while (i < 15) begin + if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop; + i += 1; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_cover_expr_dyn_array_class.py b/test_regress/t/t_cover_expr_dyn_array_class.py new file mode 100755 index 000000000..27aec629f --- /dev/null +++ b/test_regress/t/t_cover_expr_dyn_array_class.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--coverage-expr']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cover_expr_dyn_array_class.v b/test_regress/t/t_cover_expr_dyn_array_class.v new file mode 100644 index 000000000..5cd5ab1cc --- /dev/null +++ b/test_regress/t/t_cover_expr_dyn_array_class.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class Class1; + int value0 = 7; +endclass + +module t; + initial begin + int i = 0; + Class1 q[] = new [15]; + for (int j = 0; j < 15; j = j + 1) begin + Class1 x = new; + q[j] = x; + end + while (i < 15) begin + if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop; + i += 1; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_cover_expr_queue_class.py b/test_regress/t/t_cover_expr_queue_class.py new file mode 100755 index 000000000..27aec629f --- /dev/null +++ b/test_regress/t/t_cover_expr_queue_class.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--coverage-expr']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cover_expr_queue_class.v b/test_regress/t/t_cover_expr_queue_class.v new file mode 100644 index 000000000..fefcb0f36 --- /dev/null +++ b/test_regress/t/t_cover_expr_queue_class.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class Class1; + int value0 = 7; +endclass + +module t; + initial begin + int i = 0; + Class1 q[$]; + repeat(15) begin + Class1 x = new; + q = { q, x }; + end + while (i < q.size()) begin + if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop; + i += 1; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule