Skip to content

allow Allocators to be used as #[global_allocator]s#157153

Open
joboet wants to merge 3 commits into
rust-lang:mainfrom
joboet:global_allocator
Open

allow Allocators to be used as #[global_allocator]s#157153
joboet wants to merge 3 commits into
rust-lang:mainfrom
joboet:global_allocator

Conversation

@joboet
Copy link
Copy Markdown
Member

@joboet joboet commented May 30, 2026

The (hopefully) immanent stabilisation of the Allocator trait raises the question of what is to be done about the older, already-stable GlobalAlloc trait. In my opinion, having two nearly-identical traits for the same purpose is needlessly confusing. Going forward, Allocator as the more modern interface should be the allocator trait.

With Allocator being currently unstable, there is the possibility of implementing GlobalAlloc for all Allocators, thereby allowing them to be used as #[global_allocator] and allowing crates to seamlessly (and semver-compatibly) switch to Allocator. However, unconditionally implementing GlobalAlloc presents a footgun to users, as e.g. using Global as #[global_allocator] will lead to infinite recursion. @nia-e initially tried to resolve this in e1b7097 (#156882) by using weird trait trickery to implement GlobalAlloc for every allocator except Global. But this does not go far enough, e.g. a bump allocator that itself allocates from Global is 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]:

// in core::alloc

trait GlobalAllocator: Allocator {}

GlobalAlloc can then be implemented for all GlobalAllocators:

impl<A> GlobalAlloc for A
where
    A: GlobalAllocator
{
    /* ... */
}

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 that GlobalAlloc will become more and more of an implementation detail of the #[global_allocator] macro (for instance, one might add perma-unstable, hidden methods for things like grow_zeroed that are customised only by the blanket implementation).

With regards to naming, I chose GlobalAllocator to mirror Allocator. GlobalAlloc should probably be deprecated quickly after stabilising GlobalAllocator to avoid confusion. For the same reason, I think it'd be better to add GlobalAllocator before stabilising Allocator – but that is not a necessity.

r? @nia-e
@rustbot label +I-libs-api-nominated

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 30, 2026
@rustbot

This comment has been minimized.

@rustbot rustbot added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label May 30, 2026
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer
Copy link
Copy Markdown
Collaborator

The job x86_64-gnu-miri failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
tests/fail/tree_borrows/wildcard/subtree_internal_relatedness.rs ... ok
tests/fail/tree_borrows/wildcard/subtree_internal_relatedness_wildcard.rs ... ok

FAILED TEST: tests/fail/alloc/global_system_mixup.rs
command: MIRI_ENV_VAR_TEST="0" MIRI_TEMP="/tmp/miri-uitest-RWaWuj" RUST_BACKTRACE="1" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/release/miri" "--error-format=json" "--sysroot=/checkout/obj/build/x86_64-unknown-linux-gnu/miri-sysroot" "-Dwarnings" "-Dunused" "-Ainternal_features" "-Zui-testing" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/tmp/miri_ui/0/tests/fail/alloc" "tests/fail/alloc/global_system_mixup.rs" "--edition" "2021"

error: actual output differed from expected
Execute `./miri test --bless` to update `tests/fail/alloc/global_system_mixup.stderr` to the actual output
--- tests/fail/alloc/global_system_mixup.stderr
+++ <stderr output>
---
Location:
   /cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ui_test-0.30.5/src/lib.rs:365

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   1: <color_eyre[e6538edabc56319b]::config::EyreHook>::into_eyre_hook::{closure#0}<unknown>
      at <unknown source file>:<unknown line>
   2: eyre[a1ff9ab0cec10395]::capture_handler<unknown>
      at <unknown source file>:<unknown line>
   3: eyre[a1ff9ab0cec10395]::private::format_err<unknown>
      at <unknown source file>:<unknown line>
   4: ui_test[ab4a314f2f7c2eee]::run_tests_generic::<ui_test[ab4a314f2f7c2eee]::default_file_filter, ui[49cfd3b95c6867e5]::run_tests::{closure#1}, alloc[5177c7dff3210e7c]::boxed::Box<dyn ui_test[ab4a314f2f7c2eee]::status_emitter::StatusEmitter>><unknown>
      at <unknown source file>:<unknown line>
   5: ui[49cfd3b95c6867e5]::ui<unknown>
      at <unknown source file>:<unknown line>
   6: ui[49cfd3b95c6867e5]::main<unknown>
      at <unknown source file>:<unknown line>
   7: std[a074f615509283a]::sys::backtrace::__rust_begin_short_backtrace::<fn() -> core[158a6f452d22dda3]::result::Result<(), eyre[a1ff9ab0cec10395]::Report>, core[158a6f452d22dda3]::result::Result<(), eyre[a1ff9ab0cec10395]::Report>><unknown>
      at <unknown source file>:<unknown line>
   8: std[a074f615509283a]::rt::lang_start::<core[158a6f452d22dda3]::result::Result<(), eyre[a1ff9ab0cec10395]::Report>>::{closure#0}<unknown>
      at <unknown source file>:<unknown line>
   9: std[a074f615509283a]::rt::lang_start_internal<unknown>
      at <unknown source file>:<unknown line>
  10: main<unknown>
      at <unknown source file>:<unknown line>
  11: __libc_start_main<unknown>
      at <unknown source file>:<unknown line>
  12: _start<unknown>
      at <unknown source file>:<unknown line>

Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering.
Run with RUST_BACKTRACE=full to include source snippets.
error: test failed, to rerun pass `--test ui`

Caused by:
  process didn't exit successfully: `/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/release/deps/ui-c78e55c335da16a3` (exit status: 1)
Bootstrap failed while executing `test --stage 2 src/tools/miri src/tools/miri/cargo-miri`
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo test -Zwarnings --target x86_64-unknown-linux-gnu -Zbinary-dep-depinfo -j 4 -Zroot-dir=/checkout --locked --color=always --profile=release --manifest-path /checkout/src/tools/miri/Cargo.toml -- [workdir=/checkout]` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:191:21
Executed at: src/bootstrap/src/core/build_steps/test.rs:740:19

--- BACKTRACE vvv
   0: <bootstrap::utils::exec::DeferredCommand>::finish_process
             at /checkout/src/bootstrap/src/utils/exec.rs:939:17
   1: <bootstrap::utils::exec::DeferredCommand>::wait_for_output::<&bootstrap::utils::exec::ExecutionContext>
             at /checkout/src/bootstrap/src/utils/exec.rs:831:21
   2: <bootstrap::utils::exec::ExecutionContext>::run
             at /checkout/src/bootstrap/src/utils/exec.rs:741:45
   3: <bootstrap::utils::exec::BootstrapCommand>::run::<&bootstrap::core::builder::Builder>
             at /checkout/src/bootstrap/src/utils/exec.rs:339:27
   4: <bootstrap::core::build_steps::test::Miri as bootstrap::core::builder::Step>::run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:740:19
   5: <bootstrap::core::builder::Builder>::ensure::<bootstrap::core::build_steps::test::Miri>
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1595:36
   6: <bootstrap::core::build_steps::test::Miri as bootstrap::core::builder::Step>::make_run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:666:21
   7: <bootstrap::core::builder::StepDescription>::maybe_run
             at /checkout/src/bootstrap/src/core/builder/mod.rs:476:13
   8: bootstrap::core::builder::cli_paths::match_paths_to_steps_and_run
             at /checkout/src/bootstrap/src/core/builder/cli_paths.rs:232:18
   9: <bootstrap::core::builder::Builder>::run_step_descriptions
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1138:9
  10: <bootstrap::core::builder::Builder>::execute_cli
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1117:14
  11: <bootstrap::Build>::build
             at /checkout/src/bootstrap/src/lib.rs:803:25
  12: bootstrap::main
             at /checkout/src/bootstrap/src/bin/main.rs:130:11
  13: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/ops/function.rs:250:5
  14: std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/sys/backtrace.rs:166:18
  15: std::rt::lang_start::<()>::{closure#0}
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/rt.rs:206:18
  16: <&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe as core::ops::function::FnOnce<()>>::call_once
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/ops/function.rs:287:21
  17: std::panicking::catch_unwind::do_call::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
  18: std::panicking::catch_unwind::<i32, &dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
  19: std::panic::catch_unwind::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
  20: std::rt::lang_start_internal::{closure#0}
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/rt.rs:175:24
  21: std::panicking::catch_unwind::do_call::<std::rt::lang_start_internal::{closure#0}, isize>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
---
  28: __libc_start_main
  29: _start


Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:42:20
  local time: Sat May 30 14:05:45 UTC 2026
  network time: Sat, 30 May 2026 14:05:45 GMT
##[error]Process completed with exit code 1.
##[group]Run echo "disk usage:"

/// * 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 {}
Copy link
Copy Markdown
Member

@nia-e nia-e May 30, 2026

Choose a reason for hiding this comment

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

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

View changes since the review

@nia-e
Copy link
Copy Markdown
Member

nia-e commented May 30, 2026

Seems great! I just had one two comments, but otherwise r=me

#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe impl<A> GlobalAlloc for A
where
A: GlobalAllocator,
Copy link
Copy Markdown
Member

@nia-e nia-e May 30, 2026

Choose a reason for hiding this comment

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

Suggested change
A: GlobalAllocator,
A: GlobalAllocator + ?Sized,

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-libs-api-nominated Nominated for discussion during a libs-api team meeting. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants