On Mon, 17 Jun 2024 at 11:18, Jonathan Wakely <jwak...@redhat.com> wrote: > > On Sat, 15 Jun 2024 at 14:04, François Dumont <frs.dum...@gmail.com> wrote: > > > > Here is the simplified patch then. > > The use of std::__to_address seems wrong. > > The allocator returns a __buckets_ptr, and that function returns a > __buckets_ptr, so it should just be returned unchanged, not by > converting to a raw pointer with __to_address.
It was already wrong, but we should fix that now not keep it wrong. Using __to_address to get a pointer to pass to memset was correct. But the result of the __to_address call was used to initialize another __buckets_ptr variable. Which is what we already had before calling __to_address. It would have made sense like this: auto __ptr = __buckets_alloc_traits::allocate(__alloc, __bkt_count); auto* __p = std::__to_address(__ptr); __builtin_memset(__p, 0, __bkt_count * sizeof(__node_base_ptr)); return __ptr; i.e. __p should be a raw pointer (not a __buckets_ptr), and then it should return __ptr not __p. But that isn't what we had. Anyway, now that we're not using memset, we don't need any raw pointer at all, so don't need std::__to_address at all. > > > > > > libstdc++: Do not use memset in _Hashtable buckets allocation > > > > Using memset is incorrect if the __bucket_ptr type is non-trivial, or > > does not use an all-zero bit pattern for its null value. > > > > Replace the use of memset with std::__uinitialized_default_n to set the > > pointers to nullptr. Doing so and corresponding std::_Destroy_n > > when deallocating > > buckets. > > > > libstdc++-v3/ChangeLog: > > > > * include/bits/hashtable_policy.h > > (_Hashtable_alloc::_M_allocate_buckets): Do not use memset > > to zero > > out bucket pointers. > > (_Hashtable_alloc::_M_deallocate_buckets): Add destroy of > > buckets. > > > > Tested under Linux x64, ok to commit ? > > > > François > > > > On 13/06/2024 20:58, Jonathan Wakely wrote: > > > On Thu, 13 Jun 2024 at 19:57, Jonathan Wakely <jwak...@redhat.com> wrote: > > >> On Thu, 13 Jun 2024 at 18:40, François Dumont <frs.dum...@gmail.com> > > >> wrote: > > >>> Hi > > >>> > > >>> Following your recent change here: > > >>> > > >>> https://gcc.gnu.org/pipermail/libstdc++/2024-June/058998.html > > >>> > > >>> I think we also need to fix the memset at bucket allocation level. > > >>> > > >>> I did it trying also to be more fancy pointer friendly by running > > >>> __uninitialized_default_n_a on the allocator returned pointer rather > > >>> than on the __to_address result. I wonder if an __uninitialized_fill_n_a > > >>> would have been better ? Doing so I also had to call std::_Destroy on > > >>> deallocation. Let me know if it is too early. > > >> You don't need the RAII guard. Initializing Alloc::pointer isn't > > >> allowed to throw exceptions: > > >> > > >> "An allocator type X shall meet the Cpp17CopyConstructible > > >> requirements (Table 32). The XX::pointer, > > >> XX::const_pointer, XX::void_pointer, and XX::const_void_pointer types > > >> shall meet the Cpp17Nullable- > > >> Pointer requirements (Table 36). No constructor, comparison operator > > >> function, copy operation, move > > >> operation, or swap operation on these pointer types shall exit via an > > >> exception." > > >> > > >> And you should not pass the allocator to the __uninitialized_xxx call, > > >> nor the _Destroy call. We don't want to use the allocator's > > >> construct/destroy members for those pointers. They are not container > > >> elements. > > >> > > >> I think either uninitialized_fill_n with nullptr or > > >> __uninitialized_default_n is fine. Not the _a forms taking an > > >> allocator though. > > > And I'd use _Destroy_n(_M_buckets, _M_bucket_count) > > > > > > > > >>> I also wonder if the compiler will be able to optimize it to a memset > > >>> call ? I'm interested to work on it if you confirm that it won't. > > >> It will do whatever is fastest, which might be memset or might be > > >> vectorized code to zero it out (which is probably what libc memset > > >> does too). > > >> > > >>> libstdc++: Do not use memset in _Hashtable buckets allocation > > >>> > > >>> Using memset is incorrect if the __bucket_ptr type is non-trivial, or > > >>> does not use an all-zero bit pattern for its null value. > > >>> > > >>> Replace the use of memset with std::__uinitialized_default_n_a to set > > >>> the > > >>> pointers to nullptr. Doing so and corresponding std::_Destroy when > > >>> deallocating > > >>> buckets. > > >>> > > >>> libstdc++-v3/ChangeLog: > > >>> > > >>> * include/bits/hashtable_policy.h > > >>> (_Hashtable_alloc::_M_allocate_buckets): Do not use memset to zero > > >>> out bucket pointers. > > >>> (_Hashtable_alloc::_M_deallocate_buckets): Add destroy of buckets. > > >>> > > >>> > > >>> I hope you won't ask for copy rights on the changelog entry :-) > > >>> > > >>> Tested under Linux x64, ok to commit ? > > >>> > > >>> François