Skip to content

fix(examples): guard shape_buf overflow in npy_writer#167

Closed
LeoBuron wants to merge 1 commit into
developfrom
fix-npy-writer-shape-buf
Closed

fix(examples): guard shape_buf overflow in npy_writer#167
LeoBuron wants to merge 1 commit into
developfrom
fix-npy-writer-shape-buf

Conversation

@LeoBuron
Copy link
Copy Markdown
Member

Summary

Fix the latent buffer-bounds bug in examples/_shared/npy_writer.c flagged in #165.

writeNpy filled shape_buf[256] via a snprintf loop whose remaining-size argument sizeof(shape_buf) - shape_len unsigned-underflowed when shape_len exceeded 256. The underflowed huge size_t bypassed snprintf's bounds check and allowed OOB writes — caught by UBSan at npy_writer.c:22 as index 257 out of bounds for type 'char[256]'. Triggered by high-rank shapes (ndim ~120+, or smaller with multi-digit dims).

What changed

  • Extracted appendBounded helper in npy_writer.c that wraps vsnprintf with explicit bounds checking (offset >= buf_size → -1; truncation → -1).
  • Replaced the 4 inline snprintf sites for shape_buf with appendBounded calls; single rc=6 returned at end if any indicates truncation.
  • Added #include <stdarg.h> for va_list.

Test plan

  • Added test_npy_writer_rejects_high_rank_shape_that_overflows_buf (TDD: written before the fix). Compiles an ASan+UBSan harness with ndim=200, asserts no sanitizer trip and rc != 0.
  • Without the fix: test fails with UndefinedBehaviorSanitizer: runtime error: index 257 out of bounds for type 'char[256]' at npy_writer.c:22.
  • With the fix: test passes (rc=6, no sanitizer trips).
  • Full CI: alloc-locality OK, format OK, unit_test (gcc) 42/42, unit_test_asan 42/42, pytest 22 passed (was 21, +1 new test).

Closes #165

🤖 Generated with Claude Code

writeNpy's shape_buf[256] is filled by snprintf calls whose remaining-size
argument `sizeof(shape_buf) - shape_len` unsigned-underflowed when
shape_len exceeded 256 (e.g., ndim around 120+, or smaller with multi-
digit dims). The underflowed huge size_t bypassed snprintf's bounds check
and allowed OOB writes — caught by UBSan at npy_writer.c:22 as
"index 257 out of bounds for type 'char[256]'".

Fix: extract appendBounded helper that vsnprintf's into a fixed buffer
with explicit bounds checking (returns -1 on truncation, error, or
already-past-end offset). All four shape_buf append sites route through
it; a single rc=6 is returned if any indicates truncation.

Regression test builds an ASan+UBSan harness with ndim=200, asserts no
sanitizer trip and rc != 0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@LeoBuron LeoBuron closed this May 11, 2026
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