Fix #9944 FP: terminateStrncpy doesn't account for size check (#4252)

* Fix #9944 FP: terminateStrncpy doesn't account for size check

* Fix container size check

* Undo

* Format

* Rebuild

* Rebuild
This commit is contained in:
chrchr-github 2022-07-08 12:35:21 +02:00 committed by GitHub
parent a71a647c39
commit 89a9e5ecc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 3 deletions

View File

@ -739,9 +739,18 @@ void CheckBufferOverrun::stringNotZeroTerminated()
const ValueFlow::Value &bufferSize = getBufferSize(args[0]); const ValueFlow::Value &bufferSize = getBufferSize(args[0]);
if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue) if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue)
continue; continue;
const Token *srcValue = args[1]->getValueTokenMaxStrLength(); if (Token::simpleMatch(args[1], "(") && Token::simpleMatch(args[1]->astOperand1(), ". c_str") && args[1]->astOperand1()->astOperand1()) {
if (srcValue && Token::getStrLength(srcValue) < sizeToken->getKnownIntValue()) const std::list<ValueFlow::Value>& contValues = args[1]->astOperand1()->astOperand1()->values();
continue; auto it = std::find_if(contValues.begin(), contValues.end(), [](const ValueFlow::Value& value) {
return value.isContainerSizeValue() && !value.isImpossible();
});
if (it != contValues.end() && it->intvalue < sizeToken->getKnownIntValue())
continue;
} else {
const Token* srcValue = args[1]->getValueTokenMaxStrLength();
if (srcValue && Token::getStrLength(srcValue) < sizeToken->getKnownIntValue())
continue;
}
// Is the buffer zero terminated after the call? // Is the buffer zero terminated after the call?
bool isZeroTerminated = false; bool isZeroTerminated = false;
for (const Token *tok2 = tok->next()->link(); tok2 != scope->bodyEnd; tok2 = tok2->next()) { for (const Token *tok2 = tok->next()->link(); tok2 != scope->bodyEnd; tok2 = tok2->next()) {

View File

@ -289,6 +289,7 @@ private:
TEST_CASE(terminateStrncpy2); TEST_CASE(terminateStrncpy2);
TEST_CASE(terminateStrncpy3); TEST_CASE(terminateStrncpy3);
TEST_CASE(terminateStrncpy4); TEST_CASE(terminateStrncpy4);
TEST_CASE(terminateStrncpy5); // #9944
TEST_CASE(recursive_long_time); TEST_CASE(recursive_long_time);
TEST_CASE(crash1); // Ticket #1587 - crash TEST_CASE(crash1); // Ticket #1587 - crash
@ -4342,6 +4343,23 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'buf' may not be null-terminated after the call to strncpy().\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'buf' may not be null-terminated after the call to strncpy().\n", errout.str());
} }
void terminateStrncpy5() { // #9944
check("void f(const std::string& buf) {\n"
" char v[255];\n"
" if (buf.size() >= sizeof(v))\n"
" return;\n"
" strncpy(v, buf.c_str(), sizeof(v));\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("void f(const std::string& buf) {\n"
" char v[255];\n"
" if (buf.size() >= sizeof(v))\n"
" strncpy(v, buf.c_str(), sizeof(v));\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) The buffer 'v' may not be null-terminated after the call to strncpy().\n", errout.str());
}
// extracttests.enable // extracttests.enable
void recursive_long_time() { void recursive_long_time() {