Skip to content

Commit f01e7aa

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 5703d4d commit f01e7aa

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
@@ -250,15 +250,16 @@ fn init_current(current: *mut ()) -> Thread {
250250
// extra TLS write above shouldn't matter. The alternative is nearly always
251251
// a stack overflow.
252252

253-
// If you came across this message, contact the author of your allocator.
254-
// If you are said author: A surprising amount of functions inside the
255-
// standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
256-
// paths, even `panic!` when using unwinding), need memory allocation, so
257-
// you'll get circular dependencies all over the place when using them.
258-
// I (joboet) highly recommend using only APIs from core in your allocator
259-
// and implementing your own system abstractions. Still, if you feel that
260-
// a particular API should be entirely allocation-free, feel free to open
261-
// an issue on the Rust repository, we'll see what we can do.
253+
// If you came across this message, contact the author of your
254+
// allocator. If you are said author: A surprising amount of functions
255+
// inside the standard library (e.g. `Mutex`, `File` when using long
256+
// paths, even `panic!` when using unwinding), need memory allocation,
257+
// so you'll get circular dependencies all over the place when using
258+
// them. I (joboet) highly recommend using only APIs from core in your
259+
// allocator and implementing your own system abstractions. Still, if
260+
// you feel that a particular API should be entirely allocation-free,
261+
// feel free to open an issue on the Rust repository, we'll see what we
262+
// can do.
262263
rtabort!(
263264
"\n\
264265
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, should 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)