Disclaimer: Never, ever count on this working. Consider this only "toy code" and never use it in "real" software!
Often times, the new operator ends up calling right to malloc(), which is known to exhibit this behavior in many versions of libc.
The problem with your code is that your pointer is a char* but the data you're after is probably really a size_t (4 bytes on a 32-bit system).
The following code does demonstrate almost what you're after:
#include <stddef.h> // for size_t
#include <stdio.h>
void test(size_t size) {
size_t result;
char* p = new char[size];
result = *((size_t*)p - 1);
printf("Allocated: %d (0x%X) Preceding value: %d (0x%X)\n",
size, size, result, result);
delete p;
}
int main() {
test(1);
test(40);
test(100);
test(0x100);
test(6666);
test(0xDEAD);
return 0;
}
Note that I'm first casting p to a size_t*, and then subtracting 1 (which equates to sizeof(size_t) bytes).
Output:
$ ./a.exe
Allocated: 1 (0x1) Preceding value: 19 (0x13)
Allocated: 40 (0x28) Preceding value: 51 (0x33)
Allocated: 100 (0x64) Preceding value: 107 (0x6B)
Allocated: 256 (0x100) Preceding value: 267 (0x10B)
Allocated: 6666 (0x1A0A) Preceding value: 6675 (0x1A13)
Allocated: 57005 (0xDEAD) Preceding value: 57019 (0xDEBB)
So the output is close.
Looking at malloc/malloc.c from glibc, we see the following comment:
Alignment: 2 * sizeof(size_t) (default)
(i.e., 8 byte alignment with 4byte size_t). This suffices for
nearly all current machines and C compilers. However, you can
define MALLOC_ALIGNMENT to be wider than this if necessary.
Minimum overhead per allocated chunk: 4 or 8 bytes
Each malloced chunk has a hidden word of overhead holding size
and status information
Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
These are excellent clues. There are two things that are probably happening:
- Your requested allocation sizes are being aligned up to the next alignment size.
- The lowest bits (not used because of the above alignment) are used for this "status information.
So we add the code to show numbers that "play along" with these rules:
#define SIZE sizeof(size_t)
#define MAX(x,y) ((x)>(y) ? (x) : (y))
#define align(x) (((x)+2*SIZE-1) & ~(2*SIZE-1))
#define mask(x) ((x) & ~0x3)
printf("align(size): 0x%X mask(result): 0x%X\n\n",
align(MAX(size+SIZE, 16)), mask(result));
The size also includes SIZE, and must be at least 16. This value is then aligned to the next 2*SIZE multiple. And the result we read out has the bottom 2 bits ANDed off. These are the "status information. The result:
$ ./a.exe
sizeof(size_t) = 4
size: 1 (0x1) result: 19 (0x13)
align(size): 0x10 mask(result): 0x10
size: 40 (0x28) result: 51 (0x33)
align(size): 0x30 mask(result): 0x30
size: 100 (0x64) result: 107 (0x6B)
align(size): 0x68 mask(result): 0x68
size: 256 (0x100) result: 267 (0x10B)
align(size): 0x108 mask(result): 0x108
size: 6666 (0x1A0A) result: 6675 (0x1A13)
align(size): 0x1A10 mask(result): 0x1A10
size: 57005 (0xDEAD) result: 57019 (0xDEBB)
align(size): 0xDEB8 mask(result): 0xDEB8
And there you have it!
Note that I'm using:
$ uname
CYGWIN_NT-6.1-WOW64
$ g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Again, this is highly implementation-specific and should never be trusted. However, it is true that many allocators store the allocation size right before the actual block of memory.
See also:
ch[-1](which would limit such strings to 255 bytes!) and I know no specs claiming that. And there is no way to portably retrieve that information, even if of course most implementations have their way to get it.