Collections crate that uses allocator api

Is there some crate that implements collections, such as vector or hashmaps but uses the new allocator API solely, that is, doesn't rely on the GlobalAlloc trait?

Both std::vec::Vec and hashbrown::HashMap use the allocator API, allowing you to specify an allocator. Is that not what you're referring to?

Yes they do. But I found out that in-order to use the alloc crate in a no-std binary, you need to define a #[global_allocator] nevertheless.
Or am I wrong about this part?

I haven’t tried it, but I assume you could define a global allocator that simply panics whenever an allocation request comes in. It’s not the best solution, as the errors come at runtime instead of compile time, but it might get the job done in practice.

4 Likes

Thanks! I'll try it out.

I just pulled up the docs for GlobalAlloc, and panicking is UB. You can return a NULL pointer from the allocation methods, though, to indicate an allocation failure. All of the other methods require a previously-allocated chunk to be passed in— If you never gave any of those out, the program is already in UB-land anyway.

So I guess the solution would be return null from alloc and put unreachable in the rest since they literally should not be called?

3 Likes

That’s essentially the way I read it:

  • alloc always returns null
  • dealloc calls unreachable!
  • Default implementation for everything else
3 Likes

With Allocator::deallocate it's clear (nonnull), but for GlobalAlloc::dealloc it's not - is a null pointer a legal input to dealloc? Given how free works, I assume it is and is a no-op. So that's how I'd implement dealloc.

5 Likes

No-op would certainly be acceptable here. I’m basing my UB claim on this clause from the dealloc docs:

This function is unsafe because undefined behavior can result if the caller does not ensure all of the following:

  • ptr must denote a block of memory currently allocated via this allocator,
  • layout must be the same layout that was used to allocate that block of memory.

As ‘this allocator’ never allocates blocks of memory, it’s always UB to call its dealloc method. If you’re feeling particularly daring, I’m pretty sure unreachable_unchecked would be valid here, which might optimize out all code paths that involve a successful allocation. Personally, that seems like too risky a move.


Also, the alloc docs say that the method

Returns a pointer to newly-allocated memory, or null to indicate allocation failure.

I don’t believe that an explicitly-listed sentinel value indicating failure can reasonably be construed as representing a “block of memory currently allocated”.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.