Exemple #1
0
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());
            }
        }
    }
}
Exemple #2
0
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());
        }
    }
}