Skip to content

Don't read from a zero-length buffer when growing print output - #1129

Open
ck0i wants to merge 1 commit into
DaveGamble:masterfrom
ck0i:fix-printbuffered-zero-prebuffer
Open

ck0i wants to merge 1 commit into
DaveGamble:masterfrom
ck0i:fix-printbuffered-zero-prebuffer

Conversation

@ck0i

@ck0i ck0i commented Nov 8, 2026

Copy link
Copy Markdown

Fixes #1122

Root cause

cJSON_PrintBuffered accepts a prebuffer of 0. It then calls allocate(0), which may return a non-null pointer to a zero-byte object, and stores that size in the print buffer's length.

Custom hooks installed with cJSON_InitHooks set malloc_fn/free_fn and leave reallocate unset, unless those functions are the raw libc malloc/free pair. ensure() grows such a buffer by allocating a new one and copying with memcpy(newbuffer, p->buffer, p->offset + 1). When length and offset are both 0, that copy reads one byte from a zero-sized allocation. The default hooks use realloc and never reach this path.

Fix

In the manual growth path of ensure(), copy from the old buffer only when p->length > 0. A zero-length buffer owns no bytes.

Testing

Windows 11 x64, MSVC 19.51.36256, CMake + Ninja, Debug.

New tests in tests/misc_tests.c:

  • ensure_should_not_copy_from_zero_length_buffer points a zero-length print buffer at a static 'X' byte, uses a zero-filling malloc and no reallocate hook, grows it with ensure(), and checks the first byte of the new buffer is still 0
  • print_buffered_should_print_with_zero_prebuffer_and_custom_hooks prints 42 through cJSON_PrintBuffered with prebuffer 0 and custom hooks

Before: ensure_should_not_copy_from_zero_length_buffer fails (Expected 0 Was 88), misc_tests 31/32.
After: passes, misc_tests 32/32 and the full ctest suite 22/22.

When custom hooks leave reallocate unset, ensure() copies the old
buffer with memcpy(..., offset + 1). A PrintBuffered prebuffer of 0
can produce a zero-length allocation, so that copy reads one byte
the buffer does not own. Skip the copy when length is 0.

Issue DaveGamble#1122
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.

[BUG] cJSON_PrintBuffered(item, 0, ...) with custom hooks: ensure() reads 1 byte from a zero-sized buffer (memcpy(..., p->offset + 1))

1 participant