Пример #1
0
void CheckNullPointer::nullPointerByDeRefAndChec()
{
    const bool printInconclusive = (mSettings->inconclusive);

    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
        if (Token::Match(tok, "sizeof|decltype|typeid|typeof (")) {
            tok = tok->next()->link();
            continue;
        }

        const Variable *var = tok->variable();
        if (!var || !var->isPointer() || tok == var->nameToken())
            continue;

        // Can pointer be NULL?
        const ValueFlow::Value *value = tok->getValue(0);
        if (!value)
            continue;

        if (!printInconclusive && value->isInconclusive())
            continue;

        // Pointer dereference.
        bool unknown = false;
        if (!isPointerDeRef(tok,unknown)) {
            if (unknown)
                nullPointerError(tok, tok->str(), value, true);
            continue;
        }

        nullPointerError(tok, tok->str(), value, value->isInconclusive());
    }
}
Пример #2
0
void CheckNullPointer::nullPointerByDeRefAndChec()
{
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
        const Variable *var = tok->variable();
        if (!var || !var->isPointer() || tok == var->nameToken())
            continue;

        // Can pointer be NULL?
        const ValueFlow::Value *value = tok->getValue(0);
        if (!value)
            continue;

        if (!_settings->inconclusive && value->inconclusive)
            continue;

        // Is pointer used as function parameter?
        if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
            const Token *ftok = tok->previous();
            while (ftok && ftok->str() != "(") {
                if (ftok->str() == ")")
                    ftok = ftok->link();
                ftok = ftok->previous();
            }
            if (!ftok || !ftok->previous())
                continue;
            std::list<const Token *> varlist;
            parseFunctionCall(*ftok->previous(), varlist, &_settings->library, 0);
            if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
                if (value->condition == nullptr)
                    nullPointerError(tok, tok->str());
                else if (_settings->isEnabled("warning"))
                    nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
            }
            continue;
        }

        // Pointer dereference.
        bool unknown = false;
        if (!isPointerDeRef(tok,unknown)) {
            if (_settings->inconclusive && unknown) {
                if (value->condition == nullptr)
                    nullPointerError(tok, tok->str(), true);
                else
                    nullPointerError(tok, tok->str(), value->condition, true);
            }
            continue;
        }

        if (value->condition == nullptr)
            nullPointerError(tok, tok->str(), value->inconclusive);
        else if (_settings->isEnabled("warning"))
            nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
    }
}
Пример #3
0
/**
* @brief Does one part of the check for nullPointer().
* -# default argument that sets a pointer to 0
* -# dereference pointer
*/
void CheckNullPointer::nullPointerDefaultArgument()
{
    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 == 0 || !scope->function->hasBody) // We only look for functions with a body
            continue;

        // Scan the argument list for default arguments that are pointers and
        // which default to a NULL pointer if no argument is specified.
        std::set<unsigned int> pointerArgs;
        for (const Token *tok = scope->function->arg; tok != scope->function->arg->link(); tok = tok->next()) {

            if (Token::Match(tok, "%var% = 0 ,|)") && tok->varId() != 0) {
                const Variable *var = tok->variable();
                if (var && var->isPointer())
                    pointerArgs.insert(tok->varId());
            }
        }

        // Report an error if any of the default-NULL arguments are dereferenced
        if (!pointerArgs.empty()) {
            for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {

                // If we encounter a possible NULL-pointer check, skip over its body
                if (Token::simpleMatch(tok, "if ( "))  {
                    bool dependsOnPointer = false;
                    const Token *endOfCondition = tok->next()->link();
                    if (!endOfCondition)
                        continue;

                    const Token *startOfIfBlock =
                        Token::simpleMatch(endOfCondition, ") {") ? endOfCondition->next() : nullptr;
                    if (!startOfIfBlock)
                        continue;

                    // If this if() statement may return, it may be a null
                    // pointer check for the pointers referenced in its condition
                    const Token *endOfIf = startOfIfBlock->link();
                    bool isExitOrReturn =
                        Token::findmatch(startOfIfBlock, "exit|return|throw", endOfIf) != nullptr;

                    if (Token::Match(tok, "if ( %var% == 0 )")) {
                        const unsigned int var = tok->tokAt(2)->varId();
                        if (var > 0 && pointerArgs.count(var) > 0) {
                            if (isExitOrReturn)
                                pointerArgs.erase(var);
                            else
                                dependsOnPointer = true;
                        }
                    } else {
                        for (const Token *tok2 = tok->next(); tok2 != endOfCondition; tok2 = tok2->next()) {
                            if (tok2->isName() && tok2->varId() > 0 &&
                                pointerArgs.count(tok2->varId()) > 0) {

                                // If the if() depends on a pointer and may return, stop
                                // considering that pointer because it may be a NULL-pointer
                                // check that returns if the pointer is NULL.
                                if (isExitOrReturn)
                                    pointerArgs.erase(tok2->varId());
                                else
                                    dependsOnPointer = true;
                            }
                        }
                    }

                    if (dependsOnPointer && endOfIf) {
                        for (; tok != endOfIf; tok = tok->next()) {
                            // If a pointer is assigned a new value, stop considering it.
                            if (Token::Match(tok, "%var% ="))
                                pointerArgs.erase(tok->varId());
                            else
                                removeAssignedVarFromSet(tok, pointerArgs);
                        }
                        continue;
                    }
                }

                // If there is a noreturn function (e.g. exit()), stop considering the rest of
                // this function.
                bool unknown = false;
                if (Token::Match(tok, "return|throw|exit") ||
                    (_tokenizer->IsScopeNoReturn(tok, &unknown) && !unknown))
                    break;

                removeAssignedVarFromSet(tok, pointerArgs);

                if (tok->varId() == 0 || pointerArgs.count(tok->varId()) == 0)
                    continue;

                // If a pointer is assigned a new value, stop considering it.
                if (Token::Match(tok, "%var% ="))
                    pointerArgs.erase(tok->varId());

                // If a pointer dereference is preceded by an && or ||,
                // they serve as a sequence point so the dereference
                // may not be executed.
                if (isPointerDeRef(tok, unknown) && !unknown &&
                    tok->strAt(-1) != "&&" && tok->strAt(-1) != "||" &&
                    tok->strAt(-2) != "&&" && tok->strAt(-2) != "||")
                    nullPointerDefaultArgError(tok, tok->str());
            }
        }
    }
}
Пример #4
0
void CheckNullPointer::nullPointerByCheckAndDeRef()
{
    const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();

    // Check if pointer is NULL and then dereference it..
    for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
        if (i->type != Scope::eIf && i->type != Scope::eElseIf && i->type != Scope::eWhile)
            continue;
        if (!i->classDef || i->classDef->isExpandedMacro())
            continue;

        const Token* const tok = i->type != Scope::eElseIf ? i->classDef->next() : i->classDef->tokAt(2);
        // TODO: investigate false negatives:
        // - handle "while"?
        // - if there are logical operators
        // - if (x) { } else { ... }

        // If the if-body ends with a unknown macro then bailout
        if (Token::Match(i->classEnd->tokAt(-3), "[;{}] %var% ;") && i->classEnd->tokAt(-2)->isUpperCaseName())
            continue;

        // vartok : token for the variable
        const Token *vartok = nullptr;
        const Token *checkConditionStart = nullptr;
        if (Token::Match(tok, "( ! %var% )|&&")) {
            vartok = tok->tokAt(2);
            checkConditionStart = vartok->next();
        } else if (Token::Match(tok, "( %var% )|&&")) {
            vartok = tok->next();
        } else if (Token::Match(tok, "( ! ( %var% =")) {
            vartok = tok->tokAt(3);
            if (Token::simpleMatch(tok->linkAt(2), ") &&"))
                checkConditionStart = tok->linkAt(2);
        } else
            continue;

        // Check if variable is a pointer
        const Variable *var = vartok->variable();
        if (!var || !var->isPointer())
            continue;

        // variable id for pointer
        const unsigned int varid(vartok->varId());

        const Scope* declScope = &*i;
        while (declScope->nestedIn && var->scope() != declScope && declScope->type != Scope::eFunction)
            declScope = declScope->nestedIn;

        if (Token::Match(vartok->next(), "&& ( %varid% =", varid))
            continue;

        // Name and line of the pointer
        const std::string &pointerName = vartok->str();

        // Check the condition (eg. ( !x && x->i )
        if (checkConditionStart) {
            const Token * const conditionEnd = tok->link();
            for (const Token *tok2 = checkConditionStart; tok2 != conditionEnd; tok2 = tok2->next()) {
                // If we hit a || operator, abort
                if (tok2->str() == "||")
                    break;

                // Pointer is used
                bool unknown = _settings->inconclusive;
                if (tok2->varId() == varid && (isPointerDeRef(tok2, unknown) || unknown)) {
                    nullPointerError(tok2, pointerName, vartok, unknown);
                    break;
                }
            }
        }

        // start token = inside the if-body
        const Token *tok1 = i->classStart;

        if (Token::Match(tok, "( %var% )|&&")) {
            // start token = first token after the if/while body
            tok1 = i->classEnd->next();
            if (!tok1)
                continue;
        }

        int indentlevel = 0;

        // Set to true if we would normally bail out the check.
        bool inconclusive = false;

        // Count { and } for tok2
        for (const Token *tok2 = tok1; tok2 != declScope->classEnd; tok2 = tok2->next()) {
            if (tok2->str() == "{")
                ++indentlevel;
            else if (tok2->str() == "}") {
                if (indentlevel == 0) {
                    if (_settings->inconclusive)
                        inconclusive = true;
                    else
                        break;
                }
                --indentlevel;

                // calling exit function?
                bool unknown = false;
                if (_tokenizer->IsScopeNoReturn(tok2, &unknown)) {
                    if (_settings->inconclusive && unknown)
                        inconclusive = true;
                    else
                        break;
                }

                if (indentlevel <= 0) {
                    // skip all "else" blocks because they are not executed in this execution path
                    while (Token::simpleMatch(tok2, "} else if ("))
                        tok2 = tok2->linkAt(3)->linkAt(1);
                    if (Token::simpleMatch(tok2, "} else {"))
                        tok2 = tok2->linkAt(2);
                }
            }

            if (tok2->str() == "return" || tok2->str() == "throw") {
                bool unknown = _settings->inconclusive;
                for (; tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
                    if (tok2->varId() == varid) {
                        if (CheckNullPointer::isPointerDeRef(tok2, unknown))
                            nullPointerError(tok2, pointerName, vartok, inconclusive);
                        else if (unknown)
                            nullPointerError(tok2, pointerName, vartok, true);
                        if (Token::Match(tok2, "%var% %oror%|&&|?"))
                            break;
                    }
                }
                break;
            }

            // Bailout for "if".
            if (tok2->str() == "if") {
                if (_settings->inconclusive)
                    inconclusive = true;
                else
                    break;
            }

            if (Token::Match(tok2, "goto|continue|break|switch|for"))
                break;

            // parameters to sizeof are not dereferenced
            if (Token::Match(tok2, "decltype|sizeof|typeof")) {
                if (tok2->strAt(1) != "(")
                    tok2 = tok2->next();
                else
                    tok2 = tok2->next()->link();
                continue;
            }

            // function call, check if pointer is dereferenced
            if (Token::Match(tok2, "%var% (") && !Token::Match(tok2, "if|while")) {
                std::list<const Token *> vars;
                parseFunctionCall(*tok2, vars, &_settings->library, 0);
                for (std::list<const Token *>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
                    if (Token::Match(*it, "%varid% [,)]", varid)) {
                        nullPointerError(*it, pointerName, vartok, inconclusive);
                        break;
                    }
                }
            }

            // calling unknown function (abort/init)..
            else if (Token::simpleMatch(tok2, ") ;") &&
                     (Token::Match(tok2->link()->tokAt(-2), "[;{}.] %var% (") ||
                      Token::Match(tok2->link()->tokAt(-5), "[;{}] ( * %var% ) ("))) {
                // noreturn function?
                bool unknown = false;
                if (_tokenizer->IsScopeNoReturn(tok2->tokAt(2), &unknown)) {
                    if (!unknown || !_settings->inconclusive) {
                        break;
                    }
                    inconclusive = _settings->inconclusive;
                }

                // init function (global variables)
                if (!(var->isLocal() || var->isArgument()))
                    break;
            }

            if (tok2->varId() == varid) {
                // unknown: this is set to true by isPointerDeRef if
                //          the function fails to determine if there
                //          is a dereference or not
                bool unknown = _settings->inconclusive;

                if (Token::Match(tok2->previous(), "[;{}=] %var% = 0 ;"))
                    ;

                else if (CheckNullPointer::isPointerDeRef(tok2, unknown))
                    nullPointerError(tok2, pointerName, vartok, inconclusive);

                else if (unknown && _settings->inconclusive)
                    nullPointerError(tok2, pointerName, vartok, true);

                else
                    break;
            }
        }
    }
}
Пример #5
0
bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings *settings)
{
    unknown = false;

    // Is pointer used as function parameter?
    if (Token::Match(tok->previous(), "[(,] %name% [,)]") && settings) {
        const Token *ftok = tok->previous();
        while (ftok && ftok->str() != "(") {
            if (ftok->str() == ")")
                ftok = ftok->link();
            ftok = ftok->previous();
        }
        if (ftok && ftok->previous()) {
            std::list<const Token *> varlist;
            parseFunctionCall(*ftok->previous(), varlist, &settings->library);
            if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
                return true;
            }
        }
    }

    const Token* parent = tok->astParent();
    if (!parent)
        return false;
    if (parent->str() == "." && parent->astOperand2() == tok)
        return isPointerDeRef(parent, unknown, settings);
    const bool firstOperand = parent->astOperand1() == tok;
    while (parent->str() == "(" && (parent->astOperand2() == nullptr && parent->strAt(1) != ")")) { // Skip over casts
        parent = parent->astParent();
        if (!parent)
            return false;
    }

    // Dereferencing pointer..
    if (parent->isUnaryOp("*") && !Token::Match(parent->tokAt(-2), "sizeof|decltype|typeof"))
        return true;

    // array access
    if (firstOperand && parent->str() == "[" && (!parent->astParent() || parent->astParent()->str() != "&"))
        return true;

    // address of member variable / array element
    const Token *parent2 = parent;
    while (Token::Match(parent2, "[|."))
        parent2 = parent2->astParent();
    if (parent2 != parent && parent2 && parent2->isUnaryOp("&"))
        return false;

    // read/write member variable
    if (firstOperand && parent->str() == "." && (!parent->astParent() || parent->astParent()->str() != "&")) {
        if (!parent->astParent() || parent->astParent()->str() != "(" || parent->astParent() == tok->previous())
            return true;
        unknown = true;
        return false;
    }

    if (Token::Match(tok, "%name% ("))
        return true;

    if (Token::Match(tok, "%var% = %var% .") &&
        tok->varId() == tok->tokAt(2)->varId())
        return true;

    // std::string dereferences nullpointers
    if (Token::Match(parent->tokAt(-3), "std :: string|wstring (") && tok->strAt(1) == ")")
        return true;
    if (Token::Match(parent->previous(), "%name% (") && tok->strAt(1) == ")") {
        const Variable* var = tok->tokAt(-2)->variable();
        if (var && !var->isPointer() && !var->isArray() && var->isStlStringType())
            return true;
    }

    // streams dereference nullpointers
    if (Token::Match(parent, "<<|>>") && !firstOperand) {
        const Variable* var = tok->variable();
        if (var && var->isPointer() && Token::Match(var->typeStartToken(), "char|wchar_t")) { // Only outputting or reading to char* can cause problems
            const Token* tok2 = parent; // Find start of statement
            for (; tok2; tok2 = tok2->previous()) {
                if (Token::Match(tok2->previous(), ";|{|}|:"))
                    break;
            }
            if (Token::Match(tok2, "std :: cout|cin|cerr"))
                return true;
            if (tok2 && tok2->varId() != 0) {
                const Variable* var2 = tok2->variable();
                if (var2 && var2->isStlType(stl_stream))
                    return true;
            }
        }
    }

    const Variable *ovar = nullptr;
    if (Token::Match(parent, "+|==|!=") || (parent->str() == "=" && !firstOperand)) {
        if (parent->astOperand1() == tok && parent->astOperand2())
            ovar = parent->astOperand2()->variable();
        else if (parent->astOperand1() && parent->astOperand2() == tok)
            ovar = parent->astOperand1()->variable();
    }
    if (ovar && !ovar->isPointer() && !ovar->isArray() && ovar->isStlStringType())
        return true;

    // assume that it's not a dereference (no false positives)
    return false;
}
Пример #6
0
/**
 * Is there a pointer dereference? Everything that should result in
 * a nullpointer dereference error message will result in a true
 * return value. If it's unknown if the pointer is dereferenced false
 * is returned.
 * @param tok token for the pointer
 * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message)
 * @return true => there is a dereference
 */
bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const
{
    return isPointerDeRef(tok, unknown, mSettings);
}