https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119978

            Bug ID: 119978
           Summary: False positive Wdangling-pointer on intrusive list
                    implementatino
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This is a reduced implementation of an intrusive list, similar to how
boost::intrusive_list works:

struct ListNode {
    ListNode() = default;
    ListNode(ListNode&& rhs) noexcept
        : prev(rhs.prev)
        , next(rhs.next)
    {
        rhs.prev = nullptr;
        rhs.next = nullptr;

        if (linked()) {
            prev->next = this;
            next->prev = this;
        }
    }

    auto linked() const -> bool { return prev; }
    auto unlink() -> void {
        prev->next = next;
        next->prev = prev;
        prev = nullptr;
        next = nullptr;
    }

    ListNode* prev = nullptr;
    ListNode* next = nullptr;
};

struct ListAutoLink : ListNode {
    ListAutoLink() = default;
    ListAutoLink(ListAutoLink&&) = default;
    ~ListAutoLink() {
        if (linked()) {
            unlink();
        }
    }
};

struct Handle : public ListAutoLink
{
    int v;
    Handle(int v) : v(v) { }
};

struct Scheduler {
    struct IntrusiveList {
        ListNode node;

        IntrusiveList() {
            node.next = &node;
            node.prev = &node;
        }

        auto push_back(Handle& handle) -> void {
            ListNode& cur = handle;
            cur.next = &node;
            cur.prev = node.prev;
            node.prev->next = &cur;
            node.prev = &cur;
        }
    };

    IntrusiveList active_handles_;

    auto make_handle(int v) -> Handle {
        auto h = Handle(v);
        active_handles_.push_back(h);
        return h;
    }

    struct Wrapped {
        Handle h;
    };

    auto make_wrapped_handle(int v) -> Wrapped {
        Handle h = make_handle(v);
        return {.h=(Handle&&)h};
    }
};

int main() {
    Scheduler s;
    auto h1 = s.make_wrapped_handle(1);
    auto h2 = s.make_wrapped_handle(2);

    // make sure nothing is dangling
    ListNode* a = s.active_handles_.node.next;
    ListNode* b = a->next;
    ListNode* c = b->next;
    return (a == &h1.h and b == &h2.h and c == &s.active_handles_.node) ? 0 :
1;
}


gcc 14.2 -std=c++20 -Wall -O1, this gives a Wdangling-pointer warning here:

<source>:58:23: warning: storing the address of local variable 'h' in
'*(Scheduler::IntrusiveList*)this.Scheduler::IntrusiveList::node.ListNode::prev'
[-Wdangling-pointer=]
   58 |             node.prev = &cur;
      |             ~~~~~~~~~~^~~~~~


But nothing actually dangles. This program nevertheless returns 0, the move
constructor of Handle rebinds the pointers to make sure that it works. 

This is the best I could reduce it. Further reductions still emit the warning
on gcc 14.2 but no longer on gcc 15.1 (e.g. Handle inheriting directly from
ListNode instead of ListAutoLink), so there have been some improvements in this
area, but this particular one still warns.
  • [Bug c++/119978] New: False pos... barry.revzin at gmail dot com via Gcc-bugs

Reply via email to