ValueFlow: Limit the combinations of arguments passed to subfunctions in normal analysis (#4950)

This commit is contained in:
Paul Fultz II 2023-04-12 15:09:48 -05:00 committed by GitHub
parent afb9e43f2a
commit 1f0376b32d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 6 deletions

View File

@ -229,10 +229,12 @@ void Settings::setCheckLevelExhaustive()
{ {
// Checking can take a little while. ~ 10 times slower than normal analysis is OK. // Checking can take a little while. ~ 10 times slower than normal analysis is OK.
performanceValueFlowMaxIfCount = -1; performanceValueFlowMaxIfCount = -1;
performanceValueFlowMaxSubFunctionArgs = 256;
} }
void Settings::setCheckLevelNormal() void Settings::setCheckLevelNormal()
{ {
// Checking should finish in reasonable time. // Checking should finish in reasonable time.
performanceValueFlowMaxSubFunctionArgs = 8;
performanceValueFlowMaxIfCount = 100; performanceValueFlowMaxIfCount = 100;
} }

View File

@ -252,6 +252,9 @@ public:
/** @brief --performance-valueflow-max-if-count=C */ /** @brief --performance-valueflow-max-if-count=C */
int performanceValueFlowMaxIfCount; int performanceValueFlowMaxIfCount;
/** @brief max number of sets of arguments to pass to subfuncions in valueflow */
int performanceValueFlowMaxSubFunctionArgs;
/** @brief plist output (--plist-output=<dir>) */ /** @brief plist output (--plist-output=<dir>) */
std::string plistOutput; std::string plistOutput;

View File

@ -7244,7 +7244,7 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
}; };
template<class Key, class F> template<class Key, class F>
bool productParams(const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f) bool productParams(const Settings* settings, const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
{ {
using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>; using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
Args args(1); Args args(1);
@ -7254,9 +7254,15 @@ bool productParams(const std::unordered_map<Key, std::list<ValueFlow::Value>>& v
continue; continue;
args.back()[p.first] = p.second.front(); args.back()[p.first] = p.second.front();
} }
bool bail = false;
int max = 8;
if (settings)
max = settings->performanceValueFlowMaxSubFunctionArgs;
for (const auto& p:vars) { for (const auto& p:vars) {
if (args.size() > 256) if (args.size() > max) {
return false; bail = true;
break;
}
if (p.second.empty()) if (p.second.empty())
continue; continue;
std::for_each(std::next(p.second.begin()), p.second.end(), [&](const ValueFlow::Value& value) { std::for_each(std::next(p.second.begin()), p.second.end(), [&](const ValueFlow::Value& value) {
@ -7279,6 +7285,11 @@ bool productParams(const std::unordered_map<Key, std::list<ValueFlow::Value>>& v
}); });
} }
if (args.size() > max) {
bail = true;
args.resize(max);
}
for (const auto& arg:args) { for (const auto& arg:args) {
if (arg.empty()) if (arg.empty())
continue; continue;
@ -7290,7 +7301,7 @@ bool productParams(const std::unordered_map<Key, std::list<ValueFlow::Value>>& v
continue; continue;
f(arg); f(arg);
} }
return true; return !bail;
} }
static void valueFlowInjectParameter(TokenList* tokenlist, static void valueFlowInjectParameter(TokenList* tokenlist,
@ -7300,7 +7311,7 @@ static void valueFlowInjectParameter(TokenList* tokenlist,
const Scope* functionScope, const Scope* functionScope,
const std::unordered_map<const Variable*, std::list<ValueFlow::Value>>& vars) const std::unordered_map<const Variable*, std::list<ValueFlow::Value>>& vars)
{ {
const bool r = productParams(vars, [&](const std::unordered_map<const Variable*, ValueFlow::Value>& arg) { const bool r = productParams(&settings, vars, [&](const std::unordered_map<const Variable*, ValueFlow::Value>& arg) {
MultiValueFlowAnalyzer a(arg, tokenlist, &settings, symboldatabase); MultiValueFlowAnalyzer a(arg, tokenlist, &settings, symboldatabase);
valueFlowGenericForward(const_cast<Token*>(functionScope->bodyStart), functionScope->bodyEnd, a, settings); valueFlowGenericForward(const_cast<Token*>(functionScope->bodyStart), functionScope->bodyEnd, a, settings);
}); });
@ -7431,7 +7442,7 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue,
} }
if (returnValue.find("arg") != std::string::npos && argValues.empty()) if (returnValue.find("arg") != std::string::npos && argValues.empty())
return; return;
productParams(argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) { productParams(settings, argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
ValueFlow::Value value = evaluateLibraryFunction(arg, returnValue, settings); ValueFlow::Value value = evaluateLibraryFunction(arg, returnValue, settings);
if (value.isUninitValue()) if (value.isUninitValue())
return; return;