parent
5a444f764b
commit
5bc039b7da
|
@ -661,6 +661,8 @@ static unsigned int getSizeOfType(const Token *typeTok, const Settings *settings
|
||||||
return settings->sizeof_int;
|
return settings->sizeof_int;
|
||||||
else if (typeStr == "long")
|
else if (typeStr == "long")
|
||||||
return typeTok->isLong() ? settings->sizeof_long_long : settings->sizeof_long;
|
return typeTok->isLong() ? settings->sizeof_long_long : settings->sizeof_long;
|
||||||
|
else if (typeStr == "wchar_t")
|
||||||
|
return settings->sizeof_wchar_t;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -692,6 +694,13 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
|
||||||
setTokenValue(const_cast<Token *>(tok), value, settings);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
} else if (Token::simpleMatch(tok, "sizeof (")) {
|
} else if (Token::simpleMatch(tok, "sizeof (")) {
|
||||||
const Token *tok2 = tok->tokAt(2);
|
const Token *tok2 = tok->tokAt(2);
|
||||||
|
// skip over tokens to find variable or type
|
||||||
|
while (Token::Match(tok2, "%name% ::|.|[")) {
|
||||||
|
if (tok2->next()->str() == "[")
|
||||||
|
tok2 = tok2->linkAt(1)->next();
|
||||||
|
else
|
||||||
|
tok2 = tok2->tokAt(2);
|
||||||
|
}
|
||||||
if (tok2->enumerator() && tok2->enumerator()->scope) {
|
if (tok2->enumerator() && tok2->enumerator()->scope) {
|
||||||
long long size = settings->sizeof_int;
|
long long size = settings->sizeof_int;
|
||||||
const Token * type = tok2->enumerator()->scope->enumType;
|
const Token * type = tok2->enumerator()->scope->enumType;
|
||||||
|
@ -732,6 +741,35 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok->tokAt(4)), value, settings);
|
setTokenValue(const_cast<Token *>(tok->tokAt(4)), value, settings);
|
||||||
}
|
}
|
||||||
|
} else if (Token::Match(tok2, "%var% )")) {
|
||||||
|
const Variable *var = tok2->variable();
|
||||||
|
// only look for single token types (no pointers or references yet)
|
||||||
|
if (var && var->typeStartToken() == var->typeEndToken()) {
|
||||||
|
// find the size of the type
|
||||||
|
size_t size = 0;
|
||||||
|
if (var->isEnumType()) {
|
||||||
|
size = settings->sizeof_int;
|
||||||
|
if (var->type()->classScope && var->type()->classScope->enumType)
|
||||||
|
size = getSizeOfType(var->type()->classScope->enumType, settings);
|
||||||
|
} else if (!var->type()) {
|
||||||
|
size = getSizeOfType(var->typeStartToken(), settings);
|
||||||
|
}
|
||||||
|
// find the number of elements
|
||||||
|
size_t count = 1;
|
||||||
|
for (size_t i = 0; i < var->dimensions().size(); ++i) {
|
||||||
|
if (var->dimensionKnown(i))
|
||||||
|
count *= var->dimension(i);
|
||||||
|
else
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
if (size && count > 0) {
|
||||||
|
ValueFlow::Value value(count * size);
|
||||||
|
if (settings->platformType != cppcheck::Platform::Unspecified)
|
||||||
|
value.setKnown();
|
||||||
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
|
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (!tok2->type()) {
|
} else if (!tok2->type()) {
|
||||||
const ValueType &vt = ValueType::parseDecl(tok2,settings);
|
const ValueType &vt = ValueType::parseDecl(tok2,settings);
|
||||||
if (vt.pointer) {
|
if (vt.pointer) {
|
||||||
|
|
|
@ -150,6 +150,7 @@ private:
|
||||||
TEST_CASE(array_index_valueflow);
|
TEST_CASE(array_index_valueflow);
|
||||||
TEST_CASE(array_index_valueflow_pointer);
|
TEST_CASE(array_index_valueflow_pointer);
|
||||||
TEST_CASE(array_index_function_parameter);
|
TEST_CASE(array_index_function_parameter);
|
||||||
|
TEST_CASE(array_index_enum_array); // #8439
|
||||||
|
|
||||||
TEST_CASE(buffer_overrun_2_struct);
|
TEST_CASE(buffer_overrun_2_struct);
|
||||||
TEST_CASE(buffer_overrun_3);
|
TEST_CASE(buffer_overrun_3);
|
||||||
|
@ -171,6 +172,7 @@ private:
|
||||||
TEST_CASE(buffer_overrun_27); // #4444 (segmentation fault)
|
TEST_CASE(buffer_overrun_27); // #4444 (segmentation fault)
|
||||||
TEST_CASE(buffer_overrun_28); // Out of bound char array access
|
TEST_CASE(buffer_overrun_28); // Out of bound char array access
|
||||||
TEST_CASE(buffer_overrun_29); // #7083: false positive: typedef and initialization with strings
|
TEST_CASE(buffer_overrun_29); // #7083: false positive: typedef and initialization with strings
|
||||||
|
TEST_CASE(buffer_overrun_30); // #6367
|
||||||
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
|
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
|
||||||
TEST_CASE(buffer_overrun_function_array_argument);
|
TEST_CASE(buffer_overrun_function_array_argument);
|
||||||
TEST_CASE(possible_buffer_overrun_1); // #3035
|
TEST_CASE(possible_buffer_overrun_1); // #3035
|
||||||
|
@ -2168,6 +2170,15 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void array_index_enum_array() { // #8439
|
||||||
|
check("enum E : unsigned int { e1, e2 };\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" E arrE[] = { e1, e2 };\n"
|
||||||
|
" arrE[sizeof(arrE)] = e1;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'arrE[2]' accessed at index 8, which is out of bounds.\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void buffer_overrun_2_struct() {
|
void buffer_overrun_2_struct() {
|
||||||
check("struct ABC\n"
|
check("struct ABC\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -2533,6 +2544,19 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #6367
|
||||||
|
void buffer_overrun_30() {
|
||||||
|
check("struct S { int m[9]; };\n"
|
||||||
|
"int f(S * s) {\n"
|
||||||
|
" return s->m[sizeof(s->m)];\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Array 's->m[9]' accessed at index 36, which is out of bounds.\n"
|
||||||
|
"[test.cpp:3]: (error) Array 's.m[9]' accessed at index 36, which is out of bounds.\n",
|
||||||
|
errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void buffer_overrun_bailoutIfSwitch() {
|
void buffer_overrun_bailoutIfSwitch() {
|
||||||
// No false positive
|
// No false positive
|
||||||
check("void f1(char *s) {\n"
|
check("void f1(char *s) {\n"
|
||||||
|
|
|
@ -59,6 +59,7 @@ private:
|
||||||
TEST_CASE(valueFlowBitAnd);
|
TEST_CASE(valueFlowBitAnd);
|
||||||
|
|
||||||
TEST_CASE(valueFlowCalculations);
|
TEST_CASE(valueFlowCalculations);
|
||||||
|
TEST_CASE(valueFlowSizeof);
|
||||||
|
|
||||||
TEST_CASE(valueFlowErrorPath);
|
TEST_CASE(valueFlowErrorPath);
|
||||||
|
|
||||||
|
@ -559,22 +560,6 @@ private:
|
||||||
ASSERT_EQUALS(1U, values.size());
|
ASSERT_EQUALS(1U, values.size());
|
||||||
ASSERT_EQUALS(-10, values.back().intvalue);
|
ASSERT_EQUALS(-10, values.back().intvalue);
|
||||||
|
|
||||||
// sizeof
|
|
||||||
code = "void f() {\n"
|
|
||||||
" x = sizeof(int);\n"
|
|
||||||
"}";
|
|
||||||
values = tokenValues(code,"( int )");
|
|
||||||
ASSERT_EQUALS(1U, values.size());
|
|
||||||
ASSERT_EQUALS(settings.sizeof_int, values.back().intvalue);
|
|
||||||
|
|
||||||
code = "void f() {\n"
|
|
||||||
" struct S *a[10];"
|
|
||||||
" x = sizeof(a) / sizeof(a[0]);\n"
|
|
||||||
"}";
|
|
||||||
values = tokenValues(code,"/");
|
|
||||||
ASSERT_EQUALS(1U, values.size());
|
|
||||||
ASSERT_EQUALS(10, values.back().intvalue);
|
|
||||||
|
|
||||||
// function call => calculation
|
// function call => calculation
|
||||||
code = "void f(int x) {\n"
|
code = "void f(int x) {\n"
|
||||||
" a = x + 8;\n"
|
" a = x + 8;\n"
|
||||||
|
@ -621,6 +606,175 @@ private:
|
||||||
ASSERT_EQUALS(1, values.front().intvalue);
|
ASSERT_EQUALS(1, values.front().intvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void valueFlowSizeof() {
|
||||||
|
const char *code;
|
||||||
|
std::list<ValueFlow::Value> values;
|
||||||
|
|
||||||
|
#define CHECK(A, B) \
|
||||||
|
code = "void f() {\n" \
|
||||||
|
" x = sizeof(" A ");\n" \
|
||||||
|
"}"; \
|
||||||
|
values = tokenValues(code,"( " A " )"); \
|
||||||
|
ASSERT_EQUALS(1U, values.size()); \
|
||||||
|
ASSERT_EQUALS(B, values.back().intvalue);
|
||||||
|
|
||||||
|
// standard types
|
||||||
|
CHECK("void *", settings.sizeof_pointer);
|
||||||
|
CHECK("char", 1U);
|
||||||
|
CHECK("short", settings.sizeof_short);
|
||||||
|
CHECK("int", settings.sizeof_int);
|
||||||
|
CHECK("long", settings.sizeof_long);
|
||||||
|
#undef CHECK
|
||||||
|
|
||||||
|
// array size
|
||||||
|
code = "void f() {\n"
|
||||||
|
" struct S *a[10];"
|
||||||
|
" x = sizeof(a) / sizeof(a[0]);\n"
|
||||||
|
"}";
|
||||||
|
values = tokenValues(code,"/");
|
||||||
|
ASSERT_EQUALS(1U, values.size());
|
||||||
|
ASSERT_EQUALS(10, values.back().intvalue);
|
||||||
|
|
||||||
|
#define CHECK(A, B, C, D) \
|
||||||
|
code = "enum " A " E " B " { E0, E1 };\n" \
|
||||||
|
"void f() {\n" \
|
||||||
|
" x = sizeof(" C ");\n" \
|
||||||
|
"}"; \
|
||||||
|
values = tokenValues(code,"( " C " )"); \
|
||||||
|
ASSERT_EQUALS(1U, values.size()); \
|
||||||
|
ASSERT_EQUALS(D, values.back().intvalue);
|
||||||
|
|
||||||
|
// enums
|
||||||
|
CHECK("", "", "E", settings.sizeof_int);
|
||||||
|
|
||||||
|
// typed enums
|
||||||
|
CHECK("", ": char", "E", 1U);
|
||||||
|
CHECK("", ": signed char", "E", 1U);
|
||||||
|
CHECK("", ": unsigned char", "E", 1U);
|
||||||
|
CHECK("", ": short", "E", settings.sizeof_short);
|
||||||
|
CHECK("", ": signed short", "E", settings.sizeof_short);
|
||||||
|
CHECK("", ": unsigned short", "E", settings.sizeof_short);
|
||||||
|
CHECK("", ": int", "E", settings.sizeof_int);
|
||||||
|
CHECK("", ": signed int", "E", settings.sizeof_int);
|
||||||
|
CHECK("", ": unsigned int", "E", settings.sizeof_int);
|
||||||
|
CHECK("", ": long", "E", settings.sizeof_long);
|
||||||
|
CHECK("", ": signed long", "E", settings.sizeof_long);
|
||||||
|
CHECK("", ": unsigned long", "E", settings.sizeof_long);
|
||||||
|
CHECK("", ": long long", "E", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": signed long long", "E", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": unsigned long long", "E", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": wchar_t", "E", settings.sizeof_wchar_t);
|
||||||
|
CHECK("", ": size_t", "E", settings.sizeof_size_t);
|
||||||
|
|
||||||
|
// enumerators
|
||||||
|
CHECK("", "", "E0", settings.sizeof_int);
|
||||||
|
|
||||||
|
// typed enumerators
|
||||||
|
CHECK("", ": char", "E0", 1U);
|
||||||
|
CHECK("", ": signed char", "E0", 1U);
|
||||||
|
CHECK("", ": unsigned char", "E0", 1U);
|
||||||
|
CHECK("", ": short", "E0", settings.sizeof_short);
|
||||||
|
CHECK("", ": signed short", "E0", settings.sizeof_short);
|
||||||
|
CHECK("", ": unsigned short", "E0", settings.sizeof_short);
|
||||||
|
CHECK("", ": int", "E0", settings.sizeof_int);
|
||||||
|
CHECK("", ": signed int", "E0", settings.sizeof_int);
|
||||||
|
CHECK("", ": unsigned int", "E0", settings.sizeof_int);
|
||||||
|
CHECK("", ": long", "E0", settings.sizeof_long);
|
||||||
|
CHECK("", ": signed long", "E0", settings.sizeof_long);
|
||||||
|
CHECK("", ": unsigned long", "E0", settings.sizeof_long);
|
||||||
|
CHECK("", ": long long", "E0", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": signed long long", "E0", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": unsigned long long", "E0", settings.sizeof_long_long);
|
||||||
|
CHECK("", ": wchar_t", "E0", settings.sizeof_wchar_t);
|
||||||
|
CHECK("", ": size_t", "E0", settings.sizeof_size_t);
|
||||||
|
|
||||||
|
// class typed enumerators
|
||||||
|
CHECK("class", ": char", "E :: E0", 1U);
|
||||||
|
CHECK("class", ": signed char", "E :: E0", 1U);
|
||||||
|
CHECK("class", ": unsigned char", "E :: E0", 1U);
|
||||||
|
CHECK("class", ": short", "E :: E0", settings.sizeof_short);
|
||||||
|
CHECK("class", ": signed short", "E :: E0", settings.sizeof_short);
|
||||||
|
CHECK("class", ": unsigned short", "E :: E0", settings.sizeof_short);
|
||||||
|
CHECK("class", ": int", "E :: E0", settings.sizeof_int);
|
||||||
|
CHECK("class", ": signed int", "E :: E0", settings.sizeof_int);
|
||||||
|
CHECK("class", ": unsigned int", "E :: E0", settings.sizeof_int);
|
||||||
|
CHECK("class", ": long", "E :: E0", settings.sizeof_long);
|
||||||
|
CHECK("class", ": signed long", "E :: E0", settings.sizeof_long);
|
||||||
|
CHECK("class", ": unsigned long", "E :: E0", settings.sizeof_long);
|
||||||
|
CHECK("class", ": long long", "E :: E0", settings.sizeof_long_long);
|
||||||
|
CHECK("class", ": signed long long", "E :: E0", settings.sizeof_long_long);
|
||||||
|
CHECK("class", ": unsigned long long", "E :: E0", settings.sizeof_long_long);
|
||||||
|
CHECK("class", ": wchar_t", "E :: E0", settings.sizeof_wchar_t);
|
||||||
|
CHECK("class", ": size_t", "E :: E0", settings.sizeof_size_t);
|
||||||
|
#undef CHECK
|
||||||
|
|
||||||
|
#define CHECK(A, B) \
|
||||||
|
code = "enum E " A " { E0, E1 };\n" \
|
||||||
|
"void f() {\n" \
|
||||||
|
" E arrE[] = { E0, E1 };\n" \
|
||||||
|
" x = sizeof(arrE);\n" \
|
||||||
|
"}"; \
|
||||||
|
values = tokenValues(code,"( arrE )"); \
|
||||||
|
ASSERT_EQUALS(1U, values.size()); \
|
||||||
|
ASSERT_EQUALS(B * 2U, values.back().intvalue);
|
||||||
|
|
||||||
|
// enum array
|
||||||
|
CHECK("", settings.sizeof_int);
|
||||||
|
|
||||||
|
// typed enum array
|
||||||
|
CHECK(": char", 1U);
|
||||||
|
CHECK(": signed char", 1U);
|
||||||
|
CHECK(": unsigned char", 1U);
|
||||||
|
CHECK(": short", settings.sizeof_short);
|
||||||
|
CHECK(": signed short", settings.sizeof_short);
|
||||||
|
CHECK(": unsigned short", settings.sizeof_short);
|
||||||
|
CHECK(": int", settings.sizeof_int);
|
||||||
|
CHECK(": signed int", settings.sizeof_int);
|
||||||
|
CHECK(": unsigned int", settings.sizeof_int);
|
||||||
|
CHECK(": long", settings.sizeof_long);
|
||||||
|
CHECK(": signed long", settings.sizeof_long);
|
||||||
|
CHECK(": unsigned long", settings.sizeof_long);
|
||||||
|
CHECK(": long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": signed long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": unsigned long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": wchar_t", settings.sizeof_wchar_t);
|
||||||
|
CHECK(": size_t", settings.sizeof_size_t);
|
||||||
|
#undef CHECK
|
||||||
|
|
||||||
|
#define CHECK(A, B) \
|
||||||
|
code = "enum class E " A " { E0, E1 };\n" \
|
||||||
|
"void f() {\n" \
|
||||||
|
" E arrE[] = { E::E0, E::E1 };\n" \
|
||||||
|
" x = sizeof(arrE);\n" \
|
||||||
|
"}"; \
|
||||||
|
values = tokenValues(code,"( arrE )"); \
|
||||||
|
ASSERT_EQUALS(1U, values.size()); \
|
||||||
|
ASSERT_EQUALS(B * 2U, values.back().intvalue);
|
||||||
|
|
||||||
|
// enum array
|
||||||
|
CHECK("", settings.sizeof_int);
|
||||||
|
|
||||||
|
// typed enum array
|
||||||
|
CHECK(": char", 1U);
|
||||||
|
CHECK(": signed char", 1U);
|
||||||
|
CHECK(": unsigned char", 1U);
|
||||||
|
CHECK(": short", settings.sizeof_short);
|
||||||
|
CHECK(": signed short", settings.sizeof_short);
|
||||||
|
CHECK(": unsigned short", settings.sizeof_short);
|
||||||
|
CHECK(": int", settings.sizeof_int);
|
||||||
|
CHECK(": signed int", settings.sizeof_int);
|
||||||
|
CHECK(": unsigned int", settings.sizeof_int);
|
||||||
|
CHECK(": long", settings.sizeof_long);
|
||||||
|
CHECK(": signed long", settings.sizeof_long);
|
||||||
|
CHECK(": unsigned long", settings.sizeof_long);
|
||||||
|
CHECK(": long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": signed long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": unsigned long long", settings.sizeof_long_long);
|
||||||
|
CHECK(": wchar_t", settings.sizeof_wchar_t);
|
||||||
|
CHECK(": size_t", settings.sizeof_size_t);
|
||||||
|
#undef CHECK
|
||||||
|
}
|
||||||
|
|
||||||
void valueFlowErrorPath() {
|
void valueFlowErrorPath() {
|
||||||
const char *code;
|
const char *code;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue