void CheckAutoVariables::returnPointerToLocalArray() { 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 pointer if (tok->previous() && tok->previous()->str() == "*") { for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { // Return pointer to local array variable.. if (Token::Match(tok2, "return %var% ;")) { if (isAutoVarArray(tok2->next())) { errorReturnPointerToLocalArray(tok2); } } } } } }
void CheckAutoVariables::returnPointerToLocalArray() { 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 pointer if (tok->previous() && tok->previous()->str() == "*") { for (const Token *tok2 = scope->classStart; tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { // Return pointer to local array variable.. if (Token::Match(tok2, "return %var% ;")) { const unsigned int varid = tok2->next()->varId(); if (isAutoVarArray(varid)) { errorReturnPointerToLocalArray(tok2); } } } } } }
bool CheckAutoVariables::isAutoVarArray(const Token *tok) { if (!tok) return false; // &x[..] if (tok->str() == "&" && Token::simpleMatch(tok->astOperand1(), "[") && !tok->astOperand2()) return isAutoVarArray(tok->astOperand1()->astOperand1()); // x+y if (tok->str() == "+") return isAutoVarArray(tok->astOperand1()) || isAutoVarArray(tok->astOperand2()); // x-intexpr if (tok->str() == "-") return isAutoVarArray(tok->astOperand1()) && tok->astOperand2() && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->isIntegral(); const Variable *var = tok->variable(); if (!var) return false; // Variable if (var->isLocal() && !var->isStatic() && var->isArray() && !var->isPointer()) return true; // ValueFlow if (var->isPointer() && !var->isArgument()) { for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) { const ValueFlow::Value &val = *it; if (val.isTokValue() && isAutoVarArray(val.tokvalue)) return true; } } return false; }
void CheckAutoVariables::autoVariables() { 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; unsigned int indentlevel = 0; for (const Token *tok = scope->classDef->next()->link(); tok; tok = tok->next()) { // indentlevel.. if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") { if (indentlevel <= 1) break; --indentlevel; } //Critical assignment if (Token::Match(tok, "[;{}] * %var% = & %var%") && errorAv(tok->tokAt(2), tok->tokAt(5))) { errorAutoVariableAssignment(tok); } else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7))) { errorAutoVariableAssignment(tok); } // Critical return else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId())) { reportError(tok, Severity::error, "autoVariables", "Return of the address of an auto-variable"); } // Invalid pointer deallocation else if (Token::Match(tok, "free ( %var% ) ;") && isAutoVarArray(tok->tokAt(2)->varId())) { reportError(tok, Severity::error, "autoVariables", "Invalid deallocation"); } } } }
void CheckAutoVariables::autoVariables() { 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; for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { // Critical assignment if (Token::Match(tok, "[;{}] %var% = & %var%") && isRefArg(tok->next()->varId()) && isAutoVar(tok->tokAt(4)->varId())) { const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(4)->varId()); if (checkRvalueExpression(var, tok->tokAt(5))) errorAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)->varId()) && isAutoVar(tok->tokAt(5)->varId())) { const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId()); if (checkRvalueExpression(var, tok->tokAt(6))) errorAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->next()->varId()); if (var1 && var1->isArgument() && var1->isPointer()) { const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(6)->varId()); if (isAutoVar(tok->tokAt(6)->varId()) && checkRvalueExpression(var2, tok->tokAt(7))) errorAutoVariableAssignment(tok->next(), true); } } tok = tok->tokAt(6); } else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->next()->varId()); if (var1 && var1->isArgument() && var1->isPointer()) { if (isAutoVarArray(tok->tokAt(5)->varId())) errorAutoVariableAssignment(tok->next(), true); } } tok = tok->tokAt(5); } else if (Token::Match(tok, "[;{}] * %var% = %var% ;")) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()); if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-3), "%type% * *")) { if (isAutoVarArray(tok->tokAt(4)->varId())) errorAutoVariableAssignment(tok->next(), false); } tok = tok->tokAt(4); } else if (Token::Match(tok, "[;{}] %var% [") && Token::Match(tok->linkAt(2), "] = & %var%") && isPtrArg(tok->next()->varId()) && isAutoVar(tok->linkAt(2)->tokAt(3)->varId())) { const Token* const varTok = tok->linkAt(2)->tokAt(3); const Variable * var = symbolDatabase->getVariableFromVarId(varTok->varId()); if (checkRvalueExpression(var, varTok->next())) errorAutoVariableAssignment(tok->next(), false); } // Critical return else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId())) { errorReturnAddressToAutoVariable(tok); } else if (Token::Match(tok, "return & %var% [") && Token::simpleMatch(tok->linkAt(3), "] ;") && isAutoVarArray(tok->tokAt(2)->varId())) { errorReturnAddressToAutoVariable(tok); } else if (Token::Match(tok, "return & %var% ;") && tok->tokAt(2)->varId()) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()); if (var1 && var1->isArgument() && var1->typeEndToken()->str() != "&") errorReturnAddressOfFunctionParameter(tok, tok->strAt(2)); } // Invalid pointer deallocation else if (Token::Match(tok, "free ( %var% ) ;") || Token::Match(tok, "delete [| ]| (| %var% !![")) { tok = Token::findmatch(tok->next(), "%var%"); if (isAutoVarArray(tok->varId())) errorInvalidDeallocation(tok); } } } }
void CheckAutoVariables::autoVariables() { 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]; for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { // Critical assignment if (Token::Match(tok, "[;{}] %var% = & %var%") && isRefPtrArg(tok->next()) && isAutoVar(tok->tokAt(4))) { if (checkRvalueExpression(tok->tokAt(4))) errorAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] * %var% = & %var%") && isPtrArg(tok->tokAt(2)) && isAutoVar(tok->tokAt(5))) { if (checkRvalueExpression(tok->tokAt(5))) errorAutoVariableAssignment(tok->next(), false); } else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = tok->next()->variable(); if (var1 && var1->isArgument() && var1->isPointer()) { const Token * const var2tok = tok->tokAt(6); if (isAutoVar(var2tok) && checkRvalueExpression(var2tok)) errorAutoVariableAssignment(tok->next(), true); } } tok = tok->tokAt(6); } else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = tok->next()->variable(); if (var1 && var1->isArgument() && var1->isPointer()) { if (isAutoVarArray(tok->tokAt(5))) errorAutoVariableAssignment(tok->next(), true); } } tok = tok->tokAt(5); } else if (Token::Match(tok, "[;{}] * %var% = %var% ;")) { const Variable * var1 = tok->tokAt(2)->variable(); if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-3), "%type% * *")) { if (isAutoVarArray(tok->tokAt(4))) errorAutoVariableAssignment(tok->next(), false); } tok = tok->tokAt(4); } else if (Token::Match(tok, "[;{}] %var% [") && Token::Match(tok->linkAt(2), "] = & %var%") && isPtrArg(tok->next()) && isAutoVar(tok->linkAt(2)->tokAt(3))) { const Token* const varTok = tok->linkAt(2)->tokAt(3); if (checkRvalueExpression(varTok)) errorAutoVariableAssignment(tok->next(), false); } // Critical return else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2))) { errorReturnAddressToAutoVariable(tok); } else if (Token::Match(tok, "return & %var% [") && Token::simpleMatch(tok->linkAt(3), "] ;") && isAutoVarArray(tok->tokAt(2))) { errorReturnAddressToAutoVariable(tok); } else if (Token::Match(tok, "return & %var% ;") && tok->tokAt(2)->varId()) { const Variable * var1 = tok->tokAt(2)->variable(); if (var1 && var1->isArgument() && var1->typeEndToken()->str() != "&") errorReturnAddressOfFunctionParameter(tok, tok->strAt(2)); } // Invalid pointer deallocation else if (Token::Match(tok, "free ( %var% ) ;") || (_tokenizer->isCPP() && Token::Match(tok, "delete [| ]| (| %var% !!["))) { tok = Token::findmatch(tok->next(), "%var%"); if (isAutoVarArray(tok)) errorInvalidDeallocation(tok); } else if (Token::Match(tok, "free ( & %var% ) ;") || (_tokenizer->isCPP() && Token::Match(tok, "delete [| ]| (| & %var% !!["))) { tok = Token::findmatch(tok->next(), "%var%"); if (isAutoVar(tok)) errorInvalidDeallocation(tok); } } } }
void CheckAutoVariables::autoVariables() { 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; unsigned int indentlevel = 0; for (const Token *tok = scope->classDef->next()->link(); tok; tok = tok->next()) { // indentlevel.. if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") { if (indentlevel <= 1) break; --indentlevel; } //Critical assignment if (Token::Match(tok, "[;{}] * %var% = & %var%") && errorAv(tok->tokAt(2), tok->tokAt(5))) { const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId()); if (var && (!var->isClass() || var->type())) errorAutoVariableAssignment(tok, false); } else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId()); if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *")) { const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(6)->varId()); if (var2 && var2->isLocal() && !var2->isStatic()) errorAutoVariableAssignment(tok, _settings->inconclusive); } } tok = tok->tokAt(6); } else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;")) { // TODO: check if the parameter is only changed temporarily (#2969) if (_settings->inconclusive) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId()); if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *")) { const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId()); if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic()) errorAutoVariableAssignment(tok, _settings->inconclusive); } } tok = tok->tokAt(5); } else if (Token::Match(tok, "[;{}] * %var% = %var% ;")) { const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(2)->varId()); if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-3), "%type% * *")) { const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(4)->varId()); if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic()) errorAutoVariableAssignment(tok, false); } tok = tok->tokAt(4); } else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7))) { errorAutoVariableAssignment(tok, false); } // Critical return else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId())) { errorReturnAddressToAutoVariable(tok); } // Invalid pointer deallocation else if (Token::Match(tok, "free ( %var% ) ;") && isAutoVarArray(tok->tokAt(2)->varId())) { errorInvalidDeallocation(tok); } } } }
void CheckAutoVariables::autoVariables() { bool begin_function = false; bool begin_function_decl = false; int bindent = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "%type% *|::| %var% (")) { begin_function = true; fp_list.clear(); vd_list.clear(); vda_list.clear(); } else if (begin_function && begin_function_decl && Token::Match(tok, "%type% * * %var%")) { fp_list.insert(tok->tokAt(3)->str()); } else if (begin_function && begin_function_decl && Token::Match(tok, "%type% * %var% [")) { fp_list.insert(tok->tokAt(2)->str()); } else if (begin_function && tok->str() == "(") { begin_function_decl = true; } else if (begin_function && tok->str() == ")") { begin_function_decl = false; } else if (begin_function && tok->str() == "{") { bindent++; } else if (begin_function && tok->str() == "}") { bindent--; } else if (bindent <= 0) { continue; } // Inside a function body if (Token::Match(tok, "%type% :: %any%") && !isExternOrStatic(tok)) { addVD(tok->tokAt(2)->varId()); } else if (Token::Match(tok, "%type% %var% [")) { addVDA(tok->next()->varId()); } else if (Token::Match(tok, "%var% %var% ;") && !isExternOrStatic(tok) && isTypeName(tok)) { addVD(tok->next()->varId()); } else if (Token::Match(tok, "const %var% %var% ;") && !isExternOrStatic(tok) && isTypeName(tok->next())) { addVD(tok->tokAt(2)->varId()); } //Critical assignment else if (Token::Match(tok, "[;{}] %var% = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(4))) { errorAutoVariableAssignment(tok); } else if (Token::Match(tok, "[;{}] * %var% = & %var%") && errorAv(tok->tokAt(2), tok->tokAt(5))) { errorAutoVariableAssignment(tok); } else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7))) { errorAutoVariableAssignment(tok); } // Critical return else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId())) { reportError(tok, Severity::error, "autoVariables", "Return of the address of an auto-variable"); } // Invalid pointer deallocation else if (Token::Match(tok, "free ( %var% ) ;") && isAutoVarArray(tok->tokAt(2)->varId())) { reportError(tok, Severity::error, "autoVariables", "Invalid deallocation"); } } vd_list.clear(); vda_list.clear(); fp_list.clear(); }