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>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<element name="minsize">
|
<choice>
|
||||||
<attribute name="type">
|
<element name="minsize">
|
||||||
<choice>
|
<attribute name="type">
|
||||||
<value>strlen</value>
|
<choice>
|
||||||
<value>argvalue</value>
|
<value>strlen</value>
|
||||||
<value>sizeof</value>
|
<value>argvalue</value>
|
||||||
<value>mul</value>
|
<value>sizeof</value>
|
||||||
</choice>
|
<value>mul</value>
|
||||||
</attribute>
|
</choice>
|
||||||
<attribute name="arg">
|
</attribute>
|
||||||
<ref name="ARGNO"/>
|
<attribute name="arg">
|
||||||
</attribute>
|
|
||||||
<optional>
|
|
||||||
<attribute name="arg2">
|
|
||||||
<ref name="ARGNO"/>
|
<ref name="ARGNO"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
<optional>
|
||||||
</element>
|
<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>
|
</zeroOrMore>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="iterator">
|
<element name="iterator">
|
||||||
|
@ -495,4 +507,11 @@
|
||||||
<value>empty</value>
|
<value>empty</value>
|
||||||
</choice>
|
</choice>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="MINSIZE-VALUE">
|
||||||
|
<data type="unsignedLong">
|
||||||
|
<param name="minInclusive">1</param>
|
||||||
|
<param name="maxInclusive">9223372036854775807</param>
|
||||||
|
</data>
|
||||||
|
</define>
|
||||||
</grammar>
|
</grammar>
|
||||||
|
|
|
@ -2776,7 +2776,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="2" direction="out">
|
<arg nr="2" direction="out">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<!-- TODO: add something like "<minsize type="value" value="26"/>" when implemented, see #8335 -->
|
<minsize type="value" value="26"/>
|
||||||
</arg>
|
</arg>
|
||||||
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
||||||
</function>
|
</function>
|
||||||
|
@ -2793,7 +2793,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
|
||||||
<arg nr="2" direction="out">
|
<arg nr="2" direction="out">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-bool/>
|
<not-bool/>
|
||||||
<!-- TODO: add something like "<minsize type="value" value="26"/>" when implemented, see #8335 -->
|
<minsize type="value" value="26"/>
|
||||||
</arg>
|
</arg>
|
||||||
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
|
||||||
</function>
|
</function>
|
||||||
|
|
|
@ -372,6 +372,8 @@ 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:
|
||||||
|
return minsize.value <= bufferSize;
|
||||||
case Library::ArgumentChecks::MinSize::Type::NONE:
|
case Library::ArgumentChecks::MinSize::Type::NONE:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
|
@ -662,24 +662,42 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
|
||||||
type = ArgumentChecks::MinSize::Type::SIZEOF;
|
type = ArgumentChecks::MinSize::Type::SIZEOF;
|
||||||
else if (strcmp(typeattr,"mul")==0)
|
else if (strcmp(typeattr,"mul")==0)
|
||||||
type = ArgumentChecks::MinSize::Type::MUL;
|
type = ArgumentChecks::MinSize::Type::MUL;
|
||||||
|
else if (strcmp(typeattr,"value")==0)
|
||||||
|
type = ArgumentChecks::MinSize::Type::VALUE;
|
||||||
else
|
else
|
||||||
return Error(BAD_ATTRIBUTE_VALUE, typeattr);
|
return Error(BAD_ATTRIBUTE_VALUE, typeattr);
|
||||||
|
|
||||||
const char *argattr = argnode->Attribute("arg");
|
if (type == ArgumentChecks::MinSize::Type::VALUE) {
|
||||||
if (!argattr)
|
const char *valueattr = argnode->Attribute("value");
|
||||||
return Error(MISSING_ATTRIBUTE, "arg");
|
if (!valueattr)
|
||||||
if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9')
|
return Error(MISSING_ATTRIBUTE, "value");
|
||||||
return Error(BAD_ATTRIBUTE_VALUE, argattr);
|
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.reserve(type == ArgumentChecks::MinSize::Type::MUL ? 2 : 1);
|
||||||
ac.minsizes.emplace_back(type,argattr[0]-'0');
|
ac.minsizes.emplace_back(type, argattr[0] - '0');
|
||||||
if (type == ArgumentChecks::MinSize::Type::MUL) {
|
if (type == ArgumentChecks::MinSize::Type::MUL) {
|
||||||
const char *arg2attr = argnode->Attribute("arg2");
|
const char *arg2attr = argnode->Attribute("arg2");
|
||||||
if (!arg2attr)
|
if (!arg2attr)
|
||||||
return Error(MISSING_ATTRIBUTE, "arg2");
|
return Error(MISSING_ATTRIBUTE, "arg2");
|
||||||
if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
|
if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
|
||||||
return Error(BAD_ATTRIBUTE_VALUE, arg2attr);
|
return Error(BAD_ATTRIBUTE_VALUE, arg2attr);
|
||||||
ac.minsizes.back().arg2 = arg2attr[0] - '0';
|
ac.minsizes.back().arg2 = arg2attr[0] - '0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,11 +254,12 @@ public:
|
||||||
|
|
||||||
class MinSize {
|
class MinSize {
|
||||||
public:
|
public:
|
||||||
enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL };
|
enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL, VALUE };
|
||||||
MinSize(Type t, int a) : type(t), arg(a), arg2(0) {}
|
MinSize(Type t, int a) : type(t), arg(a), arg2(0), value(0) {}
|
||||||
Type type;
|
Type type;
|
||||||
int arg;
|
int arg;
|
||||||
int arg2;
|
int arg2;
|
||||||
|
long long value;
|
||||||
};
|
};
|
||||||
std::vector<MinSize> minsizes;
|
std::vector<MinSize> minsizes;
|
||||||
|
|
||||||
|
|
|
@ -350,3 +350,65 @@ void dl(const char* libname, const char* func)
|
||||||
dlclose(uninit);
|
dlclose(uninit);
|
||||||
// cppcheck-suppress resourceLeak
|
// 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=\"1\"><minsize type=\"strlen\" arg=\"2\"/></arg>\n"
|
||||||
" <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"
|
||||||
" </function>\n"
|
" </function>\n"
|
||||||
"</def>";
|
"</def>";
|
||||||
|
|
||||||
|
@ -455,7 +456,7 @@ private:
|
||||||
ASSERT_EQUALS(true, Library::OK == (readLibrary(library, xmldata)).errorcode);
|
ASSERT_EQUALS(true, Library::OK == (readLibrary(library, xmldata)).errorcode);
|
||||||
|
|
||||||
TokenList tokenList(nullptr);
|
TokenList tokenList(nullptr);
|
||||||
std::istringstream istr("foo(a,b,c);");
|
std::istringstream istr("foo(a,b,c,d);");
|
||||||
tokenList.createTokens(istr);
|
tokenList.createTokens(istr);
|
||||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||||
|
|
||||||
|
@ -478,6 +479,16 @@ private:
|
||||||
ASSERT_EQUALS(Library::ArgumentChecks::MinSize::ARGVALUE, m.type);
|
ASSERT_EQUALS(Library::ArgumentChecks::MinSize::ARGVALUE, m.type);
|
||||||
ASSERT_EQUALS(3, m.arg);
|
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 {
|
void function_namespace() const {
|
||||||
|
|
Loading…
Reference in New Issue