allow Allocators to be used as #[global_allocator]s#157153
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| /// * for wrappers of arbitrary allocators (which might end up being `Global`, | ||
| /// leading to infinite recursion). | ||
| #[unstable(feature = "allocator_api", issue = "32838")] | ||
| pub trait GlobalAllocator: Allocator {} |
There was a problem hiding this comment.
Should this be an unsafe trait? If so the safety contract can just be that it doesn't use std, and so we can do what was suggested in rust-lang/libs-team#743
There was a problem hiding this comment.
I initially thought that was unnecessary, but it definitely has to be: GlobalAlloc requires the allocator not to panic and allows the allocation-removal optimisation. These two requirements are not on Allocator, so I'll add them here.
There was a problem hiding this comment.
I think we want those requirements on Allocator as well, but I'd like to extend GlobalAllocator in the future with stuff that might be unsafe to set incorrectly (see https://hackmd.io/nNHdKkp1TTK7jat0I-ABqA#Conditional-reentrancy-in-std). Also, it might make sense to make Sync a supertrait too?
There was a problem hiding this comment.
I don't think adding Sync is a good idea as it may make it impossible for crates to upgrade from implementing GlobalAlloc to Allocator + GlobalAllocator.
|
Seems great! I just had |
| #[stable(feature = "global_alloc", since = "1.28.0")] | ||
| unsafe impl<A> GlobalAlloc for A | ||
| where | ||
| A: GlobalAllocator, |
There was a problem hiding this comment.
| A: GlobalAllocator, | |
| A: GlobalAllocator + ?Sized, |
|
Test failure may be related to rust-lang/miri#5067, see if setting that flag addresses it |
|
The following code does not compile on nightly, but compiles with this PR. That is, this PR has insta-stable behavior. use std::alloc::{GlobalAlloc, System};
fn require_global_alloc<T: GlobalAlloc>() {}
fn main() {
require_global_alloc::<&System>();
} |
I think this plan is reasonable, but I would strike marker trait: if we're writing a new trait I think it would also make sense to land rust-lang/libs-team#743 as required for the new trait, forcing implementors to opt in or out of the re-entrancy guarantees. I'd do that for GlobalAlloc too, we just can't do that backwards compatibly today. We have to have defaults anyway, so it's not too big a deal, but I think it's good for users to think about the configuration of at least the re-entrancy guarantees (not sure if we have other properties we'd put in the same bucket). cc @orlp |
|
Agreed with Mark here, this can be an unsafe trait with an associated constant à la |
|
We discussed this in the libs-api meeting today; our conclusions were
|
|
cc @rust-lang/miri |
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
I've added the bounds and removed the reference blanket-implementations, but would prefer not to add the reentrancy constant in this PR for fear of it being bikeshedded to eternity – is it okay to make that change later (obviously still before stabilisation)? On second thought, Also I've added another commit that probably leads to better optimisation of the @rustbot ready |
|
The job Click to see the possible cause of the failure (guessed by this bot) |
The (hopefully) immanent stabilisation of the
Allocatortrait raises the question of what is to be done about the older, already-stableGlobalAlloctrait. In my opinion, having two nearly-identical traits for the same purpose is needlessly confusing. Going forward,Allocatoras the more modern interface should be the allocator trait.With
Allocatorbeing currently unstable, there is the possibility of implementingGlobalAllocfor allAllocators, thereby allowing them to be used as#[global_allocator]and allowing crates to seamlessly (and semver-compatibly) switch toAllocator. However, unconditionally implementingGlobalAllocpresents a footgun to users, as e.g. usingGlobalas#[global_allocator]will lead to infinite recursion. @nia-e initially tried to resolve this in e1b7097 (#156882) by using weird trait trickery to implementGlobalAllocfor every allocator exceptGlobal. But this does not go far enough, e.g. a bump allocator that itself allocates fromGlobalis similarly unsuitable as global allocator.Thus, with this PR, I'd like to propose adding a new marker trait for allocators that can be used as
#[global_allocator]:GlobalAlloccan then be implemented for allGlobalAllocators:This provides a backwards-compatible way for allocator libraries to switch to the new interface and allows deprecating
GlobalAlloc(not done here). Over time, I expect thatGlobalAllocwill become more and more of an implementation detail of the#[global_allocator]macro (for instance, one might add perma-unstable, hidden methods for things likegrow_zeroedthat are customised only by the blanket implementation).With regards to naming, I chose
GlobalAllocatorto mirrorAllocator.GlobalAllocshould probably be deprecated quickly after stabilisingGlobalAllocatorto avoid confusion. For the same reason, I think it'd be better to addGlobalAllocatorbefore stabilisingAllocator– but that is not a necessity.r? @nia-e
@rustbot label +I-libs-api-nominated