Starting in Android 11, for 64-bit processes, all heap allocations have an implementation defined tag set in the top byte of the pointer on devices with kernel support for ARM Top-byte Ignore (TBI). Any application that modifies this tag is terminated when the tag is checked during deallocation. This is necessary for future hardware with ARM Memory Tagging Extension (MTE) support.
ARM's Top-byte Ignore feature is available for 64-bit code in all Armv8 AArch64 hardware. This feature means that the hardware ignores the top byte of a pointer when accessing memory.
TBI requires a compatible kernel that correctly handles tagged pointers passed from userspace. Android Common Kernels from 4.14 (Pixel 4) and higher feature the required TBI patches.
Devices with the TBI support in the kernel are dynamically detected at process start time and an implementation-dependent tag is inserted into the top byte of the pointer for all heap allocations. After this, a check is run to ensure the tag hasn't been truncated when deallocating the memory.
Memory Tagging Extension readiness
ARM's Memory Tagging Extension (MTE) helps address memory safety issues. MTE works by tagging the 56th-59th address bits of each memory allocation on the stack, heap, and globals. The hardware and instruction set automatically checks that the correct tag is used upon every memory access.
Android apps that incorrectly store information in the top byte of the pointer are guaranteed to break on an MTE-enabled device. Tagged pointers make it easier to detect and reject incorrect uses of the top byte of the pointer before MTE devices are available.
If your app crashed and you were prompted with this link, it could mean one of the following:
- The application tried to free a pointer that wasn't allocated by the system's heap allocator.
- Something in your app modified the top byte of a pointer. The top byte of the pointer can't be modified and your code needs to be changed to fix this issue.
Examples of the top byte pointer being incorrectly used or modified.
- Pointers to a particular type have application specific metadata stored in the top 16 address bits.
- A pointer cast to double and then back, losing the lower address bits.
- Code computing the difference between the addresses of local variables from different stack frames as a way to measure recursion depth.
Some applications may depend on libraries that behave incorrectly when the
top byte of the pointer is set. We recognise that it may be
nontrivial to fix these underlying problems in libraries quickly. As such,
applications that use
targetSdkLevel < 30
will not have pointer tagging enabled by default. We also provide an escape
hatch for applications built with
targetSdkLevel >= 30
to ease the transitional period.
The escape hatch is used by adding the following to your
<application android:allowNativeHeapPointerTagging="false"> ... </application>
This will disable the Pointer Tagging feature for your application. Please note that this does not address the underlying code health problem. This escape hatch will disappear in future versions of Android, because issues of this nature will be incompatible with MTE.