Library: Enhance minsize configuration and allow simple values. (#1736)
Some POSIX and Windows functions require buffers of at least some specific size. This is now possible to configure via for example this minsize configuration: `<minsize type="value" value="26"/>`. The range for valid buffer size values is 1 to LLONG_MAX (9223372036854775807)
This commit is contained in:
parent
0771929518
commit
19e9e42dd7
|
@ -196,24 +196,36 @@
|
|||
</element>
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<element name="minsize">
|
||||
<attribute name="type">
|
||||
<choice>
|
||||
<value>strlen</value>
|
||||
<value>argvalue</value>
|
||||
<value>sizeof</value>
|
||||
<value>mul</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
<attribute name="arg">
|
||||
<ref name="ARGNO"/>
|
||||
</attribute>
|
||||
<optional>
|
||||
<attribute name="arg2">
|
||||
<choice>
|
||||
<element name="minsize">
|
||||
<attribute name="type">
|
||||
<choice>
|
||||
<value>strlen</value>
|
||||
<value>argvalue</value>
|
||||
<value>sizeof</value>
|
||||
<value>mul</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
<attribute name="arg">
|
||||
<ref name="ARGNO"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</element>
|
||||
<optional>
|
||||
<attribute name="arg2">
|
||||
<ref name="ARGNO"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</element>
|
||||
<element name="minsize">
|
||||
<attribute name="type">
|
||||
<choice>
|
||||
<value>value</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
<attribute name="value">
|
||||
<ref name="MINSIZE-VALUE"/>
|
||||
</attribute>
|
||||
</element>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<element name="iterator">
|
||||
|
@ -495,4 +507,11 @@
|
|||
<value>empty</value>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
<define name="MINSIZE-VALUE">
|
||||
<data type="unsignedLong">
|
||||
<param name="minInclusive">1</param>
|
||||
<param name="maxInclusive">9223372036854775807</param>
|
||||
</data>
|
||||
</define>
|
||||
</grammar>
|
||||
|
|
|
@ -2776,7 +2776,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
|||
<arg nr="2" direction="out">
|
||||
<not-null/>
|
||||
<not-bool/>
|
||||
<!-- TODO: add something like "<minsize type="value" value="26"/>" when implemented, see #8335 -->
|
||||
<minsize type="value" value="26"/>
|
||||
</arg>
|
||||
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
||||
</function>
|
||||
|
@ -2793,7 +2793,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
|||
<arg nr="2" direction="out">
|
||||
<not-null/>
|
||||
<not-bool/>
|
||||
<!-- TODO: add something like "<minsize type="value" value="26"/>" when implemented, see #8335 -->
|
||||
<minsize type="value" value="26"/>
|
||||
</arg>
|
||||
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
||||
</function>
|
||||
|
|
|
@ -372,6 +372,8 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
|
|||
if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue())
|
||||
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize;
|
||||
break;
|
||||
case Library::ArgumentChecks::MinSize::Type::VALUE:
|
||||
return minsize.value <= bufferSize;
|
||||
case Library::ArgumentChecks::MinSize::Type::NONE:
|
||||
break;
|
||||
};
|
||||
|
|
|
@ -662,24 +662,42 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
|
|||
type = ArgumentChecks::MinSize::Type::SIZEOF;
|
||||
else if (strcmp(typeattr,"mul")==0)
|
||||
type = ArgumentChecks::MinSize::Type::MUL;
|
||||
else if (strcmp(typeattr,"value")==0)
|
||||
type = ArgumentChecks::MinSize::Type::VALUE;
|
||||
else
|
||||
return Error(BAD_ATTRIBUTE_VALUE, typeattr);
|
||||
|
||||
const char *argattr = argnode->Attribute("arg");
|
||||
if (!argattr)
|
||||
return Error(MISSING_ATTRIBUTE, "arg");
|
||||
if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9')
|
||||
return Error(BAD_ATTRIBUTE_VALUE, argattr);
|
||||
if (type == ArgumentChecks::MinSize::Type::VALUE) {
|
||||
const char *valueattr = argnode->Attribute("value");
|
||||
if (!valueattr)
|
||||
return Error(MISSING_ATTRIBUTE, "value");
|
||||
long long minsizevalue = 0;
|
||||
try {
|
||||
minsizevalue = MathLib::toLongNumber(valueattr);
|
||||
} catch (const InternalError&) {
|
||||
return Error(BAD_ATTRIBUTE_VALUE, valueattr);
|
||||
}
|
||||
if (minsizevalue <= 0)
|
||||
return Error(BAD_ATTRIBUTE_VALUE, valueattr);
|
||||
ac.minsizes.emplace_back(type, 0);
|
||||
ac.minsizes.back().value = minsizevalue;
|
||||
} else {
|
||||
const char *argattr = argnode->Attribute("arg");
|
||||
if (!argattr)
|
||||
return Error(MISSING_ATTRIBUTE, "arg");
|
||||
if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9')
|
||||
return Error(BAD_ATTRIBUTE_VALUE, argattr);
|
||||
|
||||
ac.minsizes.reserve(type == ArgumentChecks::MinSize::Type::MUL ? 2 : 1);
|
||||
ac.minsizes.emplace_back(type,argattr[0]-'0');
|
||||
if (type == ArgumentChecks::MinSize::Type::MUL) {
|
||||
const char *arg2attr = argnode->Attribute("arg2");
|
||||
if (!arg2attr)
|
||||
return Error(MISSING_ATTRIBUTE, "arg2");
|
||||
if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
|
||||
return Error(BAD_ATTRIBUTE_VALUE, arg2attr);
|
||||
ac.minsizes.back().arg2 = arg2attr[0] - '0';
|
||||
ac.minsizes.reserve(type == ArgumentChecks::MinSize::Type::MUL ? 2 : 1);
|
||||
ac.minsizes.emplace_back(type, argattr[0] - '0');
|
||||
if (type == ArgumentChecks::MinSize::Type::MUL) {
|
||||
const char *arg2attr = argnode->Attribute("arg2");
|
||||
if (!arg2attr)
|
||||
return Error(MISSING_ATTRIBUTE, "arg2");
|
||||
if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
|
||||
return Error(BAD_ATTRIBUTE_VALUE, arg2attr);
|
||||
ac.minsizes.back().arg2 = arg2attr[0] - '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -254,11 +254,12 @@ public:
|
|||
|
||||
class MinSize {
|
||||
public:
|
||||
enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL };
|
||||
MinSize(Type t, int a) : type(t), arg(a), arg2(0) {}
|
||||
enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL, VALUE };
|
||||
MinSize(Type t, int a) : type(t), arg(a), arg2(0), value(0) {}
|
||||
Type type;
|
||||
int arg;
|
||||
int arg2;
|
||||
long long value;
|
||||
};
|
||||
std::vector<MinSize> minsizes;
|
||||
|
||||
|
|
|
@ -350,3 +350,65 @@ void dl(const char* libname, const char* func)
|
|||
dlclose(uninit);
|
||||
// cppcheck-suppress resourceLeak
|
||||
}
|
||||
|
||||
void asctime_r_test(struct tm * tm, char * bufSizeUnknown)
|
||||
{
|
||||
struct tm tm_uninit_data;
|
||||
struct tm * tm_uninit_pointer;
|
||||
char bufSize5[5];
|
||||
char bufSize25[25];
|
||||
char bufSize26[26];
|
||||
char bufSize100[100];
|
||||
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
// cppcheck-suppress bufferAccessOutOfBounds
|
||||
asctime_r(tm, bufSize5);
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
// cppcheck-suppress bufferAccessOutOfBounds
|
||||
asctime_r(tm, bufSize25);
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
asctime_r(tm, bufSize26);
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
asctime_r(tm, bufSize100);
|
||||
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
// cppcheck-suppress uninitvar
|
||||
asctime_r(&tm_uninit_data, bufSize100);
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
// cppcheck-suppress uninitvar
|
||||
asctime_r(tm_uninit_pointer, bufSize100);
|
||||
|
||||
// cppcheck-suppress asctime_rCalled
|
||||
asctime_r(tm, bufSizeUnknown);
|
||||
}
|
||||
|
||||
void ctime_r_test(time_t * timep, char * bufSizeUnknown)
|
||||
{
|
||||
time_t time_t_uninit_data;
|
||||
time_t * time_t_uninit_pointer;
|
||||
char bufSize5[5];
|
||||
char bufSize25[25];
|
||||
char bufSize26[26];
|
||||
char bufSize100[100];
|
||||
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
// cppcheck-suppress bufferAccessOutOfBounds
|
||||
ctime_r(timep, bufSize5);
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
// cppcheck-suppress bufferAccessOutOfBounds
|
||||
ctime_r(timep, bufSize25);
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
ctime_r(timep, bufSize26);
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
ctime_r(timep, bufSize100);
|
||||
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
// cppcheck-suppress uninitvar
|
||||
ctime_r(&time_t_uninit_data, bufSize100);
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
// cppcheck-suppress uninitvar
|
||||
ctime_r(time_t_uninit_pointer, bufSize100);
|
||||
|
||||
// cppcheck-suppress ctime_rCalled
|
||||
ctime_r(timep, bufSizeUnknown);
|
||||
}
|
||||
|
|
|
@ -448,6 +448,7 @@ private:
|
|||
" <arg nr=\"1\"><minsize type=\"strlen\" arg=\"2\"/></arg>\n"
|
||||
" <arg nr=\"2\"><minsize type=\"argvalue\" arg=\"3\"/></arg>\n"
|
||||
" <arg nr=\"3\"/>\n"
|
||||
" <arg nr=\"4\"><minsize type=\"value\" value=\"500\"/></arg>\n"
|
||||
" </function>\n"
|
||||
"</def>";
|
||||
|
||||
|
@ -455,7 +456,7 @@ private:
|
|||
ASSERT_EQUALS(true, Library::OK == (readLibrary(library, xmldata)).errorcode);
|
||||
|
||||
TokenList tokenList(nullptr);
|
||||
std::istringstream istr("foo(a,b,c);");
|
||||
std::istringstream istr("foo(a,b,c,d);");
|
||||
tokenList.createTokens(istr);
|
||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||
|
||||
|
@ -478,6 +479,16 @@ private:
|
|||
ASSERT_EQUALS(Library::ArgumentChecks::MinSize::ARGVALUE, m.type);
|
||||
ASSERT_EQUALS(3, m.arg);
|
||||
}
|
||||
|
||||
// arg4: type=value
|
||||
minsizes = library.argminsizes(tokenList.front(), 4);
|
||||
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_EQUALS(Library::ArgumentChecks::MinSize::VALUE, m.type);
|
||||
ASSERT_EQUALS(500, m.value);
|
||||
}
|
||||
}
|
||||
|
||||
void function_namespace() const {
|
||||
|
|
Loading…
Reference in New Issue