From 922571c18201e499437ef68103b3c9596372e313 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:37:15 +0200 Subject: [PATCH 1/6] Update checkbufferoverrun.cpp --- lib/checkbufferoverrun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index b3aa09d137c..bdd18ee21d2 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -461,7 +461,7 @@ void CheckBufferOverrunImpl::negativeIndexError(const Token* tok, } reportError(getErrorPath(tok, negativeValue, "Negative array index"), - negativeValue->errorSeverity() ? Severity::error : Severity::warning, + (negativeValue->errorSeverity() && !negativeValue->conditional) ? Severity::error : Severity::warning, "negativeIndex", arrayIndexMessage(tok, dimensions, indexes, condition), CWE_BUFFER_UNDERRUN, From fe2254b0e7b817f2afaec512eb31e894cf2215df Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:37:46 +0200 Subject: [PATCH 2/6] Update checkother.cpp --- lib/checkother.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 0aa9dd18a84..7ba87873ae1 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2570,8 +2570,8 @@ void CheckOtherImpl::zerodivError(const Token *tok, const ValueFlow::Value *valu errmsg << "Division by zero."; reportError(std::move(errorPath), - value->errorSeverity() ? Severity::error : Severity::warning, - value->condition ? "zerodivcond" : "zerodiv", + (value->errorSeverity() && !value->conditional) ? Severity::error : Severity::warning, + (value->condition || value->conditional) ? "zerodivcond" : "zerodiv", errmsg.str(), CWE369, value->isInconclusive() ? Certainty::inconclusive : Certainty::normal); } From 9e74aa510d8a77988e6c7631c5abf98c13519714 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:38:14 +0200 Subject: [PATCH 3/6] Update vf_settokenvalue.cpp --- lib/vf_settokenvalue.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index 9f56b57db0a..824c129c846 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -407,6 +407,8 @@ namespace ValueFlow } else if (parent->str() == ":" && Token::simpleMatch(parent->astParent(), "?")) { + const std::string condStr(tok == parent->astOperand1() ? "true" : "false"); + value.errorPath.emplace_back(parent->astParent()->astOperand1(), "Assuming condition '" + parent->astParent()->astOperand1()->expressionString() + "' is " + condStr); setTokenValue(parent,std::move(value),settings); } From 0b5c882861b9f9097fba44ba56260cf2e8b67068 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:38:47 +0200 Subject: [PATCH 4/6] Update testbufferoverrun.cpp --- test/testbufferoverrun.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 7b36dbac035..f6a2e1a5ec1 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3676,6 +3676,34 @@ class TestBufferOverrun : public TestFixture { "[test.cpp:8:12]: warning: Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n" "[test.cpp:7:11]: note: Assuming that condition 'i!=2' is not redundant\n" "[test.cpp:8:12]: note: Buffer overrun\n", errout_str()); + + check("int a[3];\n" + "int f1(int i, bool b) {\n" + " int j = b ? i : -1;\n" + " return a[j];\n" + "}" + "int f2(int i, bool b) {\n" + " int j = b ? -1 : i;\n" + " return a[j];\n" + "}" + "int f3(int i, bool b) {\n" + " int j = -1;\n" + " if (b)\n" + " j = i;\n" + " return a[j];\n" + "}", s); + ASSERT_EQUALS("[test.cpp:4:13]: warning: Array 'a[3]' accessed at index -1, which is out of bounds. [negativeIndex]\n" + "[test.cpp:3:13]: note: Assuming condition 'b' is false\n" + "[test.cpp:3:15]: note: Assignment 'j=b?i:-1', assigned value is -1\n" + "[test.cpp:4:13]: note: Negative array index\n" + "[test.cpp:7:13]: warning: Array 'a[3]' accessed at index -1, which is out of bounds. [negativeIndex]\n" + "[test.cpp:6:13]: note: Assuming condition 'b' is true\n" + "[test.cpp:6:15]: note: Assignment 'j=b?-1:i', assigned value is -1\n" + "[test.cpp:7:13]: note: Negative array index\n" + "[test.cpp:12:13]: warning: Array 'a[3]' accessed at index -1, which is out of bounds. [negativeIndex]\n" + "[test.cpp:9:14]: note: Assignment 'j=-1', assigned value is -1\n" + "[test.cpp:10:9]: note: Assuming condition is false\n" + "[test.cpp:12:13]: note: Negative array index\n", errout_str()); } void buffer_overrun_bailoutIfSwitch() { From 9d9305aa4df134b31ff8711bbdeef35bef1eeb0c Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:39:12 +0200 Subject: [PATCH 5/6] Update testother.cpp --- test/testother.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index 27f7700bd54..7287d0339fb 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -76,6 +76,7 @@ class TestOther : public TestFixture { TEST_CASE(zeroDiv22); TEST_CASE(zeroDivCond); // division by zero / useless condition + TEST_CASE(zeroDivErrorPath); TEST_CASE(nanInArithmeticExpression); @@ -897,6 +898,38 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void zeroDivErrorPath() { + setMultiline(); + Settings s = settings0; + s.templateLocation = "{file}:{line}:note:{info}\n"; + + check("int f1(int i, bool b) {\n" + " int j = b ? i : 0;\n" + " return 1 / j;\n" + "}\n" + "int f2(int i, bool b) {\n" + " int j = b ? 0 : i;\n" + " return 1 / j;\n" + "}\n" + "int f3(int i, bool b) {\n" + " int j = 1;\n" + " if (b)\n" + " j = 0;\n" + " return 1 / j;\n" + "}\n", dinit(CheckOptions, $.settings = &s)); + ASSERT_EQUALS("[test.cpp:3:14]: warning: Division by zero. [zerodivcond]\n" + "[test.cpp:2:13]: note: Assuming condition 'b' is false\n" + "[test.cpp:2:15]: note: Assignment 'j=b?i:0', assigned value is 0\n" + "[test.cpp:3:14]: note: Division by zero\n" + "[test.cpp:7:14]: warning: Division by zero. [zerodivcond]\n" + "[test.cpp:6:13]: note: Assuming condition 'b' is true\n" + "[test.cpp:6:15]: note: Assignment 'j=b?0:i', assigned value is 0\n" + "[test.cpp:7:14]: note: Division by zero\n" + "[test.cpp:13:14]: warning: Division by zero. [zerodivcond]\n" + "[test.cpp:12:13]: note: Assignment 'j=0', assigned value is 0\n" + "[test.cpp:13:14]: note: Division by zero\n", errout_str()); + } + void nanInArithmeticExpression() { check("void f()\n" "{\n" From 6b12ec5f113f989fb3ece7ea6472c5514e296f3b Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Fri, 18 Sep 2026 22:55:12 +0200 Subject: [PATCH 6/6] Fix #15016 Inconsistent error paths for if conditions --- lib/forwardanalyzer.cpp | 2 +- lib/vf_analyzers.cpp | 14 ++++++++++++-- test/testautovariables.cpp | 16 ++++++++-------- test/testother.cpp | 1 + 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 3e227873b26..7658172ca8d 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -709,7 +709,7 @@ namespace { return Break(); } } - analyzer->assume(condTok, !inElse, Analyzer::Assume::Quiet); + analyzer->assume(condTok, !inElse); assert(!inDoWhile || Token::simpleMatch(tok, "} while (")); if (hasElse || inDoWhile) tok = tok->linkAt(2); diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index e61f786a526..1a4d17aa849 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -998,7 +998,12 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer { void addErrorPath(const Token* tok, const std::string& s) override { for (auto&& p:values) { - p.second.errorPath.emplace_back(tok, s); + auto& ep = p.second.errorPath; + if (std::any_of(ep.begin(), ep.end(), [&](const ErrorPathItem& epi) { + return epi.first == tok && epi.second == s; + })) + continue; + ep.emplace_back(tok, s); } } @@ -1146,7 +1151,12 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { } void addErrorPath(const Token* tok, const std::string& s) override { - value.errorPath.emplace_back(tok, s); + auto& ep = value.errorPath; + if (std::any_of(ep.begin(), ep.end(), [&](const ErrorPathItem& epi) { + return epi.first == tok && epi.second == s; + })) + return; + ep.emplace_back(tok, s); } template diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 3679a91db6c..d1bc3bf830f 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -3591,7 +3591,7 @@ class TestAutoVariables : public TestFixture { " }\n" " *p = 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:13] -> [test.cpp:2:9] -> [test.cpp:7:6]: (error) Static variable 'p' will use pointer to local variable 'a'. [danglingLifetime]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:13] -> [test.cpp:4:9] -> [test.cpp:2:9] -> [test.cpp:7:6]: (error) Static variable 'p' will use pointer to local variable 'a'. [danglingLifetime]\n", errout_str()); // #10902 check("void f() {\n" @@ -4330,7 +4330,7 @@ class TestAutoVariables : public TestFixture { " std::vector cargs = f({ \"0\", \"0\" });\n" " (void)cargs;\n" "};\n"); - ASSERT_EQUALS("[test.cpp:6:12] -> [test.cpp:4:47] -> [test.cpp:3:22] -> [test.cpp:1:58] -> [test.cpp:4:40] -> [test.cpp:9:34] -> [test.cpp:9:34] -> [test.cpp:10:11]: (error) Using object that is a temporary. [danglingTemporaryLifetime]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:6:12] -> [test.cpp:4:47] -> [test.cpp:3:22] -> [test.cpp:1:58] -> [test.cpp:4:40] -> [test.cpp:3:24] -> [test.cpp:9:34] -> [test.cpp:9:34] -> [test.cpp:10:11]: (error) Using object that is a temporary. [danglingTemporaryLifetime]\n", errout_str()); check("struct C {\n" // #9194 " const int& m;\n" @@ -4692,7 +4692,7 @@ class TestAutoVariables : public TestFixture { " }\n" " f();\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:25] -> [test.cpp:4:13] -> [test.cpp:7:5]: (error) Using lambda that captures local variable 'b' that is out of scope. [invalidLifetime]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:25] -> [test.cpp:3:11] -> [test.cpp:4:13] -> [test.cpp:7:5]: (error) Using lambda that captures local variable 'b' that is out of scope. [invalidLifetime]\n", errout_str()); check("void f(bool b) {\n" " int* x;\n" @@ -4703,7 +4703,7 @@ class TestAutoVariables : public TestFixture { " x[3];\n" "}\n"); ASSERT_EQUALS( - "[test.cpp:5:9] -> [test.cpp:4:9] -> [test.cpp:7:3]: (error) Using pointer to local variable 'y' that is out of scope. [invalidLifetime]\n", + "[test.cpp:5:9] -> [test.cpp:3:6] -> [test.cpp:4:9] -> [test.cpp:7:3]: (error) Using pointer to local variable 'y' that is out of scope. [invalidLifetime]\n", errout_str()); check("void foo(int a) {\n" @@ -4893,7 +4893,7 @@ class TestAutoVariables : public TestFixture { " }\n" " *p = 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9] -> [test.cpp:7:4]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:3:7] -> [test.cpp:4:9] -> [test.cpp:7:4]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str()); // FP: don't warn in subfunction check("void f(struct KEY *key) {\n" @@ -4934,7 +4934,7 @@ class TestAutoVariables : public TestFixture { " dosth();\n" "}\n"); ASSERT_EQUALS( - "[test.cpp:5:24] -> [test.cpp:3:47] -> [test.cpp:4:26] -> [test.cpp:7:9]: (error) Using pointer to local variable 'item' that is out of scope. [invalidLifetime]\n", + "[test.cpp:5:24] -> [test.cpp:3:47] -> [test.cpp:3:47] -> [test.cpp:4:26] -> [test.cpp:7:9]: (error) Using pointer to local variable 'item' that is out of scope. [invalidLifetime]\n", errout_str()); // #6575 @@ -4960,7 +4960,7 @@ class TestAutoVariables : public TestFixture { " return 0;\n" "}\n"); ASSERT_EQUALS( - "[test.cpp:5:16] -> [test.cpp:7:10] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", + "[test.cpp:5:16] -> [test.cpp:3:8] -> [test.cpp:7:10] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str()); // #11753 @@ -4972,7 +4972,7 @@ class TestAutoVariables : public TestFixture { " }\n" " std::cout << s;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:26] -> [test.cpp:4:14] -> [test.cpp:7:18]: (error) Using pointer to local variable 'buff' that is out of scope. [invalidLifetime]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:26] -> [test.cpp:3:14] -> [test.cpp:4:14] -> [test.cpp:7:18]: (error) Using pointer to local variable 'buff' that is out of scope. [invalidLifetime]\n", errout_str()); check("char* f(char* dst) {\n" " const char* src = \"abc\";\n" diff --git a/test/testother.cpp b/test/testother.cpp index 7287d0339fb..68284a98111 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -927,6 +927,7 @@ class TestOther : public TestFixture { "[test.cpp:7:14]: note: Division by zero\n" "[test.cpp:13:14]: warning: Division by zero. [zerodivcond]\n" "[test.cpp:12:13]: note: Assignment 'j=0', assigned value is 0\n" + "[test.cpp:11:9]: note: Assuming condition is true\n" "[test.cpp:13:14]: note: Division by zero\n", errout_str()); }