Warning: Your application is relying on an implementation detail of your particular heap implementation, it's not supported by the C standard and and is likely to break on other systems.
Over to the problem. In your heap implementation, the size of a heap block is stored right before the heap block itself. This helps free
to release the right amount of memory. The following image demonstrates this:
Lower memory ^^^
...
+----------------+
| size (4 bytes) |
+----------------+
p -> | struct st |
| ... |
+----------------+
In C, when you perform pointer arithmetic, the pointer is adjusted the same number of bytes as the object it points to. For integer pointers, they are adjusted 4 bytes (assuming you are using 32 integers). As you claim that this work, we can assume that this is the correct number of bytes to adjust the pointer to find the size field.
For the struct pointer, however, the pointer is adjusted sizeof(struct st)
, on most systems this is 16 bytes (14 for the actual content and another two to pad the struct to ensure correct alignment of the int
member, in case the struct is used in arrays). When you do (p-1)
you adjust the pointer 16 bytes. Furthermore, when you do *(p-1)
you pass the entire structure to printf
, something printf
does not expect. This is most likely the cause of the crash.
So, what can you do? The best answer to this question is don't, as this is not correct C. The second best answer to this is to write something the explicitly describes that you do, and which could be adjusted to match other systems, for example:
#define OFFSET_TO_HEAP_SIZE 4
#define HEAP_SIZE_TYPE uint32_t
* ( (HEAP_SIZE_TYPE *)(((char const *)p) - OFFSET_TO_HEAP_SIZE) )