Search code examples
c++cppcheck

Is it unsafe to take the address of a variable inside a loop where it is defined?


I came across a comment in cppcheck source code here, stating that it is unsafe to move the definition of i in the example into the inner loop. Why is that?

void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
 {
     reportError(tok,
                 Severity::style,
                 "variableScope",
                 "$symbol:" + varname + "\n"
                 "The scope of the variable '$symbol' can be reduced.\n"
                 "The scope of the variable '$symbol' can be reduced. Warning: Be careful "
                 "when fixing this message, especially when there are inner loops. Here is an "
                 "example where cppcheck will write that the scope for 'i' can be reduced:\n"
                 "void f(int x)\n"
                 "{\n"
                 "    int i = 0;\n"
                 "    if (x) {\n"
                 "        // it's safe to move 'int i = 0;' here\n"
                 "        for (int n = 0; n < 10; ++n) {\n"
                 "            // it is possible but not safe to move 'int i = 0;' here\n"
                 "            do_something(&i);\n"
                 "        }\n"
                 "    }\n"
                 "}\n"
                 "When you see this message it is always safe to reduce the variable scope 1 level.", CWE398, Certainty::normal);
 }

Solution

  • The question is focused on the second comment in this hypothetical code:

    void f(int x)
        int i = 0;
        if (x) {
            // it's safe to move 'int i = 0;' here
            for (int n = 0; n < 10; ++n) {
                 int i=0;
                 // it is possible but not safe to move 'int i = 0;' here
                 do_something(&i);
            }
        }
    }
    

    There is no general issue taking the address of a variable declared in a loop so long as that address (so taken) is not dereferenced after the loop.

    Here's a code fragment similar to the question with variable moved inside the loop as per that comment.

    int *p=nullptr;
    for(int n=0;n<10;++n){
        int i=0; //Where the code in question says it's possible but not safe!
        p=&i; 
        //can use value of p here.
    }
    //address of i assigned to p now invalid.
    

    This is the same general notion of variable scope that means pointers to local variables can't be used after the function that defined them returns(*). In this case in anything but the iteration the address was taken.

    int *q=nullptr;
    for(int n=0;n<10;++n){
        int i=0;
        if(n==0){
            q=&i;
        }else{
            //cannot use q here. 
            //That would using the address from the first iteration in a later iteration.
        }
    }
    

    So it's not clear what the original author's concern is. What is clear in the code as presented is i will be 0 when do_something(&i) is called every time and in the code as shown nothing is done with any value do_something() assigns to the variable through its pointer.

    Sometimes it is necessary to provide an address to a general purpose function that the specific caller doesn't then need to use.

    But the code provided isn't sufficient to explain the comment.

    (*) For the same reasons that the implementation may have released or reused the memory for other purposes as it leaves the relevant scope.