Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22299

GCC -Wdangling-pointer correct or bug?

$
0
0

I ran into some code that builds a linked list on the stack and via destructors cleans up correctly AFAICT

Code:

#include <iostream>#include <sstream>template <typename T>struct ConsList{    T value;    ConsList<T> *tail;};struct NodeStackGuard{    ConsList<const char*> oldNodeStack;    ConsList<const char*> &nodeStack;    NodeStackGuard(ConsList<const char *> &nodeStack, const char *str)        : oldNodeStack(nodeStack), nodeStack(nodeStack)    {        nodeStack = {str, &oldNodeStack};    }    ~NodeStackGuard() { nodeStack = oldNodeStack; }};void printPath(const ConsList<const char *>* node){    if (node) {        if (node->value) {            std::cout << node->value;        }        printPath(node->tail);    } else {        std::cout << "\n";    }}void push(int depth, ConsList<const char *>& stack){    std::stringstream ss;    ss << " depth: " << depth;    std::string s(ss.str());    NodeStackGuard guard(stack, s.c_str());    if (depth > 0) {        push(depth - 1, stack);    } else {        printPath(&stack);    }}int main(){    ConsList<const char *> stack{nullptr, nullptr};    push(5, stack);}

Note: The actual code was not stacking strings, it was stacking pointers to parents while traversing an AST so that it could access the parents while deep in the AST hierarchy.

To explain what's happening. At the bottom a "stack" is started

ConsList<const char *> stack{nullptr, nullptr};

So we have

stack: {value: null, tail: null}

At the first iteration of push we create guard0

guard0: oldNodeStack: {value: null, tail: null}, nodeStack: stackstack:  {value: "depth 5", tail: guard0}

At the 2nd iteration of push we'd have this

guard1: oldNodeStack: {value: "depth 5", tail: guard0}, nodeStack: stackguard0: oldNodeStack: {value: null, tail: null},        nodeStack: stackstack:  {value: "depth 4", tail: guard1}

At the 3rd iteration of push we'd have this

guard2: oldNodeStack: {value: "depth 4", tail: guard1}, nodeStack: stackguard1: oldNodeStack: {value: "depth 5", tail: guard0}, nodeStack: stackguard0: oldNodeStack: {value: null, tail: null},        nodeStack: stackstack:  {value: "depth 3", tail: guard2}

Following that you see stack->guard2->guard1->guard0

Going backward, at the end of push guard2's destructorwill restore `stack' so we'd have this

guard2: destroyedguard1: oldNodeStack {value: "depth 5", tail: guard0}, nodeStack: stackguard0: oldNodeStack {value: null, tail: null},        nodeStack: stackstack:  {value: "depth 4", tail: guard1}               // restored by guard2's destructor

again

guard1: destroyedguard0: oldNodeStack {value: null, tail: null},        nodeStack: stackstack:  {value: "depth 5", tail: guard0}               // restored by guard1's destructor

again

guard0: destroyedstack:  {value: null, tail: null}                     // restored by guard0's destructor

The issue is, with -Wdangling-pointer GCC complains

warning: storing the address of local variable 

As far as I can tell there's nothing wrong with the code above.

A pointer is made to a variable that exists on the stack but that pointer is deleted when the local variable is deleted so nothing is dangling AFAICT.

I'm am missing where the dangling pointer is? Is this a bug in GCC? Is there some quirk of C++ I'm unaware of that's being triggered here? Is this just a limitation of what's possible it check for and I need to disable the warning?


Viewing all articles
Browse latest Browse all 22299

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>