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

--- Comment #9 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jonathan Wakely <r...@gcc.gnu.org>:

https://gcc.gnu.org/g:fa8475b96579d16ae4e908b89104adcbcb9477b4

commit r15-6274-gfa8475b96579d16ae4e908b89104adcbcb9477b4
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Thu Dec 5 15:48:30 2024 +0000

    libstdc++: Simplify storage of hasher in local iterators

    The fix for PR libstdc++/56267 (relating to the lifetime of the hash
    object stored in a local iterator) has undefined behaviour, as it relies
    on being able to call a member function on an empty object that never
    started its lifetime. Although the member function probably doesn't care
    about the empty object's state, this is still technically undefined
    because there is no object of that type at that address. It's also
    possible that the hash object would have a stricter alignment than the
    _Hash_code_storage object, so that the reinterpret_cast would produce a
    misaligned pointer.

    This fix replaces _Local_iterator_base's _Hash_code_storage base-class
    with a new class template containing a potentially-overlapping (i.e.
    [[no_unique_address]]) union member.  This means that we always have
    storage of the correct type, and it can be initialized/destroyed when
    required. We no longer need a reinterpret_cast that gives us a pointer
    that we should not dereference.

    It would be nice if we could just use a union containing the _Hash
    object as a data member of _Local_iterator_base, but that would be an
    ABI change. The _Hash_code_storage that contains the _Hash object is the
    first base-class, before the _Node_iterator_base base-class. Making the
    union a data member of _Local_iterator_base would make it come after the
    _Node_iterator_base base instead of before it, altering the layout.

    Since we're changing _Hash_code_storage anyway, we can replace it with a
    new class template that stores the _Hash object itself in the union,
    rather than a _Hash_code_base that holds the _Hash. This removes an
    unnecessary level of indirection in the class hierarchy. This change
    requires the effects of _Hash_code_base::_M_bucket_index to be inlined
    into the _Local_iterator_base::_M_incr function, but that's easy.

    We don't need separate specializations of _Hash_obj_storage for an empty
    hash function and a non-empty one. Using [[no_unique_address]] gives us
    an empty base-class when possible.

    libstdc++-v3/ChangeLog:

            * include/bits/hashtable_policy.h (_Hash_code_storage): Remove.
            (_Hash_obj_storage): New class template. Store the hash
            function as a union member instead of using a byte buffer.
            (_Local_iterator_base): Use _Hash_obj_storage instead of
            _Hash_code_storage, adjust members that construct and destroy
            the hash object.
            (_Local_iterator_base::_M_incr): Calculate bucket index.

Reply via email to