Skip to content

[AArch64] Zig compiler uses x8 as vtable dispatch scratch register, corrupting sret return buffer and causing SIGSEGV #252

@xiangguomin

Description

@xiangguomin

Environment

  • hermetic_cc_toolchain: v4.1.0
  • Zig version: 0.12.0 (LLVM 17)
  • Target: aarch64-linux-gnu
  • Host: x86_64-linux
  • Bazel compilation modes affected: fastbuild, dbg (not opt)

Symptom

Indirect or virtual C++ calls that return large structs (e.g. std::string) crash with
SIGSEGV in fastbuild and dbg modes on AArch64. The same code works correctly in
opt mode.

Root Cause

The Zig compiler (LLVM 17) selects x8 as a scratch register when dispatching indirect
or virtual calls (blr x8). On AArch64, x8 is also the struct-return (sret) register:
the caller writes the return buffer address into x8 before the call, and the callee writes
the result to that address.

When x8 holds a vtable function pointer at the call site, the callee receives
x8 = function address instead of x8 = return buffer address, and writes the returned
struct into the function's own .text — which is read-only — causing SIGSEGV.

At -O2 the register allocator avoids this conflict by choosing a different register
(e.g. x9) for the function pointer and preserving x8 for sret. opt mode already
implies -O2 via --compilation_mode=opt, which is why only fastbuild and dbg are
affected.

Workaround

Append -O2 to compiler_flags for all AArch64 targets in toolchain/zig_cc_toolchain.bzl:

if ctx.attr.target.startswith("aarch64"):
    compiler_flags.append("-O2")

Applying this unconditionally (including in opt mode) is harmless since opt already
compiles at -O2.

▎ Note: ctx.attr.target_cpu is always "k8" for Linux regardless of architecture.
▎ Use ctx.attr.target (the full Zig target triple, e.g. "aarch64-linux-gnu.2.35") todetect AArch64.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions