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:
Rikard Falkeborn 2019-06-16 16:02:27 +02:00 committed by Daniel Marjamäki
parent ba0a75881a
commit d909ac8565
2 changed files with 47 additions and 1 deletions

View File

@ -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;
};

View File

@ -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)