#4664: new check: (POSIX) write outside buffer size.
This commit is contained in:
parent
cc3139cf39
commit
ff826d7c62
|
@ -2222,3 +2222,51 @@ void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::s
|
||||||
"Reorder conditions such as '(a[i] && i < 10)' to '(i < 10 && a[i])'. That way the array will "
|
"Reorder conditions such as '(a[i] && i < 10)' to '(i < 10 && a[i])'. That way the array will "
|
||||||
"not be accessed if the index is out of limits.");
|
"not be accessed if the index is out of limits.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Check the second and the third parameter of the POSIX function write and validate
|
||||||
|
// their values.
|
||||||
|
// The parameters have the following meaning:
|
||||||
|
// - 1.parameter: file descripter (not required for this check)
|
||||||
|
// - 2.parameter: is a null terminated character string of the content to write.
|
||||||
|
// - 3.parameter: the number of bytes to write.
|
||||||
|
//
|
||||||
|
// This check is triggered if the size of the string ( 2. parameter) is lower than
|
||||||
|
// the number of bytes provided at the 3. parameter.
|
||||||
|
//
|
||||||
|
// References:
|
||||||
|
// - http://gd.tuwien.ac.at/languages/c/programming-bbrown/c_075.htm
|
||||||
|
// - http://codewiki.wikidot.com/c:system-calls:write
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
void CheckBufferOverrun::writeOutsideBufferSize()
|
||||||
|
{
|
||||||
|
if (!_settings->standards.posix)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
|
for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "pwrite|write ( %any% , %str% , %num%")) {
|
||||||
|
const std::string functionName(tok->str());
|
||||||
|
tok = tok->tokAt(4); // set tokenptr to %str% parameter
|
||||||
|
const std::size_t stringLength = Token::getStrLength(tok);
|
||||||
|
tok = tok->tokAt(2); // set tokenptr to %num% parameter
|
||||||
|
const MathLib::bigint writeLength = MathLib::toLongNumber(tok->str());
|
||||||
|
if (static_cast<unsigned long int>(writeLength) > stringLength)
|
||||||
|
writeOutsideBufferSizeError(tok, stringLength, writeLength,functionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckBufferOverrun::writeOutsideBufferSizeError(const Token *tok, const std::size_t stringLength, const MathLib::bigint writeLength, const std::string &strFunctionName)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::error, "writeOutsideBufferSize",
|
||||||
|
"Writing '" +MathLib::longToString(writeLength-stringLength)+"' bytes outside buffer size.\n"
|
||||||
|
"The number of bytes to write ('" +MathLib::longToString(writeLength)+ "' bytes) are bigger than the source buffer ('" +MathLib::longToString(stringLength)+ "' bytes)."
|
||||||
|
" Please check the second and the third parameter of the function '"+strFunctionName+"'.");
|
||||||
|
}
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
|
|
||||||
/** ExecutionPath checking.. */
|
/** ExecutionPath checking.. */
|
||||||
checkBufferOverrun.executionPaths();
|
checkBufferOverrun.executionPaths();
|
||||||
|
checkBufferOverrun.writeOutsideBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief %Check for buffer overruns */
|
/** @brief %Check for buffer overruns */
|
||||||
|
@ -78,6 +79,9 @@ public:
|
||||||
/** @brief %Check for buffer overruns by inspecting execution paths */
|
/** @brief %Check for buffer overruns by inspecting execution paths */
|
||||||
void executionPaths();
|
void executionPaths();
|
||||||
|
|
||||||
|
/** @brief %Check using POSIX write function and writing outside buffer size */
|
||||||
|
void writeOutsideBufferSize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get minimum length of format string result
|
* @brief Get minimum length of format string result
|
||||||
* @param input_string format string
|
* @param input_string format string
|
||||||
|
@ -229,6 +233,7 @@ private:
|
||||||
void possibleBufferOverrunError(const Token *tok, const std::string &src, const std::string &dst, bool cat);
|
void possibleBufferOverrunError(const Token *tok, const std::string &src, const std::string &dst, bool cat);
|
||||||
void possibleReadlinkBufferOverrunError(const Token *tok, const std::string &funcname, const std::string &varname);
|
void possibleReadlinkBufferOverrunError(const Token *tok, const std::string &funcname, const std::string &varname);
|
||||||
void argumentSizeError(const Token *tok, const std::string &functionName, const std::string &varname);
|
void argumentSizeError(const Token *tok, const std::string &functionName, const std::string &varname);
|
||||||
|
void writeOutsideBufferSizeError(const Token *tok, const std::size_t stringLength, const MathLib::bigint writeLength, const std::string& functionName);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||||
|
@ -249,6 +254,7 @@ public:
|
||||||
c.possibleBufferOverrunError(0, "source", "destination", false);
|
c.possibleBufferOverrunError(0, "source", "destination", false);
|
||||||
c.possibleReadlinkBufferOverrunError(0, "readlink", "buffer");
|
c.possibleReadlinkBufferOverrunError(0, "readlink", "buffer");
|
||||||
c.argumentSizeError(0, "function", "array");
|
c.argumentSizeError(0, "function", "array");
|
||||||
|
c.writeOutsideBufferSizeError(0,2,3,"write");
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ private:
|
||||||
checkBufferOverrun.bufferOverrun();
|
checkBufferOverrun.bufferOverrun();
|
||||||
checkBufferOverrun.negativeIndex();
|
checkBufferOverrun.negativeIndex();
|
||||||
checkBufferOverrun.arrayIndexThenCheck();
|
checkBufferOverrun.arrayIndexThenCheck();
|
||||||
|
checkBufferOverrun.writeOutsideBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
|
@ -252,6 +253,8 @@ private:
|
||||||
TEST_CASE(bufferNotZeroTerminated);
|
TEST_CASE(bufferNotZeroTerminated);
|
||||||
TEST_CASE(readlink);
|
TEST_CASE(readlink);
|
||||||
TEST_CASE(readlinkat);
|
TEST_CASE(readlinkat);
|
||||||
|
|
||||||
|
TEST_CASE(writeOutsideBufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4090,6 +4093,18 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeOutsideBufferSize() {
|
||||||
|
check("void f(void){\n"
|
||||||
|
"write(1, \"Dump string \\n\", 100);\n"
|
||||||
|
"}"); // ^ number of bytes too big
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (error) Writing '87' bytes outside buffer size.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(void){\n"
|
||||||
|
"write(1, \"Dump string \\n\", 10);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestBufferOverrun)
|
REGISTER_TEST(TestBufferOverrun)
|
||||||
|
|
Loading…
Reference in New Issue