Let's Decode the Mystery Bytes [video]

Hacker News Top Tools

Summary

This video uses disassembly and the WinDbg debugging tool to reveal that the eight mystery bytes that appear when calloc allocates memory in an x86 environment are actually the entry header of the Windows heap manager, containing information such as the current block size and the previous block size.

No content available
Original Article
View Cached Full Text

Cached at: 06/29/26, 11:04 AM

# TL;DR This article uses disassembly and the WinDbg debugging tool to reveal that the 8 "mystery bytes" that appear before the allocated address when `calloc` allocates memory in an x86 environment are actually the heap manager's entry header in Windows, containing information such as the current block size, previous block size, unused bytes, and flags. --- ## Background: Starting from the Previous Video In the previous video "Let's Answer Ray's Question", we analyzed a piece of code by Raylib author Ramon Santamaria: the same C code, when compiled for x86 and x64 targets, produced different runtime results. One of the differences was that in the x86 version, there were an extra 8 bytes between the two string pointers allocated by `calloc`. At the time, we only gave a basic explanation and promised to dive deeper into the assembly-level details. This video is the first follow-up—specifically analyzing what those 8 bytes are. If you haven't watched the previous video yet, please do (link in the description). This video assumes you already know the pattern in which those 8 bytes are generated and where they appear in the code. --- ## Method: Tracing from `calloc` ### Initial Assembly-Level Investigation We opened the debugger, set a breakpoint at the first `calloc` call, then stepped into the disassembly code. In x86, instruction lengths are variable (unlike ARM). We saw `push` (pushing arguments), `call` (calling a function), and then through a jump table eventually reaching the actual `calloc` implementation. After stepping through several jumps, we discovered that `calloc` is not an allocator implemented by the C runtime library itself; rather, it is a thin wrapper that directly calls the Windows system routine `RtlAllocateHeap` (located in NTDLL). This is an important clue: it means we can use Windows' built-in heap debugging tools to observe the allocation behavior without having to delve into the internal implementation of the C runtime library. ### Using WinDbg's `!heap` Command Exiting the disassembly, we returned to just before the allocation of string 02, after string 01 had already been allocated at address `0xE77320`. The address of those 8 mystery bytes is `0xE77318`. In WinDbg, execute: `` !heap -x 0xE77320 `` The output shows: - This address belongs to the unique process heap. - The `size` is `0x10` (i.e., 16 bytes). - The `prev size` is `0x18` (24 bytes). - The `unused` is `8` bytes. - There are also some flags. This information directly corresponds to the 8 bytes we just saw. It is evident that the Windows heap manager treats these 8 bytes as the header of the heap allocation entry, containing the size of the current block, the size of the previous block, and some metadata. --- ## In-Depth Analysis: Heap Entry Structure ### Using the `dt` Command to Display the Structure WinDbg can load debugging symbols for NTDLL, so we can use the `dt` command to view the heap entry type. Assuming the heap entry type is named `_HEAP_ENTRY`, but the actual command requires an address. However, the author demonstrated in the video that `dt _HEAP_ENTRY` directly displays the structure definition. The structure looks roughly like this (based on transcription): - `Size`: the size of the current block (in units of 16 bytes? This needs verification, but the transcript says `size` is 0x10 which is 16 bytes) - `PreviousSize`: the size of the previous block - `UnusedBytes`: the number of unused bytes - `SmallTagIndex` and other flag fields It is this 8-byte structure that allows the heap manager to know the size of each allocated block, the addresses of preceding and following blocks, thus supporting memory allocation and deallocation. ### Interpreting the Specific Values Taking the 8 bytes we obtained (at address `0xE77318`) as an example, their contents (hexadecimal) might be arranged as: - 2 bytes: `size` (current block size) - 2 bytes: `prev size` (previous block size) - 1 byte: `segment index` - 1 byte: `flags` - 1 byte: `unused bytes` - 1 byte: `small tag index` However, the exact layout varies depending on the Windows version and heap implementation. The important point is that these 8 bytes are not generated at the C language level; they are a header automatically attached to each allocated block by the Windows heap manager. --- ## Verification: Consistent with Our Guess Our initial intuition was correct: these 8 bytes are the header of the allocated block, used for heap management. Because `calloc` calls the Windows heap, every allocation has such an entry prefixed. In the x64 version, due to the different structure of the 64-bit heap manager (the heap entry size might be 16 bytes or something else), combined with address alignment and header size variations, the same phenomenon is not seen in the x64 code. Additionally, through `!heap -x` we can see the complete information of the allocation entry, including the number of unused bytes (`unused` is 8), which exactly matches the space reserved by the heap manager after `calloc` allocates an 8-byte string. --- ## Summary Those 8 mystery bytes are not an error, nor garbage produced by the compiler or linker. They are the heap entry header placed before each allocated block by the Windows heap manager. Its purpose is to record the size of the current block, the size of the previous block, and other metadata, facilitating memory management (such as coalescing free blocks, checking for heap corruption, etc.). By reading the assembly call chain, we located `RtlAllocateHeap`, and then used WinDbg's `!heap` and `dt` commands to visually see this structure. The entire process demonstrates how to start from a "strange phenomenon" and, using system tools and low-level debugging techniques, arrive at a reasonable explanation. --- Source: https://www.youtube.com/watch?v=GZqB4D_Do38

Similar Articles

Bytecode VMs in surprising places (2024)

Hacker News Top

This article explores surprising uses of bytecode virtual machines, specifically eBPF in the Linux kernel and DWARF expressions for debug information in compiled binaries.

WriteUp: 16 Bytes of x86 that turn Matrix rain into sound

Hacker News Top

A detailed write-up of a 16-byte x86 real-mode DOS demo that generates an infinite Sierpinski fractal in video memory while simultaneously producing audio output, showcasing extreme algorithmic density in the demoscene tradition.

The evolution of window and class extra bytes in Windows

The Old New Thing (Raymond Chen)

The article traces the evolution of window and class extra bytes in Windows from 16-bit to 32-bit to 64-bit, detailing changes in function names and data sizes as handles and pointers expanded.

@xiaogaifun: ByteDance's reflections on AI Coding in big companies are so real. I watched the sharing by Hong Dingkun, ByteDance's VP of Technology, several times and found it very inspiring. ByteDance's practices in AI Coding are quite representative; I recommend all R&D peers to take a look. You'll probably relate. After watching, I filled a whole page with notes, and...

X AI KOLs Timeline

ByteDance's VP of Technology Hong Dingkun shared reflections on AI Coding, pointing out that AI code contribution rate should not be a KPI, functional correctness does not equal engineering readiness, and the challenges of team collaboration after the lowering of the coding bar, emphasizing the importance of systematic AI development and foundational engineering.