Ejemplo n.º 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());
    }
}
Ejemplo n.º 2
0
void CheckNullPointer::nullPointerAfterLoop()
{
    // Locate insufficient null-pointer handling after loop
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // only interested in while ( %var% )
        // TODO: Aren't there false negatives. Shouldn't other loops be handled such as:
        //       - while ( ! %var% )
        //       - while ( %var% && .. )
        if (! Token::Match(tok, "while ( %var% )"))
            continue;

        // Get variable id for the loop variable
        const unsigned int varid(tok->tokAt(2)->varId());
        if (varid == 0)
            continue;

        // Is variable a pointer?
        if (!isPointer(varid))
            continue;

        // Get variable name for the loop variable
        const std::string varname(tok->strAt(2));

        // Locate the end of the while loop body..
        const Token *tok2 = tok->tokAt(4)->link();

        // Check if the variable is dereferenced after the while loop
        while (0 != (tok2 = tok2 ? tok2->next() : 0))
        {
            // Don't check into inner scopes or outer scopes. Stop checking if "break" is found
            if (tok2->str() == "{" || tok2->str() == "}" || tok2->str() == "break")
                break;

            // loop variable is found..
            if (tok2->varId() == varid)
            {
                // dummy variable.. is it unknown if pointer is dereferenced or not?
                bool unknown = false;

                // Is the loop variable dereferenced?
                if (CheckNullPointer::isPointerDeRef(tok2, unknown))
                {
                    nullPointerError(tok2, varname, tok->linenr());
                }
                break;
            }
        }
    }
}
Ejemplo n.º 3
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);
    }
}
Ejemplo n.º 4
0
/** Dereferencing null constant (simplified token list) */
void CheckNullPointer::nullConstantDereference()
{
    // this is kept at 0 for all scopes that are not executing
    unsigned int indentlevel = 0;

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // start of executable scope..
        if (indentlevel == 0 && Token::Match(tok, ") const| {"))
            indentlevel = 1;

        else if (indentlevel >= 1)
        {
            if (tok->str() == "{")
                ++indentlevel;

            else if (tok->str() == "}")
            {
                if (indentlevel <= 2)
                    indentlevel = 0;
                else
                    --indentlevel;
            }

            if (tok->str() == "(" && Token::Match(tok->previous(), "sizeof|decltype"))
                tok = tok->link();

            else if (Token::simpleMatch(tok, "exit ( )"))
            {
                // Goto end of scope
                while (tok && tok->str() != "}")
                {
                    if (tok->str() == "{")
                        tok = tok->link();
                    tok = tok->next();
                }
                if (!tok)
                    break;
            }

            else if (Token::simpleMatch(tok, "* 0"))
            {
                if (Token::Match(tok->previous(), "return|;|{|}|=|(|,|%op%"))
                {
                    nullPointerError(tok);
                }
            }

            else if (indentlevel > 0 && Token::Match(tok, "%var% ("))
            {
                std::list<const Token *> var;
                parseFunctionCall(*tok, var, 0);

                // is one of the var items a NULL pointer?
                for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
                {
                    if ((*it)->str() == "0")
                    {
                        nullPointerError(*it);
                    }
                }
            }
        }
    }
}
Ejemplo n.º 5
0
void CheckNullPointer::nullPointerByCheckAndDeRef()
{
    // Check if pointer is NULL and then dereference it..

    // used to check if a variable is a pointer.
    // TODO: Use isPointer?
    std::set<unsigned int> pointerVariables;

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::Match(tok, "* %var% [;,)=]"))
            pointerVariables.insert(tok->next()->varId());

        else if (Token::simpleMatch(tok, "if ("))
        {
            // 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
            {
                // goto the end parenthesis
                const Token *endpar = tok->next()->link();
                const Token *endbody = Token::simpleMatch(endpar, ") {") ? endpar->next()->link() : 0;
                if (endbody &&
                    Token::Match(endbody->tokAt(-3), "[;{}] %var% ;") &&
                    isUpper(endbody->tokAt(-2)->str()))
                    continue;
            }

            // vartok : token for the variable
            const Token *vartok = 0;
            if (Token::Match(tok, "if ( ! %var% )|&&"))
                vartok = tok->tokAt(3);
            else if (Token::Match(tok, "if|while ( %var% )|&&"))
                vartok = tok->tokAt(2);
            else
                continue;

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

            const unsigned int linenr = vartok->linenr();

            // Check if variable is a pointer. TODO: Use isPointer?
            if (pointerVariables.find(varid) == pointerVariables.end())
                continue;

            // if this is true then it is known that the pointer is null
            bool null = true;

            // start token = inside the if-body
            const Token *tok1 = tok->next()->link()->tokAt(2);

            // indentlevel inside the if-body is 1
            unsigned int indentlevel = 1;

            if (Token::Match(tok, "if|while ( %var% )|&&"))
            {
                // pointer might be null
                null = false;

                // start token = first token after the if/while body
                tok1 = tok1->previous()->link();
                tok1 = tok1 ? tok1->next() : NULL;
                if (!tok1)
                    continue;

                // indentlevel at the base level is 0
                indentlevel = 0;
            }

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

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

                    if (null && indentlevel == 0)
                    {
                        // skip all "else" blocks because they are not executed in this execution path
                        while (Token::simpleMatch(tok2, "} else {"))
                            tok2 = tok2->tokAt(2)->link();
                        null = false;
                    }
                }

                if (Token::Match(tok2, "goto|return|continue|break|throw|if|switch"))
                {
                    if (Token::Match(tok2, "return * %varid%", varid))
                        nullPointerError(tok2, tok->strAt(3), linenr);
                    break;
                }

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

                // calling unknown function (abort/init)..
                if (Token::simpleMatch(tok2, ") ;") &&
                    (Token::Match(tok2->link()->tokAt(-2), "[;{}] %var% (") ||
                     Token::Match(tok2->link()->tokAt(-5), "[;{}] ( * %var% ) (")))
                {
                    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 = false;

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

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

                    else
                        break;
                }
            }
        }
    }
}
Ejemplo n.º 6
0
void CheckNullPointer::nullPointerByDeRefAndChec()
{
    // Dereferencing a pointer and then checking if it's NULL..
    // This check will first scan for the check. And then scan backwards
    // from the check, searching for dereferencing.
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // TODO: false negatives.
        // - logical operators
        // - while
        if (tok->str() == "if" && Token::Match(tok->previous(), "; if ( ! %var% )"))
        {
            // Variable id for pointer
            const unsigned int varid(tok->tokAt(3)->varId());
            if (varid == 0)
                continue;

            // Name of pointer
            const std::string varname(tok->strAt(3));

            // Check that variable is a pointer..
            if (!isPointer(varid))
                continue;

            // Token where pointer is declared
            const Token * const decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", varid);

            for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous())
            {
                if (tok1->str() == ")" && Token::Match(tok1->link()->previous(), "%var% ("))
                {
                    const Token *tok2 = tok1->link();
                    while (tok2 && !Token::Match(tok2, "[;{}]"))
                        tok2 = tok2->previous();
                    if (Token::Match(tok2, "[;{}] %varid% = %var%", varid))
                        break;
                }

                if (tok1->str() == ")" && Token::Match(tok1->link()->previous(), "while ( %varid%", varid))
                {
                    break;
                }

                if (tok1->str() == ")" && Token::simpleMatch(tok1->link()->previous(), "sizeof ("))
                {
                    tok1 = tok1->link()->previous();
                    continue;
                }

                if (tok1->str() == "break")
                    break;

                if (tok1->varId() == varid && !Token::Match(tok1->previous(), "[?:]"))
                {
                    // unknown : this is set by isPointerDeRef if it is
                    //           uncertain
                    bool unknown = false;

                    if (Token::Match(tok1->tokAt(-2), "%varid% = %varid% .", varid))
                    {
                        break;
                    }
                    else if (CheckNullPointer::isPointerDeRef(tok1, unknown))
                    {
                        nullPointerError(tok1, varname, tok->linenr());
                        break;
                    }
                    else if (Token::simpleMatch(tok1->previous(), "&"))
                    {
                        break;
                    }
                    else if (Token::simpleMatch(tok1->next(), "="))
                    {
                        break;
                    }
                }

                else if (tok1->str() == "{" ||
                         tok1->str() == "}")
                    break;

                // label..
                else if (Token::Match(tok1, "%type% :"))
                    break;
            }
        }
    }
}
Ejemplo n.º 7
0
void CheckNullPointer::nullPointerStructByDeRefAndChec()
{
    // Dereferencing a struct pointer and then checking if it's NULL..

    // skipvar: don't check vars that has been tested against null already
    std::set<unsigned int> skipvar;
    skipvar.insert(0);

    // Scan through all tokens
    for (const Token *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
    {
        // Checking if some pointer is null.
        // then add the pointer to skipvar => is it known that it isn't NULL
        if (Token::Match(tok1, "if|while ( !| %var% )"))
        {
            tok1 = tok1->tokAt(2);
            if (tok1->str() == "!")
                tok1 = tok1->next();
            skipvar.insert(tok1->varId());
            continue;
        }

        /**
         * @todo There are lots of false negatives here. A dereference
         *  is only investigated if a few specific conditions are met.
         */

        // dereference in assignment
        if (Token::Match(tok1, "[;{}] %var% . %var%"))
        {
            tok1 = tok1->next();
        }

        // dereference in assignment
        else if (Token::Match(tok1, "[{};] %var% = %var% . %var%"))
        {
            if (std::string(tok1->strAt(1)) == tok1->strAt(3))
                continue;
            tok1 = tok1->tokAt(3);
        }

        // dereference in function call (but not sizeof|decltype)
        else if ((Token::Match(tok1->tokAt(-2), "%var% ( %var% . %var%") && !Token::Match(tok1->tokAt(-2), "sizeof|decltype ( %var% . %var%")) ||
                 Token::Match(tok1->previous(), ", %var% . %var%"))
        {
            // Is the function return value taken by the pointer?
            bool assignment = false;
            const unsigned int varid1(tok1->varId());
            if (varid1 == 0)
                continue;
            const Token *tok2 = tok1->previous();
            while (tok2 && !Token::Match(tok2, "[;{}]"))
            {
                if (Token::Match(tok2, "%varid% =", varid1))
                {
                    assignment = true;
                    break;
                }
                tok2 = tok2->previous();
            }
            if (assignment)
                continue;
        }

        // Goto next token
        else
        {
            continue;
        }

        // struct dereference was found - investigate if it is later
        // checked that it is not NULL
        const unsigned int varid1(tok1->varId());
        if (skipvar.find(varid1) != skipvar.end())
            continue;

        // name of struct pointer
        const std::string varname(tok1->str());

        // is pointer local?
        bool isLocal = false;
        const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok1->varId());
        if (var && (var->isLocal() || var->isArgument()))
            isLocal = true;

        // member function may or may not nullify the pointer if it's global (#2647)
        if (!isLocal)
        {
            const Token *tok2 = tok1;
            while (Token::Match(tok2, "%var% ."))
                tok2 = tok2->tokAt(2);
            if (Token::Match(tok2,"%var% ("))
                continue;
        }

        // count { and } using tok2
        unsigned int indentlevel2 = 0;
        for (const Token *tok2 = tok1->tokAt(3); tok2; tok2 = tok2->next())
        {
            if (tok2->str() == "{")
                ++indentlevel2;

            else if (tok2->str() == "}")
            {
                if (indentlevel2 <= 1)
                    break;
                --indentlevel2;
            }

            // label / ?:
            else if (tok2->str() == ":")
                break;

            // Reassignment of the struct
            else if (tok2->varId() == varid1)
            {
                if (tok2->next()->str() == "=")
                    break;
                if (Token::Match(tok2->tokAt(-2), "[,(] &"))
                    break;
            }

            // Loop..
            /** @todo don't bail out if the variable is not used in the loop */
            else if (tok2->str() == "do")
                break;

            // return/break at base level => stop checking
            else if (indentlevel2 == 0 && (tok2->str() == "return" || tok2->str() == "break"))
                break;

            // Function call: If the pointer is not a local variable it
            // might be changed by the call.
            else if (Token::Match(tok2, "[;{}] %var% (") &&
                     Token::simpleMatch(tok2->tokAt(2)->link(), ") ;") && !isLocal)
            {
                break;
            }

            // Check if pointer is null.
            // TODO: false negatives for "if (!p || .."
            else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1))
            {
                // Is this variable a pointer?
                if (isPointer(varid1))
                    nullPointerError(tok1, varname, tok2->linenr());
                break;
            }
        }
    }
}
Ejemplo n.º 8
0
void CheckNullPointer::nullPointerLinkedList()
{
    // looping through items in a linked list in a inner loop.
    // Here is an example:
    //    for (const Token *tok = tokens; tok; tok = tok->next) {
    //        if (tok->str() == "hello")
    //            tok = tok->next;   // <- tok might become a null pointer!
    //    }
    for (const Token *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next())
    {
        // search for a "for" token..
        if (!Token::simpleMatch(tok1, "for ("))
            continue;

        // is there any dereferencing occurring in the for statement
        // parlevel2 counts the parentheses when using tok2.
        unsigned int parlevel2 = 1;
        for (const Token *tok2 = tok1->tokAt(2); tok2; tok2 = tok2->next())
        {
            // Parentheses..
            if (tok2->str() == "(")
                ++parlevel2;
            else if (tok2->str() == ")")
            {
                if (parlevel2 <= 1)
                    break;
                --parlevel2;
            }

            // Dereferencing a variable inside the "for" parentheses..
            else if (Token::Match(tok2, "%var% . %var%"))
            {
                // Variable id for dereferenced variable
                const unsigned int varid(tok2->varId());
                if (varid == 0)
                    continue;

                if (Token::Match(tok2->tokAt(-2), "%varid% ?", varid))
                    continue;

                // Variable name of dereferenced variable
                const std::string varname(tok2->str());

                // Check usage of dereferenced variable in the loop..
                unsigned int indentlevel3 = 0;
                for (const Token *tok3 = tok1->next()->link(); tok3; tok3 = tok3->next())
                {
                    if (tok3->str() == "{")
                        ++indentlevel3;
                    else if (tok3->str() == "}")
                    {
                        if (indentlevel3 <= 1)
                            break;
                        --indentlevel3;
                    }

                    // TODO: are there false negatives for "while ( %varid% ||"
                    else if (Token::Match(tok3, "while ( %varid% &&|)", varid))
                    {
                        // Make sure there is a "break" or "return" inside the loop.
                        // Without the "break" a null pointer could be dereferenced in the
                        // for statement.
                        // indentlevel4 is a counter for { and }. When scanning the code with tok4
                        unsigned int indentlevel4 = indentlevel3;
                        for (const Token *tok4 = tok3->next()->link(); tok4; tok4 = tok4->next())
                        {
                            if (tok4->str() == "{")
                                ++indentlevel4;
                            else if (tok4->str() == "}")
                            {
                                if (indentlevel4 <= 1)
                                {
                                    // Is this variable a pointer?
                                    if (isPointer(varid))
                                        nullPointerError(tok1, varname, tok3->linenr());

                                    break;
                                }
                                --indentlevel4;
                            }

                            // There is a "break" or "return" inside the loop.
                            // TODO: there can be false negatives. There could still be
                            //       execution paths that are not properly terminated
                            else if (tok4->str() == "break" || tok4->str() == "return")
                                break;
                        }
                    }
                }
            }
        }
    }
}
Ejemplo n.º 9
0
/** Dereferencing null constant (simplified token list) */
void CheckNullPointer::nullConstantDereference()
{
    const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();

    // THIS ARRAY MUST BE ORDERED ALPHABETICALLY
    static const char* const stl_stream[] = {
        "fstream", "ifstream", "iostream", "istream",
        "istringstream", "stringstream", "wistringstream", "wstringstream"
    };

    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;

        const Token *tok = scope->classStart;

        if (scope->function && scope->function->isConstructor())
            tok = scope->function->token; // Check initialization list

        for (; tok != scope->classEnd; tok = tok->next()) {
            if (Token::Match(tok, "sizeof|decltype|typeid|typeof ("))
                tok = tok->next()->link();

            else if (Token::simpleMatch(tok, "* 0")) {
                if (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isOp()) {
                    nullPointerError(tok);
                }
            }

            else if (Token::Match(tok, "0 [") && (tok->previous()->str() != "&" || !Token::Match(tok->next()->link()->next(), "[.(]")))
                nullPointerError(tok);

            else if (Token::Match(tok->previous(), "!!. %var% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
                if (Token::simpleMatch(tok->tokAt(2), "0 )") && tok->varId()) { // constructor call
                    const Variable *var = tok->variable();
                    if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string|wstring !!::"))
                        nullPointerError(tok);
                } else { // function call
                    std::list<const Token *> var;
                    parseFunctionCall(*tok, var, &_settings->library, 0);

                    // is one of the var items a NULL pointer?
                    for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
                        if (Token::Match(*it, "0|NULL [,)]")) {
                            nullPointerError(*it);
                        }
                    }
                }
            } else if (Token::Match(tok, "std :: string|wstring ( 0 )"))
                nullPointerError(tok);

            else if (Token::simpleMatch(tok->previous(), ">> 0")) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
                const Token* tok2 = tok->previous(); // Find start of statement
                for (; tok2; tok2 = tok2->previous()) {
                    if (Token::Match(tok2->previous(), ";|{|}|:"))
                        break;
                }
                if (Token::simpleMatch(tok2, "std :: cin"))
                    nullPointerError(tok);
                if (tok2 && tok2->varId() != 0) {
                    const Variable *var = tok2->variable();
                    if (var && var->isStlType(stl_stream))
                        nullPointerError(tok);
                }
            }

            const Variable *ovar = nullptr;
            if (Token::Match(tok, "0 ==|!= %var% !!."))
                ovar = tok->tokAt(2)->variable();
            else if (Token::Match(tok, "%var% ==|!= 0"))
                ovar = tok->variable();
            else if (Token::Match(tok, "%var% =|+ 0 )|]|,|;|+"))
                ovar = tok->variable();
            if (ovar && !ovar->isPointer() && !ovar->isArray() && Token::Match(ovar->typeStartToken(), "std :: string|wstring !!::"))
                nullPointerError(tok);
        }
    }
}
Ejemplo n.º 10
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;
            }
        }
    }
}
Ejemplo n.º 11
0
void CheckNullPointer::nullPointerLinkedList()
{
    const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();

    // looping through items in a linked list in a inner loop.
    // Here is an example:
    //    for (const Token *tok = tokens; tok; tok = tok->next) {
    //        if (tok->str() == "hello")
    //            tok = tok->next;   // <- tok might become a null pointer!
    //    }
    for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
        const Token* const tok1 = i->classDef;
        // search for a "for" scope..
        if (i->type != Scope::eFor || !tok1)
            continue;

        // is there any dereferencing occurring in the for statement
        const Token* end2 = tok1->linkAt(1);
        for (const Token *tok2 = tok1->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
            // Dereferencing a variable inside the "for" parentheses..
            if (Token::Match(tok2, "%var% . %var%")) {
                // Is this variable a pointer?
                const Variable *var = tok2->variable();
                if (!var || !var->isPointer())
                    continue;

                // Variable id for dereferenced variable
                const unsigned int varid(tok2->varId());

                // We don't support variables without a varid
                if (varid == 0)
                    continue;

                if (Token::Match(tok2->tokAt(-2), "%varid% ?", varid))
                    continue;

                // Check usage of dereferenced variable in the loop..
                for (std::list<Scope*>::const_iterator j = i->nestedList.begin(); j != i->nestedList.end(); ++j) {
                    Scope* scope = *j;
                    if (scope->type != Scope::eWhile)
                        continue;

                    // TODO: are there false negatives for "while ( %varid% ||"
                    if (Token::Match(scope->classDef->next(), "( %varid% &&|)", varid)) {
                        // Make sure there is a "break" or "return" inside the loop.
                        // Without the "break" a null pointer could be dereferenced in the
                        // for statement.
                        for (const Token *tok4 = scope->classStart; tok4; tok4 = tok4->next()) {
                            if (tok4 == i->classEnd) {
                                nullPointerError(tok1, var->name(), scope->classDef);
                                break;
                            }

                            // There is a "break" or "return" inside the loop.
                            // TODO: there can be false negatives. There could still be
                            //       execution paths that are not properly terminated
                            else if (tok4->str() == "break" || tok4->str() == "return")
                                break;
                        }
                    }
                }
            }
        }
    }
}
Ejemplo n.º 12
0
/** Dereferencing null constant (simplified token list) */
void CheckNullPointer::nullConstantDereference()
{
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();

    for (const Scope * scope : symbolDatabase->functionScopes) {
        if (scope->function == nullptr || !scope->function->hasBody()) // We only look for functions with a body
            continue;

        const Token *tok = scope->bodyStart;

        if (scope->function->isConstructor())
            tok = scope->function->token; // Check initialization list

        for (; tok != scope->bodyEnd; tok = tok->next()) {
            if (Token::Match(tok, "sizeof|decltype|typeid|typeof ("))
                tok = tok->next()->link();

            else if (Token::simpleMatch(tok, "* 0")) {
                if (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isOp()) {
                    nullPointerError(tok);
                }
            }

            else if (Token::Match(tok, "0 [") && (tok->previous()->str() != "&" || !Token::Match(tok->next()->link()->next(), "[.(]")))
                nullPointerError(tok);

            else if (Token::Match(tok->previous(), "!!. %name% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
                if (Token::Match(tok->tokAt(2), "0|NULL|nullptr )") && tok->varId()) { // constructor call
                    const Variable *var = tok->variable();
                    if (var && !var->isPointer() && !var->isArray() && var->isStlStringType())
                        nullPointerError(tok);
                } else { // function call
                    std::list<const Token *> var;
                    parseFunctionCall(*tok, var, &mSettings->library);

                    // is one of the var items a NULL pointer?
                    for (const Token *vartok : var) {
                        if (Token::Match(vartok, "0|NULL|nullptr [,)]")) {
                            nullPointerError(vartok);
                        }
                    }
                }
            } else if (Token::Match(tok, "std :: string|wstring ( 0|NULL|nullptr )"))
                nullPointerError(tok);

            else if (Token::Match(tok->previous(), "::|. %name% (")) {
                const std::vector<const Token *> &args = getArguments(tok);
                for (int argnr = 0; argnr < args.size(); ++argnr) {
                    const Token *argtok = args[argnr];
                    if (!argtok->hasKnownIntValue())
                        continue;
                    if (argtok->values().front().intvalue != 0)
                        continue;
                    if (mSettings->library.isnullargbad(tok, argnr+1))
                        nullPointerError(argtok);
                }
            }

            else if (Token::Match(tok->previous(), ">> 0|NULL|nullptr")) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
                const Token* tok2 = tok->previous(); // Find start of statement
                for (; tok2; tok2 = tok2->previous()) {
                    if (Token::Match(tok2->previous(), ";|{|}|:|("))
                        break;
                }
                if (tok2 && tok2->previous() && tok2->previous()->str()=="(")
                    continue;
                if (Token::simpleMatch(tok2, "std :: cin"))
                    nullPointerError(tok);
                if (tok2 && tok2->varId() != 0) {
                    const Variable *var = tok2->variable();
                    if (var && var->isStlType(stl_istream))
                        nullPointerError(tok);
                }
            }

            const Variable *ovar = nullptr;
            const Token *tokNull = nullptr;
            if (Token::Match(tok, "0|NULL|nullptr ==|!=|>|>=|<|<= %var%")) {
                if (!Token::Match(tok->tokAt(3),".|[")) {
                    ovar = tok->tokAt(2)->variable();
                    tokNull = tok;
                }
            } else if (Token::Match(tok, "%var% ==|!=|>|>=|<|<= 0|NULL|nullptr") ||
                       Token::Match(tok, "%var% =|+ 0|NULL|nullptr )|]|,|;|+")) {
                ovar = tok->variable();
                tokNull = tok->tokAt(2);
            }
            if (ovar && !ovar->isPointer() && !ovar->isArray() && ovar->isStlStringType() && tokNull && tokNull->originalName() != "'\\0'")
                nullPointerError(tokNull);
        }
    }
}
Ejemplo n.º 13
0
void CheckNullPointer::nullPointerLinkedList()
{

    if (!mSettings->isEnabled(Settings::WARNING))
        return;

    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();

    // looping through items in a linked list in a inner loop.
    // Here is an example:
    //    for (const Token *tok = tokens; tok; tok = tok->next) {
    //        if (tok->str() == "hello")
    //            tok = tok->next;   // <- tok might become a null pointer!
    //    }
    for (const Scope &forScope : symbolDatabase->scopeList) {
        const Token* const tok1 = forScope.classDef;
        // search for a "for" scope..
        if (forScope.type != Scope::eFor || !tok1)
            continue;

        // is there any dereferencing occurring in the for statement
        const Token* end2 = tok1->linkAt(1);
        for (const Token *tok2 = tok1->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
            // Dereferencing a variable inside the "for" parentheses..
            if (Token::Match(tok2, "%var% . %name%")) {
                // Is this variable a pointer?
                const Variable *var = tok2->variable();
                if (!var || !var->isPointer())
                    continue;

                // Variable id for dereferenced variable
                const unsigned int varid(tok2->varId());

                if (Token::Match(tok2->tokAt(-2), "%varid% ?", varid))
                    continue;

                // Check usage of dereferenced variable in the loop..
                // TODO: Move this to ValueFlow
                for (const Scope *innerScope : forScope.nestedList) {
                    if (innerScope->type != Scope::eWhile)
                        continue;

                    // TODO: are there false negatives for "while ( %varid% ||"
                    if (Token::Match(innerScope->classDef->next(), "( %varid% &&|)", varid)) {
                        // Make sure there is a "break" or "return" inside the loop.
                        // Without the "break" a null pointer could be dereferenced in the
                        // for statement.
                        for (const Token *tok4 = innerScope->bodyStart; tok4; tok4 = tok4->next()) {
                            if (tok4 == forScope.bodyEnd) {
                                const ValueFlow::Value v(innerScope->classDef, 0LL);
                                nullPointerError(tok1, var->name(), &v, false);
                                break;
                            }

                            // There is a "break" or "return" inside the loop.
                            // TODO: there can be false negatives. There could still be
                            //       execution paths that are not properly terminated
                            else if (tok4->str() == "break" || tok4->str() == "return")
                                break;
                        }
                    }
                }
            }
        }
    }
}
Ejemplo n.º 14
0
/** Dereferencing null constant (simplified token list) */
void CheckNullPointer::nullConstantDereference()
{
	const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
	for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
		if (i->type != Scope::eFunction || !i->classStart)
			continue;

		const Token *tok = i->classStart;

		if (i->function && (i->function->type == Function::eConstructor || i->function->type == Function::eCopyConstructor))
			tok = i->function->token; // Check initialization list

		for (; tok && tok != i->classEnd; tok = tok->next()) {
			if (Token::Match(tok, "sizeof|decltype|typeid ("))
				tok = tok->next()->link();

			else if (tok && Token::simpleMatch(tok, "* 0")) {
				if (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isOp() || tok->previous()->isAssignmentOp()) {
					nullPointerError(tok);
				}
			}

			else if (tok && Token::Match(tok, "0 [") && (tok->previous()->str() != "&" || !Token::Match(tok->next()->link()->next(), "[.(]")))
				nullPointerError(tok);

			else if (tok && Token::Match(tok->previous(), "!!. %var% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
				if (Token::simpleMatch(tok->tokAt(2), "0 )") && tok->varId()) { // constructor call
					const Variable* var = symbolDatabase->getVariableFromVarId(tok->varId());
					if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
						nullPointerError(tok);
				} else { // function call
					std::list<const Token *> var;
					parseFunctionCall(*tok, var, 0);

					// is one of the var items a NULL pointer?
					for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
						if (Token::Match(*it, "0 [,)]")) {
							nullPointerError(*it);
						}
					}
				}
			} else if (Token::simpleMatch(tok, "std :: string ( 0 )"))
				nullPointerError(tok);

			else if (tok && Token::simpleMatch(tok->previous(), ">> 0")) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
				const Token* tok2 = tok->previous(); // Find start of statement
				for (; tok2; tok2 = tok2->previous()) {
					if (Token::Match(tok2->previous(), ";|{|}|:"))
						break;
				}
				if (Token::simpleMatch(tok2, "std :: cin"))
					nullPointerError(tok);
				if (tok2 && tok2->varId() != 0) {
					const Variable* var = symbolDatabase->getVariableFromVarId(tok2->varId());
					if (var && Token::Match(var->typeStartToken(), "std :: istream|ifstream|istringstream|stringstream|fstream|iostream"))
						nullPointerError(tok);
				}
			}

			unsigned int ovarid = 0;
			if (Token::Match(tok, "0 ==|!= %var%"))
				ovarid = tok->tokAt(2)->varId();
			else if (Token::Match(tok, "%var% ==|!= 0"))
				ovarid = tok->varId();
			else if (Token::Match(tok, "%var% =|+=|+ 0 )|]|,|;|+"))
				ovarid = tok->varId();
			if (ovarid) {
				const Variable* var = symbolDatabase->getVariableFromVarId(ovarid);
				if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string !!::"))
					nullPointerError(tok);
			}
		}
	}
}
Ejemplo n.º 15
0
//dereferenceBeforeCheck
void CheckNullPointer::nullPointerByDeRefAndChec()
{
	const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();

	// Dereferencing a pointer and then checking if it's NULL..
	// This check will first scan for the check. And then scan backwards
	// from the check, searching for dereferencing.
	for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
		// TODO: false negatives.
		// - logical operators
		const Token* tok = i->classDef;
		if ((i->type == Scope::eIf || i->type == Scope::eElseIf || i->type == Scope::eWhile) &&
			tok && Token::Match(tok, "else| %var% ( !| %var% )|%oror%|&&") && !tok->next()->isExpandedMacro()) {

				if (tok->str() == "else")
					tok = tok->next();

				const Token * vartok = tok->tokAt(2);
				if (vartok && vartok->str() == "!")
					vartok = vartok->next();

				if(!vartok)
					continue;
				// Variable id for pointer
				const unsigned int varid(vartok->varId());
				if (varid == 0)
					continue;

				// Name of pointer
				const std::string& varname(vartok->str());

				const Variable* var = symbolDatabase->getVariableFromVarId(varid);
				// Check that variable is a pointer..
				if (!var || !var->isPointer())
					continue;

				const Token * const decltok = var->nameToken();
				bool inconclusive = false;

				for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous()) {
					if (tok1->str() == ")" && Token::Match(tok1->link()->previous(), "%var% (")) {
						const Token *tok2 = tok1->link();
						while (tok2 && !Token::Match(tok2, "[;{}?:]"))
							tok2 = tok2->previous();
						if (tok2 && Token::Match(tok2, "[?:]"))
							break;
						if (tok2 && Token::Match(tok2->next(), "%varid% = %var%", varid))
							break;

						if (tok2 && Token::Match(tok2->next(), "while ( %varid%", varid))
							break;

						if (Token::Match(tok1->link(), "( ! %varid% %oror%", varid) ||
							Token::Match(tok1->link(), "( %varid% &&", varid)) {
								tok1 = tok1->link();
								continue;
						}

						if (Token::simpleMatch(tok1->link()->previous(), "sizeof (")) {
							tok1 = tok1->link()->previous();
							continue;
						}

						if (tok2 && Token::Match(tok2->next(), "%var% ( %varid% ,", varid)) {
							std::list<const Token *> varlist;
							parseFunctionCall(*(tok2->next()), varlist, 0);
							if (!varlist.empty() && varlist.front() == tok2->tokAt(3)) {
								nullPointerError(tok2->tokAt(3), varname, tok, inconclusive);
								// break;
								continue;
							}
						}

						// Passing pointer as parameter..
						if (tok2 && Token::Match(tok2->next(), "%type% (")) {
							bool unknown = false;
							if (CanFunctionAssignPointer(tok2->next(), varid, unknown)) {
								if (!_settings->inconclusive || !unknown)
									break;
								inconclusive = true;
							}
						}

						// calling unknown function => it might initialize the pointer
						if (!(var->isLocal() || var->isArgument()))
							break;
					}

					if (tok1->str() == "break")
						break;

					if (tok1->varId() == varid) {
						// Don't write warning if the dereferencing is
						// guarded by ?: or &&
						const Token *tok2 = tok1->previous();
						if (tok2 && (tok2->isArithmeticalOp() || tok2->str() == "(")) {
							while (tok2 && !Token::Match(tok2, "[;{}?:]")) {
								if (tok2->str() == ")") {
									tok2 = tok2->link();
									if (Token::Match(tok2, "( %varid% =", varid)) {
										tok2 = tok2->next();
										break;
									}
								}
								// guarded by &&
								if (tok2->varId() == varid && tok2->next()->str() == "&&")
									break;
								tok2 = tok2->previous();
							}
						}
						if (!tok2 || Token::Match(tok2, "[?:]") || tok2->varId() == varid)
							continue;

						// unknown : this is set by isPointerDeRef if it is
						//           uncertain
						bool unknown = _settings->inconclusive;

						// reassign : is the pointer reassigned like this:
						//            tok = tok->next();
						bool reassign = false;
						if (Token::Match(tok1->previous(), "= %varid% .", varid)) {
							const Token *back = tok1->tokAt(-2);
							while (back) {
								if (back->varId() == varid) {
									reassign = true;
									break;
								}
								if (Token::Match(back, "[{};,(]")) {
									break;
								}
								back = back->previous();
							}
						}

						if (reassign) {
							break;
						} else if (Token::simpleMatch(tok1->tokAt(-2), "* )") &&
							Token::Match(tok1->linkAt(-1)->tokAt(-2), "%varid% = (", tok1->varId())) {
								break;
						} else if (Token::simpleMatch(tok1->tokAt(-3), "* ) (") &&
							Token::Match(tok1->linkAt(-2)->tokAt(-2), "%varid% = (", tok1->varId())) {
								break;
						} else if (Token::Match(tok1->previous(), "&&|%oror%")) {
							break;
						} else if (Token::Match(tok1->tokAt(-2), "&&|%oror% !")) {
							break;
						} else if (CheckNullPointer::isPointerDeRef(tok1, unknown, symbolDatabase)) {
							nullPointerError(tok1, varname, tok, inconclusive);
							break;
						} else if (tok1->strAt(-1) == "&") {
							break;
						} else if (tok1->strAt(1) == "=") {
							break;
						}
					}

					else if (tok1->str() == "{" ||
						tok1->str() == "}")
						break;

					// label..
					else if (Token::Match(tok1, "%type% :"))
						break;
				}
		}
	}
}