2014-01-04 20:57:02 +01:00
|
|
|
/*
|
|
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
2016-01-01 14:34:45 +01:00
|
|
|
* Copyright (C) 2007-2016 Cppcheck team.
|
2014-01-04 20:57:02 +01:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "testsuite.h"
|
|
|
|
#include "testutils.h"
|
|
|
|
#include "valueflow.h"
|
|
|
|
#include "tokenize.h"
|
|
|
|
#include "token.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
|
2015-03-11 22:26:33 +01:00
|
|
|
|
2014-01-04 20:57:02 +01:00
|
|
|
class TestValueFlow : public TestFixture {
|
|
|
|
public:
|
2014-11-20 14:20:09 +01:00
|
|
|
TestValueFlow() : TestFixture("TestValueFlow") {
|
2014-01-04 20:57:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-10-07 18:33:57 +02:00
|
|
|
Settings settings;
|
2014-01-04 20:57:02 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void run() {
|
2015-10-07 18:33:57 +02:00
|
|
|
// strcpy cfg
|
|
|
|
const char cfg[] = "<?xml version=\"1.0\"?>\n"
|
|
|
|
"<def>\n"
|
|
|
|
" <function name=\"strcpy\"> <arg nr=\"1\"><not-null/></arg> </function>\n"
|
|
|
|
"</def>";
|
|
|
|
settings.library.loadxmldata(cfg, sizeof(cfg));
|
|
|
|
|
2014-01-18 19:30:44 +01:00
|
|
|
TEST_CASE(valueFlowNumber);
|
2014-08-03 20:11:22 +02:00
|
|
|
TEST_CASE(valueFlowString);
|
|
|
|
TEST_CASE(valueFlowPointerAlias);
|
2015-02-24 15:57:39 +01:00
|
|
|
TEST_CASE(valueFlowArrayElement);
|
2014-01-18 19:30:44 +01:00
|
|
|
|
2014-04-14 06:45:39 +02:00
|
|
|
TEST_CASE(valueFlowBitAnd);
|
|
|
|
|
2014-01-18 19:30:44 +01:00
|
|
|
TEST_CASE(valueFlowCalculations);
|
|
|
|
|
2014-01-06 10:09:49 +01:00
|
|
|
TEST_CASE(valueFlowBeforeCondition);
|
2014-01-18 08:45:24 +01:00
|
|
|
TEST_CASE(valueFlowBeforeConditionAndAndOrOrGuard);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionAssignIncDec);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionFunctionCall);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionGlobalVariables);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionGoto);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionIfElse);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionLoop);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionMacro);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionSizeof);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionSwitch);
|
|
|
|
TEST_CASE(valueFlowBeforeConditionTernaryOp);
|
|
|
|
|
2014-01-21 21:13:49 +01:00
|
|
|
TEST_CASE(valueFlowAfterAssign);
|
|
|
|
|
2014-06-15 16:47:01 +02:00
|
|
|
TEST_CASE(valueFlowAfterCondition);
|
|
|
|
|
2015-07-20 19:45:38 +02:00
|
|
|
TEST_CASE(valueFlowSwitchVariable);
|
|
|
|
|
2014-01-07 19:20:56 +01:00
|
|
|
TEST_CASE(valueFlowForLoop);
|
2014-01-06 16:37:52 +01:00
|
|
|
TEST_CASE(valueFlowSubFunction);
|
2014-06-29 18:04:38 +02:00
|
|
|
TEST_CASE(valueFlowFunctionReturn);
|
2015-02-03 22:12:05 +01:00
|
|
|
|
|
|
|
TEST_CASE(valueFlowFunctionDefaultParameter);
|
2015-07-16 17:33:16 +02:00
|
|
|
|
|
|
|
TEST_CASE(knownValue);
|
2014-01-04 20:57:02 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
2014-01-04 20:57:02 +01:00
|
|
|
// Tokenize..
|
|
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
|
|
|
if (tok->str() == "x" && tok->linenr() == linenr) {
|
|
|
|
std::list<ValueFlow::Value>::const_iterator it;
|
|
|
|
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
2014-08-03 20:11:22 +02:00
|
|
|
if (it->intvalue == value && !it->tokvalue)
|
2014-01-04 20:57:02 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-06 07:44:58 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
bool testValueOfX(const char code[], unsigned int linenr, const char value[]) {
|
2014-08-03 20:11:22 +02:00
|
|
|
// Tokenize..
|
|
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
|
|
|
if (tok->str() == "x" && tok->linenr() == linenr) {
|
|
|
|
std::list<ValueFlow::Value>::const_iterator it;
|
|
|
|
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
|
|
|
if (Token::simpleMatch(it->tokvalue, value))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-29 19:54:57 +02:00
|
|
|
bool testConditionalValueOfX(const char code[], unsigned int linenr, int value) {
|
|
|
|
// Tokenize..
|
|
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
|
|
|
if (tok->str() == "x" && tok->linenr() == linenr) {
|
|
|
|
std::list<ValueFlow::Value>::const_iterator it;
|
|
|
|
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
|
|
|
if (it->intvalue == value && !it->tokvalue && it->condition)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void bailout(const char code[]) {
|
2014-01-06 07:44:58 +01:00
|
|
|
settings.debugwarnings = true;
|
|
|
|
|
|
|
|
// Tokenize..
|
|
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
|
|
errout.str("");
|
|
|
|
tokenizer.tokenize(istr, "test.cpp");
|
2015-10-07 18:33:57 +02:00
|
|
|
|
|
|
|
settings.debugwarnings = false;
|
2014-01-06 07:44:58 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
std::list<ValueFlow::Value> tokenValues(const char code[], const char tokstr[]) {
|
2014-01-18 19:30:44 +01:00
|
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
|
|
errout.str("");
|
|
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
const Token *tok = Token::findmatch(tokenizer.tokens(), tokstr);
|
2014-01-20 21:45:30 +01:00
|
|
|
return tok ? tok->values : std::list<ValueFlow::Value>();
|
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
ValueFlow::Value valueOfTok(const char code[], const char tokstr[]) {
|
2014-01-20 21:45:30 +01:00
|
|
|
std::list<ValueFlow::Value> values = tokenValues(code, tokstr);
|
2014-08-03 20:11:22 +02:00
|
|
|
return values.size() == 1U && !values.front().tokvalue ? values.front() : ValueFlow::Value();
|
2014-01-18 19:30:44 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowNumber() {
|
2015-07-14 18:02:26 +02:00
|
|
|
ASSERT_EQUALS(123, valueOfTok("x=123;", "123").intvalue);
|
2015-11-12 16:38:58 +01:00
|
|
|
ASSERT_EQUALS(0, valueOfTok("x=false;", "false").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("x=true;", "true").intvalue);
|
|
|
|
ASSERT_EQUALS((int)('a'), valueOfTok("x='a';", "'a'").intvalue);
|
|
|
|
ASSERT_EQUALS((int)('\n'), valueOfTok("x='\\n';", "'\\n'").intvalue);
|
2014-01-18 19:30:44 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowString() {
|
2014-08-03 20:11:22 +02:00
|
|
|
const char *code;
|
|
|
|
|
2014-08-04 12:13:15 +02:00
|
|
|
// valueFlowAfterAssign
|
2014-08-03 20:11:22 +02:00
|
|
|
code = "const char * f() {\n"
|
|
|
|
" static const char *x;\n"
|
|
|
|
" if (a) x = \"123\";\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4, "\"123\""));
|
2014-08-04 12:13:15 +02:00
|
|
|
|
|
|
|
// valueFlowSubFunction
|
|
|
|
code = "void dostuff(const char *x) {\n"
|
|
|
|
" f(x);\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"void test() { dostuff(\"abc\"); }";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2, "\"abc\""));
|
2014-08-03 20:11:22 +02:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowPointerAlias() {
|
2014-08-03 20:11:22 +02:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "const char * f() {\n"
|
|
|
|
" static const char *x;\n"
|
|
|
|
" static char ret[10];\n"
|
|
|
|
" if (a) x = &ret[0];\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5, "& ret [ 0 ]"));
|
2014-08-05 06:24:23 +02:00
|
|
|
|
|
|
|
// dead pointer
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int *x;\n"
|
|
|
|
" if (cond) { int i; x = &i; }\n"
|
|
|
|
" *x = 0;\n" // <- x can point at i
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4, "& i"));
|
2015-11-15 23:38:23 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" struct X *x;\n"
|
|
|
|
" x = &x[1];\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, tokenValues(code, "&").empty());
|
|
|
|
ASSERT_EQUALS(true, tokenValues(code, "x [").empty());
|
2014-08-03 20:11:22 +02:00
|
|
|
}
|
|
|
|
|
2015-02-24 15:57:39 +01:00
|
|
|
void valueFlowArrayElement() {
|
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
2015-07-27 16:25:14 +02:00
|
|
|
" const int x[] = {43,23,12};\n"
|
2015-02-24 15:57:39 +01:00
|
|
|
" return x;\n"
|
|
|
|
"}";
|
2015-07-27 16:25:14 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, "{ 43 , 23 , 12 }"));
|
2015-02-24 15:57:39 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
2015-07-27 16:25:14 +02:00
|
|
|
" const char x[] = \"abcd\";\n"
|
2015-02-24 15:57:39 +01:00
|
|
|
" return x;\n"
|
|
|
|
"}";
|
2015-07-27 16:25:14 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, "\"abcd\""));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" char x[32] = \"abcd\";\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, "\"abcd\""));
|
2015-11-07 15:07:26 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int a[10];\n"
|
|
|
|
" int *x = a;\n" // <- a value is a
|
|
|
|
" *x = 0;\n" // .. => x value is a
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4, "a"));
|
2015-11-12 16:14:27 +01:00
|
|
|
|
|
|
|
code = "char f() {\n"
|
|
|
|
" const char *x = \"abcd\";\n"
|
|
|
|
" return x[0];\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS((int)('a'), valueOfTok(code, "[").intvalue);
|
|
|
|
|
|
|
|
code = "char f() {\n"
|
|
|
|
" const char *x = \"\";\n"
|
|
|
|
" return x[0];\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(0, valueOfTok(code, "[").intvalue);
|
2015-02-24 15:57:39 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowCalculations() {
|
2014-01-18 19:30:44 +01:00
|
|
|
const char *code;
|
2015-07-18 15:03:57 +02:00
|
|
|
|
2015-07-26 12:00:42 +02:00
|
|
|
// Different operators
|
|
|
|
ASSERT_EQUALS(5, valueOfTok("3 + (a ? b : 2);", "+").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("3 - (a ? b : 2);", "-").intvalue);
|
|
|
|
ASSERT_EQUALS(6, valueOfTok("3 * (a ? b : 2);", "*").intvalue);
|
|
|
|
ASSERT_EQUALS(6, valueOfTok("13 / (a ? b : 2);", "/").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("13 % (a ? b : 2);", "%").intvalue);
|
|
|
|
ASSERT_EQUALS(0, valueOfTok("3 == (a ? b : 2);", "==").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("3 != (a ? b : 2);", "!=").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("3 > (a ? b : 2);", ">").intvalue);
|
|
|
|
ASSERT_EQUALS(1, valueOfTok("3 >= (a ? b : 2);", ">=").intvalue);
|
|
|
|
ASSERT_EQUALS(0, valueOfTok("3 < (a ? b : 2);", "<").intvalue);
|
|
|
|
ASSERT_EQUALS(0, valueOfTok("3 <= (a ? b : 2);", "<=").intvalue);
|
|
|
|
|
|
|
|
// calculation using 1,2 variables/values
|
2014-01-18 19:30:44 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x+456;\n"
|
|
|
|
" if (x==123) {}"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(579, valueOfTok(code, "+").intvalue);
|
|
|
|
|
2014-01-20 21:45:30 +01:00
|
|
|
code = "void f(int x, int y) {\n"
|
|
|
|
" a = x+y;\n"
|
|
|
|
" if (x==123 || y==456) {}"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(0, valueOfTok(code, "+").intvalue);
|
|
|
|
|
2014-01-18 19:30:44 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x+x;\n"
|
|
|
|
" if (x==123) {}"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(246, valueOfTok(code, "+").intvalue);
|
|
|
|
|
|
|
|
code = "void f(int x, int y) {\n"
|
2014-01-20 21:45:30 +01:00
|
|
|
" a = x*x;\n"
|
|
|
|
" if (x==2) {}\n"
|
|
|
|
" if (x==4) {}\n"
|
2014-01-18 19:30:44 +01:00
|
|
|
"}";
|
2014-01-20 21:45:30 +01:00
|
|
|
std::list<ValueFlow::Value> values = tokenValues(code,"*");
|
|
|
|
ASSERT_EQUALS(2U, values.size());
|
|
|
|
ASSERT_EQUALS(4, values.front().intvalue);
|
|
|
|
ASSERT_EQUALS(16, values.back().intvalue);
|
2014-06-13 16:34:57 +02:00
|
|
|
|
2015-07-18 15:03:57 +02:00
|
|
|
// addition of different variables with known values
|
|
|
|
code = "int f(int x) {\n"
|
|
|
|
" int a = 1;\n"
|
|
|
|
" while (x!=3) { x+=a; }\n"
|
|
|
|
" return x/a;\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(3, valueOfTok(code, "/").intvalue);
|
|
|
|
|
2015-07-02 20:11:27 +02:00
|
|
|
// ? :
|
|
|
|
code = "x = y ? 2 : 3;\n";
|
|
|
|
values = tokenValues(code,"?");
|
|
|
|
ASSERT_EQUALS(2U, values.size());
|
|
|
|
ASSERT_EQUALS(2, values.front().intvalue);
|
|
|
|
ASSERT_EQUALS(3, values.back().intvalue);
|
|
|
|
|
2015-07-02 20:52:04 +02:00
|
|
|
code = "void f(int a) { x = a ? 2 : 3; }\n";
|
|
|
|
values = tokenValues(code,"?");
|
|
|
|
ASSERT_EQUALS(2U, values.size());
|
|
|
|
ASSERT_EQUALS(2, values.front().intvalue);
|
|
|
|
ASSERT_EQUALS(3, values.back().intvalue);
|
|
|
|
|
2015-07-16 21:17:44 +02:00
|
|
|
// !
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = !x;\n"
|
|
|
|
" if (x==0) {}\n"
|
|
|
|
"}";
|
|
|
|
values = tokenValues(code,"!");
|
|
|
|
ASSERT_EQUALS(1U, values.size());
|
|
|
|
ASSERT_EQUALS(1, values.back().intvalue);
|
|
|
|
|
2014-06-13 16:34:57 +02:00
|
|
|
// function call => calculation
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x + 8;\n"
|
|
|
|
"}\n"
|
|
|
|
"void callf() {\n"
|
|
|
|
" f(7);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(15, valueOfTok(code, "+").intvalue);
|
2014-06-29 10:57:39 +02:00
|
|
|
|
|
|
|
code = "void f(int x, int y) {\n"
|
|
|
|
" a = x + y;\n"
|
|
|
|
"}\n"
|
|
|
|
"void callf() {\n"
|
|
|
|
" f(1,1);\n"
|
|
|
|
" f(10,10);\n"
|
|
|
|
"}";
|
|
|
|
values = tokenValues(code, "+");
|
|
|
|
ASSERT_EQUALS(true, values.empty());
|
|
|
|
if (!values.empty()) {
|
|
|
|
/* todo.. */
|
|
|
|
ASSERT_EQUALS(2U, values.size());
|
|
|
|
ASSERT_EQUALS(2, values.front().intvalue);
|
|
|
|
ASSERT_EQUALS(22, values.back().intvalue);
|
|
|
|
}
|
2015-08-02 18:12:03 +02:00
|
|
|
|
|
|
|
// Comparison of string
|
|
|
|
values = tokenValues("f(\"xyz\" == \"xyz\");", "=="); // implementation defined
|
|
|
|
ASSERT_EQUALS(0U, values.size()); // <- no value
|
|
|
|
|
|
|
|
values = tokenValues("f(\"xyz\" == 0);", "==");
|
|
|
|
ASSERT_EQUALS(1U, values.size());
|
|
|
|
ASSERT_EQUALS(0, values.front().intvalue);
|
|
|
|
|
|
|
|
values = tokenValues("f(0 == \"xyz\");", "==");
|
|
|
|
ASSERT_EQUALS(1U, values.size());
|
|
|
|
ASSERT_EQUALS(0, values.front().intvalue);
|
|
|
|
|
|
|
|
values = tokenValues("f(\"xyz\" != 0);", "!=");
|
|
|
|
ASSERT_EQUALS(1U, values.size());
|
|
|
|
ASSERT_EQUALS(1, values.front().intvalue);
|
|
|
|
|
|
|
|
values = tokenValues("f(0 != \"xyz\");", "!=");
|
|
|
|
ASSERT_EQUALS(1U, values.size());
|
|
|
|
ASSERT_EQUALS(1, values.front().intvalue);
|
2014-01-18 19:30:44 +01:00
|
|
|
}
|
2014-01-06 07:44:58 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeCondition() {
|
2014-01-08 06:39:15 +01:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}";
|
2014-01-04 20:57:02 +01:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
2014-01-06 07:44:58 +01:00
|
|
|
|
2014-01-08 06:53:17 +01:00
|
|
|
code = "void f(unsigned int x) {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x >= 1) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 1));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
2014-01-08 17:37:39 +01:00
|
|
|
|
2014-01-19 20:16:55 +01:00
|
|
|
code = "void f(unsigned int x) {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x > 0) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
|
|
|
|
|
|
|
code = "void f(unsigned int x) {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x > 1) {}\n" // not zero => don't consider > condition
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 1));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n" // not unsigned => don't consider > condition
|
|
|
|
" int a = x;\n"
|
2014-01-20 06:31:28 +01:00
|
|
|
" if (x > 0) {}\n"
|
2014-01-19 20:16:55 +01:00
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
|
|
|
|
2014-01-08 17:37:39 +01:00
|
|
|
code = "void f(int *x) {\n"
|
|
|
|
" *x = 100;\n"
|
|
|
|
" if (x) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
2014-01-08 06:53:17 +01:00
|
|
|
|
2014-01-10 05:47:56 +01:00
|
|
|
code = "extern const int x;\n"
|
|
|
|
"void f() {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionAssignIncDec() { // assignment / increment
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
2014-01-10 05:47:56 +01:00
|
|
|
|
2014-01-11 15:36:09 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" x = 2 + x;\n"
|
|
|
|
" if (x == 65);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 65));
|
|
|
|
|
2014-01-11 20:53:23 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" x = y = 2 + x;\n"
|
|
|
|
" if (x == 65);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 65));
|
2014-01-11 15:36:09 +01:00
|
|
|
|
2014-01-17 19:28:28 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a[x++] = 0;\n"
|
|
|
|
" if (x == 5);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 5));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" x++;\n"
|
|
|
|
" if (x == 4);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 3));
|
|
|
|
|
2014-01-18 08:45:24 +01:00
|
|
|
// bailout: assignment
|
|
|
|
bailout("void f(int x) {\n"
|
|
|
|
" x = y;\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}");
|
|
|
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of x\n", errout.str());
|
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionAndAndOrOrGuard() { // guarding by &&
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
|
|
|
|
2014-01-11 12:44:55 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (!x || \n" // <- x can be 0
|
|
|
|
" a/x) {}\n" // <- x can't be 0
|
|
|
|
" if (x==0) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
2014-01-11 11:30:34 +01:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
|
|
|
|
2014-01-11 14:54:10 +01:00
|
|
|
code = "void f(int *x) {\n"
|
2014-01-11 15:18:39 +01:00
|
|
|
" ((x=ret())&&\n"
|
|
|
|
" (*x==0));\n" // <- x is not 0
|
2014-01-11 14:54:10 +01:00
|
|
|
" if (x==0) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2015-09-27 13:29:28 +02:00
|
|
|
|
|
|
|
code = "void f(int *x) {\n"
|
|
|
|
" int a = (x && *x == '1');\n"
|
|
|
|
" int b = a ? atoi(x) : 0;\n" // <- x is not 0
|
|
|
|
" if (x==0) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionFunctionCall() { // function calls
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
2014-01-11 14:54:10 +01:00
|
|
|
|
2014-01-11 14:31:51 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" setx(x);\n"
|
|
|
|
" if (x == 1) {}\n"
|
|
|
|
"}";
|
2014-04-02 17:33:04 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX((std::string("void setx(int x);")+code).c_str(), 2U, 1));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX((std::string("void setx(int &x);")+code).c_str(), 2U, 1));
|
2014-03-18 17:04:33 +01:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 1));
|
2014-01-11 14:31:51 +01:00
|
|
|
|
2014-01-12 18:19:00 +01:00
|
|
|
code = "void f(char* x) {\n"
|
|
|
|
" strcpy(x,\"abc\");\n"
|
|
|
|
" if (x) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
|
|
|
|
2014-01-13 05:52:28 +01:00
|
|
|
code = "void addNewFunction(Scope**scope, const Token**tok);\n"
|
|
|
|
"void f(Scope *x) {\n"
|
|
|
|
" x->functionList.back();\n"
|
|
|
|
" addNewFunction(&x,&tok);\n" // address-of, x can be changed by subfunction
|
|
|
|
" if (x) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionLoop() { // while, for, do-while
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
2014-01-13 05:52:28 +01:00
|
|
|
|
2014-01-12 11:58:10 +01:00
|
|
|
code = "void f(int x) {\n" // loop condition, x is not assigned inside loop => use condition
|
2014-01-11 20:25:49 +01:00
|
|
|
" a = x;\n" // x can be 37
|
|
|
|
" while (x == 37) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 37));
|
|
|
|
|
2014-01-12 11:58:10 +01:00
|
|
|
code = "void f(int x) {\n" // loop condition, x is assigned inside loop => dont use condition
|
2014-01-11 20:25:49 +01:00
|
|
|
" a = x;\n" // don't assume that x can be 37
|
|
|
|
" while (x != 37) { x++; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 37));
|
|
|
|
|
2014-12-14 14:10:42 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" for (; x!=1; x++) { }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 1));
|
|
|
|
|
2014-01-14 17:57:50 +01:00
|
|
|
code = "void f(menu *x) {\n"
|
|
|
|
" a = x->parent;\n"
|
|
|
|
" for (i=0;(i<10) && (x!=0); i++) { x = x->next; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
|
|
|
|
2014-01-12 11:58:10 +01:00
|
|
|
code = "void f(int x) {\n" // condition inside loop, x is NOT assigned inside loop => use condition
|
|
|
|
" a = x;\n"
|
|
|
|
" do {\n"
|
|
|
|
" if (x==76) {}\n"
|
|
|
|
" } while (1);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 76));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n" // conditions inside loop, x is assigned inside do-while => dont use condition
|
|
|
|
" a = x;\n"
|
|
|
|
" do {\n"
|
|
|
|
" if (x!=76) { x=do_something(); }\n"
|
|
|
|
" } while (1);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 76));
|
2014-01-18 11:54:00 +01:00
|
|
|
|
|
|
|
code = "void f(X x) {\n" // conditions inside loop, x is assigned inside do-while => dont use condition
|
|
|
|
" a = x;\n"
|
|
|
|
" for (i=1;i<=count;i++) {\n"
|
|
|
|
" BUGON(x==0)\n"
|
|
|
|
" x = x.next;\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionTernaryOp() { // bailout: ?:
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
2014-01-12 11:58:10 +01:00
|
|
|
|
2014-01-07 19:46:13 +01:00
|
|
|
bailout("void f(int x) {\n"
|
|
|
|
" y = ((x<0) ? x : ((x==2)?3:4));\n"
|
|
|
|
"}");
|
2014-01-08 06:39:15 +01:00
|
|
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: no simplification of x within ?: expression\n", errout.str());
|
|
|
|
|
|
|
|
bailout("int f(int x) {\n"
|
|
|
|
" int r = x ? 1 / x : 0;\n"
|
|
|
|
" if (x == 0) {}\n"
|
|
|
|
"}");
|
|
|
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: no simplification of x within ?: expression\n", errout.str());
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
2014-01-10 16:13:39 +01:00
|
|
|
" int a =v x;\n"
|
2014-01-08 06:39:15 +01:00
|
|
|
" a = b ? x/2 : 20/x;\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
2014-01-07 19:46:13 +01:00
|
|
|
|
2014-01-10 16:13:39 +01:00
|
|
|
code = "void f(int x, int y) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" if (y){}\n"
|
|
|
|
" if (x==123){}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionSizeof() { // skip sizeof
|
2014-01-18 08:45:24 +01:00
|
|
|
const char *code;
|
2014-01-10 16:13:39 +01:00
|
|
|
|
2014-01-11 21:10:01 +01:00
|
|
|
code = "void f(int *x) {\n"
|
|
|
|
" sizeof(x[0]);\n"
|
|
|
|
" if (x==63){}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 63));
|
2014-04-29 20:09:11 +02:00
|
|
|
|
|
|
|
code = "void f(int *x) {\n"
|
|
|
|
" char a[sizeof x.y];\n"
|
|
|
|
" if (x==0){}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
2014-01-11 21:10:01 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionIfElse() { // bailout: if/else/etc
|
2014-01-19 09:05:48 +01:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f(X * x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" if ((x != NULL) &&\n"
|
|
|
|
" (a(x->name, html)) &&\n"
|
|
|
|
" (a(x->name, body))) {}\n"
|
|
|
|
" if (x != NULL) { }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
2014-01-19 09:31:40 +01:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
2014-01-19 09:05:48 +01:00
|
|
|
|
2014-01-06 11:27:56 +01:00
|
|
|
bailout("void f(int x) {\n"
|
|
|
|
" if (x != 123) { b = x; }\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}");
|
|
|
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: variable x stopping on }\n", errout.str());
|
2014-06-30 00:02:49 +02:00
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" if (abc) { x = 1; }\n" // <- condition must be false if x is 7 in next line
|
|
|
|
" if (x == 7) { }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 7));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
2014-01-06 11:27:56 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionGlobalVariables() {
|
2014-01-06 07:44:58 +01:00
|
|
|
// bailout: global variables
|
|
|
|
bailout("int x;\n"
|
|
|
|
"void f() {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
"}");
|
|
|
|
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str());
|
2014-01-19 11:55:02 +01:00
|
|
|
|
|
|
|
// class variable
|
|
|
|
const char *code;
|
|
|
|
code = "class Fred { int x; void clear(); void f(); };\n"
|
|
|
|
"void Fred::f() {\n"
|
|
|
|
" int a = x;\n"
|
|
|
|
" clear();\n" // <- x might be assigned
|
|
|
|
" if (x == 234) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code,3,234));
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
2014-01-11 21:21:00 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionSwitch() {
|
2014-01-11 21:21:00 +01:00
|
|
|
// bailout: switch
|
2014-01-12 15:07:58 +01:00
|
|
|
// TODO : handle switch/goto more intelligently
|
2014-01-11 21:21:00 +01:00
|
|
|
bailout("void f(int x, int y) {\n"
|
|
|
|
" switch (y) {\n"
|
|
|
|
" case 1: a=x; break;\n"
|
|
|
|
" case 2: if (x==5) {} break;\n"
|
|
|
|
" };\n"
|
|
|
|
"}");
|
2014-06-30 17:56:42 +02:00
|
|
|
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on break\n", errout.str());
|
2014-01-12 15:07:58 +01:00
|
|
|
|
|
|
|
bailout("void f(int x, int y) {\n"
|
|
|
|
" switch (y) {\n"
|
|
|
|
" case 1: a=x; return 1;\n"
|
|
|
|
" case 2: if (x==5) {} break;\n"
|
|
|
|
" };\n"
|
|
|
|
"}");
|
2014-06-30 17:56:42 +02:00
|
|
|
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on return\n", errout.str());
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
2014-01-12 17:16:51 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionMacro() {
|
2014-01-12 17:16:51 +01:00
|
|
|
// bailout: condition is a expanded macro
|
|
|
|
bailout("void f(int x) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" $if ($x==$123){}\n"
|
|
|
|
"}");
|
|
|
|
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x, condition is defined in macro\n", errout.str());
|
2014-01-18 08:45:24 +01:00
|
|
|
}
|
2014-01-13 16:07:25 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBeforeConditionGoto() {
|
2014-01-13 16:07:25 +01:00
|
|
|
// bailout: goto label (TODO: handle gotos more intelligently)
|
|
|
|
bailout("void f(int x) {\n"
|
|
|
|
" if (x == 123) { goto out; }\n"
|
|
|
|
" a=x;\n" // <- x is not 123
|
|
|
|
"out:"
|
|
|
|
" if (x==123){}\n"
|
|
|
|
"}");
|
2014-06-15 16:47:01 +02:00
|
|
|
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: variable x stopping on goto label\n"
|
|
|
|
"[test.cpp:2]: (debug) ValueFlow bailout: variable x. noreturn conditional scope.\n"
|
|
|
|
, errout.str());
|
2014-04-28 06:21:48 +02:00
|
|
|
|
|
|
|
// #5721 - FP
|
|
|
|
bailout("static void f(int rc) {\n"
|
|
|
|
" ABC* abc = getabc();\n"
|
|
|
|
" if (!abc) { goto out };\n"
|
|
|
|
"\n"
|
|
|
|
" abc->majortype = 0;\n"
|
|
|
|
" if (FAILED(rc)) {}\n"
|
|
|
|
"\n"
|
|
|
|
"out:\n"
|
|
|
|
" if (abc) {}\n"
|
|
|
|
"}\n");
|
|
|
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of abc\n"
|
2014-06-16 16:39:41 +02:00
|
|
|
"[test.cpp:8]: (debug) ValueFlow bailout: variable abc stopping on goto label\n"
|
|
|
|
"[test.cpp:3]: (debug) ValueFlow bailout: variable abc. noreturn conditional scope.\n",
|
2014-04-28 06:21:48 +02:00
|
|
|
errout.str());
|
2014-01-04 20:57:02 +01:00
|
|
|
}
|
2014-01-06 16:37:52 +01:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowAfterAssign() {
|
2014-01-21 21:13:49 +01:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" a = sizeof(x);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
|
2014-01-22 06:10:17 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" a = 2 + x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
2014-01-22 20:16:31 +01:00
|
|
|
|
2014-01-24 18:22:38 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 9;\n"
|
|
|
|
" --x;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 9));
|
2015-05-02 17:30:09 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 8));
|
2014-01-24 18:22:38 +01:00
|
|
|
|
2014-05-03 12:49:07 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" y = x += z;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-01-25 18:31:02 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" static int x = 2;\n"
|
|
|
|
" x++;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 2));
|
|
|
|
|
2014-02-22 12:09:54 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" static int x = 2;\n"
|
|
|
|
" a >> x;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 2));
|
|
|
|
|
2014-03-23 17:57:27 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" static int x = 0;\n"
|
|
|
|
" if (x==0) x = getX();\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-01-24 17:47:49 +01:00
|
|
|
// function
|
|
|
|
code = "void f() {\n"
|
|
|
|
" char *x = 0;\n"
|
|
|
|
" int success = getx((char**)&x);\n"
|
|
|
|
" if (success) x[0] = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-04-01 07:06:20 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" char *x = 0;\n"
|
|
|
|
" getx(reinterpret_cast<void **>(&x));\n"
|
|
|
|
" *x = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2015-07-26 19:28:42 +02:00
|
|
|
// lambda
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" Q q = [&]() {\n"
|
|
|
|
" if (x > 0) {}\n"
|
|
|
|
" x++;\n"
|
|
|
|
" };\n"
|
|
|
|
" dosomething(q);\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2015-11-30 16:15:58 +01:00
|
|
|
// ?:
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 8;\n"
|
|
|
|
" a = ((x > 10) ?\n"
|
|
|
|
" x : 0);\n" // <- x is not 8
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 8));
|
|
|
|
|
|
|
|
code = "void f() {\n" // #6973
|
|
|
|
" char *x = \"\";\n"
|
|
|
|
" a = ((x[0] == 'U') ?\n"
|
|
|
|
" x[1] : 0);\n" // <- x is not ""
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, "\"\""));
|
|
|
|
|
2015-12-01 07:49:19 +01:00
|
|
|
code = "void f() {\n" // #6973
|
|
|
|
" char *x = getenv (\"LC_ALL\");\n"
|
|
|
|
" if (x == NULL)\n"
|
|
|
|
" x = \"\";\n"
|
|
|
|
"\n"
|
|
|
|
" if ( (x[0] == 'U') &&\n" // x can be ""
|
|
|
|
" (x[1] ?\n" // x can't be ""
|
|
|
|
" x[3] :\n" // x can't be ""
|
|
|
|
" x[2] ))\n" // x can't be ""
|
|
|
|
" {}\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 6U, "\"\""));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, "\"\""));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 8U, "\"\""));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 9U, "\"\""));
|
|
|
|
|
2014-01-22 20:16:31 +01:00
|
|
|
// if/else
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" if (condition) return;\n"
|
|
|
|
" a = 2 + x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 123));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 1;\n"
|
|
|
|
" if (condition) x = 2;\n"
|
|
|
|
" a = 2 + x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 1));
|
2014-08-03 20:11:22 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 2));
|
2014-01-22 20:16:31 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" if (condition1) x = 456;\n"
|
|
|
|
" if (condition2) x = 789;\n"
|
2014-08-05 08:28:46 +02:00
|
|
|
" a = 2 + x;\n" // <- either assignment "x=123" is redundant or x can be 123 here.
|
2014-01-22 20:16:31 +01:00
|
|
|
"}";
|
2014-08-05 08:28:46 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 123));
|
2014-01-22 20:16:31 +01:00
|
|
|
|
2014-01-24 18:22:38 +01:00
|
|
|
code = "void f(int a) {\n"
|
|
|
|
" int x = 123;\n"
|
|
|
|
" if (a > 1)\n"
|
|
|
|
" ++x;\n"
|
|
|
|
" else\n"
|
|
|
|
" ++x;\n"
|
|
|
|
" return 2 + x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 123));
|
|
|
|
|
2014-01-22 20:16:31 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 1;\n"
|
|
|
|
" if (condition1) x = 2;\n"
|
|
|
|
" else return;\n"
|
|
|
|
" a = 2 + x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 1));
|
2014-01-25 19:13:33 +01:00
|
|
|
|
2014-01-26 15:50:25 +01:00
|
|
|
code = "void f(){\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" if (a>=0) { x = getx(); }\n"
|
|
|
|
" if (x==0) { return; }\n"
|
|
|
|
" return 123 / x;\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
|
|
|
|
2014-01-31 15:43:34 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" X *x = getx();\n"
|
2015-10-27 12:33:46 +01:00
|
|
|
" if(0) { x = 0; }\n"
|
2014-01-31 15:43:34 +01:00
|
|
|
" else { x->y = 1; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2015-10-27 12:33:46 +01:00
|
|
|
code = "void f() {\n" // #6239
|
|
|
|
" int x = 4;\n"
|
|
|
|
" if(1) { x = 0; }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 4));
|
|
|
|
|
2014-03-18 17:04:33 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 32;\n"
|
|
|
|
" if (x>=32) return;\n"
|
|
|
|
" a[x]=0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 32));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 32;\n"
|
|
|
|
" if (x>=32) {\n"
|
|
|
|
" a[x] = 0;\n" // <- should have possible value 32
|
|
|
|
" return;\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
2014-06-15 17:15:09 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 32));
|
2014-03-18 17:04:33 +01:00
|
|
|
|
2015-01-01 14:29:49 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 33;\n"
|
|
|
|
" if (x==33) goto fail;\n"
|
|
|
|
" a[x]=0;\n"
|
|
|
|
"fail:\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 33));
|
|
|
|
|
2014-04-22 16:10:20 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 32;\n"
|
|
|
|
" if (a==1) { z=x+12; }\n"
|
|
|
|
" if (a==2) { z=x+32; }\n"
|
|
|
|
" z = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 32));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 32));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 32));
|
|
|
|
|
2014-04-18 16:10:18 +02:00
|
|
|
code = "void f() {\n" // #5656 - FP
|
|
|
|
" int x = 0;\n"
|
|
|
|
" if (!x) {\n"
|
|
|
|
" x = getx();\n"
|
|
|
|
" }\n"
|
|
|
|
" y = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 0));
|
|
|
|
|
2015-02-08 19:20:05 +01:00
|
|
|
code = "void f(int y) {\n" // alias
|
|
|
|
" int x = y;\n"
|
|
|
|
" if (y == 54) {}\n"
|
|
|
|
" else { a = x; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 54));
|
|
|
|
|
2014-04-26 11:27:58 +02:00
|
|
|
code = "void f () {\n"
|
|
|
|
" ST * x = g_pST;\n"
|
|
|
|
" if (x->y == 0) {\n"
|
|
|
|
" x = NULL;\n"
|
|
|
|
" return 1;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x->y;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 0));
|
|
|
|
|
2014-04-26 14:41:28 +02:00
|
|
|
code = "void f () {\n"
|
|
|
|
" ST * x = g_pST;\n"
|
|
|
|
" if (x->y == 0) {\n"
|
|
|
|
" x = NULL;\n"
|
|
|
|
" goto label;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x->y;\n"
|
|
|
|
"label:\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 0));
|
|
|
|
|
2014-05-01 15:15:26 +02:00
|
|
|
code = "void f() {\n" // #5752 - FP
|
|
|
|
" int *x = 0;\n"
|
|
|
|
" if (x && *x == 123) {\n"
|
|
|
|
" getx(*x);\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-07-30 18:12:33 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" if (!x) {}\n"
|
|
|
|
" else { y = x; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-09-04 17:52:14 +02:00
|
|
|
code = "void f() {\n" // #6118 - FP
|
|
|
|
" int x = 0;\n"
|
|
|
|
" x = x & 0x1;\n"
|
|
|
|
" if (x == 0) { x = 2; }\n"
|
2015-10-14 10:44:04 +02:00
|
|
|
" y = 42 / x;\n" // <- x is 2
|
2014-09-04 17:52:14 +02:00
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
2015-10-14 10:44:04 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 2));
|
2014-09-04 17:52:14 +02:00
|
|
|
|
|
|
|
code = "void f() {\n" // #6118 - FN
|
|
|
|
" int x = 0;\n"
|
|
|
|
" x = x & 0x1;\n"
|
|
|
|
" if (x == 0) { x += 2; }\n"
|
2015-10-14 10:44:04 +02:00
|
|
|
" y = 42 / x;\n" // <- x is 2
|
2014-09-04 17:52:14 +02:00
|
|
|
"}";
|
2015-10-14 10:44:04 +02:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 5U, 2));
|
2014-09-04 17:52:14 +02:00
|
|
|
|
2015-01-06 14:12:35 +01:00
|
|
|
code = "void f(int mode) {\n"
|
|
|
|
" struct ABC *x;\n"
|
|
|
|
"\n"
|
|
|
|
" if (mode) { x = &y; }\n"
|
|
|
|
" else { x = NULL; }\n"
|
|
|
|
"\n"
|
|
|
|
" if (!x) exit(1);\n"
|
|
|
|
"\n"
|
|
|
|
" a = x->a;\n" // <- x can't be 0
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 9U, 0));
|
|
|
|
|
2014-01-25 19:13:33 +01:00
|
|
|
// multivariables
|
|
|
|
code = "void f(int a) {\n"
|
|
|
|
" int x = a;\n"
|
|
|
|
" if (a!=132) { b = x; }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 132));
|
|
|
|
|
|
|
|
code = "void f(int a) {\n"
|
|
|
|
" int x = a;\n"
|
2014-02-17 20:07:38 +01:00
|
|
|
" b = x;\n" // <- line 3
|
2014-01-25 19:13:33 +01:00
|
|
|
" if (a!=132) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 132));
|
2014-01-25 20:14:49 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int a;\n"
|
|
|
|
" if (n) { a = n; }\n"
|
|
|
|
" else { a = 0; }\n"
|
|
|
|
" int x = a;\n"
|
2014-02-17 20:07:38 +01:00
|
|
|
" if (a > 0) { a = b / x; }\n" // <- line 6
|
2014-01-25 20:14:49 +01:00
|
|
|
"}";
|
2014-02-17 20:07:38 +01:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 0)); // x is not 0 at line 6
|
|
|
|
|
2014-08-27 17:11:38 +02:00
|
|
|
code = "void f(int x1) {\n" // #6086
|
|
|
|
" int x = x1;\n"
|
|
|
|
" if (x1 >= 3) {\n"
|
|
|
|
" return;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n" // <- x is not 3
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 3));
|
|
|
|
|
2015-02-07 10:45:30 +01:00
|
|
|
code = "int f(int *x) {\n" // #5980
|
|
|
|
" if (!x) {\n"
|
|
|
|
" switch (i) {\n"
|
|
|
|
" default:\n"
|
|
|
|
" throw std::runtime_error(msg);\n"
|
|
|
|
" };\n"
|
|
|
|
" }\n"
|
|
|
|
" return *x;\n" // <- x is not 0
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 8U, 0));
|
|
|
|
|
2015-07-12 19:35:47 +02:00
|
|
|
code = "void f(int a) {\n" // #6826
|
|
|
|
" int x = a ? a : 87;\n"
|
|
|
|
" if (a && x) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 87));
|
|
|
|
|
2016-01-24 08:57:57 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int first=-1, x=0;\n"
|
|
|
|
" do {\n"
|
|
|
|
" if (first >= 0) { a = x; }\n" // <- x is not 0
|
|
|
|
" first++; x=3;\n"
|
|
|
|
" } while (1);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-10-20 15:54:02 +02:00
|
|
|
// pointer/reference to x
|
|
|
|
code = "int f(void) {\n"
|
|
|
|
" int x = 2;\n"
|
|
|
|
" int *px = &x;\n"
|
|
|
|
" for (int i = 0; i < 1; i++) {\n"
|
|
|
|
" *px = 1;\n"
|
|
|
|
" }\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 2));
|
|
|
|
|
|
|
|
code = "int f(void) {\n"
|
|
|
|
" int x = 5;\n"
|
|
|
|
" int &rx = x;\n"
|
|
|
|
" for (int i = 0; i < 1; i++) {\n"
|
|
|
|
" rx = 1;\n"
|
|
|
|
" }\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 5));
|
|
|
|
|
2014-02-17 20:07:38 +01:00
|
|
|
// break
|
|
|
|
code = "void f() {\n"
|
|
|
|
" for (;;) {\n"
|
|
|
|
" int x = 1;\n"
|
|
|
|
" if (!abc()) {\n"
|
|
|
|
" x = 2;\n"
|
|
|
|
" break;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n" // <- line 8
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 8U, 2)); // x is not 2 at line 8
|
2014-06-30 17:56:42 +02:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" switch (ab) {\n"
|
|
|
|
" case A: x = 12; break;\n"
|
|
|
|
" case B: x = 34; break;\n"
|
|
|
|
" }\n"
|
|
|
|
" v = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 7U, 12));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 7U, 34));
|
2014-07-16 09:12:56 +02:00
|
|
|
|
|
|
|
code = "void f() {\n" // #5981
|
|
|
|
" int x;\n"
|
|
|
|
" switch (ab) {\n"
|
|
|
|
" case A: x = 12; break;\n"
|
|
|
|
" case B: x = 34; break;\n"
|
|
|
|
" }\n"
|
|
|
|
" switch (ab) {\n"
|
|
|
|
" case A: v = x; break;\n" // <- x is not 34
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 8U, 34));
|
2014-09-23 16:06:02 +02:00
|
|
|
|
|
|
|
// while/for
|
2014-10-11 17:48:51 +02:00
|
|
|
code = "void f() {\n" // #6138
|
|
|
|
" ENTRY *x = 0;\n"
|
|
|
|
" while (x = get()) {\n"
|
|
|
|
" set(x->value);\n" // <- x is not 0
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-09-23 16:06:02 +02:00
|
|
|
code = "void f(const int *buf) {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" for (int i = 0; i < 10; i++) {\n"
|
|
|
|
" if (buf[i] == 123) {\n"
|
|
|
|
" x = i;\n"
|
|
|
|
" break;\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n" // <- x can be 0
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 9U, 0)); // x can be 0 at line 9
|
|
|
|
|
|
|
|
code = "void f(const int *buf) {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" for (int i = 0; i < 10; i++) {\n"
|
|
|
|
" if (buf[i] == 123) {\n"
|
|
|
|
" x = i;\n"
|
|
|
|
" ;\n" // <- no break
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n" // <- x cant be 0
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 9U, 0)); // x cant be 0 at line 9
|
|
|
|
|
|
|
|
code = "void f(const int *buf) {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" while (++i < 10) {\n"
|
|
|
|
" if (buf[i] == 123) {\n"
|
|
|
|
" x = i;\n"
|
|
|
|
" break;\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n" // <- x can be 0
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 9U, 0)); // x can be 0 at line 9
|
2014-01-21 21:13:49 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowAfterCondition() {
|
2014-06-15 16:47:01 +02:00
|
|
|
const char *code;
|
|
|
|
|
2015-07-28 08:58:05 +02:00
|
|
|
// in if
|
2014-06-15 16:47:01 +02:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x == 123) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x != 123) {\n"
|
|
|
|
" a = x;\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
|
|
|
|
|
2015-07-28 08:58:05 +02:00
|
|
|
// in else
|
2014-06-15 16:47:01 +02:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x == 123) {}\n"
|
|
|
|
" else a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x != 123) {}\n"
|
|
|
|
" else a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
2014-06-16 16:39:41 +02:00
|
|
|
|
2015-07-28 08:58:05 +02:00
|
|
|
// after if
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x == 10) {\n"
|
|
|
|
" x++;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 10));
|
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 5U, 11));
|
|
|
|
|
2014-06-16 16:39:41 +02:00
|
|
|
// !
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (!x) { a = x; }\n"
|
|
|
|
" else a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
|
|
|
|
2014-07-07 17:48:58 +02:00
|
|
|
code = "void f(int x, int y) {\n"
|
|
|
|
" if (!(x&&y)) { return; }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
|
|
|
|
2016-01-18 15:39:20 +01:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (!x) { { throw new string(); }; }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
|
|
|
|
2014-06-18 06:57:48 +02:00
|
|
|
// if (var)
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x) { a = x; }\n" // <- x is not 0
|
|
|
|
" else { b = x; }\n" // <- x is 0
|
|
|
|
" c = x;\n" // <- x might be 0
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-06-18 05:51:23 +02:00
|
|
|
// After while
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" while (x != 3) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 3));
|
2014-06-19 17:29:41 +02:00
|
|
|
|
2014-08-16 18:32:25 +02:00
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" while (11 != (x = dostuff())) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 11));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" while (11 != (x = dostuff()) && y) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, 11));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" while (x = dostuff()) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
|
|
|
|
code = "void f(const Token *x) {\n" // #5866
|
|
|
|
" x = x->next();\n"
|
|
|
|
" while (x) { x = x->next(); }\n"
|
|
|
|
" if (x->str()) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
|
|
|
|
|
|
|
|
code = "void f(const Token *x) {\n"
|
|
|
|
" while (0 != (x = x->next)) {}\n"
|
|
|
|
" x->ab = 0;\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
|
|
|
|
code = "void f(const Token* x) {\n"
|
|
|
|
" while (0 != (x = x->next)) {}\n"
|
|
|
|
" if (x->str) {\n" // <- possible value 0
|
|
|
|
" x = y;\n" // <- this caused some problem
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
|
2014-06-25 16:00:56 +02:00
|
|
|
// conditional code after if/else/while
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" if (x == 2) {}\n"
|
|
|
|
" if (x > 0)\n"
|
2014-10-17 06:50:33 +02:00
|
|
|
" a = x;\n" // <- TODO, x can be 2
|
2014-06-25 16:00:56 +02:00
|
|
|
" else\n"
|
|
|
|
" b = x;\n"
|
|
|
|
"}";
|
2014-10-17 06:50:33 +02:00
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 4U, 2));
|
2014-06-25 16:00:56 +02:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 2));
|
|
|
|
|
2014-08-01 07:35:15 +02:00
|
|
|
// condition with 2nd variable
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" int y = 0;\n"
|
|
|
|
" if (x == 7) { y = 1; }\n"
|
|
|
|
" if (!y)\n"
|
|
|
|
" a = x;\n" // <- x can not be 7 here
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 7));
|
|
|
|
|
2014-10-17 06:50:33 +02:00
|
|
|
code = "void f(struct X *x) {\n"
|
|
|
|
" bool b = TRUE;\n"
|
|
|
|
" if(x) { }\n"
|
|
|
|
" else\n"
|
|
|
|
" b = FALSE;\n"
|
|
|
|
" if (b)\n"
|
|
|
|
" abc(x->value);\n" // <- x is not 0
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 0));
|
|
|
|
|
2014-06-19 17:29:41 +02:00
|
|
|
// In condition, after && and ||
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = (x != 3 ||\n"
|
|
|
|
" x);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 3));
|
|
|
|
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = (x == 4 &&\n"
|
|
|
|
" x);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 4));
|
2014-06-25 06:17:44 +02:00
|
|
|
|
2014-08-11 16:21:20 +02:00
|
|
|
// protected usage with &&
|
|
|
|
code = "void f(const Token* x) {\n"
|
|
|
|
" if (x) {}\n"
|
|
|
|
" for (; x && \n"
|
|
|
|
" x->str() != y; x = x->next()) {}\n"
|
|
|
|
"}";
|
2014-10-11 17:48:51 +02:00
|
|
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, 0));
|
2014-08-11 16:21:20 +02:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
|
|
|
code = "void f(const Token* x) {\n"
|
|
|
|
" if (x) {}\n"
|
|
|
|
" if (x && \n"
|
|
|
|
" x->str() != y) {}\n"
|
|
|
|
"}";
|
2015-02-01 15:05:00 +01:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
2014-08-11 16:21:20 +02:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-08-27 16:59:18 +02:00
|
|
|
// return
|
|
|
|
code = "void f(int x) {\n" // #6024
|
2014-08-26 18:48:11 +02:00
|
|
|
" if (x == 5) {\n"
|
|
|
|
" if (z) return; else return;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 5));
|
|
|
|
|
2015-08-11 11:21:03 +02:00
|
|
|
code = "void f(int x) {\n" // #6730
|
|
|
|
" if (x == 5) {\n"
|
|
|
|
" if (z) continue; else throw e;\n"
|
|
|
|
" }\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 5));
|
|
|
|
|
2014-06-25 06:17:44 +02:00
|
|
|
// TODO: float
|
|
|
|
code = "void f(float x) {\n"
|
|
|
|
" if (x == 0.5) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-06-15 16:47:01 +02:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowBitAnd() {
|
2014-04-14 06:45:39 +02:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "int f(int a) {\n"
|
|
|
|
" int x = a & 0x80;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code,3U,0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code,3U,0x80));
|
2015-07-04 11:17:38 +02:00
|
|
|
|
|
|
|
code = "int f(int a) {\n"
|
|
|
|
" int x = a & 0x80 ? 1 : 2;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code,3U,0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code,3U,0x80));
|
2015-10-14 10:44:04 +02:00
|
|
|
|
|
|
|
code = "int f() {\n"
|
|
|
|
" int x = (19 - 3) & 15;\n"
|
|
|
|
" return x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code,3U,0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code,3U,16));
|
2014-04-14 06:45:39 +02:00
|
|
|
}
|
|
|
|
|
2015-07-20 19:45:38 +02:00
|
|
|
void valueFlowSwitchVariable() {
|
|
|
|
const char *code;
|
|
|
|
code = "void f(int x) {\n"
|
|
|
|
" a = x;\n" // <- x can be 14
|
|
|
|
" switch (x) {\n"
|
|
|
|
" case 14: a=x; break;\n" // <- x is 14
|
|
|
|
" };\n"
|
|
|
|
" a = x;\n" // <- x can be 14
|
|
|
|
"}";
|
2015-07-29 19:54:57 +02:00
|
|
|
ASSERT_EQUALS(true, testConditionalValueOfX(code, 2U, 14));
|
|
|
|
ASSERT_EQUALS(true, testConditionalValueOfX(code, 4U, 14));
|
|
|
|
ASSERT_EQUALS(true, testConditionalValueOfX(code, 6U, 14));
|
2015-07-20 19:45:38 +02:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowForLoop() {
|
2014-01-10 16:51:58 +01:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" for (int x = 0; x < 10; x++)\n"
|
|
|
|
" a[x] = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 9));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 10));
|
|
|
|
|
2014-08-18 16:45:22 +02:00
|
|
|
code = "void f() {\n"
|
2014-12-30 18:50:22 +01:00
|
|
|
" int x;\n"
|
|
|
|
" for (x = 2; x < 1; x++)\n"
|
2014-08-18 16:45:22 +02:00
|
|
|
" a[x] = 0;\n" // <- not 2
|
2014-12-30 18:50:22 +01:00
|
|
|
" b = x;\n" // 2
|
2014-08-18 16:45:22 +02:00
|
|
|
"}";
|
2014-12-30 18:50:22 +01:00
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 2));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 2));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 2; x < 1; ++x)\n"
|
|
|
|
" a[x] = 0;\n" // <- not 2
|
|
|
|
" b = x;\n" // 2
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 2));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 2));
|
2014-08-18 16:45:22 +02:00
|
|
|
|
2014-03-29 20:20:22 +01:00
|
|
|
code = "void f(int a) {\n"
|
|
|
|
" for (int x = a; x < 10; x++)\n"
|
|
|
|
" a[x] = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 9));
|
|
|
|
|
2014-03-22 19:02:33 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" for (int x = 0; x < 10; x = x + 2)\n"
|
|
|
|
" a[x] = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 8));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 10));
|
|
|
|
|
2014-03-23 20:37:56 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" for (int x = 0; x < 10; x = x / 0)\n"
|
|
|
|
" a[x] = 0;\n"
|
|
|
|
"}";
|
2014-03-24 00:16:02 +01:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0)); // don't crash
|
2014-03-23 20:37:56 +01:00
|
|
|
|
2014-02-22 17:58:48 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" for (int x = 0; x < 10; x++)\n"
|
|
|
|
" x<4 ?\n"
|
|
|
|
" a[x] : 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 9));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 9));
|
2014-03-25 18:22:22 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" for (int x = 0; x < 10; x++)\n"
|
|
|
|
" x==0 ?\n"
|
|
|
|
" 0 : a[x];\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
2014-04-28 15:54:54 +02:00
|
|
|
|
2014-12-30 19:56:47 +01:00
|
|
|
code = "void f() {\n" // #5223
|
|
|
|
" for (int x = 0; x < 300 && x < 18; x++)\n"
|
|
|
|
" x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 17));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 299));
|
|
|
|
|
2014-04-28 15:54:54 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (int i = 0; x = bar[i]; i++)\n"
|
|
|
|
" x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
2014-06-30 07:26:48 +02:00
|
|
|
|
2015-02-07 18:14:22 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" const char abc[] = \"abc\";\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; abc[x] != '\\0'; x++) {}\n"
|
|
|
|
" a[x] = 0;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 5U, 3));
|
|
|
|
|
2014-06-30 07:26:48 +02:00
|
|
|
code = "void f() {\n" // #5939
|
|
|
|
" int x;\n"
|
|
|
|
" for (int x = 0; (x = do_something()) != 0;)\n"
|
|
|
|
" x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (int x = 0; x < 10 && y = do_something();)\n"
|
|
|
|
" x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
|
2014-07-17 08:44:55 +02:00
|
|
|
|
2014-08-17 06:42:16 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x,y;\n"
|
|
|
|
" for (x = 0, y = 0; x < 10, y < 10; x++, y++)\n" // usage of ,
|
|
|
|
" x;\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
|
|
|
|
|
2014-07-17 08:44:55 +02:00
|
|
|
code = "void foo(double recoveredX) {\n"
|
|
|
|
" for (double x = 1e-18; x < 1e40; x *= 1.9) {\n"
|
|
|
|
" double relativeError = (x - recoveredX) / x;\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-08-01 16:12:57 +02:00
|
|
|
|
|
|
|
// &&
|
|
|
|
code = "void foo() {\n"
|
|
|
|
" for (int x = 0; x < 10; x++) {\n"
|
|
|
|
" if (x > 1\n"
|
|
|
|
" && x) {}" // <- x is not 0
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 9));
|
|
|
|
|
|
|
|
// ||
|
|
|
|
code = "void foo() {\n"
|
|
|
|
" for (int x = 0; x < 10; x++) {\n"
|
|
|
|
" if (x == 0\n"
|
|
|
|
" || x) {}" // <- x is not 0
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 9));
|
2014-08-13 04:03:17 +02:00
|
|
|
|
2014-08-17 10:40:22 +02:00
|
|
|
// After loop
|
|
|
|
code = "void foo() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; x < 10; x++) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 10));
|
|
|
|
|
|
|
|
code = "void foo() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; 2 * x < 20; x++) {}\n"
|
|
|
|
" a = x;\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 10));
|
|
|
|
|
|
|
|
code = "void foo() {\n" // related with #887
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; x < 20; x++) {}\n"
|
|
|
|
" a = x++;\n"
|
|
|
|
"}\n";
|
2015-05-02 17:30:09 +02:00
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 20));
|
2014-08-17 10:40:22 +02:00
|
|
|
|
2015-01-05 14:00:12 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; x < 5; x++) {}\n"
|
|
|
|
" if (x == 5) {\n"
|
|
|
|
" panic();\n"
|
|
|
|
" }\n"
|
2015-01-05 16:39:47 +01:00
|
|
|
" a = x;\n" // <- x can't be 5
|
2015-01-05 14:00:12 +01:00
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 7U, 5));
|
2015-01-05 16:39:47 +01:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" for (x = 0; x < 5; x++) {}\n"
|
|
|
|
" if (x < 5) {}\n"
|
|
|
|
" else return;\n"
|
|
|
|
" a = x;\n" // <- x can't be 5
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 5));
|
2015-01-05 14:00:12 +01:00
|
|
|
|
2014-08-13 04:03:17 +02:00
|
|
|
// hang
|
|
|
|
code = "void f() {\n"
|
|
|
|
" for(int i = 0; i < 20; i++)\n"
|
|
|
|
" n = (int)(i < 10 || abs(negWander) < abs(negTravel));\n"
|
|
|
|
"}";
|
|
|
|
testValueOfX(code,0,0); // <- dont hang
|
2016-01-24 13:11:51 +01:00
|
|
|
|
|
|
|
// conditional code in loop
|
|
|
|
code = "void f(int mask) {\n" // #6000
|
|
|
|
" for (int x = 10; x < 14; x++) {\n"
|
|
|
|
" int bit = mask & (1 << i);\n"
|
|
|
|
" if (bit) {\n"
|
|
|
|
" if (bit == (1 << 10)) {}\n"
|
|
|
|
" else { a = x; }\n" // <- x is not 10
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 10));
|
|
|
|
|
2014-01-07 19:20:56 +01:00
|
|
|
}
|
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowSubFunction() {
|
2014-01-06 16:37:52 +01:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f1(int x) { return x; }\n"
|
|
|
|
"void f2(int x) {\n"
|
|
|
|
" f1(123);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 123));
|
|
|
|
|
|
|
|
code = "void f1(int x) { return x; }\n"
|
|
|
|
"void f2(int x) {\n"
|
|
|
|
" f1(x);\n"
|
|
|
|
" if (x==0){}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 0));
|
2014-01-08 06:04:51 +01:00
|
|
|
|
|
|
|
code = "void f1(int x) {\n"
|
|
|
|
" if (x == 0) return;\n"
|
|
|
|
" int y = 1234 / x;\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"void f2() {\n"
|
|
|
|
" f1(0);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-01-08 16:17:47 +01:00
|
|
|
|
|
|
|
code = "void f1(int x) { a=x; }\n"
|
|
|
|
"void f2(int y) { f1(y<123); }\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 0));
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 1));
|
2014-01-11 07:52:25 +01:00
|
|
|
|
|
|
|
code = "void f1(int x) { a=(abc)x; }\n"
|
|
|
|
"void f2(int y) { f1(123); }\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 123));
|
2014-06-24 19:30:46 +02:00
|
|
|
|
|
|
|
code = "void f1(int x) {\n"
|
|
|
|
" x ?\n"
|
|
|
|
" 1024 / x :\n"
|
|
|
|
" 0; }\n"
|
|
|
|
"void f2() { f1(0); }";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-06-28 12:04:20 +02:00
|
|
|
|
2014-10-15 16:34:03 +02:00
|
|
|
code = "void f1(int *x) {\n"
|
|
|
|
" if (x &&\n"
|
|
|
|
" *x) {}\n"
|
|
|
|
"}\n"
|
|
|
|
"void f2() { f1(0); }";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
|
|
|
|
2014-06-28 12:04:20 +02:00
|
|
|
// #5861 - fp with float
|
|
|
|
code = "void f1(float x) {\n"
|
|
|
|
" return 1.0 / x;\n"
|
|
|
|
"}\n"
|
|
|
|
"void f2() { f1(0.5); }";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0));
|
2014-08-04 12:31:04 +02:00
|
|
|
|
|
|
|
code = "void dostuff(int x) {\n"
|
|
|
|
" return x/x;\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"void test(int x) {\n"
|
|
|
|
" if(x==1) {}\n"
|
|
|
|
" dostuff(x+1);\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 2));
|
2015-01-31 10:33:15 +01:00
|
|
|
|
|
|
|
code = "void leaveNotifyEvent(const XCrossingEvent * const) { }\n"
|
|
|
|
"void motionNotifyEvent() {\n"
|
|
|
|
" leaveNotifyEvent(0);\n"
|
|
|
|
"}";
|
|
|
|
testValueOfX(code, 2U, 2); // No complaint about Token::Match called with varid 0. (#6443)
|
2015-05-24 17:02:00 +02:00
|
|
|
|
|
|
|
// #6560 - multivariables
|
|
|
|
code = "void f1(int x) {\n"
|
|
|
|
" int a = x && y;\n"
|
|
|
|
" int b = a ? x : 0;\n"
|
|
|
|
"}\n"
|
|
|
|
"void f2() {\n"
|
|
|
|
" f1(0);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
2014-01-06 16:37:52 +01:00
|
|
|
}
|
2014-06-29 18:04:38 +02:00
|
|
|
|
2014-11-20 14:20:09 +01:00
|
|
|
void valueFlowFunctionReturn() {
|
2014-06-29 18:04:38 +02:00
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "void f1(int x) {\n"
|
|
|
|
" return x+1;\n"
|
|
|
|
"}\n"
|
|
|
|
"void f2() {\n"
|
|
|
|
" x = 10 - f1(2);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(7, valueOfTok(code, "-").intvalue);
|
|
|
|
|
|
|
|
code = "void add(int x, int y) {\n"
|
|
|
|
" return x+y;\n"
|
|
|
|
"}\n"
|
|
|
|
"void f2() {\n"
|
|
|
|
" x = 1 * add(10+1,4);\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(15, valueOfTok(code, "*").intvalue);
|
|
|
|
}
|
2015-02-03 22:12:05 +01:00
|
|
|
|
|
|
|
void valueFlowFunctionDefaultParameter() {
|
|
|
|
const char *code;
|
|
|
|
|
|
|
|
code = "class continuous_src_time {\n"
|
|
|
|
" continuous_src_time(std::complex<double> f, double st = 0.0, double et = infinity) {}\n"
|
|
|
|
"};";
|
|
|
|
testValueOfX(code, 2U, 2); // Don't crash (#6494)
|
|
|
|
}
|
2015-07-16 17:33:16 +02:00
|
|
|
|
2015-07-20 09:36:56 +02:00
|
|
|
bool isNotKnownValues(const char code[], const char str[]) {
|
|
|
|
const std::list<ValueFlow::Value> values = tokenValues(code, str);
|
|
|
|
for (std::list<ValueFlow::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
2015-07-25 19:36:29 +02:00
|
|
|
if (it->isKnown())
|
2015-07-20 09:36:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-01-24 08:57:57 +01:00
|
|
|
return true;
|
2015-07-20 09:36:56 +02:00
|
|
|
}
|
|
|
|
|
2015-07-16 17:33:16 +02:00
|
|
|
void knownValue() {
|
|
|
|
const char *code;
|
|
|
|
ValueFlow::Value value;
|
|
|
|
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(valueOfTok("x = 1;", "1").isKnown());
|
2015-07-16 17:33:16 +02:00
|
|
|
|
|
|
|
// after assignment
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 1;\n"
|
|
|
|
" return x + 2;\n" // <- known value
|
|
|
|
"}";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(3, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isKnown());
|
2015-07-16 17:33:16 +02:00
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x;\n"
|
|
|
|
" if (ab) { x = 7; }\n"
|
|
|
|
" return x + 2;\n" // <- possible value
|
|
|
|
"}";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(9, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isPossible());
|
2015-07-16 17:33:16 +02:00
|
|
|
|
2015-07-29 10:49:17 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" fred.dostuff(x);\n"
|
|
|
|
" if (x < 0) {}\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT(isNotKnownValues(code, "<"));
|
|
|
|
|
2015-11-12 14:59:35 +01:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" do {\n"
|
|
|
|
" if (x < 0) {}\n"
|
|
|
|
" fred.dostuff(x);\n"
|
|
|
|
" } while (abc);\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT(isNotKnownValues(code, "<"));
|
|
|
|
|
2015-07-21 17:56:40 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" if (y) { dostuff(x); }\n"
|
|
|
|
" if (!x) {}\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT(isNotKnownValues(code, "!"));
|
|
|
|
|
2015-08-05 14:08:57 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" MACRO( v, { if (y) { x++; } } );\n"
|
|
|
|
" if (!x) {}\n"
|
|
|
|
"}\n";
|
|
|
|
ASSERT(isNotKnownValues(code, "!"));
|
|
|
|
|
2015-07-16 21:08:32 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" for (int i = 0; i < 10; i++) {\n"
|
|
|
|
" if (cond) {\n"
|
|
|
|
" x = 1;\n"
|
|
|
|
" break;\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
" if (!x) {}\n" // <- possible value
|
|
|
|
"}";
|
2015-07-20 09:36:56 +02:00
|
|
|
ASSERT(isNotKnownValues(code, "!"));
|
|
|
|
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" switch (state) {\n"
|
|
|
|
" case 1:\n"
|
|
|
|
" x = 1;\n"
|
|
|
|
" break;\n"
|
|
|
|
" }\n"
|
|
|
|
" if (!x) {}\n" // <- possible value
|
|
|
|
"}";
|
|
|
|
ASSERT(isNotKnownValues(code, "!"));
|
2015-07-16 21:08:32 +02:00
|
|
|
|
2015-11-08 14:08:47 +01:00
|
|
|
code = "void f() {\n" // #7049
|
|
|
|
" int x = 0;\n"
|
|
|
|
" switch (a) {\n"
|
|
|
|
" case 1:\n"
|
|
|
|
" x = 1;\n"
|
|
|
|
" case 2:\n"
|
|
|
|
" if (!x) {}\n" // <- possible value
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
ASSERT(isNotKnownValues(code, "!"));
|
|
|
|
|
2015-07-17 10:24:24 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" while (!x) {\n" // <- possible value
|
2015-07-18 15:35:39 +02:00
|
|
|
" scanf(\"%d\", &x);\n"
|
2015-07-17 10:24:24 +02:00
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
value = valueOfTok(code, "!");
|
|
|
|
ASSERT_EQUALS(1, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isPossible());
|
2015-07-17 10:24:24 +02:00
|
|
|
|
2015-07-29 11:55:07 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
" do { } while (++x < 12);\n" // <- possible value
|
|
|
|
"}";
|
|
|
|
ASSERT(isNotKnownValues(code, "<"));
|
|
|
|
|
2015-07-17 20:30:34 +02:00
|
|
|
code = "void f() {\n"
|
2015-07-17 20:48:37 +02:00
|
|
|
" static int x = 0;\n"
|
|
|
|
" return x + 1;\n" // <- possible value
|
|
|
|
"}\n";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(1, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isPossible());
|
2015-07-17 20:48:37 +02:00
|
|
|
|
2015-07-26 17:05:21 +02:00
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 0;\n"
|
|
|
|
"a:\n"
|
|
|
|
" a = x + 1;\n" // <- possible value
|
|
|
|
"}";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(1, value.intvalue);
|
|
|
|
ASSERT(value.isPossible());
|
|
|
|
|
2015-07-16 17:33:16 +02:00
|
|
|
// after condition
|
|
|
|
code = "int f(int x) {\n"
|
|
|
|
" if (x == 4) {}\n"
|
|
|
|
" return x + 1;\n" // <- possible value
|
|
|
|
"}";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(5, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isPossible());
|
2015-07-16 20:49:14 +02:00
|
|
|
|
|
|
|
// function
|
|
|
|
code = "int f(int x) { return x + 1; }\n" // <- possible value
|
|
|
|
"void a() { f(12); }\b";
|
|
|
|
value = valueOfTok(code, "+");
|
|
|
|
ASSERT_EQUALS(13, value.intvalue);
|
2015-07-25 19:36:29 +02:00
|
|
|
ASSERT(value.isPossible());
|
2015-10-04 10:33:43 +02:00
|
|
|
|
|
|
|
// known and possible value
|
|
|
|
code = "void f() {\n"
|
|
|
|
" int x = 1;\n"
|
|
|
|
" int y = 2 + x;\n" // <- known value, don't care about condition
|
|
|
|
" if (x == 2) {}\n"
|
|
|
|
"}";
|
|
|
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 1)); // value of x can be 1
|
|
|
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 2)); // value of x can't be 2
|
2015-07-16 17:33:16 +02:00
|
|
|
}
|
2014-01-04 20:57:02 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
REGISTER_TEST(TestValueFlow)
|