Skip to content

Commit 1a9fc36

Browse files
orlpMark-Simulacrum
andcommitted
Add documentation guaranteeing global allocator use of TLS
Remove outdated part of comment claiming thread_local re-enters global allocator Fix typo in doc comment Add comments for guarantees given and footnote that System may still be called Revise mention of using the global allocator Allow for the possibility that the global allocator is the system allocator. Co-authored-by: Mark Rousskov <[email protected]>
1 parent d17b0c3 commit 1a9fc36

File tree

4 files changed

+49
-11
lines changed

4 files changed

+49
-11
lines changed

library/core/src/alloc/global.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,31 @@ use crate::{cmp, ptr};
115115
/// Whether allocations happen or not is not part of the program behavior, even if it
116116
/// could be detected via an allocator that tracks allocations by printing or otherwise
117117
/// having side effects.
118+
///
119+
/// # Re-entrance
120+
///
121+
/// When implementing a global allocator one has to be careful not to create an infinitely recursive
122+
/// implementation by accident, as many constructs in the Rust standard library may allocate in
123+
/// their implementation. For example, on some platforms [`std::sync::Mutex`] may allocate, so using
124+
/// it is highly problematic in a global allocator.
125+
///
126+
/// Generally speaking for this reason one should stick to library features available through
127+
/// [`core`], and avoid using [`std`] in a global allocator. A few features from [`std`] are
128+
/// guaranteed to not use `#[global_allocator]` to allocate:
129+
///
130+
/// - [`std::thread_local`],
131+
/// - [`std::thread::current`],
132+
/// - [`std::thread::park`] and [`std::thread::Thread`]'s [`unpark`] method and
133+
/// [`Clone`] implementation.
134+
///
135+
/// [`std`]: ../../std/index.html
136+
/// [`std::sync::Mutex`]: ../../std/sync/struct.Mutex.html
137+
/// [`std::thread_local`]: ../../std/macro.thread_local.html
138+
/// [`std::thread::current`]: ../../std/thread/fn.current.html
139+
/// [`std::thread::park`]: ../../std/thread/fn.park.html
140+
/// [`std::thread::Thread`]: ../../std/thread/struct.Thread.html
141+
/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
142+
118143
#[stable(feature = "global_alloc", since = "1.28.0")]
119144
pub unsafe trait GlobalAlloc {
120145
/// Allocates memory as described by the given `layout`.

library/std/src/alloc.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//!
1212
//! This attribute allows configuring the choice of global allocator.
1313
//! You can use this to implement a completely custom global allocator
14-
//! to route all default allocation requests to a custom object.
14+
//! to route all[^system-alloc] default allocation requests to a custom object.
1515
//!
1616
//! ```rust
1717
//! use std::alloc::{GlobalAlloc, System, Layout};
@@ -52,6 +52,13 @@
5252
//!
5353
//! The `#[global_allocator]` can only be used once in a crate
5454
//! or its recursive dependencies.
55+
//!
56+
//! [^system-alloc]: Note that the Rust standard library internals may still
57+
//! directly call [`System`] when necessary (for example for the runtime
58+
//! support typically required to implement a global allocator, see [re-entrance] on [`GlobalAlloc`]
59+
//! for more details).
60+
//!
61+
//! [re-entrance]: trait.GlobalAlloc.html#re-entrance
5562
5663
#![deny(unsafe_op_in_unsafe_fn)]
5764
#![stable(feature = "alloc_module", since = "1.28.0")]

library/std/src/thread/current.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,16 @@ fn init_current(current: *mut ()) -> Thread {
270270
// extra TLS write above shouldn't matter. The alternative is nearly always
271271
// a stack overflow.
272272

273-
// If you came across this message, contact the author of your allocator.
274-
// If you are said author: A surprising amount of functions inside the
275-
// standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
276-
// paths, even `panic!` when using unwinding), need memory allocation, so
277-
// you'll get circular dependencies all over the place when using them.
278-
// I (joboet) highly recommend using only APIs from core in your allocator
279-
// and implementing your own system abstractions. Still, if you feel that
280-
// a particular API should be entirely allocation-free, feel free to open
281-
// an issue on the Rust repository, we'll see what we can do.
273+
// If you came across this message, contact the author of your
274+
// allocator. If you are said author: A surprising amount of functions
275+
// inside the standard library (e.g. `Mutex`, `File` when using long
276+
// paths, even `panic!` when using unwinding), need memory allocation,
277+
// so you'll get circular dependencies all over the place when using
278+
// them. I (joboet) highly recommend using only APIs from core in your
279+
// allocator and implementing your own system abstractions. Still, if
280+
// you feel that a particular API should be entirely allocation-free,
281+
// feel free to open an issue on the Rust repository, we'll see what we
282+
// can do.
282283
rtabort!(
283284
"\n\
284285
Attempted to access thread-local data while allocating said data.\n\

library/std/src/thread/local.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ use crate::fmt;
2424
/// [`with`]) within a thread, and values that implement [`Drop`] get
2525
/// destructed when a thread exits. Some platform-specific caveats apply, which
2626
/// are explained below.
27-
/// Note that if the destructor panics, the whole process will be [aborted].
27+
/// Note that, should the destructor panic, the whole process will be [aborted].
28+
/// On platforms where initialization requires memory allocation, this is
29+
/// performed directly through [`System`], allowing the [global allocator]
30+
/// to make use of thread local storage.
2831
///
2932
/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
3033
/// `LocalKey` in this way may cause panics, aborts, or infinite recursion on
3134
/// the first call to `with`.
3235
///
36+
/// [`System`]: crate::alloc::System
37+
/// [global allocator]: crate::alloc
3338
/// [aborted]: crate::process::abort
3439
///
3540
/// # Single-thread Synchronization

0 commit comments

Comments
 (0)