From c9569aff1a453e69ec1b2099d357f27acee58f51 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:33:27 +0100 Subject: [PATCH 1/6] Fix #8983 FN containerOutOfBounds (passing empty init list) --- lib/valueflow.cpp | 48 ++++++++++++++++++++++++++++++++++++----------- test/teststl.cpp | 22 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8eb5735c986..ae54415795a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6884,11 +6884,33 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } for (const ValueFlow::Value& value : values) setTokenValue(tok, value, settings); - } else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && - // init list - ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || - // constructor - (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { + } + else if (Token::Match(tok->previous(), ",|( {")) { + int nArg{}; + if (const Token* funcTok = getTokenArgumentFunction(tok, nArg)) { + if (const Function* func = funcTok->function()) { + if (const Variable* var = func->getArgumentVar(nArg)) { + if (var->valueType() && var->valueType()->container && var->valueType()->container->size_templateArgNo < 0) { + std::vector values = getInitListSize(tok, var->valueType(), settings, true); + ValueFlow::Value value; + value.valueType = ValueFlow::Value::ValueType::TOK; + value.tokvalue = tok; + value.setKnown(); + values.push_back(std::move(value)); + + for (const ValueFlow::Value &value : values) + setTokenValue(tok, value, settings); + } + } + } + } + } + else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && + // init list + ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || + // constructor + (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) + { Token* containerTok = tok->next(); if (containerTok->exprId() == 0) continue; @@ -6899,8 +6921,10 @@ static void valueFlowContainerSize(const TokenList& tokenlist, for (const ValueFlow::Value& value : values) valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings); } - } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && - tok->astOperand1()->valueType()->container) { + } + else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && + tok->astOperand1()->valueType()->container) + { const Token* containerTok = tok->astOperand1(); if (containerTok->exprId() == 0) continue; @@ -6925,14 +6949,16 @@ static void valueFlowContainerSize(const TokenList& tokenlist, valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings); } // TODO: handle more actions? - - } else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) { + } + else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) + { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok); forwardMinimumContainerSize(size, tok, containerTok); - - } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) { + } + else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) + { const Token* tok2 = tok->astOperand2(); MathLib::bigint size = 0; while (Token::simpleMatch(tok2, "+") && tok2->astOperand2()) { diff --git a/test/teststl.cpp b/test/teststl.cpp index 43f5ca2eda5..9f3ddba54de 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -945,6 +945,28 @@ class TestStl : public TestFixture { " (void)v[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + checkNormal("int f(const std::vector& v) {\n" // #8983 + " return v[2];\n" + "}\n" + "int g() {\n" + " return f({});\n" + "}\n" + "int h() {\n" + " return f({ 1, 2 });\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 2 and '2' is 2 [containerOutOfBounds]\n" + "[test.cpp:2:13]: error: Out of bounds access in expression 'v[2]' because 'v' is empty. [containerOutOfBounds]\n", + errout_str()); + + checkNormal("int f(int x, const std::vector& v) {\n" + " return x + v[0];\n" + "}\n" + "int g() {\n" + " return f(1, {});\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: error: Out of bounds access in expression 'v[0]' because 'v' is empty. [containerOutOfBounds]\n", + errout_str()); } void outOfBoundsSymbolic() From dc3831151875b57d4a68a2e3e306b5a30371db23 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:37:03 +0100 Subject: [PATCH 2/6] Format --- lib/valueflow.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ae54415795a..52219457379 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6904,13 +6904,11 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } } } - } - else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && + } else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && // init list ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || // constructor - (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) - { + (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { Token* containerTok = tok->next(); if (containerTok->exprId() == 0) continue; @@ -6921,10 +6919,8 @@ static void valueFlowContainerSize(const TokenList& tokenlist, for (const ValueFlow::Value& value : values) valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings); } - } - else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && - tok->astOperand1()->valueType()->container) - { + } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && + tok->astOperand1()->valueType()->container) { const Token* containerTok = tok->astOperand1(); if (containerTok->exprId() == 0) continue; @@ -6949,16 +6945,12 @@ static void valueFlowContainerSize(const TokenList& tokenlist, valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings); } // TODO: handle more actions? - } - else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) - { + } else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok); forwardMinimumContainerSize(size, tok, containerTok); - } - else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) - { + } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) { const Token* tok2 = tok->astOperand2(); MathLib::bigint size = 0; while (Token::simpleMatch(tok2, "+") && tok2->astOperand2()) { From 432921207654fac0dc3552f6eda7de743e34a523 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:38:46 +0100 Subject: [PATCH 3/6] Format --- lib/valueflow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 52219457379..12322c9b7bf 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6905,10 +6905,10 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } } } else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && - // init list - ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || - // constructor - (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { + // init list + ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || + // constructor + (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { Token* containerTok = tok->next(); if (containerTok->exprId() == 0) continue; From 602110416f8feadce18e791b89870a060aba9eb7 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:40:19 +0100 Subject: [PATCH 4/6] Format --- lib/valueflow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 12322c9b7bf..27473871a88 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6907,8 +6907,8 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") && // init list ((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") || - // constructor - (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { + // constructor + (!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) { Token* containerTok = tok->next(); if (containerTok->exprId() == 0) continue; @@ -6920,7 +6920,7 @@ static void valueFlowContainerSize(const TokenList& tokenlist, valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings); } } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && - tok->astOperand1()->valueType()->container) { + tok->astOperand1()->valueType()->container) { const Token* containerTok = tok->astOperand1(); if (containerTok->exprId() == 0) continue; From b9d4a8bc31789d308fbf23e9d535977ec67ab5a3 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:42:01 +0100 Subject: [PATCH 5/6] Format --- lib/valueflow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 27473871a88..d27b9c102a3 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6945,11 +6945,13 @@ static void valueFlowContainerSize(const TokenList& tokenlist, valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings); } // TODO: handle more actions? + } else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok); forwardMinimumContainerSize(size, tok, containerTok); + } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) { const Token* tok2 = tok->astOperand2(); MathLib::bigint size = 0; From 49c9b90f7cd9c2c750217ea14ffe6d6245cd438c Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 20 Dec 2025 22:48:22 +0100 Subject: [PATCH 6/6] Fix --- lib/valueflow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index d27b9c102a3..8da6695eb3e 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6892,11 +6892,11 @@ static void valueFlowContainerSize(const TokenList& tokenlist, if (const Variable* var = func->getArgumentVar(nArg)) { if (var->valueType() && var->valueType()->container && var->valueType()->container->size_templateArgNo < 0) { std::vector values = getInitListSize(tok, var->valueType(), settings, true); - ValueFlow::Value value; - value.valueType = ValueFlow::Value::ValueType::TOK; - value.tokvalue = tok; - value.setKnown(); - values.push_back(std::move(value)); + ValueFlow::Value tokValue; + tokValue.valueType = ValueFlow::Value::ValueType::TOK; + tokValue.tokvalue = tok; + tokValue.setKnown(); + values.push_back(std::move(tokValue)); for (const ValueFlow::Value &value : values) setTokenValue(tok, value, settings);