ValueFlow: Limit the combinations of arguments passed to subfunctions in normal analysis (#4950)
This commit is contained in:
parent
afb9e43f2a
commit
1f0376b32d
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue