Skip to content

Fix CMock_Guts_MemBytesCapacity() integer underflow#536

Merged
mvandervoord merged 1 commit into
ThrowTheSwitch:masterfrom
94xhn:fix-membytescapacity-underflow
Jul 16, 2026
Merged

Fix CMock_Guts_MemBytesCapacity() integer underflow#536
mvandervoord merged 1 commit into
ThrowTheSwitch:masterfrom
94xhn:fix-membytescapacity-underflow

Conversation

@94xhn

@94xhn 94xhn commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🍍

Bug

CMock_Guts_MemBytesCapacity() (src/cmock.c) returns:

return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);

CMock_Guts_Buffer is declared as static unsigned char* CMock_Guts_Buffer, so sizeof(CMock_Guts_Buffer) is the size of the pointer (8 bytes on a typical 64-bit build), not the size of the buffer it points to. Whenever CMOCK_MEM_ALIGN_SIZE > sizeof(void*) -- which happens by default on C11+ toolchains, since CMOCK_MEM_ALIGN_SIZE auto-upgrades to sizeof(max_align_t) unless the user overrides CMOCK_MEM_ALIGN (see src/cmock_internals.h) -- the subtraction underflows and CMock_Guts_MemBytesCapacity() returns a huge garbage value instead of the real capacity.

Confirmed by compiling the unmodified src/cmock.c with vendor/unity/src/unity.c (GCC, -std=c11, no CMOCK_MEM_ALIGN/CMOCK_MEM_SIZE overrides): sizeof(void*)=8, sizeof(max_align_t)=32, so CMOCK_MEM_ALIGN_SIZE=32, and CMock_Guts_MemBytesCapacity() returns 18446744073709551592 (0xffffffffffffffe8) instead of the true capacity of 32768.

This is why CI doesn't catch it: test/c/TestCMockC.yml pins CMOCK_MEM_ALIGN=2, which keeps CMOCK_MEM_ALIGN_SIZE below sizeof(void*) so no underflow occurs there, and the self-test only asserts Capacity() <= CMOCK_MEM_SIZE (an upper bound), so a wrong-but-small value still passes silently.

Fix

Use CMock_Guts_BufferSize instead, which already tracks the real buffer size in both the default/static branch and the CMOCK_MEM_DYNAMIC branch (including growth via realloc). This makes MemBytesCapacity() == MemBytesUsed() + MemBytesFree() by construction, matching the two sibling accessors that already use CMock_Guts_BufferSize/CMock_Guts_FreePtr correctly.

Testing

  • Compiled the unmodified function standalone and confirmed the underflow reproduces exactly as described above.
  • Applied this fix and confirmed MemBytesCapacity() == MemBytesUsed() + MemBytesFree() in the default/static config, and in CMOCK_MEM_DYNAMIC mode both before and after a realloc-driven buffer growth.
  • Built and ran the existing test/c/TestCMockC.c suite with the exact CMOCK_MEM_STATIC / CMOCK_MEM_ALIGN=2 / CMOCK_MEM_INDEX_TYPE=int configuration from test/c/TestCMockC.yml: all 9 tests still pass with this fix (no regression).

CMock_Guts_MemBytesCapacity() returned sizeof(CMock_Guts_Buffer), which
is the size of the pointer variable itself (not the buffer it points
to), minus CMOCK_MEM_ALIGN_SIZE. On a typical 64-bit build this is
8 - CMOCK_MEM_ALIGN_SIZE, which underflows to a huge garbage value
whenever CMOCK_MEM_ALIGN_SIZE > sizeof(void*) (e.g. when it defaults
to sizeof(max_align_t) on C11+ toolchains).

Use CMock_Guts_BufferSize instead, which already tracks the real
buffer size (including growth via realloc under CMOCK_MEM_DYNAMIC).
This makes MemBytesCapacity() == MemBytesUsed() + MemBytesFree() by
construction, matching the two sibling accessors.
@mvandervoord
mvandervoord merged commit 6ea5033 into ThrowTheSwitch:master Jul 16, 2026
10 checks passed
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.

2 participants