Skip to content

Global allocator re-entrancy guarantees missing tests #160776

Closed

Description

@Mark-Simulacrum

Thread::new tries to avoid invoking the global allocator for re-entrancy reasons (https://doc.rust-lang.org/nightly/std/alloc/trait.GlobalAlloc.html#re-entrance), but CString::new invoked indirectly here will reserve an extra byte of memory in the passed String using the Global, not System, allocator. I think we don't actually have a problem here because Thread::new isn't called with a name from thread::current(), but it's probably worth adding some comments for that.

Separately from those comments, I also noticed while poking at this that the PR adding those guarantees (#144465) didn't add tests confirming that the functions in question didn't invoke the global allocator when called. I don't recall seeing a subsequent PR with tests but cutting this to track adding some. I think we wouldn't be able to easily write a unit test since those run concurrently, but it seems doable to put together a UI test or run-make test (we may need to use a C / raw pthread spawned thread, not sure).

cc @orlp

Activity

  1. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Aug 8, 2026
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 8, 2026
  3. valentynkit commented on Aug 12, 2026

    @valentynkit
    Contributor

    I think we don't actually have a problem here because Thread::new isn't called with a name from thread::current(), but it's probably worth adding some comments for that.

    I was going through this code, and the thread name doesn't look like a problem on the creation path. But when the name is freed it does call the global allocator.

    Creation:
    Builder::new().name("worker").spawn() -> Thread::new(id, Some(name)) -> CString

    When the last handle is dropped:
    MyAlloc::dealloc() -> drop(last Thread handle) -> drop Inner.name (CString) -> __rust_dealloc -> MyAlloc::dealloc

    So an allocator that keeps a handle around can end up dropping the last ref. I tried this with an allocator that registers threads and releases the handle from inside dealloc, and it does re-enter (only when the thread was named).

    I may be missing something, just wanted to share some findings in case it may be helpful.

  4. zanville commented on Oct 3, 2026

    @zanville
    Contributor

    @rustbot claim

  5. added
    A-allocatorsArea: Custom and system allocators
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    A-threadArea: `std::thread`
    A-global-allocator-reentryArea: cases where global allocators should not be used, but are
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Oct 4, 2026
  6. added a commit that references this issue on Oct 25, 2026
    4466158
  7. added a commit that references this issue on Oct 26, 2026
    e8952c8
  8. added a commit that references this issue on Oct 26, 2026
    be90645
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-allocatorsArea: Custom and system allocatorsA-global-allocator-reentryArea: cases where global allocators should not be used, but areA-threadArea: `std::thread`E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions