Skip to content

Commit d8270c7

Browse files
committed
Add new experimental value flow analysis
1 parent f4c1aa5 commit d8270c7

12 files changed

Lines changed: 302 additions & 79 deletions

Makefile

Lines changed: 87 additions & 75 deletions
Large diffs are not rendered by default.

cli/cmdlineparser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
302302
_settings->_xml = true;
303303
}
304304

305+
// Enable experimental value flow analysis
306+
else if (std::strcmp(argv[i], "--value-flow") == 0)
307+
_settings->valueFlow = true;
308+
305309
// Only print something when there are errors
306310
else if (std::strcmp(argv[i], "-q") == 0 || std::strcmp(argv[i], "--quiet") == 0)
307311
_settings->_errorsOnly = true;

lib/checkother.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,6 +2152,16 @@ void CheckOther::checkZeroDivision()
21522152
continue;
21532153
}
21542154
zerodivError(tok);
2155+
} else if (Token::Match(tok, "[/%]") && tok->astOperand2() && !tok->astOperand2()->values.empty()) {
2156+
// Value flow..
2157+
const std::list<ValueFlow::Value> &values = tok->astOperand2()->values;
2158+
std::list<ValueFlow::Value>::const_iterator it;
2159+
for (it = values.begin(); it != values.end(); ++it) {
2160+
if (it->intvalue == 0) {
2161+
if (!it->link || _settings->isEnabled("warning"))
2162+
zerodivError(tok);
2163+
}
2164+
}
21552165
}
21562166
}
21572167
}

lib/lib.pri

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ HEADERS += $${BASEPATH}check.h \
4444
$${BASEPATH}token.h \
4545
$${BASEPATH}tokenize.h \
4646
$${BASEPATH}tokenlist.h \
47+
$${BASEPATH}valueflow.h \
4748

4849

4950
SOURCES += $${BASEPATH}check64bit.cpp \
@@ -83,4 +84,5 @@ SOURCES += $${BASEPATH}check64bit.cpp \
8384
$${BASEPATH}timer.cpp \
8485
$${BASEPATH}token.cpp \
8586
$${BASEPATH}tokenize.cpp \
86-
$${BASEPATH}tokenlist.cpp
87+
$${BASEPATH}tokenlist.cpp \
88+
$${BASEPATH}valueflow.cpp

lib/settings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ Settings::Settings()
4040
enforcedLang(None),
4141
reportProgress(false),
4242
checkConfiguration(false),
43-
checkLibrary(false)
43+
checkLibrary(false),
44+
valueFlow(false)
4445
{
4546
// This assumes the code you are checking is for the same architecture this is compiled on.
4647
#if defined(_WIN64)

lib/settings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ class CPPCHECKLIB Settings {
251251
platformType == Win32W ||
252252
platformType == Win64;
253253
}
254+
255+
bool valueFlow;
254256
};
255257

256258
/// @}

lib/token.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
#define tokenH
2222
//---------------------------------------------------------------------------
2323

24+
#include <list>
2425
#include <string>
2526
#include <vector>
2627
#include <ostream>
2728
#include "config.h"
29+
#include "valueflow.h"
2830

2931
class Scope;
3032
class Function;
@@ -575,6 +577,9 @@ class CPPCHECKLIB Token {
575577
_originalName = name;
576578
}
577579

580+
/** Values of token */
581+
std::list<struct ValueFlow::Value> values;
582+
578583
private:
579584
void next(Token *nextToken) {
580585
_next = nextToken;

lib/tokenize.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,10 @@ bool Tokenizer::tokenize(std::istream &code,
16031603
}
16041604

16051605
list.createAst();
1606+
1607+
if (_settings->valueFlow)
1608+
ValueFlow::setValues(list.front());
1609+
16061610
return true;
16071611
}
16081612
return false;
@@ -7020,7 +7024,7 @@ bool Tokenizer::simplifyRedundantParentheses()
70207024
tok->deleteNext();
70217025
ret = true;
70227026
}
7023-
7027+
70247028
if (Token::Match(tok->previous(), "[,;{}] ( %var% ) .")) {
70257029
// Remove the parentheses
70267030
tok->deleteThis();

lib/valueflow.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Cppcheck - A tool for static C/C++ code analysis
3+
* Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "valueflow.h"
20+
#include "token.h"
21+
#include "mathlib.h"
22+
23+
static void valueFlowBeforeCondition(Token *tokens)
24+
{
25+
for (Token *tok = tokens; tok; tok = tok->next()) {
26+
unsigned int varid;
27+
MathLib::bigint num;
28+
if (Token::Match(tok, "==|!=|>=|<=") && tok->astOperand2()) {
29+
if (tok->astOperand1()->isName() && tok->astOperand2()->isNumber()) {
30+
varid = tok->astOperand1()->varId();
31+
} else if (tok->astOperand1()->isNumber() && tok->astOperand2()->isName()) {
32+
varid = tok->astOperand2()->varId();
33+
num = MathLib::toLongNumber(tok->astOperand1()->str());
34+
} else {
35+
continue;
36+
}
37+
} else if (Token::Match(tok->previous(), "if|while ( %var% %oror%|&&|)") ||
38+
Token::Match(tok, "%oror%|&& %var% %oror%|&&|)")) {
39+
varid = tok->next()->varId();
40+
num = 0;
41+
} else if (tok->str() == "!" && tok->astOperand1() && tok->astOperand1()->isName()) {
42+
varid = tok->astOperand1()->varId();
43+
num = 0;
44+
} else {
45+
continue;
46+
}
47+
48+
if (varid == 0U)
49+
continue;
50+
51+
struct ValueFlow::Value val;
52+
val.link = tok;
53+
val.intvalue = MathLib::toLongNumber(tok->astOperand2()->str());
54+
55+
for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) {
56+
if (tok2->varId() == varid)
57+
tok2->values.push_back(val);
58+
if (tok2->str() == "{") {
59+
if (!Token::simpleMatch(tok2->previous(), ") {"))
60+
break;
61+
if (!Token::simpleMatch(tok2->previous()->link()->previous(), "if ("))
62+
break;
63+
}
64+
}
65+
}
66+
}
67+
68+
void ValueFlow::setValues(Token *tokens)
69+
{
70+
for (Token *tok = tokens; tok; tok = tok->next())
71+
tok->values.clear();
72+
73+
valueFlowBeforeCondition(tokens);
74+
}

lib/valueflow.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Cppcheck - A tool for static C/C++ code analysis
3+
* Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
//---------------------------------------------------------------------------
20+
#ifndef valueflowH
21+
#define valueflowH
22+
//---------------------------------------------------------------------------
23+
24+
class Token;
25+
26+
namespace ValueFlow {
27+
28+
struct Value {
29+
const Token *link;
30+
long long intvalue;
31+
};
32+
33+
void setValues(Token *tokens);
34+
}
35+
36+
#endif // valueflowH

0 commit comments

Comments
 (0)