library: Improved argument <valid>-interface to defined values that are explicitly excluded. (#4111)

* library: Improved <valid>-interface to defined values that are explicitly excluded.

* std.cfg: Improved configuration of remainder[fl]().

* Fixed failing self check

* Fixed failing self check

* std.cfg: Added support for std::remquo().
This commit is contained in:
orbitcowboy 2022-05-14 16:05:18 +02:00 committed by GitHub
parent fffb03a242
commit 4f410ffb79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 193 additions and 8 deletions

View File

@ -273,7 +273,7 @@
<optional> <optional>
<element name="valid"> <element name="valid">
<data type="string"> <!-- regex test: https://regex101.com/r/LoRGVj/2/ --> <data type="string"> <!-- regex test: https://regex101.com/r/LoRGVj/2/ -->
<param name="pattern">(-?[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?[,:])*([-]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?)?</param> <param name="pattern">([-!]?[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?[,:])*([-!]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?)?</param>
</data> </data>
</element> </element>
</optional> </optional>

View File

@ -4156,6 +4156,61 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/> <not-uninit/>
</arg> </arg>
</function> </function>
<!-- float remquo (float x , float y , int *quo); -->
<!-- double remquo (double x, double y, int *quo); -->
<!-- long double remquo (long double x, long double y, int *quo); -->
<function name="remquo,std::remquo">
<use-retval/>
<pure/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
</arg>
<arg nr="2" direction="in">
<not-uninit/>
<valid>!0.0</valid>
</arg>
<arg nr="3" direction="out">
<not-null/>
</arg>
</function>
<!-- float remquof (float x , float y , int *quo); -->
<function name="remquof,std::remquof">
<use-retval/>
<pure/>
<returnValue type="float"/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
</arg>
<arg nr="2" direction="in">
<not-uninit/>
<valid>!0.0</valid>
</arg>
<arg nr="3" direction="out">
<not-null/>
</arg>
</function>
<!-- long double remquol (long double x , long double y , int *quo); -->
<function name="remquol,std::remquol">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
</arg>
<arg nr="2" direction="in">
<not-uninit/>
<valid>!0.0</valid>
</arg>
<arg nr="3" direction="out">
<not-null/>
</arg>
</function>
<!-- double remainder(double x, double y); --> <!-- double remainder(double x, double y); -->
<function name="remainder,std::remainder"> <function name="remainder,std::remainder">
<use-retval/> <use-retval/>
@ -4168,6 +4223,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
</arg> </arg>
<arg nr="2" direction="in"> <arg nr="2" direction="in">
<not-uninit/> <not-uninit/>
<valid>!0.0</valid>
</arg> </arg>
</function> </function>
<!-- float remainderf(float x, float y); --> <!-- float remainderf(float x, float y); -->
@ -4182,6 +4238,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
</arg> </arg>
<arg nr="2" direction="in"> <arg nr="2" direction="in">
<not-uninit/> <not-uninit/>
<valid>!0.0</valid>
</arg> </arg>
</function> </function>
<!-- long double remainderl(long double x, long double y); --> <!-- long double remainderl(long double x, long double y); -->
@ -4196,6 +4253,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
</arg> </arg>
<arg nr="2" direction="in"> <arg nr="2" direction="in">
<not-uninit/> <not-uninit/>
<valid>!0.0</valid>
</arg> </arg>
</function> </function>
<!-- double remquo(double, x, double y, int *quo); --> <!-- double remquo(double, x, double y, int *quo); -->

View File

@ -748,7 +748,8 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : argnode->GetText())); return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : argnode->GetText()));
// Set validation expression // Set validation expression
ac.valid = argnode->GetText(); ac.valid = argnode->GetText();
} else if (argnodename == "minsize") { }
else if (argnodename == "minsize") {
const char *typeattr = argnode->Attribute("type"); const char *typeattr = argnode->Attribute("type");
if (!typeattr) if (!typeattr)
return Error(ErrorCode::MISSING_ATTRIBUTE, "type"); return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
@ -929,6 +930,10 @@ bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) con
return true; return true;
if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1))) if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1)))
return true; return true;
if (Token::Match(tok, "%num%") && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue)))
return true;
if (Token::Match(tok, "! %num%") && MathLib::isFloat(tok->next()->str()))
return MathLib::isNotEqual(tok->next()->str(), MathLib::toString(argvalue));
} }
return false; return false;
} }
@ -1227,7 +1232,7 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
bool Library::isCompliantValidationExpression(const char* p) bool Library::isCompliantValidationExpression(const char* p)
{ {
if (!p) if (!p || !*p)
return false; return false;
bool error = false; bool error = false;
@ -1237,15 +1242,18 @@ bool Library::isCompliantValidationExpression(const char* p)
error = *p == '.'; error = *p == '.';
for (; *p; p++) { for (; *p; p++) {
if (std::isdigit(*p)) if (std::isdigit(*p)) {
error |= (*(p + 1) == '-'); error |= (*(p + 1) == '-');
}
else if (*p == ':') { else if (*p == ':') {
error |= range | (*(p + 1) == '.'); error |= range | (*(p + 1) == '.');
range = true; range = true;
has_dot = false; has_dot = false;
has_E = false; has_E = false;
} else if ((*p == '-') || (*p == '+')) }
else if ((*p == '-') || (*p == '+')) {
error |= (!std::isdigit(*(p + 1))); error |= (!std::isdigit(*(p + 1)));
}
else if (*p == ',') { else if (*p == ',') {
range = false; range = false;
error |= *(p + 1) == '.'; error |= *(p + 1) == '.';
@ -1257,6 +1265,8 @@ bool Library::isCompliantValidationExpression(const char* p)
} else if (*p == 'E' || *p == 'e') { } else if (*p == 'E' || *p == 'e') {
error |= has_E; error |= has_E;
has_E = true; has_E = true;
} else if (*p == '!') {
error |= !((*(p+1) == '-') || (*(p+1) == '+') || (std::isdigit(*(p + 1))));
} else } else
return false; return false;
} }

View File

@ -30,6 +30,60 @@
#include <float.h> #include <float.h>
float invalidFunctionArg_float_remquo (float x, float y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) remquo(x,0.0f,quo);
// cppcheck-suppress invalidFunctionArg
(void) remquof(x,0.0f,quo);
return remquo(x,y,quo);
}
double invalidFunctionArg_double_remquo (double x, double y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) remquo(x,0.0,quo);
// cppcheck-suppress invalidFunctionArg
(void) remquo(x,0.0f,quo);
// cppcheck-suppress invalidFunctionArg
(void) remquo(x,0.0L,quo);
return remquo(x,y,quo);
}
double invalidFunctionArg_long_double_remquo (long double x, long double y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) remquo(x,0.0L,quo);
// cppcheck-suppress invalidFunctionArg
(void) remquol(x,0.0L,quo);
return remquo(x,y,quo);
}
void invalidFunctionArg_remainderl(long double f1, long double f2)
{
// cppcheck-suppress invalidFunctionArg
(void)remainderl(f1,0.0);
// cppcheck-suppress invalidFunctionArg
(void)remainderl(f1,0.0L);
(void)remainderl(f1,f2);
}
void invalidFunctionArg_remainder(double f1, double f2)
{
// cppcheck-suppress invalidFunctionArg
(void)remainder(f1,0.0);
(void)remainder(f1,f2);
}
void invalidFunctionArg_remainderf(float f1, float f2)
{
// cppcheck-suppress invalidFunctionArg
(void)remainderf(f1,0.0);
// cppcheck-suppress invalidFunctionArg
(void)remainderf(f1,0.0f);
(void)remainderf(f1,f2);
}
int qsort_cmpfunc (const void * a, const void * b) { int qsort_cmpfunc (const void * a, const void * b) {
return (*(int*)a - *(int*)b); return (*(int*)a - *(int*)b);
} }

View File

@ -36,6 +36,60 @@
#include <iterator> #include <iterator>
#include <vector> #include <vector>
float invalidFunctionArg_remquo (float x, float y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) std::remquo(x,0.0f,quo);
// cppcheck-suppress invalidFunctionArg
(void) std::remquof(x,0.0f,quo);
return std::remquo(x,y,quo);
}
double invalidFunctionArg_remquo (double x, double y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) std::remquo(x,0.0,quo);
// cppcheck-suppress invalidFunctionArg
(void) std::remquo(x,0.0f,quo);
// cppcheck-suppress invalidFunctionArg
(void) std::remquo(x,0.0L,quo);
return std::remquo(x,y,quo);
}
double invalidFunctionArg_remquo (long double x, long double y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
(void) std::remquo(x,0.0L,quo);
// cppcheck-suppress invalidFunctionArg
(void) std::remquol(x,0.0L,quo);
return std::remquo(x,y,quo);
}
void invalidFunctionArg_remainderl(long double f1, long double f2)
{
// cppcheck-suppress invalidFunctionArg
(void)std::remainderl(f1,0.0);
// cppcheck-suppress invalidFunctionArg
(void)std::remainderl(f1,0.0L);
(void)std::remainderl(f1,f2);
}
void invalidFunctionArg_remainder(double f1, double f2)
{
// cppcheck-suppress invalidFunctionArg
(void)std::remainder(f1,0.0);
(void)std::remainder(f1,f2);
}
void invalidFunctionArg_remainderf(float f1, float f2)
{
// cppcheck-suppress invalidFunctionArg
(void)std::remainderf(f1,0.0);
// cppcheck-suppress invalidFunctionArg
(void)std::remainderf(f1,0.0f);
(void)std::remainderf(f1,f2);
}
void uninitvar_std_fstream_open(std::fstream &fs, const std::string &strFileName, const char* filename, std::ios_base::openmode mode) void uninitvar_std_fstream_open(std::fstream &fs, const std::string &strFileName, const char* filename, std::ios_base::openmode mode)
{ {
std::string s; std::string s;

View File

@ -89,10 +89,13 @@ private:
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:")); ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:"));
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38")); ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38"));
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0")); ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0"));
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("!42.0"));
// Robustness tests // Robustness tests
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr)); ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr));
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x")); ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x"));
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("!"));
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(""));
} }
void empty() const { void empty() const {
@ -336,6 +339,7 @@ private:
" <arg nr=\"8\"><valid>0.0:</valid></arg>\n" " <arg nr=\"8\"><valid>0.0:</valid></arg>\n"
" <arg nr=\"9\"><valid>:2.0</valid></arg>\n" " <arg nr=\"9\"><valid>:2.0</valid></arg>\n"
" <arg nr=\"10\"><valid>0.0</valid></arg>\n" " <arg nr=\"10\"><valid>0.0</valid></arg>\n"
" <arg nr=\"11\"><valid>!0.0</valid></arg>\n"
" </function>\n" " </function>\n"
"</def>"; "</def>";
@ -343,7 +347,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,e,f,g,h,i,j);"); std::istringstream istr("foo(a,b,c,d,e,f,g,h,i,j,k);");
tokenList.createTokens(istr); tokenList.createTokens(istr);
tokenList.front()->next()->astOperand1(tokenList.front()); tokenList.front()->next()->astOperand1(tokenList.front());
@ -460,8 +464,13 @@ private:
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 200.0)); ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 200.0));
// 0.0 // 0.0
ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 10, 0)); ASSERT_EQUALS(true, library.isIntArgValid(tokenList.front(), 10, 0));
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 10, 0.0)); ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 10, 0.0));
// ! 0.0
ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 11, -0.42));
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 11, 0.0));
ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 11, 0.42));
} }
void function_arg_minsize() const { void function_arg_minsize() const {