Skip to content

Detect the effective virtual-address width at runtime instead of assu… - #1282

Open
hrabanazviking wants to merge 1 commit into
google:masterfrom
hrabanazviking:fix/39bit-va-aarch64
Open

hrabanazviking wants to merge 1 commit into
google:masterfrom
hrabanazviking:fix/39bit-va-aarch64

Conversation

@hrabanazviking

Copy link
Copy Markdown

…ming 48 bits on aarch64

tcmalloc hardcodes a 48-bit virtual address space on Linux/aarch64 (kAddressBits = 48 in tcmalloc/internal/config.h). On kernels built with a narrower user VA width -- e.g. Raspberry Pi OS and Android GKI, which ship CONFIG_ARM64_VA_BITS=39 -- every mmap hint RandomMmapHint() generates (up to 2^47, with memory-tag bits at bit 42) is rejected by the kernel. After 1000 retries MmapAligned() returns null and the process aborts during allocator init. This makes tcmalloc unusable on these kernels with no workaround short of rebuilding the kernel.

This change probes the running kernel's user VA width at runtime (reading the most-significant set bit of the stack pointer, the same probe ThreadSanitizer uses; no syscalls, no /proc parsing), clamped to [39, kAddressBits], and places mmap hints and memory-tag bits accordingly. A single binary now works on 39-bit, 42-bit, and 48-bit aarch64 kernels; on 48-bit kernels the behavior is bit-identical to before.

It also implements the advice the OOM error message itself gives: the message suggests rebuilding "with TCMALLOC_ADDRESS_BITS defined", but no such macro existed anywhere in the tree. It does now (aarch64/Linux), lowering the compile-time maximum and shrinking the page map for builders who want a fixed width.

Test evidence:

  • config_test and system_allocator_test pass on x86_64 Linux (48-bit kernel; patched lib reports bits=48/shift=42 -- identical to pristine).
  • A/B verification on a Raspberry Pi 5 (kernel 6.12, 39-bit VA): pristine library aborts with the exact reported crash; patched library reports EffectiveAddressBits()=39, TagShift()=35, and all checks pass.

Fixes #82.

…ming 48 bits on aarch64

tcmalloc hardcodes a 48-bit virtual address space on Linux/aarch64
(kAddressBits = 48 in tcmalloc/internal/config.h). On kernels built with a
narrower user VA width -- e.g. Raspberry Pi OS and Android GKI, which ship
CONFIG_ARM64_VA_BITS=39 -- every mmap hint RandomMmapHint() generates (up
to 2^47, with memory-tag bits at bit 42) is rejected by the kernel. After
1000 retries MmapAligned() returns null and the process aborts during
allocator init. This makes tcmalloc unusable on these kernels with no
workaround short of rebuilding the kernel.

This change probes the running kernel's user VA width at runtime (reading
the most-significant set bit of the stack pointer, the same probe
ThreadSanitizer uses; no syscalls, no /proc parsing), clamped to
[39, kAddressBits], and places mmap hints and memory-tag bits accordingly.
A single binary now works on 39-bit, 42-bit, and 48-bit aarch64 kernels;
on 48-bit kernels the behavior is bit-identical to before.

It also implements the advice the OOM error message itself gives: the
message suggests rebuilding "with TCMALLOC_ADDRESS_BITS defined", but no
such macro existed anywhere in the tree. It does now (aarch64/Linux),
lowering the compile-time maximum and shrinking the page map for builders
who want a fixed width.

Test evidence:
- config_test and system_allocator_test pass on x86_64 Linux (48-bit
  kernel; patched lib reports bits=48/shift=42 -- identical to pristine).
- A/B verification on a Raspberry Pi 5 (kernel 6.12, 39-bit VA): pristine
  library aborts with the exact reported crash; patched library reports
  EffectiveAddressBits()=39, TagShift()=35, and all checks pass.

Fixes google#82.
@google-cla

google-cla Bot commented Oct 5, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@hrabanazviking

Copy link
Copy Markdown
Author

I signed the agreement. Don't think it is recognizing that though.

@hrabanazviking

Copy link
Copy Markdown
Author
agreementsigned

Comment thread tcmalloc/tcmalloc.cc
static_cast<uintptr_t>(MemoryTag::kNormal) << TagShift();
// NB: dynamic (not constexpr): the tag placement now depends on the
// runtime-detected address width (see TagShift()/TagMask()).
static const uintptr_t kColdMask = static_cast<uintptr_t>(MemoryTag::kCold)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is potentially unsafe: The initializer for this can happen after we've attempted the first allocation.

It also has significant performance consequences, since we need to do a load for many instructions when an immediate would have previously sufficed.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Is it possible to detect kAddressBits at runtime?

2 participants