Skip to content

Fix broken detached storage ownership in gtl::vector extensions#50

Merged
greg7mdp merged 5 commits into
greg7mdp:mainfrom
zhao-shihan:fix/vector-detached-storage-ownership
Mar 30, 2026
Merged

Fix broken detached storage ownership in gtl::vector extensions#50
greg7mdp merged 5 commits into
greg7mdp:mainfrom
zhao-shihan:fix/vector-detached-storage-ownership

Conversation

@zhao-shihan

Copy link
Copy Markdown
Contributor

Summary

This PR fixes two critical issues in the gtl vector ownership-transfer extensions and makes detached storage deallocation allocator-correct.

Files Changed

  • vector.hpp

Problem Statement

  1. The previous steal_data implementation attempted to call impl_.set(nullptr, nullptr, nullptr), which is not type-correct because set expects size_type values for size and capacity.
  2. The previous extension API used std::unique_ptr with the default deleter, which is incompatible with vector storage allocated via malloc/free or allocator allocate/deallocate paths. This can lead to invalid deallocation and undefined behavior.

What Changed

  1. Added detached_storage_deleter that stores allocator_type and capacity, and deallocates through the correct allocator path.
  2. Added detached_storage_ptr as an alias for unique_ptr with detached_storage_deleter.
  3. Changed the extension constructor from the old std::unique_ptr-based signature to vector(detached_storage_ptr data, size_type sz).
  4. Updated steal_data to return detached_storage_ptr and directly null internal pointers after detaching storage, instead of calling impl_.set with nullptr arguments.
  5. Added basic assertions for detached buffer invariants (for example, sz <= cap).

Behavioral and Safety Impact

  1. Fixes compile-time breakage in the previous steal_data path.
  2. Ensures detached storage is freed in a way consistent with the original allocation strategy.
  3. Limits changes to extension APIs only; normal vector operations are not altered.

Breaking Change Note

This change is API-breaking for two gtl extensions (constructor and steal_data return type).
However, the previous API was already functionally broken and unsafe. Therefore, the project should choose one of these two directions:

  1. Merge this PR as a corrective API break.
  2. Remove these two gtl extension APIs entirely.

Migration Notes

Callers using the previous unique_ptr-based extension API should migrate to detached_storage_ptr and detached_storage_deleter so deallocation remains allocator-correct.

@zhao-shihan zhao-shihan force-pushed the fix/vector-detached-storage-ownership branch from 34f69d9 to 6340eae Compare March 29, 2026 13:32
@zhao-shihan

Copy link
Copy Markdown
Contributor Author

I found that vector::Impl::data is buggy (it returns the end of the storage) but not referenced any more, so I removed that.

@zhao-shihan

Copy link
Copy Markdown
Contributor Author

Oh, I forgot to update tests. I'll fix that.

@greg7mdp

Copy link
Copy Markdown
Owner

Hi @zhao-shihan , thank you for the great PR. Please leave the data() api which is in the standard, but fix the issue by returning b_, and then use it in steal_data() instead of b_.

@zhao-shihan

Copy link
Copy Markdown
Contributor Author

Hi @zhao-shihan , thank you for the great PR. Please leave the data() api which is in the standard, but fix the issue by returning b_, and then use it in steal_data() instead of b_.

Hi @greg7mdp!

Fixed in 962aca0.

Comment thread include/gtl/vector.hpp Outdated

// ------------------- gtl extensions -------------------------------------------------------
struct detached_storage_deleter {
allocator_type alloc;

@greg7mdp greg7mdp Mar 29, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be allocator_type &alloc here, so we use the same allocator instance to deallocate the detached storage as the one that allocated it and was passed in the detached_storage_ptr to the constructor at line 745. In essence the vector created with this special constructor should continue using the same allocator instance that was used to allocate the buffer I think. This is to address the case of stateful allocators.

Well, it is more complicated than that, but I think we can't just assume that creating a new allocator is acceptable in all cases. Maybe we need to have alternative constructors for detached_storage_deleter , including one that takes a rvalue for the allocator.

@greg7mdp greg7mdp Mar 29, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still this PR is better than the previous code. Maybe we can merge this and address remaining issues later. I am travelling and I can't investigate this as well as I'd like.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here shouldn't be an allocator reference because

  1. After steal_data, the vector turns into a "null" state and can be deconstruted. If so, the allocator instance is also deconstruted and the allocator reference will dangling.
  2. A reference member makes the deleter not default constructible, and this also propagates to the unique_ptr, which is not very easy to use.

Here, when the deleter is constructed, only the allocator is copied instead of the whole vector::Impl. I think copy the allocator is OK because all sane allocators passed to a container are stateless (because the standard API not plays well with stateful allocators, e.g. vector constructor copys an allocator, and vector::get_allocator also returns a copy of the allocator).

Actually here detached_storage_deleter can be more compact by marking alloc as [[no_unique_address]], since stateless allocators often have no data members. For example, std::allocator.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still this PR is better than the previous code. Maybe we can merge this and address remaining issues later. I am travelling and I can't investigate this as well as I'd like.

OK, just take your time. It's not urgent.

@zhao-shihan zhao-shihan force-pushed the fix/vector-detached-storage-ownership branch from 6216a01 to 621ea67 Compare March 29, 2026 15:51
@greg7mdp greg7mdp merged commit 3b91b88 into greg7mdp:main Mar 30, 2026
6 checks passed
@greg7mdp

Copy link
Copy Markdown
Owner

Thanks again @zhao-shihan !

@zhao-shihan zhao-shihan deleted the fix/vector-detached-storage-ownership branch April 2, 2026 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants