Skip to content

Commit 0cb7427

Browse files
authored
Fix 11415: FP containerOutOfBounds for container initialized in virtual method (#4622)
1 parent 04b7c0c commit 0cb7427

4 files changed

Lines changed: 42 additions & 13 deletions

File tree

lib/programmemory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
13491349
if (child->exprId() > 0 && pm.hasValue(child->exprId())) {
13501350
ValueFlow::Value& v = pm.at(child->exprId());
13511351
if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) {
1352-
if (isContainerSizeChanged(child, settings))
1352+
if (isContainerSizeChanged(child, v.indirect, settings))
13531353
v = unknown;
13541354
} else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) {
13551355
if (isVariableChanged(child, v.indirect, settings, true))

lib/valueflow.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7540,10 +7540,14 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba
75407540
static bool isContainerSizeChanged(nonneg int varId,
75417541
const Token* start,
75427542
const Token* end,
7543+
int indirect,
75437544
const Settings* settings = nullptr,
75447545
int depth = 20);
75457546

7546-
static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* settings = nullptr, int depth = 20)
7547+
static bool isContainerSizeChangedByFunction(const Token* tok,
7548+
int indirect,
7549+
const Settings* settings = nullptr,
7550+
int depth = 20)
75477551
{
75487552
if (!tok->valueType())
75497553
return false;
@@ -7566,12 +7570,13 @@ static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* s
75667570
if (!ftok)
75677571
return false; // not a function => variable not changed
75687572
const Function * fun = ftok->function();
7569-
if (fun && !fun->hasVirtualSpecifier()) {
7573+
if (fun && !fun->isImplicitlyVirtual()) {
75707574
const Variable *arg = fun->getArgumentVar(narg);
75717575
if (arg) {
7572-
if (!arg->isReference() && !addressOf)
7576+
const bool isPointer = addressOf || indirect > 0;
7577+
if (!arg->isReference() && !isPointer)
75737578
return false;
7574-
if (!addressOf && arg->isConst())
7579+
if (!isPointer && arg->isConst())
75757580
return false;
75767581
if (arg->valueType() && arg->valueType()->constness == 1)
75777582
return false;
@@ -7581,16 +7586,20 @@ static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* s
75817586
if (!arg->nameToken())
75827587
return false;
75837588
if (depth > 0)
7584-
return isContainerSizeChanged(
7585-
arg->declarationId(), scope->bodyStart, scope->bodyEnd, settings, depth - 1);
7589+
return isContainerSizeChanged(arg->declarationId(),
7590+
scope->bodyStart,
7591+
scope->bodyEnd,
7592+
addressOf ? indirect + 1 : indirect,
7593+
settings,
7594+
depth - 1);
75867595
}
75877596
// Don't know => Safe guess
75887597
return true;
75897598
}
75907599
}
75917600

75927601
bool inconclusive = false;
7593-
const bool isChanged = isVariableChangedByFunctionCall(tok, 0, settings, &inconclusive);
7602+
const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings, &inconclusive);
75947603
return (isChanged || inconclusive);
75957604
}
75967605

@@ -7685,7 +7694,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
76857694
return Action::Invalid;
76867695
if (isLikelyStreamRead(isCPP(), tok->astParent()))
76877696
return Action::Invalid;
7688-
if (astIsContainer(tok) && isContainerSizeChanged(tok, getSettings()))
7697+
if (astIsContainer(tok) && isContainerSizeChanged(tok, getIndirect(tok), getSettings()))
76897698
return read | Action::Invalid;
76907699
return read;
76917700
}
@@ -7787,7 +7796,7 @@ ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Va
77877796
return ExpressionAnalyzer(exprTok, value, tokenlist);
77887797
}
77897798

7790-
bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth)
7799+
bool isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings, int depth)
77917800
{
77927801
if (!tok)
77937802
return false;
@@ -7823,21 +7832,22 @@ bool isContainerSizeChanged(const Token* tok, const Settings* settings, int dept
78237832
case Library::Container::Action::CHANGE_INTERNAL:
78247833
break;
78257834
}
7826-
if (isContainerSizeChangedByFunction(tok, settings, depth))
7835+
if (isContainerSizeChangedByFunction(tok, indirect, settings, depth))
78277836
return true;
78287837
return false;
78297838
}
78307839

78317840
static bool isContainerSizeChanged(nonneg int varId,
78327841
const Token* start,
78337842
const Token* end,
7843+
int indirect,
78347844
const Settings* settings,
78357845
int depth)
78367846
{
78377847
for (const Token *tok = start; tok != end; tok = tok->next()) {
78387848
if (tok->varId() != varId)
78397849
continue;
7840-
if (isContainerSizeChanged(tok, settings, depth))
7850+
if (isContainerSizeChanged(tok, indirect, settings, depth))
78417851
return true;
78427852
}
78437853
return false;

lib/valueflow.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ namespace ValueFlow {
467467

468468
ValueFlow::Value asImpossible(ValueFlow::Value v);
469469

470-
bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20);
470+
bool isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings = nullptr, int depth = 20);
471471

472472
struct LifetimeToken {
473473
const Token* token;

test/teststl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,25 @@ class TestStl : public TestFixture {
867867
" return m.at(1);\n"
868868
"}\n");
869869
ASSERT_EQUALS("", errout.str());
870+
871+
checkNormal("struct A {\n"
872+
" virtual void init_v(std::vector<int> *v) = 0;\n"
873+
"};\n"
874+
"A* create_a();\n"
875+
"struct B {\n"
876+
" B() : a(create_a()) {}\n"
877+
" void init_v(std::vector<int> *v) {\n"
878+
" a->init_v(v);\n"
879+
" }\n"
880+
" A* a;\n"
881+
"};\n"
882+
"void f() {\n"
883+
" B b;\n"
884+
" std::vector<int> v;\n"
885+
" b.init_v(&v);\n"
886+
" v[0];\n"
887+
"}\n");
888+
ASSERT_EQUALS("", errout.str());
870889
}
871890

872891
void outOfBoundsSymbolic()

0 commit comments

Comments
 (0)