Evaluate math library functions in valueflow (#4255)

* Evaluate math library functions in valueflow

* Format
This commit is contained in:
Paul Fultz II 2022-07-09 00:40:32 -05:00 committed by GitHub
parent edebe746bc
commit 6b72274c67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 324 additions and 66 deletions

View File

@ -119,7 +119,7 @@
<function name="acos,std::acos">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">acos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -131,7 +131,7 @@
<function name="acosf,std::acosf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">acos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -143,7 +143,7 @@
<function name="acosl,std::acosl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">acos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -231,7 +231,7 @@
<function name="sqrt,std::sqrt">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">sqrt(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -243,7 +243,7 @@
<function name="sqrtf,std::sqrtf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">sqrt(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -255,7 +255,7 @@
<function name="sqrtl,std::sqrtl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">sqrt(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -279,7 +279,7 @@
<function name="sinh,std::sinh">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">sinh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -290,7 +290,7 @@
<function name="sinhf,std::sinhf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">sinh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -301,7 +301,7 @@
<function name="sinhl,std::sinhl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">sinh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -312,7 +312,7 @@
<function name="sin,std::sin">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">sin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -323,7 +323,7 @@
<function name="sinf,std::sinf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">sin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -334,7 +334,7 @@
<function name="sinl,std::sinl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">sin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -369,7 +369,7 @@
<function name="asin,std::asin">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">asin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -381,7 +381,7 @@
<function name="asinf,std::asinf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">asin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -393,7 +393,7 @@
<function name="asinl,std::asinl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">asin(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -486,7 +486,7 @@
<function name="tan,std::tan">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">tan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -497,7 +497,7 @@
<function name="tanf,std::tanf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">tan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -508,7 +508,7 @@
<function name="tanl,std::tanl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">tan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -531,7 +531,7 @@
<function name="tanh,std::tanh">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">tanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -542,7 +542,7 @@
<function name="tanhf,std::tanhf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">tanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -553,7 +553,7 @@
<function name="tanhl,std::tanhl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">tanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -688,7 +688,7 @@
<function name="atan,std::atan">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">atan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -699,7 +699,7 @@
<function name="atanf,std::atanf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">atan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -710,7 +710,7 @@
<function name="atanl,std::atanl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">atan(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -799,7 +799,7 @@
<function name="atanh,std::atanh">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">atanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -811,7 +811,7 @@
<function name="atanhf,std::atanhf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">atanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -823,7 +823,7 @@
<function name="atanhl,std::atanhl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">atanh(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -847,7 +847,7 @@
<function name="atan2,std::atan2">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">atan2(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -861,7 +861,7 @@
<function name="atan2f,std::atan2f">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">atan2(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -875,7 +875,7 @@
<function name="atan2l,std::atan2l">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">atan2(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1090,7 +1090,7 @@
<function name="cos,std::cos">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">cos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1101,7 +1101,7 @@
<function name="cosf,std::cosf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">cos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1112,7 +1112,7 @@
<function name="cosl,std::cosl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">cos(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1357,7 +1357,7 @@
<function name="exp,std::exp">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">exp(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1368,7 +1368,7 @@
<function name="expf,std::expf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">exp(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -1379,7 +1379,7 @@
<function name="expl,std::expl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">exp(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3217,7 +3217,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<!-- double log(double x); -->
<function name="log,std::log">
<use-retval/>
<returnValue type="double"/>
<returnValue type="double">log(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3228,7 +3228,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<!-- float logf(float x); -->
<function name="logf,std::logf">
<use-retval/>
<returnValue type="float"/>
<returnValue type="float">log(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3239,7 +3239,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<!-- long double logl(long double x);-->
<function name="logl,std::logl">
<use-retval/>
<returnValue type="long double"/>
<returnValue type="long double">log(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3544,7 +3544,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="log10,std::log10">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">log10(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3556,7 +3556,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="log10f,std::log10f">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">log10(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -3568,7 +3568,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="log10l,std::log10l">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">log10(arg1)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -4126,7 +4126,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="pow,std::pow">
<use-retval/>
<pure/>
<returnValue type="double"/>
<returnValue type="double">pow(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -4140,7 +4140,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="powf,std::powf">
<use-retval/>
<pure/>
<returnValue type="float"/>
<returnValue type="float">pow(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">
@ -4154,7 +4154,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<function name="powl,std::powl">
<use-retval/>
<pure/>
<returnValue type="long double"/>
<returnValue type="long double">pow(arg1, arg2)</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="in">

View File

@ -32,6 +32,7 @@
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <list>
#include <memory>
@ -615,6 +616,231 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value&
return result;
}
using BuiltinLibraryFunction = std::function<ValueFlow::Value(const std::vector<ValueFlow::Value>&)>;
static std::unordered_map<std::string, BuiltinLibraryFunction> createBuiltinLibraryFunctions()
{
std::unordered_map<std::string, BuiltinLibraryFunction> functions;
functions["strlen"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!(v.isTokValue() && v.tokvalue->tokType() == Token::eString))
return ValueFlow::Value::unknown();
v.valueType = ValueFlow::Value::ValueType::INT;
v.intvalue = Token::getStrLength(v.tokvalue);
v.tokvalue = nullptr;
return v;
};
functions["sin"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::sin(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["cos"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::cos(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["tan"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::tan(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["asin"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::asin(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["acos"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::acos(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["atan"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::atan(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["atan2"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["pow"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 2)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["sqrt"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::sqrt(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["exp"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::exp(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["log"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::log(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["log10"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::log10(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["sinh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::sinh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["cosh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::cosh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["tanh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::tanh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["asinh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::asinh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["acosh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::acosh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
functions["atanh"] = [](const std::vector<ValueFlow::Value>& args) {
if (args.size() != 1)
return ValueFlow::Value::unknown();
ValueFlow::Value v = args[0];
if (!v.isFloatValue() && !v.isIntValue())
return ValueFlow::Value::unknown();
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
v.floatValue = std::atanh(value);
v.valueType = ValueFlow::Value::ValueType::FLOAT;
return v;
};
return functions;
}
static BuiltinLibraryFunction getBuiltinLibraryFunction(const std::string& name)
{
static const std::unordered_map<std::string, BuiltinLibraryFunction> functions = createBuiltinLibraryFunctions();
auto it = functions.find(name);
if (it == functions.end())
return nullptr;
return it->second;
}
static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const Settings* settings)
{
ValueFlow::Value unknown = ValueFlow::Value::unknown();
@ -787,29 +1013,26 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
const Function* f = ftok->function();
// TODO: Evaluate inline functions as well
if (!f && settings && expr->str() == "(") {
std::unordered_map<nonneg int, ValueFlow::Value> args;
int argn = 0;
for (const Token* tok : getArguments(expr)) {
ValueFlow::Value result = execute(tok, pm, settings);
if (!result.isUninitValue())
args[argn] = result;
argn++;
}
// strlen is a special builtin
if (Token::simpleMatch(ftok, "strlen")) {
if (args.count(0) > 0) {
ValueFlow::Value v = args.at(0);
if (v.isTokValue() && v.tokvalue->tokType() == Token::eString) {
v.valueType = ValueFlow::Value::ValueType::INT;
v.intvalue = Token::getStrLength(v.tokvalue);
v.tokvalue = nullptr;
return v;
}
}
std::vector<const Token*> tokArgs = getArguments(expr);
std::vector<ValueFlow::Value> args(tokArgs.size());
std::transform(tokArgs.begin(), tokArgs.end(), args.begin(), [&](const Token* tok) {
return execute(tok, pm, settings);
});
BuiltinLibraryFunction lf = getBuiltinLibraryFunction(ftok->str());
if (lf) {
return lf(args);
} else {
const std::string& returnValue = settings->library.returnValue(ftok);
if (!returnValue.empty())
return evaluateLibraryFunction(args, returnValue, settings);
if (!returnValue.empty()) {
std::unordered_map<nonneg int, ValueFlow::Value> arg_map;
int argn = 0;
for (const ValueFlow::Value& result : args) {
if (!result.isUninitValue())
arg_map[argn] = result;
argn++;
}
return evaluateLibraryFunction(arg_map, returnValue, settings);
}
}
}
// Check if functon modifies argument

View File

@ -36,6 +36,41 @@
#include <iterator>
#include <vector>
int zerodiv_sqrt()
{
int i = std::sqrt(0);
// cppcheck-suppress zerodiv
return 42 / i;
}
int zerodiv_sin()
{
int i = std::sin(0);
// cppcheck-suppress zerodiv
return 42 / i;
}
int moduloofone_cos()
{
int i = std::cos(0);
// cppcheck-suppress moduloofone
return 42 % i;
}
int moduloofone_exp()
{
int i = std::exp(0);
// cppcheck-suppress moduloofone
return 42 % i;
}
int moduloofone_pow()
{
int i = std::pow(2, 0);
// cppcheck-suppress moduloofone
return 42 % i;
}
char* invalidFunctionArgStr_strncpy(char * destination)
{
// Copies the first num characters of source to destination.