--------------------------------------------------------------------------- Checks if an input argument to a function is the return value of an allocation function like malloc(), and the function does not release it. ---------------------------------------------------------------------------
| 1002 | // like malloc(), and the function does not release it. |
| 1003 | //--------------------------------------------------------------------------- |
| 1004 | void CheckMemoryLeakNoVarImpl::checkForUnreleasedInputArgument(const Scope *scope) |
| 1005 | { |
| 1006 | // parse the executable scope until tok is reached... |
| 1007 | for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { |
| 1008 | // allocating memory in parameter for function call.. |
| 1009 | if (tok->varId() || !Token::Match(tok, "%name% (")) |
| 1010 | continue; |
| 1011 | |
| 1012 | // check if the output of the function is assigned |
| 1013 | const Token* tok2 = tok->next()->astParent(); |
| 1014 | while (tok2 && (tok2->isCast() || Token::Match(tok2, "?|:"))) |
| 1015 | tok2 = tok2->astParent(); |
| 1016 | const bool hasAssign = Token::Match(tok2, "%assign%"); |
| 1017 | const bool hasReturn = Token::simpleMatch(tok->astTop(), "return"); |
| 1018 | |
| 1019 | const std::string& functionName = tok->str(); |
| 1020 | if ((tok->isCpp() && functionName == "delete") || |
| 1021 | functionName == "return") |
| 1022 | continue; |
| 1023 | |
| 1024 | if (Token::simpleMatch(tok->next()->astParent(), "(")) // passed to another function |
| 1025 | continue; |
| 1026 | if (!tok->isKeyword() && !tok->function() && !mSettings.library.isLeakIgnore(functionName)) |
| 1027 | continue; |
| 1028 | |
| 1029 | if ((hasAssign || hasReturn) && !tok->function()) { |
| 1030 | const std::string& ret = mSettings.library.returnValueType(tok); |
| 1031 | if (ret.empty() || endsWith(ret, "*")) |
| 1032 | continue; |
| 1033 | } |
| 1034 | |
| 1035 | const std::vector<const Token *> args = getArguments(tok); |
| 1036 | int argnr = -1; |
| 1037 | for (const Token* arg : args) { |
| 1038 | ++argnr; |
| 1039 | if (arg->isOp() && !(tok->isKeyword() && arg->str() == "*")) // e.g. switch (*new int) |
| 1040 | continue; |
| 1041 | while (arg->astOperand1()) { |
| 1042 | if (arg->isCpp() && Token::simpleMatch(arg, "new")) |
| 1043 | break; |
| 1044 | arg = arg->astOperand1(); |
| 1045 | } |
| 1046 | const AllocType alloc = getAllocationType(arg, 0); |
| 1047 | if (alloc == No) |
| 1048 | continue; |
| 1049 | if (alloc == New || alloc == NewArray) { |
| 1050 | const Token* typeTok = arg->next(); |
| 1051 | bool bail = !typeTok->isStandardType() && |
| 1052 | (!typeTok->valueType() || |
| 1053 | (typeTok->valueType()->type < ValueType::Type::SMART_POINTER && |
| 1054 | typeTok->valueType()->type != ValueType::Type::POD)) && |
| 1055 | !mSettings.library.detectContainerOrIterator(typeTok) && |
| 1056 | !mSettings.library.podtype(typeTok->expressionString()); |
| 1057 | if (bail && typeTok->type() && typeTok->type()->classScope && |
| 1058 | typeTok->type()->classScope->numConstructors == 0 && |
| 1059 | typeTok->type()->classScope->getDestructor() == nullptr) { |
| 1060 | bail = false; |
| 1061 | } |
nothing calls this directly
no test coverage detected