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:
Sebastian 2019-03-17 14:22:26 +01:00 committed by GitHub
parent 0771929518
commit 19e9e42dd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 148 additions and 35 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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;
};

View File

@ -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';
}
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {