Hi Martin,
I've modified the code to include heapstats:
#include "mbed.h"
int main() {
// The following lines print out a list of the blocks on the heap
// The free block size is 0xfd4
fprintf(stderr, "\nHeap at start\n");
__heapvalid((__heapprt)fprintf,stderr,1);
__heapstats((__heapprt)fprintf,stderr);
// We now allocate a block close to the size of the free block
// If the block size falls between the (0xfd4 - 15) and (0xfd4 - 8),
// malloc returns a valid pointer but the heap is corrupted.
// If the block is larger or smaller, the malloc statement operates
// correctly.
char* ptr = (char*)malloc (0xfd4 - 16); // Works correctly
// char* ptr = (char*)malloc (0xfd4 - 15); // Fails
// char* ptr = (char*)malloc (0xfd4 - 14); // Fails
// char* ptr = (char*)malloc (0xfd4 - 13); // Fails
// char* ptr = (char*)malloc (0xfd4 - 12); // Fails
// char* ptr = (char*)malloc (0xfd4 - 11); // Fails
// char* ptr = (char*)malloc (0xfd4 - 10); // Fails
// char* ptr = (char*)malloc (0xfd4 - 9); // Fails
// char* ptr = (char*)malloc (0xfd4 - 8); // Fails
// char* ptr = (char*)malloc (0xfd4 - 7); // Works correctly
fprintf(stderr, "\nHeap after allocation, ptr = %p\n", ptr);
__heapvalid((__heapprt)fprintf,stderr,1);
__heapstats((__heapprt)fprintf,stderr);
char* ptr2 = (char*)malloc (20);
fprintf(stderr, "\nHeap after another allocation, ptr2 = %p\n", ptr2);
__heapvalid((__heapprt)fprintf,stderr,1);
__heapstats((__heapprt)fprintf,stderr);
}
This produces the following output:
Heap at start
alloc block 1000034c size 18
free block 10000364 size fd4 next=00000000
------- heap validation complete
4052 bytes in 1 free blocks (avge size 4052)
1 blocks 2^10+1 to 2^11
Heap after allocation, ptr = 10000368
alloc block 1000034c size 18
alloc block 10000364 size fc8
free block 1000132c size c next=00000000
------- heap validation complete
12 bytes in 1 free blocks (avge size 12)
1 blocks 2^2+1 to 2^3
Heap after another allocation, ptr2 = 10001330
alloc block 1000034c size 18
alloc block 10000364 size fc8
alloc block 1000132c size 18
free block 10001344 size 100c next=00000000
------- heap validation complete
4108 bytes in 1 free blocks (avge size 4108)
1 blocks 2^11+1 to 2^12
Each call to heapvalid produces a list of allocated blocks, ending with a free block. The size of the free block matches the size returned by heapstats. All is working as I would expect.
Now if I change the size of the allocated block to fall within the limits I've mentioned in my original post:
// char* ptr = (char*)malloc (0xfd4 - 16); // Works correctly
char* ptr = (char*)malloc (0xfd4 - 15); // Fails
// char* ptr = (char*)malloc (0xfd4 - 14); // Fails
the following output is produced:
Heap at start
alloc block 1000034c size 18
free block 10000364 size fd4 next=00000000
------- heap validation complete
4052 bytes in 1 free blocks (avge size 4052)
1 blocks 2^10+1 to 2^11
Heap after allocation, ptr = 10000368
------- heap validation complete
0 bytes in 0 free blocks (avge size 0)
Heap after another allocation, ptr2 = 10001340
alloc block 1000034c size 18
alloc block 10000364 size fd4
alloc block 10001338 size 1018
------- heap validation complete
4092 bytes in 1 free blocks (avge size 4092)
1 blocks 2^10+1 to 2^11
The call to heapvalid after the block is allocated (line 25 of code) doesn't produce a list of allocated blocks or free blocks and the call to heapstats (line 26 of code) returns 0 free bytes. After an allocation of 20 bytes (line 27) the call to heapvalid produces a list of allocated blocks, which doesn't include the 20 bytes just allocated and doesn't include any free blocks. The call to heapstats suggests that there are 4092 free bytes which is actually what I'd expect, but it doesn't match the output from heapvalid.
Maybe it's heapvalid that is returning bad info??
Thanks in advance for your help.
I would expect that when I use malloc to allocate a block on the heap, one of the following things would happen: Either the block would be allocated correctly and I would get a pointer to it; or there would be no room for the block and I'd get a null pointer. However, I've found that if the size of the block I'm allocating is greater than (freeblocksize - 16) and less than (freeblocksize - 7) (where freeblocksize is the size of the last free block on the heap), the malloc statement returns a pointer, but the heap is corrupted.
The following code demonstrates this:
Is this something I'm doing wrong or is it a bug? Can anyone think of a workaround?