Skip to content

Add ASan redzones between zone allocations - #1194

Open
0xalpharush wants to merge 1 commit into
msgpack:cpp_masterfrom
0xalpharush:cpp-zone-asan-annotations
Open

0xalpharush wants to merge 1 commit into
msgpack:cpp_masterfrom
0xalpharush:cpp-zone-asan-annotations

Conversation

@0xalpharush

@0xalpharush 0xalpharush commented Oct 27, 2026 •

Copy link
Copy Markdown

msgpack::zone carves many objects out of one malloc()ed chunk. An overflow from one zone-allocated object into its neighbour stays inside a live heap block, so AddressSanitizer stays silent. This is detector hardening, not a bug fix, and the technique isn't new: it's the manual allocator poisoning described in Trail of Bits' "Sanitize your C++ containers: ASan annotations step-by-step" (https://blog.trailofbits.com/2024/09/10/sanitize-your-c-containers-asan-annotations-step-by-step/). zstd's ZSTD_CWKSP_ASAN_REDZONE_SIZE is a similar precedent.

  • It is active only when built with ASan (__SANITIZE_ADDRESS__ / __has_feature(address_sanitizer)). Non-ASan builds are unchanged; with -DNDEBUG the objects are byte-identical (gcc/clang, C++03/11/17). -DMSGPACK_ZONE_NO_ASAN_ANNOTATIONS opts out, e.g. when instrumented and uninstrumented code share a zone. At runtime, ASAN_OPTIONS=allow_user_poisoning=0 also disables it.
  • Each allocation starts on an 8-byte ASan granule and is followed by a poisoned redzone (MSGPACK_ZONE_ASAN_REDZONE_SIZE, default 16). Chunks of the configured size stay poisoned until handed out, and clear()/undo_allocate() re-poison. Oversized chunks aren't pre-poisoned, so one huge allocation costs nothing proportional to its size.
  • cpp03_zone.hpp and its .erb template get the same change.
  • test/zone.cpp: under ASan, allocate_no_align checks for the redzone instead of contiguity.

Validation: unpacking 92 91 01 91 02 and writing one element past the first inner array silently corrupts the neighbour on stock. With this patch it reports use-after-poison, and it is silent again with -DMSGPACK_ZONE_NO_ASAN_ANNOTATIONS. All tests pass under ASan (clang-18 C++11/17/20, gcc-13 C++17), with annotations on and off. The OSS-Fuzz public corpus plus about 46M unpack_pack_fuzzer executions show no reports. ASan overhead is about +14% time and +7% peak memory on a corpus unpack/pack/clone benchmark; non-ASan builds are unaffected.

Scope: only overflows between separately allocated zone objects. Indexing inside a single allocation is not covered, nor are reads into the unused tail of an oversized chunk.

Companion PR for the C zone on c_master: #1195.

🤖 Generated with Claude Code

The zone carves many objects out of one malloc()ed chunk, so an
overflow from one zone-allocated object into its neighbour stays inside
a live heap block and AddressSanitizer cannot see it.

When building with ASan, follow every allocation with a poisoned
redzone, keep chunks of the configured size poisoned until handed out,
and re-poison on clear() and undo_allocate(). Oversized chunks are not
pre-poisoned, so a huge allocation costs no shadow updates proportional
to its size. Builds without ASan are unchanged. Define
MSGPACK_ZONE_NO_ASAN_ANNOTATIONS to opt out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

1 participant