Replaced check for pipe() buffer size by ordinary CheckBufferOverrun, provide required Library configuration option (#4183)
Merged from LCppC.
This commit is contained in:
parent
6873f5237b
commit
9eb16e1002
|
@ -306,6 +306,9 @@
|
||||||
<attribute name="value">
|
<attribute name="value">
|
||||||
<ref name="MINSIZE-VALUE"/>
|
<ref name="MINSIZE-VALUE"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<optional>
|
||||||
|
<attribute name="baseType"><text/></attribute>
|
||||||
|
</optional>
|
||||||
</element>
|
</element>
|
||||||
</choice>
|
</choice>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
|
|
@ -414,7 +414,7 @@
|
||||||
<arg nr="1" direction="out">
|
<arg nr="1" direction="out">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="int"/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
|
|
@ -1742,7 +1742,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="timespec"/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);-->
|
<!-- int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);-->
|
||||||
|
@ -1762,7 +1762,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="3" direction="in">
|
<arg nr="3" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="timespec"/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="4" direction="in">
|
<arg nr="4" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
@ -1782,7 +1782,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="timeval"/>
|
||||||
</arg>
|
</arg>
|
||||||
<warn severity="style" reason="Obsolescent" alternatives="utimensat"/>
|
<warn severity="style" reason="Obsolescent" alternatives="utimensat"/>
|
||||||
</function>
|
</function>
|
||||||
|
@ -2749,7 +2749,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="4" direction="out">
|
<arg nr="4" direction="out">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="int"/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- http://man7.org/linux/man-pages/man2/socketpair.2.html -->
|
<!-- http://man7.org/linux/man-pages/man2/socketpair.2.html -->
|
||||||
|
@ -2761,7 +2761,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="1" direction="out">
|
<arg nr="1" direction="out">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<minsize type="value" value="2"/>
|
<minsize type="value" value="2" baseType="int"/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- int pselect(int nfds, fd_set *restrict readfds,
|
<!-- int pselect(int nfds, fd_set *restrict readfds,
|
||||||
|
|
|
@ -563,7 +563,7 @@ ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, const MathLib::bigint bufferSize, const Settings *settings)
|
static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, const MathLib::bigint bufferSize, const Settings *settings, const Tokenizer* tokenizer)
|
||||||
{
|
{
|
||||||
const Token * const arg = (minsize.arg > 0 && minsize.arg - 1 < args.size()) ? args[minsize.arg - 1] : nullptr;
|
const Token * const arg = (minsize.arg > 0 && minsize.arg - 1 < args.size()) ? args[minsize.arg - 1] : nullptr;
|
||||||
const Token * const arg2 = (minsize.arg2 > 0 && minsize.arg2 - 1 < args.size()) ? args[minsize.arg2 - 1] : nullptr;
|
const Token * const arg2 = (minsize.arg2 > 0 && minsize.arg2 - 1 < args.size()) ? args[minsize.arg2 - 1] : nullptr;
|
||||||
|
@ -589,8 +589,13 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
|
||||||
if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue())
|
if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue())
|
||||||
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize;
|
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize;
|
||||||
break;
|
break;
|
||||||
case Library::ArgumentChecks::MinSize::Type::VALUE:
|
case Library::ArgumentChecks::MinSize::Type::VALUE: {
|
||||||
return minsize.value <= bufferSize;
|
MathLib::bigint myMinsize = minsize.value;
|
||||||
|
unsigned int baseSize = tokenizer->sizeOfType(minsize.baseType);
|
||||||
|
if (baseSize != 0)
|
||||||
|
myMinsize *= baseSize;
|
||||||
|
return myMinsize <= bufferSize;
|
||||||
|
}
|
||||||
case Library::ArgumentChecks::MinSize::Type::NONE:
|
case Library::ArgumentChecks::MinSize::Type::NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -644,7 +649,7 @@ void CheckBufferOverrun::bufferOverflow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bool error = std::none_of(minsizes->begin(), minsizes->end(), [=](const Library::ArgumentChecks::MinSize &minsize) {
|
const bool error = std::none_of(minsizes->begin(), minsizes->end(), [=](const Library::ArgumentChecks::MinSize &minsize) {
|
||||||
return checkBufferSize(tok, minsize, args, bufferSize.intvalue, mSettings);
|
return checkBufferSize(tok, minsize, args, bufferSize.intvalue, mSettings, mTokenizer);
|
||||||
});
|
});
|
||||||
if (error)
|
if (error)
|
||||||
bufferOverflowError(args[argnr], &bufferSize, (bufferSize.intvalue == 1) ? Certainty::inconclusive : Certainty::normal);
|
bufferOverflowError(args[argnr], &bufferSize, (bufferSize.intvalue == 1) ? Certainty::inconclusive : Certainty::normal);
|
||||||
|
|
|
@ -384,47 +384,6 @@ void CheckOther::invalidPointerCastError(const Token* tok, const std::string& fr
|
||||||
reportError(tok, Severity::portability, "invalidPointerCast", "Casting between " + from + " and " + to + " which have an incompatible binary data representation.", CWE704, Certainty::normal);
|
reportError(tok, Severity::portability, "invalidPointerCast", "Casting between " + from + " and " + to + " which have an incompatible binary data representation.", CWE704, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
// This check detects errors on POSIX systems, when a pipe command called
|
|
||||||
// with a wrong dimensioned file descriptor array. The pipe command requires
|
|
||||||
// exactly an integer array of dimension two as parameter.
|
|
||||||
//
|
|
||||||
// References:
|
|
||||||
// - http://linux.die.net/man/2/pipe
|
|
||||||
// - ticket #3521
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void CheckOther::checkPipeParameterSize()
|
|
||||||
{
|
|
||||||
if (!mSettings->posix())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
|
||||||
for (const Scope * scope : symbolDatabase->functionScopes) {
|
|
||||||
for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
|
|
||||||
if (Token::Match(tok, "pipe ( %var% )") ||
|
|
||||||
Token::Match(tok, "pipe2 ( %var% ,")) {
|
|
||||||
const Token * const varTok = tok->tokAt(2);
|
|
||||||
|
|
||||||
const Variable *var = varTok->variable();
|
|
||||||
MathLib::bigint dim;
|
|
||||||
if (var && var->isArray() && !var->isArgument() && ((dim=var->dimension(0U)) < 2)) {
|
|
||||||
const std::string strDim = MathLib::toString(dim);
|
|
||||||
checkPipeParameterSizeError(varTok,varTok->str(), strDim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckOther::checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim)
|
|
||||||
{
|
|
||||||
reportError(tok, Severity::error,
|
|
||||||
"wrongPipeParameterSize",
|
|
||||||
"$symbol:" + strVarName + "\n"
|
|
||||||
"Buffer '$symbol' must have size of 2 integers if used as parameter of pipe().\n"
|
|
||||||
"The pipe()/pipe2() system command takes an argument, which is an array of exactly two integers.\n"
|
|
||||||
"The variable '$symbol' is an array of size " + strDim + ", which does not match.", CWE686, Certainty::safe);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Detect redundant assignments: x = 0; x = 4;
|
// Detect redundant assignments: x = 0; x = 4;
|
||||||
|
|
|
@ -87,7 +87,6 @@ public:
|
||||||
checkOther.checkKnownArgument();
|
checkOther.checkKnownArgument();
|
||||||
checkOther.checkComparePointers();
|
checkOther.checkComparePointers();
|
||||||
checkOther.checkIncompleteStatement();
|
checkOther.checkIncompleteStatement();
|
||||||
checkOther.checkPipeParameterSize();
|
|
||||||
checkOther.checkRedundantCopy();
|
checkOther.checkRedundantCopy();
|
||||||
checkOther.clarifyCalculation();
|
checkOther.clarifyCalculation();
|
||||||
checkOther.checkPassByReference();
|
checkOther.checkPassByReference();
|
||||||
|
@ -190,9 +189,6 @@ public:
|
||||||
/** @brief %Check that variadic function calls don't use NULL. If NULL is \#defined as 0 and the function expects a pointer, the behaviour is undefined. */
|
/** @brief %Check that variadic function calls don't use NULL. If NULL is \#defined as 0 and the function expects a pointer, the behaviour is undefined. */
|
||||||
void checkVarFuncNullUB();
|
void checkVarFuncNullUB();
|
||||||
|
|
||||||
/** @brief %Check that calling the POSIX pipe() system call is called with an integer array of size two. */
|
|
||||||
void checkPipeParameterSize();
|
|
||||||
|
|
||||||
/** @brief %Check to avoid casting a return value to unsigned char and then back to integer type. */
|
/** @brief %Check to avoid casting a return value to unsigned char and then back to integer type. */
|
||||||
void checkCastIntToCharAndBack();
|
void checkCastIntToCharAndBack();
|
||||||
|
|
||||||
|
@ -234,7 +230,6 @@ private:
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
|
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
|
||||||
void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName);
|
void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName);
|
||||||
void checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim);
|
|
||||||
void clarifyCalculationError(const Token *tok, const std::string &op);
|
void clarifyCalculationError(const Token *tok, const std::string &op);
|
||||||
void clarifyStatementError(const Token* tok);
|
void clarifyStatementError(const Token* tok);
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
|
@ -299,7 +294,6 @@ private:
|
||||||
c.invalidPointerCastError(nullptr, "float *", "double *", false, false);
|
c.invalidPointerCastError(nullptr, "float *", "double *", false, false);
|
||||||
c.negativeBitwiseShiftError(nullptr, 1);
|
c.negativeBitwiseShiftError(nullptr, 1);
|
||||||
c.negativeBitwiseShiftError(nullptr, 2);
|
c.negativeBitwiseShiftError(nullptr, 2);
|
||||||
c.checkPipeParameterSizeError(nullptr, "varname", "dimension");
|
|
||||||
c.raceAfterInterlockedDecrementError(nullptr);
|
c.raceAfterInterlockedDecrementError(nullptr);
|
||||||
c.invalidFreeError(nullptr, "malloc", false);
|
c.invalidFreeError(nullptr, "malloc", false);
|
||||||
c.overlappingWriteUnion(nullptr);
|
c.overlappingWriteUnion(nullptr);
|
||||||
|
@ -378,7 +372,6 @@ private:
|
||||||
"- assignment in an assert statement\n"
|
"- assignment in an assert statement\n"
|
||||||
"- free() or delete of an invalid memory location\n"
|
"- free() or delete of an invalid memory location\n"
|
||||||
"- bitwise operation with negative right operand\n"
|
"- bitwise operation with negative right operand\n"
|
||||||
"- provide wrong dimensioned array to pipe() system command (--std=posix)\n"
|
|
||||||
"- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
|
"- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
|
||||||
"- race condition with non-interlocked access after InterlockedDecrement() call\n"
|
"- race condition with non-interlocked access after InterlockedDecrement() call\n"
|
||||||
"- expression 'x = x++;' depends on order of evaluation of side effects\n"
|
"- expression 'x = x++;' depends on order of evaluation of side effects\n"
|
||||||
|
|
|
@ -782,6 +782,9 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
|
||||||
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
|
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
|
||||||
ac.minsizes.emplace_back(type, 0);
|
ac.minsizes.emplace_back(type, 0);
|
||||||
ac.minsizes.back().value = minsizevalue;
|
ac.minsizes.back().value = minsizevalue;
|
||||||
|
const char* baseTypeAttr = argnode->Attribute("baseType");
|
||||||
|
if (baseTypeAttr)
|
||||||
|
ac.minsizes.back().baseType = baseTypeAttr;
|
||||||
} else {
|
} else {
|
||||||
const char *argattr = argnode->Attribute("arg");
|
const char *argattr = argnode->Attribute("arg");
|
||||||
if (!argattr)
|
if (!argattr)
|
||||||
|
|
|
@ -327,6 +327,7 @@ public:
|
||||||
int arg;
|
int arg;
|
||||||
int arg2;
|
int arg2;
|
||||||
long long value;
|
long long value;
|
||||||
|
std::string baseType;
|
||||||
};
|
};
|
||||||
std::vector<MinSize> minsizes;
|
std::vector<MinSize> minsizes;
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,19 @@ Tokenizer::~Tokenizer()
|
||||||
// SizeOfType - gives the size of a type
|
// SizeOfType - gives the size of a type
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
nonneg int Tokenizer::sizeOfType(const std::string& type) const
|
||||||
|
{
|
||||||
|
const std::map<std::string, int>::const_iterator it = mTypeSize.find(type);
|
||||||
|
if (it == mTypeSize.end()) {
|
||||||
|
const Library::PodType* podtype = mSettings->library.podtype(type);
|
||||||
|
if (!podtype)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return podtype->size;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
nonneg int Tokenizer::sizeOfType(const Token *type) const
|
nonneg int Tokenizer::sizeOfType(const Token *type) const
|
||||||
{
|
{
|
||||||
if (!type || type->str().empty())
|
if (!type || type->str().empty())
|
||||||
|
|
|
@ -181,7 +181,8 @@ public:
|
||||||
* @param type Token which will contain e.g. "int", "*", or string.
|
* @param type Token which will contain e.g. "int", "*", or string.
|
||||||
* @return sizeof for given type, or 0 if it can't be calculated.
|
* @return sizeof for given type, or 0 if it can't be calculated.
|
||||||
*/
|
*/
|
||||||
nonneg int sizeOfType(const Token *type) const;
|
nonneg int sizeOfType(const Token* type) const;
|
||||||
|
nonneg int sizeOfType(const std::string& type) const;
|
||||||
|
|
||||||
void simplifyDebug();
|
void simplifyDebug();
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -322,6 +322,8 @@ private:
|
||||||
TEST_CASE(ctu_arithmetic);
|
TEST_CASE(ctu_arithmetic);
|
||||||
|
|
||||||
TEST_CASE(objectIndex);
|
TEST_CASE(objectIndex);
|
||||||
|
|
||||||
|
TEST_CASE(checkPipeParameterSize); // ticket #3521
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5227,6 +5229,44 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkPipeParameterSize() { // #3521
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
LOAD_LIB_2(settings.library, "posix.cfg");
|
||||||
|
|
||||||
|
check("void f(){\n"
|
||||||
|
"int pipefd[1];\n" // <-- array of two integers is needed
|
||||||
|
"if (pipe(pipefd) == -1) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"}", settings);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: pipefd\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(){\n"
|
||||||
|
"int pipefd[2];\n"
|
||||||
|
"if (pipe(pipefd) == -1) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"}", settings);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f(){\n"
|
||||||
|
"char pipefd[2];\n"
|
||||||
|
"if (pipe((int*)pipefd) == -1) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"}", settings);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: (int*)pipefd\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(){\n"
|
||||||
|
"char pipefd[20];\n" // Strange, but large enough
|
||||||
|
"if (pipe((int*)pipefd) == -1) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"}", settings);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestBufferOverrun)
|
REGISTER_TEST(TestBufferOverrun)
|
||||||
|
|
|
@ -481,6 +481,7 @@ private:
|
||||||
" <arg nr=\"2\"><minsize type=\"argvalue\" arg=\"3\"/></arg>\n"
|
" <arg nr=\"2\"><minsize type=\"argvalue\" arg=\"3\"/></arg>\n"
|
||||||
" <arg nr=\"3\"/>\n"
|
" <arg nr=\"3\"/>\n"
|
||||||
" <arg nr=\"4\"><minsize type=\"value\" value=\"500\"/></arg>\n"
|
" <arg nr=\"4\"><minsize type=\"value\" value=\"500\"/></arg>\n"
|
||||||
|
" <arg nr=\"5\"><minsize type=\"value\" value=\"4\" baseType=\"int\"/></arg>\n"
|
||||||
" </function>\n"
|
" </function>\n"
|
||||||
"</def>";
|
"</def>";
|
||||||
|
|
||||||
|
@ -488,7 +489,7 @@ private:
|
||||||
ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
|
ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
|
||||||
|
|
||||||
TokenList tokenList(nullptr);
|
TokenList tokenList(nullptr);
|
||||||
std::istringstream istr("foo(a,b,c,d);");
|
std::istringstream istr("foo(a,b,c,d,e);");
|
||||||
tokenList.createTokens(istr);
|
tokenList.createTokens(istr);
|
||||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||||
|
|
||||||
|
@ -520,6 +521,18 @@ private:
|
||||||
const Library::ArgumentChecks::MinSize &m = minsizes->front();
|
const Library::ArgumentChecks::MinSize &m = minsizes->front();
|
||||||
ASSERT(Library::ArgumentChecks::MinSize::Type::VALUE == m.type);
|
ASSERT(Library::ArgumentChecks::MinSize::Type::VALUE == m.type);
|
||||||
ASSERT_EQUALS(500, m.value);
|
ASSERT_EQUALS(500, m.value);
|
||||||
|
ASSERT_EQUALS(emptyString, m.baseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// arg5: type=value
|
||||||
|
minsizes = library.argminsizes(tokenList.front(), 5);
|
||||||
|
ASSERT_EQUALS(true, minsizes != nullptr);
|
||||||
|
ASSERT_EQUALS(1U, minsizes ? minsizes->size() : 1U);
|
||||||
|
if (minsizes && minsizes->size() == 1U) {
|
||||||
|
const Library::ArgumentChecks::MinSize& m = minsizes->front();
|
||||||
|
ASSERT(Library::ArgumentChecks::MinSize::Type::VALUE == m.type);
|
||||||
|
ASSERT_EQUALS(4, m.value);
|
||||||
|
ASSERT_EQUALS("int", m.baseType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,6 @@ private:
|
||||||
|
|
||||||
TEST_CASE(varFuncNullUB);
|
TEST_CASE(varFuncNullUB);
|
||||||
|
|
||||||
TEST_CASE(checkPipeParameterSize); // ticket #3521
|
|
||||||
|
|
||||||
TEST_CASE(checkCastIntToCharAndBack); // ticket #160
|
TEST_CASE(checkCastIntToCharAndBack); // ticket #160
|
||||||
|
|
||||||
TEST_CASE(checkCommaSeparatedReturn);
|
TEST_CASE(checkCommaSeparatedReturn);
|
||||||
|
@ -350,20 +348,6 @@ private:
|
||||||
checkOther.runChecks(&tokenizer, settings, this);
|
checkOther.runChecks(&tokenizer, settings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkposix(const char code[]) {
|
|
||||||
static Settings settings;
|
|
||||||
settings.severity.enable(Severity::warning);
|
|
||||||
settings.libraries.emplace_back("posix");
|
|
||||||
|
|
||||||
check(code,
|
|
||||||
nullptr, // filename
|
|
||||||
false, // experimental
|
|
||||||
false, // inconclusive
|
|
||||||
true, // runSimpleChecks
|
|
||||||
false, // verbose
|
|
||||||
&settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkInterlockedDecrement(const char code[]) {
|
void checkInterlockedDecrement(const char code[]) {
|
||||||
static Settings settings;
|
static Settings settings;
|
||||||
settings.platformType = Settings::Win32A;
|
settings.platformType = Settings::Win32A;
|
||||||
|
@ -8627,99 +8611,6 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkPipeParameterSize() { // #3521
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[1];\n" // <-- array of two integers is needed
|
|
||||||
"if (pipe(pipefd) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer 'pipefd' must have size of 2 integers if used as parameter of pipe().\n", errout.str());
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[2];\n"
|
|
||||||
"if (pipe(pipefd) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[20];\n"
|
|
||||||
"if (pipe(pipefd) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[1];\n" // <-- array of two integers is needed
|
|
||||||
"if (pipe2(pipefd,0) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer 'pipefd' must have size of 2 integers if used as parameter of pipe().\n", errout.str());
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[2];\n"
|
|
||||||
"if (pipe2(pipefd,0) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
checkposix("void f(){\n"
|
|
||||||
"int pipefd[20];\n"
|
|
||||||
"if (pipe2(pipefd,0) == -1) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// avoid crash with pointer variable
|
|
||||||
check("void foo (int* arrayPtr)\n"
|
|
||||||
"{\n"
|
|
||||||
" if (pipe (arrayPtr) < 0)\n"
|
|
||||||
" {}\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// avoid crash with pointer variable - for local variable on stack as well - see #4801
|
|
||||||
check("void foo() {\n"
|
|
||||||
" int *cp;\n"
|
|
||||||
" if ( pipe (cp) == -1 ) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// test with unknown variable
|
|
||||||
check("void foo() {\n"
|
|
||||||
" if ( pipe (cp) == -1 ) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// avoid crash with pointer variable - for local variable on stack as well - see #4801
|
|
||||||
check("void foo() {\n"
|
|
||||||
" int *cp;\n"
|
|
||||||
" if ( pipe (cp) == -1 ) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
// test with unknown variable
|
|
||||||
check("void foo() {\n"
|
|
||||||
" if ( pipe (cp) == -1 ) {\n"
|
|
||||||
" return;\n"
|
|
||||||
" }\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkCastIntToCharAndBack() { // #160
|
void checkCastIntToCharAndBack() { // #160
|
||||||
|
|
||||||
// check getchar
|
// check getchar
|
||||||
|
|
Loading…
Reference in New Issue