Visitar URL original
Function return: Extra check of safe function return values · napcode/cppcheck@05d35b0 · GitHub
Skip to content

Commit 05d35b0

Browse files
committed
Function return: Extra check of safe function return values
1 parent c990612 commit 05d35b0

9 files changed

Lines changed: 100 additions & 1 deletion

File tree

‎cfg/cppcheck-cfg.rng‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@
132132
<data type="positiveInteger"/>
133133
</attribute>
134134
</optional>
135+
<optional>
136+
<attribute name="safeValues">
137+
<data type="string">
138+
<param name="pattern">all|([0-9]*:[0-9]*)</param>
139+
</data>
140+
</attribute>
141+
</optional>
135142
<text/>
136143
</element>
137144
</optional>

‎cfg/std.cfg‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3054,7 +3054,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
30543054
<!-- int rand(void); -->
30553055
<function name="rand">
30563056
<use-retval/>
3057-
<returnValue type="int"/>
3057+
<returnValue type="int" safeValues="all"/>
30583058
<noreturn>false</noreturn>
30593059
<leak-ignore/>
30603060
</function>

‎cli/cmdlineparser.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
186186
else if (std::strcmp(argv[i], "--all-functions-are-safe") == 0)
187187
mSettings->allFunctionsAreSafe = true;
188188

189+
// Experimental: this flag says that all "safe output values" from functions should be checked.
190+
// todo: add proper configuration options
191+
else if (std::strcmp(argv[i], "--check-all-safe-return-values") == 0)
192+
mSettings->checkAllSafeFunctionReturnValues = true;
193+
189194
// Enforce language (--language=, -x)
190195
else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) {
191196
std::string str;

‎lib/library.cpp‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,11 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
618618
mReturnValueType[name] = type;
619619
if (const char *container = functionnode->Attribute("container"))
620620
mReturnValueContainer[name] = std::atoi(container);
621+
if (const char *safeValues = functionnode->Attribute("safeValues")) {
622+
SafeValues sf{LLONG_MIN, LLONG_MAX};
623+
if (std::strcmp(safeValues, "all") == 0)
624+
mReturnSafeValues[name] = sf;
625+
}
621626
} else if (functionnodename == "arg") {
622627
const char* argNrString = functionnode->Attribute("nr");
623628
if (!argNrString)
@@ -1195,6 +1200,19 @@ int Library::returnValueContainer(const Token *ftok) const
11951200
return it != mReturnValueContainer.end() ? it->second : -1;
11961201
}
11971202

1203+
bool Library::returnValueSafeValues(const Token *ftok, int64_t *v1, int64_t *v2) const
1204+
{
1205+
if (isNotLibraryFunction(ftok))
1206+
return false;
1207+
const std::map<std::string, SafeValues>::const_iterator it = mReturnSafeValues.find(getFunctionName(ftok));
1208+
if (it == mReturnSafeValues.end())
1209+
return false;
1210+
*v1 = it->second.minValue;
1211+
*v2 = it->second.maxValue;
1212+
return true;
1213+
1214+
}
1215+
11981216
bool Library::hasminsize(const Token *ftok) const
11991217
{
12001218
if (isNotLibraryFunction(ftok))

‎lib/library.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ class CPPCHECKLIB Library {
181181
const std::string& returnValue(const Token *ftok) const;
182182
const std::string& returnValueType(const Token *ftok) const;
183183
int returnValueContainer(const Token *ftok) const;
184+
bool returnValueSafeValues(const Token *ftok, int64_t *v1, int64_t *v2) const;
184185

185186
bool isnoreturn(const Token *ftok) const;
186187
bool isnotnoreturn(const Token *ftok) const;
@@ -541,6 +542,11 @@ class CPPCHECKLIB Library {
541542
std::map<std::string, std::string> mReturnValue;
542543
std::map<std::string, std::string> mReturnValueType;
543544
std::map<std::string, int> mReturnValueContainer;
545+
struct SafeValues {
546+
int64_t minValue;
547+
int64_t maxValue;
548+
};
549+
std::map<std::string, SafeValues> mReturnSafeValues;
544550
std::map<std::string, bool> mReportErrors;
545551
std::map<std::string, bool> mProcessAfterCode;
546552
std::set<std::string> mMarkupExtensions; // file extensions of markup files

‎lib/settings.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Settings::Settings()
4040
force(false),
4141
inconclusive(false),
4242
allFunctionsAreSafe(false),
43+
checkAllSafeFunctionReturnValues(false),
4344
inlineSuppressions(false),
4445
jobs(1),
4546
jointSuppressionReport(false),

‎lib/settings.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class CPPCHECKLIB Settings : public cppcheck::Platform {
149149
/** @brief Experimental flag that says all functions are "safe" */
150150
bool allFunctionsAreSafe;
151151

152+
/** @brief Experimental flag to safety check function output */
153+
bool checkAllSafeFunctionReturnValues;
154+
152155
/** @brief Is --inline-suppr given? */
153156
bool inlineSuppressions;
154157

‎lib/valueflow.cpp‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5393,6 +5393,18 @@ static bool getMinMaxValues(const ValueType *vt, const cppcheck::Platform &platf
53935393
return true;
53945394
}
53955395

5396+
static bool getMinMaxValues(const std::string &typestr, const Settings *settings, int64_t *minvalue, int64_t *maxvalue)
5397+
{
5398+
TokenList typeTokens(settings);
5399+
std::istringstream istr(typestr+";");
5400+
if (!typeTokens.createTokens(istr))
5401+
return false;
5402+
typeTokens.simplifyPlatformTypes();
5403+
typeTokens.simplifyStdType();
5404+
const ValueType &vt = ValueType::parseDecl(typeTokens.front(), settings);
5405+
return getMinMaxValues(&vt, *settings, minvalue, maxvalue);
5406+
}
5407+
53965408
static void valueFlowSafeFunctions(TokenList *tokenlist, SymbolDatabase *symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
53975409
{
53985410
if (settings->platformType == cppcheck::Platform::PlatformType::Unspecified)
@@ -5430,6 +5442,38 @@ static void valueFlowSafeFunctions(TokenList *tokenlist, SymbolDatabase *symbold
54305442
}
54315443
}
54325444

5445+
static void valueFlowSafeFunctionReturn(TokenList *tokenlist, const Settings *settings)
5446+
{
5447+
if (!settings->checkAllSafeFunctionReturnValues)
5448+
return;
5449+
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
5450+
if (!tok->astParent() || tok->str() != "(")
5451+
continue;
5452+
if (!Token::Match(tok->previous(), "%name%"))
5453+
continue;
5454+
int64_t v1,v2;
5455+
if (!settings->library.returnValueSafeValues(tok->previous(), &v1, &v2))
5456+
continue;
5457+
5458+
// Get min/max values for return type
5459+
const std::string typestr = settings->library.returnValueType(tok->previous());
5460+
int64_t minvalue, maxvalue;
5461+
if (!getMinMaxValues(typestr, settings, &minvalue, &maxvalue))
5462+
continue;
5463+
5464+
auto value = [](int64_t v, int64_t minvalue, int64_t maxvalue) {
5465+
if (v < minvalue)
5466+
return ValueFlow::Value(minvalue);
5467+
if (v > maxvalue)
5468+
return ValueFlow::Value(maxvalue);
5469+
return ValueFlow::Value(v);
5470+
};
5471+
5472+
setTokenValue(const_cast<Token *>(tok), value(v1, minvalue, maxvalue), settings);
5473+
setTokenValue(const_cast<Token *>(tok), value(v2, minvalue, maxvalue), settings);
5474+
}
5475+
}
5476+
54335477
ValueFlow::Value::Value(const Token *c, long long val)
54345478
: valueType(INT),
54355479
intvalue(val),
@@ -5496,6 +5540,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
54965540
valueFlowNumber(tokenlist);
54975541
valueFlowString(tokenlist);
54985542
valueFlowArray(tokenlist);
5543+
valueFlowSafeFunctionReturn(tokenlist, settings);
54995544
valueFlowGlobalConstVar(tokenlist, settings);
55005545
valueFlowGlobalStaticVar(tokenlist, settings);
55015546
valueFlowPointerAlias(tokenlist);

‎test/testvalueflow.cpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3919,6 +3919,20 @@ class TestValueFlow : public TestFixture {
39193919
ASSERT_EQUALS(-0x8000, values.front().intvalue);
39203920
ASSERT_EQUALS(0x7fff, values.back().intvalue);
39213921
}
3922+
3923+
3924+
void valueFlowSafeFunctionReturn() {
3925+
const char *code;
3926+
std::list<ValueFlow::Value> values;
3927+
Settings s;
3928+
s.checkAllSafeFunctionReturnValues = true;
3929+
3930+
code = "x = rand();";
3931+
values = tokenValues(code, "(", &s);
3932+
ASSERT_EQUALS(2, values.size());
3933+
ASSERT_EQUALS(INT_MIN, values.front().intvalue);
3934+
ASSERT_EQUALS(INT_MAX, values.back().intvalue);
3935+
}
39223936
};
39233937

39243938
REGISTER_TEST(TestValueFlow)

0 commit comments

Comments
 (0)