* Is function parameter "used" so a "usage of uninitialized variable" can * be written? If parameter is passed "by value" then it is "used". If it * is passed "by reference" then it is not necessarily "used". * @return -1 => unknown 0 => not used 1 => used */
| 1365 | * @return -1 => unknown 0 => not used 1 => used |
| 1366 | */ |
| 1367 | int CheckUninitVarImpl::isFunctionParUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) |
| 1368 | { |
| 1369 | bool unknown = false; |
| 1370 | const Token *parent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown); |
| 1371 | if (unknown || !Token::Match(parent, "[(,]")) |
| 1372 | return -1; |
| 1373 | |
| 1374 | // locate start parentheses in function call.. |
| 1375 | int argumentNumber = 0; |
| 1376 | const Token *start = vartok; |
| 1377 | while (start && !Token::Match(start, "[;{}(]")) { |
| 1378 | if (start->str() == ")") |
| 1379 | start = start->link(); |
| 1380 | else if (start->str() == ",") |
| 1381 | ++argumentNumber; |
| 1382 | start = start->previous(); |
| 1383 | } |
| 1384 | if (!start) |
| 1385 | return -1; |
| 1386 | |
| 1387 | if (Token::simpleMatch(start->link(), ") {") && Token::Match(start->previous(), "if|for|while|switch")) |
| 1388 | return (!pointer || alloc == NO_ALLOC); |
| 1389 | |
| 1390 | // is this a function call? |
| 1391 | if (Token::Match(start->previous(), "%name% (")) { |
| 1392 | const bool address(vartok->strAt(-1) == "&"); |
| 1393 | const bool array(vartok->variable() && vartok->variable()->isArray()); |
| 1394 | // check how function handle uninitialized data arguments.. |
| 1395 | const Function *func = start->previous()->function(); |
| 1396 | if (func) { |
| 1397 | const Variable *arg = func->getArgumentVar(argumentNumber); |
| 1398 | if (arg) { |
| 1399 | const Token *argStart = arg->typeStartToken(); |
| 1400 | if (!address && !array && Token::Match(argStart, "%type% %name%| [,)]")) |
| 1401 | return 1; |
| 1402 | if (pointer && !address && alloc == NO_ALLOC && Token::Match(argStart, "%type% * %name% [,)]")) |
| 1403 | return 1; |
| 1404 | while (argStart->previous() && argStart->previous()->isName()) |
| 1405 | argStart = argStart->previous(); |
| 1406 | if (Token::Match(argStart, "const %type% & %name% [,)]")) { |
| 1407 | // If it's a record it's ok to pass a partially uninitialized struct. |
| 1408 | if (vartok->variable() && vartok->variable()->valueType() && vartok->variable()->valueType()->type == ValueType::Type::RECORD) |
| 1409 | return -1; |
| 1410 | return 1; |
| 1411 | } |
| 1412 | if ((pointer || address) && Token::Match(argStart, "const %type% %name% [") && Token::Match(argStart->linkAt(3), "] [,)]")) |
| 1413 | return 1; |
| 1414 | } |
| 1415 | |
| 1416 | } else if (Token::Match(start->previous(), "if|while|for")) { |
| 1417 | // control-flow statement reading the variable "by value" |
| 1418 | return alloc == NO_ALLOC; |
| 1419 | } else { |
| 1420 | const bool isnullbad = library.isnullargbad(start->previous(), argumentNumber + 1); |
| 1421 | if (indirect == 0 && pointer && !address && isnullbad && alloc == NO_ALLOC) |
| 1422 | return 1; |
| 1423 | if (vartok->varId() == 0 && vartok->valueType()) |
| 1424 | indirect = vartok->valueType()->pointer; |
nothing calls this directly
no test coverage detected