Bugfix buffer size for strdup like functions (#1893)
strdup() allocates the string length plus one for a terminating null character. Add one to compensate for this. Fixes false positive buffer out of bounds on code like this: void f() { const char *a = "abcd"; char * b = strdup(a); printf("%c", b[4]); // prints the terminating null character free(b); } Also, add a testcase for valueFlowDynamicBufferSize() and add tests for strdup(), malloc() and calloc().
This commit is contained in:
parent
ba0a75881a
commit
d909ac8565
|
@ -5329,7 +5329,7 @@ static void valueFlowDynamicBufferSize(TokenList *tokenlist, SymbolDatabase *sym
|
|||
if (arg1 && arg1->hasKnownValue()) {
|
||||
const ValueFlow::Value &value = arg1->values().back();
|
||||
if (value.isTokValue() && value.tokvalue->tokType() == Token::eString)
|
||||
sizeValue = Token::getStrLength(value.tokvalue);
|
||||
sizeValue = Token::getStrLength(value.tokvalue) + 1; // Add one for the null terminator
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
|
|
@ -117,6 +117,8 @@ private:
|
|||
TEST_CASE(valueFlowTerminatingCond);
|
||||
|
||||
TEST_CASE(valueFlowContainerSize);
|
||||
|
||||
TEST_CASE(valueFlowDynamicBufferSize);
|
||||
}
|
||||
|
||||
static bool isNotTokValue(const ValueFlow::Value &val) {
|
||||
|
@ -223,6 +225,24 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool testValueOfX(const char code[], unsigned int linenr, int value, ValueFlow::Value::ValueType type) {
|
||||
// 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) {
|
||||
for (const ValueFlow::Value &v : tok->values()) {
|
||||
if (v.valueType == type && v.intvalue == value)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool testValueOfX(const char code[], unsigned int linenr, ValueFlow::Value::MoveKind moveKind) {
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
|
@ -3819,6 +3839,32 @@ private:
|
|||
"}";
|
||||
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "+"), 8));
|
||||
}
|
||||
|
||||
void valueFlowDynamicBufferSize() {
|
||||
const char *code;
|
||||
|
||||
LOAD_LIB_2(settings.library, "std.cfg");
|
||||
LOAD_LIB_2(settings.library, "posix.cfg");
|
||||
|
||||
code = "void* f() {\n"
|
||||
" void* x = malloc(10);\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 10, ValueFlow::Value::BUFFER_SIZE));
|
||||
|
||||
code = "void* f() {\n"
|
||||
" void* x = calloc(4, 5);\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 20, ValueFlow::Value::BUFFER_SIZE));
|
||||
|
||||
code = "void* f() {\n"
|
||||
" const char* y = \"abcd\";\n"
|
||||
" const char* x = strdup(y);\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 4U, 5, ValueFlow::Value::BUFFER_SIZE));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestValueFlow)
|
||||
|
|
Loading…
Reference in New Issue