--------------------------------------------------------------------------- Check if an exception could cause a leak in an argument constructed with shared_ptr/unique_ptr. For example, in the following code, it is possible that if g() throws an exception, the memory allocated by "new int(42)" could be leaked. See stackoverflow.com/questions/19034538/ why-is-there-memory-leak-while-using-shared-ptr
| 1149 | // } |
| 1150 | //--------------------------------------------------------------------------- |
| 1151 | void CheckMemoryLeakNoVarImpl::checkForUnsafeArgAlloc(const Scope *scope) |
| 1152 | { |
| 1153 | // This test only applies to C++ source |
| 1154 | if (!mTokenizer->isCPP()) |
| 1155 | return; |
| 1156 | |
| 1157 | if (!mSettings.isPremiumEnabled("leakUnsafeArgAlloc") && (!mSettings.certainty.isEnabled(Certainty::inconclusive) || !mSettings.severity.isEnabled(Severity::warning))) |
| 1158 | return; |
| 1159 | |
| 1160 | logChecker("CheckMemoryLeakNoVar::checkForUnsafeArgAlloc"); |
| 1161 | |
| 1162 | for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { |
| 1163 | if (Token::Match(tok, "%name% (")) { |
| 1164 | const Token *endParamToken = tok->linkAt(1); |
| 1165 | const Token* pointerType = nullptr; |
| 1166 | const Token* functionCalled = nullptr; |
| 1167 | |
| 1168 | // Scan through the arguments to the function call |
| 1169 | for (const Token *tok2 = tok->tokAt(2); tok2 && tok2 != endParamToken; tok2 = tok2->nextArgument()) { |
| 1170 | const Function *func = tok2->function(); |
| 1171 | const bool isNothrow = func && (func->isAttributeNothrow() || func->isThrow()); |
| 1172 | |
| 1173 | if (Token::Match(tok2, "shared_ptr|unique_ptr <") && Token::Match(tok2->linkAt(1), "> ( new %name%")) { |
| 1174 | pointerType = tok2; |
| 1175 | } else if (!isNothrow) { |
| 1176 | if (Token::Match(tok2, "%name% (")) |
| 1177 | functionCalled = tok2; |
| 1178 | else if (tok2->isName() && Token::simpleMatch(tok2->linkAt(1), "> (")) |
| 1179 | functionCalled = tok2; |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1183 | if (pointerType && functionCalled) { |
| 1184 | std::string functionName = functionCalled->str(); |
| 1185 | if (functionCalled->strAt(1) == "<") { |
| 1186 | functionName += '<'; |
| 1187 | for (const Token* tok2 = functionCalled->tokAt(2); tok2 != functionCalled->linkAt(1); tok2 = tok2->next()) |
| 1188 | functionName += tok2->str(); |
| 1189 | functionName += '>'; |
| 1190 | } |
| 1191 | std::string objectTypeName; |
| 1192 | for (const Token* tok2 = pointerType->tokAt(2); tok2 != pointerType->linkAt(1); tok2 = tok2->next()) |
| 1193 | objectTypeName += tok2->str(); |
| 1194 | |
| 1195 | unsafeArgAllocError(tok, functionName, pointerType->str(), objectTypeName); |
| 1196 | } |
| 1197 | } |
| 1198 | } |
| 1199 | } |
| 1200 | |
| 1201 | void CheckMemoryLeakNoVarImpl::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall) |
| 1202 | { |
nothing calls this directly
no test coverage detected