Skip to content

Commit c2df2d4

Browse files
Fix #14435 Stack overflow in isVarUsedInTree() (#8157)
1 parent 5fa13b9 commit c2df2d4

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

lib/checkleakautovar.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <algorithm>
3939
#include <array>
4040
#include <cstddef>
41+
#include <deque>
4142
#include <list>
4243
#include <vector>
4344

@@ -191,11 +192,20 @@ static bool isVarUsedInTree(const Token *tok, nonneg int varid)
191192
{
192193
if (!tok)
193194
return false;
194-
if (tok->varId() == varid)
195-
return true;
196-
if (tok->str() == "(" && Token::simpleMatch(tok->astOperand1(), "sizeof"))
197-
return false;
198-
return isVarUsedInTree(tok->astOperand1(), varid) || isVarUsedInTree(tok->astOperand2(), varid);
195+
std::deque<const Token*> nodes{ tok };
196+
while (!nodes.empty()) {
197+
const Token* node = nodes.front();
198+
if (node->varId() == varid)
199+
return true;
200+
if (node->str() != "(" || !Token::simpleMatch(node->astOperand1(), "sizeof")) {
201+
if (node->astOperand1())
202+
nodes.emplace_back(node->astOperand1());
203+
if (node->astOperand2())
204+
nodes.emplace_back(node->astOperand2());
205+
}
206+
nodes.pop_front();
207+
}
208+
return false;
199209
}
200210

201211
static bool isPointerReleased(const Token *startToken, const Token *endToken, nonneg int varid)

lib/fwdanalysis.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "token.h"
2727
#include "vfvalue.h"
2828

29+
#include <deque>
2930
#include <list>
3031
#include <string>
3132
#include <utility>
@@ -478,9 +479,18 @@ bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const
478479
{
479480
if (!tok)
480481
return false;
481-
if (isSameExpression(false, tok, lhs, mSettings, false, false, nullptr))
482-
return true;
483-
return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs);
482+
std::deque<const Token*> nodes{ tok };
483+
while (!nodes.empty()) {
484+
const Token* node = nodes.front();
485+
if (isSameExpression(false, node, lhs, mSettings, false, false, nullptr))
486+
return true;
487+
if (node->astOperand1())
488+
nodes.emplace_back(node->astOperand1());
489+
if (node->astOperand2())
490+
nodes.emplace_back(node->astOperand2());
491+
nodes.pop_front();
492+
}
493+
return false;
484494
}
485495

486496
const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, const Token *endToken)

test/cli/performance_test.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,30 @@ def test_slow_exprid(tmpdir):
146146
my_env["DISABLE_VALUEFLOW"] = "1"
147147
cppcheck([filename], env=my_env)
148148

149+
@pytest.mark.skipif(sys.platform == 'darwin', reason='GitHub macOS runners are too slow')
150+
@pytest.mark.timeout(30)
151+
def test_stack_overflow_AST(tmpdir):
152+
# 14435
153+
filename = os.path.join(tmpdir, 'hang.cpp')
154+
with open(filename, 'wt') as f:
155+
f.write("""
156+
#define ROW 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
157+
#define ROW8 ROW ROW ROW ROW ROW ROW ROW ROW
158+
#define ROW64 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8
159+
#define ROW512 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64
160+
#define ROW4096 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512
161+
#define ROW32768 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096 ROW4096
162+
void f(std::vector<int>& v) {
163+
v = {
164+
ROW32768 0
165+
};
166+
}
167+
""")
168+
169+
my_env = os.environ.copy()
170+
my_env["DISABLE_VALUEFLOW"] = "1"
171+
cppcheck([filename], env=my_env)
172+
149173

150174
@pytest.mark.timeout(10)
151175
def test_slow_initlist_varchanged(tmpdir):

0 commit comments

Comments
 (0)