void CheckSizeof::checkSizeofForPointerSize() { if (!_settings->isEnabled("warning")) 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]; for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { const Token *tokVar; const Token *variable; const Token *variable2 = 0; // Find any function that may use sizeof on a pointer // Once leaving those tests, it is mandatory to have: // - variable matching the used pointer // - tokVar pointing on the argument where sizeof may be used if (Token::Match(tok, "[*;{}] %var% = malloc|alloca (")) { variable = tok->next(); tokVar = tok->tokAt(5); } else if (Token::Match(tok, "[*;{}] %var% = calloc (")) { variable = tok->next(); tokVar = tok->tokAt(5)->nextArgument(); } else if (Token::simpleMatch(tok, "memset (")) { variable = tok->tokAt(2); tokVar = variable->tokAt(2)->nextArgument(); // The following tests can be inconclusive in case the variable in sizeof // is constant string by intention } else if (!_settings->inconclusive) { continue; } else if (Token::Match(tok, "memcpy|memcmp|memmove|strncpy|strncmp|strncat (")) { variable = tok->tokAt(2); variable2 = variable->nextArgument(); tokVar = variable2->nextArgument(); } else { continue; } // Ensure the variables are in the symbol database // Also ensure the variables are pointers // Only keep variables which are pointers const Variable *var = variable->variable(); if (!var || !var->isPointer() || var->isArray()) { variable = 0; } if (variable2) { var = variable2->variable(); if (!var || !var->isPointer() || var->isArray()) { variable2 = 0; } } // If there are no pointer variable at this point, there is // no need to continue if (variable == 0 && variable2 == 0) { continue; } // Jump to the next sizeof token in the function and in the parameter // This is to allow generic operations with sizeof for (; tokVar && tokVar->str() != ")" && tokVar->str() != "," && tokVar->str() != "sizeof"; tokVar = tokVar->next()) {} // Now check for the sizeof usage. Once here, everything using sizeof(varid) or sizeof(&varid) // looks suspicious // Do it for first variable if (variable && (Token::Match(tokVar, "sizeof ( &| %varid% )", variable->varId()) || Token::Match(tokVar, "sizeof &| %varid%", variable->varId()))) { sizeofForPointerError(variable, variable->str()); } else if (variable2 && (Token::Match(tokVar, "sizeof ( &| %varid% )", variable2->varId()) || Token::Match(tokVar, "sizeof &| %varid%", variable2->varId()))) { sizeofForPointerError(variable2, variable2->str()); } } } }
void CheckSizeof::checkSizeofForPointerSize() { if (!_settings->isEnabled(Settings::WARNING)) 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]; for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { const Token* tokSize; const Token* tokFunc; const Token *variable = nullptr; const Token *variable2 = nullptr; // Find any function that may use sizeof on a pointer // Once leaving those tests, it is mandatory to have: // - variable matching the used pointer // - tokVar pointing on the argument where sizeof may be used if (Token::Match(tok->tokAt(2), "malloc|alloca|calloc (")) { if (Token::Match(tok, "%var% =")) variable = tok; else if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-2), "%var% =")) variable = tok->linkAt(1)->tokAt(-2); else if (tok->link() && Token::Match(tok, "> ( malloc|alloca|calloc (") && Token::Match(tok->link()->tokAt(-3), "%var% =")) variable = tok->link()->tokAt(-3); tokSize = tok->tokAt(4); tokFunc = tok->tokAt(2); } else if (Token::simpleMatch(tok, "memset (") && tok->strAt(-1) != ".") { variable = tok->tokAt(2); tokSize = variable->nextArgument(); if (tokSize) tokSize = tokSize->nextArgument(); tokFunc = tok; } else if (Token::Match(tok, "memcpy|memcmp|memmove|strncpy|strncmp|strncat (") && tok->strAt(-1) != ".") { variable = tok->tokAt(2); variable2 = variable->nextArgument(); if (!variable2) continue; tokSize = variable2->nextArgument(); tokFunc = tok; } else { continue; } if (tokSize && tokFunc->str() == "calloc") tokSize = tokSize->nextArgument(); if (tokSize) { const Token * const paramsListEndTok = tokFunc->linkAt(1); for (const Token* tok2 = tokSize; tok2 != paramsListEndTok; tok2 = tok2->next()) { if (Token::simpleMatch(tok2, "/ sizeof")) { // Allow division with sizeof(char) if (Token::simpleMatch(tok2->next(), "sizeof (")) { const Token *sztok = tok2->tokAt(2)->astOperand2(); const ValueType *vt = ((sztok != nullptr) ? sztok->valueType() : nullptr); if (vt && vt->type == ValueType::CHAR && vt->pointer == 0) continue; } divideBySizeofError(tok2, tokFunc->str()); } } } if (!variable || !tokSize) continue; while (Token::Match(variable, "%var% ::|.")) variable = variable->tokAt(2); while (Token::Match(variable2, "%var% ::|.")) variable2 = variable2->tokAt(2); // Ensure the variables are in the symbol database // Also ensure the variables are pointers // Only keep variables which are pointers const Variable *var = variable->variable(); if (!var || !var->isPointer() || var->isArray()) { variable = nullptr; } if (variable2) { var = variable2->variable(); if (!var || !var->isPointer() || var->isArray()) { variable2 = nullptr; } } // If there are no pointer variable at this point, there is // no need to continue if (variable == nullptr && variable2 == nullptr) { continue; } // Jump to the next sizeof token in the function and in the parameter // This is to allow generic operations with sizeof for (; tokSize && tokSize->str() != ")" && tokSize->str() != "," && tokSize->str() != "sizeof"; tokSize = tokSize->next()) {} if (tokSize->str() != "sizeof") continue; // Now check for the sizeof usage: Does the level of pointer indirection match? if (tokSize->linkAt(1)->strAt(-1) == "*") { if (variable && variable->valueType() && variable->valueType()->pointer == 1 && variable->valueType()->type != ValueType::VOID) sizeofForPointerError(variable, variable->str()); else if (variable2 && variable2->valueType() && variable2->valueType()->pointer == 1 && variable2->valueType()->type != ValueType::VOID) sizeofForPointerError(variable2, variable2->str()); } if (Token::simpleMatch(tokSize, "sizeof ( &")) tokSize = tokSize->tokAt(3); else if (Token::Match(tokSize, "sizeof (|&")) tokSize = tokSize->tokAt(2); else tokSize = tokSize->next(); while (Token::Match(tokSize, "%var% ::|.")) tokSize = tokSize->tokAt(2); if (Token::Match(tokSize, "%var% [|(")) continue; // Now check for the sizeof usage again. Once here, everything using sizeof(varid) or sizeof(&varid) // looks suspicious if (variable && tokSize->varId() == variable->varId()) sizeofForPointerError(variable, variable->str()); if (variable2 && tokSize->varId() == variable2->varId()) sizeofForPointerError(variable2, variable2->str()); } } }