// Return c_str void CheckAutoVariables::returncstr() { // TODO: Move this to CheckStl::string_c_str // locate function that returns a const char *.. const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); std::list<Scope>::const_iterator scope; for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { // only check functions if (scope->type != Scope::eFunction || !scope->function) continue; const Token *tok = scope->function->tokenDef; // have we reached a function that returns a const char * if (Token::simpleMatch(tok->tokAt(-3), "const char *")) { for (const Token *tok2 = scope->classStart; tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { // return pointer to temporary.. if (returnTemporary(tok2)) { // report error.. errorReturnTempPointer(tok2); } } } } }
void CheckAutoVariables::returnReference() { if (_tokenizer->isC()) return; const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; if (!scope->function) continue; const Token *tok = scope->function->tokenDef; // have we reached a function that returns a reference? if (tok->previous() && tok->previous()->str() == "&") { for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { if (tok2->str() != "return") continue; // return.. if (Token::Match(tok2, "return %var% ;")) { // is the returned variable a local variable? if (isAutoVar(tok2->next())) { const Variable *var1 = tok2->next()->variable(); // If reference variable is used, check what it references if (Token::Match(var1->nameToken(), "%var% [=(]")) { const Token *tok3 = var1->nameToken()->tokAt(2); if (!Token::Match(tok3, "%var% [);.]")) continue; // Only report error if variable that is referenced is // a auto variable if (!isAutoVar(tok3)) continue; } // report error.. errorReturnReference(tok2); } } // return reference to temporary.. else if (Token::Match(tok2, "return %var% (") && Token::simpleMatch(tok2->linkAt(2), ") ;")) { if (returnTemporary(tok2->next())) { // report error.. errorReturnTempReference(tok2); } } // Return reference to a literal or the result of a calculation else if (tok2->astOperand1() && (tok2->astOperand1()->isCalculation() || tok2->next()->isLiteral()) && astHasAutoResult(tok2->astOperand1())) { errorReturnTempReference(tok2); } } } } }
// Return c_str void CheckAutoVariables::returncstr() { // locate function that returns a const char *.. const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); std::list<Scope>::const_iterator scope; for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { // only check functions if (scope->type != Scope::eFunction) continue; const Token *tok = scope->classDef; // skip any qualification while (Token::Match(tok->tokAt(-2), "%type% ::")) tok = tok->tokAt(-2); // have we reached a function that returns a const char * if (Token::simpleMatch(tok->tokAt(-3), "const char *")) { // go to the '(' const Token *tok2 = scope->classDef->next(); // go to the ')' tok2 = tok2->next()->link(); unsigned int indentlevel = 0; for (; tok2; tok2 = tok2->next()) { // indentlevel.. if (tok2->str() == "{") ++indentlevel; else if (tok2->str() == "}") { if (indentlevel <= 1) break; --indentlevel; } // return.. if (Token::Match(tok2, "return %var% . c_str ( ) ;")) { // is the returned variable a local variable? const unsigned int varid = tok2->next()->varId(); const Variable *var = symbolDatabase->getVariableFromVarId(varid); if (var && var->isLocal() && !var->isStatic()) { // report error.. errorReturnAutocstr(tok2); } } // return pointer to temporary.. else if (returnTemporary(tok2)) { // report error.. errorReturnTempPointer(tok2); } } } } }
void CheckAutoVariables::returnReference() { const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); std::list<Scope>::const_iterator scope; for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { // only check functions if (scope->type != Scope::eFunction) continue; const Token *tok = scope->classDef; // skip any qualification while (Token::Match(tok->tokAt(-2), "%type% ::")) tok = tok->tokAt(-2); // have we reached a function that returns a reference? if (tok->previous() && tok->previous()->str() == "&") { for (const Token *tok2 = scope->classStart; tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { // return.. if (Token::Match(tok2, "return %var% ;")) { // is the returned variable a local variable? const unsigned int varid1 = tok2->next()->varId(); const Variable *var1 = symbolDatabase->getVariableFromVarId(varid1); if (var1 && var1->isLocal() && !var1->isStatic()) { // If reference variable is used, check what it references if (Token::Match(var1->nameToken(), "%var% =")) { const Token *tok3 = var1->nameToken()->tokAt(2); if (!Token::Match(tok3, "%var% [;.]")) continue; // Only report error if variable that is referenced is // a auto variable const Variable *var2 = symbolDatabase->getVariableFromVarId(tok3->varId()); if (!var2 || !var2->isLocal() || var2->isStatic() || (var2->isPointer() && tok3->strAt(1) == ".")) continue; } // report error.. errorReturnReference(tok2); } } // return reference to temporary.. else if (returnTemporary(tok2)) { // report error.. errorReturnTempReference(tok2); } } } } }
// Return c_str void CheckAutoVariables::returncstr() { // locate function that returns a const char *.. for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // Skip executable scopes.. if (Token::Match(tok, ") const| {")) { tok = tok->next(); if (tok->str() == "const") tok = tok->next(); tok = tok->link(); continue; } // have we reached a function that returns a reference? if (Token::Match(tok, "const char * %var% (")) { // go to the '(' const Token *tok2 = tok->tokAt(4); // go to the ')' tok2 = tok2->link(); // is this a function implementation? if (Token::Match(tok2, ") const| {")) { unsigned int indentlevel = 0; std::set<unsigned int> localvar; // local variables in function while (0 != (tok2 = tok2->next())) { // indentlevel.. if (tok2->str() == "{") ++indentlevel; else if (tok2->str() == "}") { if (indentlevel <= 1) break; --indentlevel; } // declare local variable.. if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return") { // goto next token.. tok2 = tok2->next(); // skip "const" if (Token::Match(tok2, "const %type%")) tok2 = tok2->next(); // skip "std::" if it is seen if (Token::simpleMatch(tok2, "std ::")) tok2 = tok2->tokAt(2); // is it a variable declaration? if (Token::Match(tok2, "%type% %var% ;")) localvar.insert(tok2->next()->varId()); } // return.. else if (Token::Match(tok2, "return %var% . c_str ( ) ;")) { // is the returned variable a local variable? if ((tok2->next()->varId() > 0) && (localvar.find(tok2->next()->varId()) != localvar.end())) { // report error.. errorReturnAutocstr(tok2); } } // return pointer to temporary.. else if (returnTemporary(tok2)) { // report error.. errorReturnTempPointer(tok2); } } } } } }
// FIXME: There should be no temporary destructor in C++17. // CHECK: void returnByValueIntoVariable() // CHECK: 1: returnTemporary // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class return_stmt_with_dtor::D (*)(void)) // CXX11-ELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7]) // CXX11-NOELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D) // CXX11-NEXT: 6: [B1.5] // CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], class return_stmt_with_dtor::D) // CXX11-NEXT: 8: return_stmt_with_dtor::D d = returnTemporary(); // CXX11-NEXT: 9: ~return_stmt_with_dtor::D() (Temporary object destructor) // CXX11-NEXT: 10: [B1.8].~D() (Implicit destructor) // CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5], [B1.4]) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: return_stmt_with_dtor::D d = returnTemporary(); // CXX17-NEXT: 6: ~return_stmt_with_dtor::D() (Temporary object destructor) // CXX17-NEXT: 7: [B1.5].~D() (Implicit destructor) void returnByValueIntoVariable() { D d = returnTemporary(); }