From 0d63553859da6e2f7b8b4a7204b7aa63fe9328f6 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Mon, 20 Apr 2026 22:56:56 +0200 Subject: [PATCH 1/2] Fix #14369: Move boolean literal evaluation to valueFlowSetConstantValue Previously, boolean literals were processed in a separate loop after valueFlowSetConstantValue. This triggered nullPointer FP with code such as: int f() { const int* p = true ? new int() : nullptr; return *p; // nullPointer FP } Because the condition token had no known value, both branches of the ternary operator were treated as possible, leaking a spurious null value. Signed-off-by: Francois Berder --- lib/valueflow.cpp | 7 +------ lib/vf_common.cpp | 5 +++++ test/testvalueflow.cpp | 10 ++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 74763fde027..0f1c8a20ce7 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -430,12 +430,7 @@ static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) if (tokenlist.isCPP() || settings.standards.c >= Standards::C23) { for (Token *tok = tokenlist.front(); tok; tok = tok->next()) { - if (tok->isName() && !tok->varId() && Token::Match(tok, "%bool%")) { - ValueFlow::Value value(tok->str() == "true"); - if (!tok->isTemplateArg()) - value.setKnown(); - setTokenValue(tok, std::move(value), settings); - } else if (Token::Match(tok, "[(,] NULL [,)]")) { + if (Token::Match(tok, "[(,] NULL [,)]")) { // NULL function parameters are not simplified in the // normal tokenlist ValueFlow::Value value(0); diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index ab01acc0f16..4a793a8ed70 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -154,6 +154,11 @@ namespace ValueFlow if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok, std::move(value), settings); + } else if ((tok->isCpp() || settings.standards.c >= Standards::C23) && (tok->isName() && !tok->varId() && Token::Match(tok, "%bool%"))) { + Value value(tok->str() == "true"); + if (!tok->isTemplateArg()) + value.setKnown(); + setTokenValue(tok, std::move(value), settings); } else if (Token::simpleMatch(tok, "sizeof (")) { if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() && (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 9586e4fdca2..080e4d3f7c7 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1207,6 +1207,16 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(123, values.empty() ? 0 : values.front().intvalue); + code = "x = true ? 2 : 3;\n"; // #14369 + values = tokenValues(code, "?"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(2, values.empty() ? 0 : values.front().intvalue); + + code = "x = false ? 2 : 3;\n"; // #14369 + values = tokenValues(code, "?"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3, values.empty() ? 0 : values.front().intvalue); + code = "int f() {\n" " const int i = 1;\n" " int x = i < 0 ? 0 : 1;\n" From 940a8cfff70366dd41038f66c0d18cebad110432 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Tue, 21 Apr 2026 20:16:10 +0200 Subject: [PATCH 2/2] fixup! Fix #14369: Move boolean literal evaluation to valueFlowSetConstantValue --- lib/vf_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 4a793a8ed70..d6c6088b34b 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -154,7 +154,7 @@ namespace ValueFlow if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok, std::move(value), settings); - } else if ((tok->isCpp() || settings.standards.c >= Standards::C23) && (tok->isName() && !tok->varId() && Token::Match(tok, "%bool%"))) { + } else if ((tok->isCpp() || settings.standards.c >= Standards::C23) && (tok->isName() && tok->varId() == 0 && Token::Match(tok, "%bool%"))) { Value value(tok->str() == "true"); if (!tok->isTemplateArg()) value.setKnown();