7979
8080#include " analyzer.h"
8181#include " astutils.h"
82- #include " checkuninitvar.h"
8382#include " config.h"
8483#include " errorlogger.h"
8584#include " errortypes.h"
129128#include < unordered_set>
130129#include < vector>
131130
132- static void changeKnownToPossible (std::list<ValueFlow::Value> &values, int indirect=-1 )
133- {
134- for (ValueFlow::Value& v: values) {
135- if (indirect >= 0 && v.indirect != indirect)
136- continue ;
137- v.changeKnownToPossible ();
138- }
139- }
140-
141- static void removeImpossible (std::list<ValueFlow::Value>& values, int indirect = -1 )
142- {
143- values.remove_if ([&](const ValueFlow::Value& v) {
144- if (indirect >= 0 && v.indirect != indirect)
145- return false ;
146- return v.isImpossible ();
147- });
148- }
149-
150- static void lowerToPossible (std::list<ValueFlow::Value>& values, int indirect = -1 )
151- {
152- changeKnownToPossible (values, indirect);
153- removeImpossible (values, indirect);
154- }
155-
156131static void changePossibleToKnown (std::list<ValueFlow::Value>& values, int indirect = -1 )
157132{
158133 for (ValueFlow::Value& v : values) {
@@ -4081,85 +4056,6 @@ static void valueFlowForLoop(TokenList &tokenlist, const SymbolDatabase& symbold
40814056 }
40824057}
40834058
4084- template <class Key , class F >
4085- static bool productParams (const Settings& settings, const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
4086- {
4087- using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
4088- Args args (1 );
4089- // Compute cartesian product of all arguments
4090- for (const auto & p:vars) {
4091- if (p.second .empty ())
4092- continue ;
4093- args.back ()[p.first ] = p.second .front ();
4094- }
4095- bool bail = false ;
4096- int max = settings.vfOptions .maxSubFunctionArgs ;
4097- for (const auto & p:vars) {
4098- if (args.size () > max) {
4099- bail = true ;
4100- break ;
4101- }
4102- if (p.second .empty ())
4103- continue ;
4104- std::for_each (std::next (p.second .begin ()), p.second .end (), [&](const ValueFlow::Value& value) {
4105- Args new_args;
4106- for (auto arg:args) {
4107- if (value.path != 0 ) {
4108- for (const auto & q:arg) {
4109- if (q.first == p.first )
4110- continue ;
4111- if (q.second .path == 0 )
4112- continue ;
4113- if (q.second .path != value.path )
4114- return ;
4115- }
4116- }
4117- arg[p.first ] = value;
4118- new_args.push_back (std::move (arg));
4119- }
4120- std::copy (new_args.cbegin (), new_args.cend (), std::back_inserter (args));
4121- });
4122- }
4123-
4124- if (args.size () > max) {
4125- bail = true ;
4126- args.resize (max);
4127- // TODO: add bailout message
4128- }
4129-
4130- for (const auto & arg:args) {
4131- if (arg.empty ())
4132- continue ;
4133- // Make sure all arguments are the same path
4134- const MathLib::bigint path = arg.cbegin ()->second .path ;
4135- if (std::any_of (arg.cbegin (), arg.cend (), [&](const std::pair<Key, ValueFlow::Value>& p) {
4136- return p.second .path != path;
4137- }))
4138- continue ;
4139- f (arg);
4140- }
4141- return !bail;
4142- }
4143-
4144- static void valueFlowInjectParameter (const TokenList& tokenlist,
4145- ErrorLogger& errorLogger,
4146- const Settings& settings,
4147- const Scope* functionScope,
4148- const std::unordered_map<const Variable*, std::list<ValueFlow::Value>>& vars)
4149- {
4150- const bool r = productParams (settings, vars, [&](const std::unordered_map<const Variable*, ValueFlow::Value>& arg) {
4151- auto a = makeMultiValueFlowAnalyzer (arg, settings);
4152- valueFlowGenericForward (const_cast <Token*>(functionScope->bodyStart ), functionScope->bodyEnd , a, tokenlist, errorLogger, settings);
4153- });
4154- if (!r) {
4155- std::string fname = " <unknown>" ;
4156- if (const Function* f = functionScope->function )
4157- fname = f->name ();
4158- if (settings.debugwarnings )
4159- bailout (tokenlist, errorLogger, functionScope->bodyStart , " Too many argument passed to " + fname);
4160- }
4161- }
4162-
41634059static void valueFlowInjectParameter (const TokenList& tokenlist,
41644060 ErrorLogger& errorLogger,
41654061 const Settings& settings,
@@ -4185,131 +4081,6 @@ static void valueFlowInjectParameter(const TokenList& tokenlist,
41854081 settings);
41864082}
41874083
4188- static std::list<ValueFlow::Value> getFunctionArgumentValues (const Token *argtok)
4189- {
4190- std::list<ValueFlow::Value> argvalues (argtok->values ());
4191- removeImpossible (argvalues);
4192- if (argvalues.empty () && Token::Match (argtok, " %comp%|%oror%|&&|!" )) {
4193- argvalues.emplace_back (0 );
4194- argvalues.emplace_back (1 );
4195- }
4196- return argvalues;
4197- }
4198-
4199- static void valueFlowLibraryFunction (Token *tok, const std::string &returnValue, const Settings &settings)
4200- {
4201- std::unordered_map<nonneg int , std::list<ValueFlow::Value>> argValues;
4202- int argn = 1 ;
4203- for (const Token *argtok : getArguments (tok->previous ())) {
4204- argValues[argn] = getFunctionArgumentValues (argtok);
4205- argn++;
4206- }
4207- if (returnValue.find (" arg" ) != std::string::npos && argValues.empty ())
4208- return ;
4209- productParams (settings, argValues, [&](const std::unordered_map<nonneg int , ValueFlow::Value>& arg) {
4210- ValueFlow::Value value = evaluateLibraryFunction (arg, returnValue, settings, tok->isCpp ());
4211- if (value.isUninitValue ())
4212- return ;
4213- ValueFlow::Value::ValueKind kind = ValueFlow::Value::ValueKind::Known;
4214- for (auto && p : arg) {
4215- if (p.second .isPossible ())
4216- kind = p.second .valueKind ;
4217- if (p.second .isInconclusive ()) {
4218- kind = p.second .valueKind ;
4219- break ;
4220- }
4221- }
4222- if (value.isImpossible () && kind != ValueFlow::Value::ValueKind::Known)
4223- return ;
4224- if (!value.isImpossible ())
4225- value.valueKind = kind;
4226- setTokenValue (tok, std::move (value), settings);
4227- });
4228- }
4229-
4230- static void valueFlowSubFunction (const TokenList& tokenlist, SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
4231- {
4232- int id = 0 ;
4233- for (auto it = symboldatabase.functionScopes .crbegin (); it != symboldatabase.functionScopes .crend (); ++it) {
4234- const Scope* scope = *it;
4235- const Function* function = scope->function ;
4236- if (!function)
4237- continue ;
4238- for (auto * tok = const_cast <Token*>(scope->bodyStart ); tok != scope->bodyEnd ; tok = tok->next ()) {
4239- if (tok->isKeyword () || !Token::Match (tok, " %name% (" ))
4240- continue ;
4241-
4242- const Function * const calledFunction = tok->function ();
4243- if (!calledFunction) {
4244- // library function?
4245- const std::string& returnValue (settings.library .returnValue (tok));
4246- if (!returnValue.empty ())
4247- valueFlowLibraryFunction (tok->next (), returnValue, settings);
4248- continue ;
4249- }
4250-
4251- const Scope * const calledFunctionScope = calledFunction->functionScope ;
4252- if (!calledFunctionScope)
4253- continue ;
4254-
4255- id++;
4256- std::unordered_map<const Variable*, std::list<ValueFlow::Value>> argvars;
4257- // TODO: Rewrite this. It does not work well to inject 1 argument at a time.
4258- const std::vector<const Token *> &callArguments = getArguments (tok);
4259- for (int argnr = 0U ; argnr < callArguments.size (); ++argnr) {
4260- const Token *argtok = callArguments[argnr];
4261- // Get function argument
4262- const Variable * const argvar = calledFunction->getArgumentVar (argnr);
4263- if (!argvar)
4264- break ;
4265-
4266- // passing value(s) to function
4267- std::list<ValueFlow::Value> argvalues (getFunctionArgumentValues (argtok));
4268-
4269- // Remove non-local lifetimes
4270- argvalues.remove_if ([](const ValueFlow::Value& v) {
4271- if (v.isLifetimeValue ())
4272- return !v.isLocalLifetimeValue () && !v.isSubFunctionLifetimeValue ();
4273- return false ;
4274- });
4275- // Remove uninit values if argument is passed by value
4276- if (argtok->variable () && !argtok->variable ()->isPointer () && argvalues.size () == 1 && argvalues.front ().isUninitValue ()) {
4277- if (CheckUninitVar::isVariableUsage (argtok, settings.library , false , CheckUninitVar::Alloc::NO_ALLOC, 0 ))
4278- continue ;
4279- }
4280-
4281- if (argvalues.empty ())
4282- continue ;
4283-
4284- // Error path..
4285- for (ValueFlow::Value &v : argvalues) {
4286- const std::string nr = std::to_string (argnr + 1 ) + getOrdinalText (argnr + 1 );
4287-
4288- v.errorPath .emplace_back (argtok,
4289- " Calling function '" +
4290- calledFunction->name () +
4291- " ', " +
4292- nr +
4293- " argument '" +
4294- argtok->expressionString () +
4295- " ' value is " +
4296- v.infoString ());
4297- v.path = 256 * v.path + id % 256 ;
4298- // Change scope of lifetime values
4299- if (v.isLifetimeValue ())
4300- v.lifetimeScope = ValueFlow::Value::LifetimeScope::SubFunction;
4301- }
4302-
4303- // passed values are not "known"..
4304- lowerToPossible (argvalues);
4305-
4306- argvars[argvar] = std::move (argvalues);
4307- }
4308- valueFlowInjectParameter (tokenlist, errorLogger, settings, calledFunctionScope, argvars);
4309- }
4310- }
4311- }
4312-
43134084static void valueFlowFunctionDefaultParameter (const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
43144085{
43154086 if (!tokenlist.isCPP ())
@@ -5687,7 +5458,7 @@ void ValueFlow::setValues(TokenList& tokenlist,
56875458 VFA (analyzeInferCondition (tokenlist, settings)),
56885459 VFA (analyzeSwitchVariable (tokenlist, symboldatabase, errorLogger, settings)),
56895460 VFA (valueFlowForLoop (tokenlist, symboldatabase, errorLogger, settings)),
5690- VFA (valueFlowSubFunction (tokenlist, symboldatabase, errorLogger, settings)),
5461+ VFA (analyzeSubFunction (tokenlist, symboldatabase, errorLogger, settings)),
56915462 VFA (analyzeFunctionReturn (tokenlist, errorLogger, settings)),
56925463 VFA (valueFlowLifetime (tokenlist, errorLogger, settings)),
56935464 VFA (valueFlowFunctionDefaultParameter (tokenlist, symboldatabase, errorLogger, settings)),
0 commit comments