Pure curiosity, not to be used in production, because obviously it could cause major problems.
With C++, when you allocate new memory ( var *ch = new char[x]
), the size is stored essentially in ch[-1]
according to the C++ specs.
The question is, is there a way to get that value? I've tried:
char* ptr = ch;
--ptr
cout << *ptr;
// AND
cout << ch[-sizeof(char)];
So is there a way to hack this? Again, pure curiosity.
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:
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:
malloc/malloc.c
- especially " malloc_chunk details
" around line 1119 No. Standard C++ provides no mechanism that given only the pointer to a dynamically allocated buffer, to determine the size of the buffer. It is assumed that internally these dynamically allocated regions are somehow tracked, such that delete [] pblah
can work, but the C++ standard imposes nothing on the implementation on how it is done. Therefore what you are asking may, theoretically, be possible, it cannot be done without knowing the internals of your compiler, library, platform and implementation.
Others already stated that it is implementation specific. On MS VS2012 I find the default allocations to be aligned at a 16 byte granularity with 16 bytes preceeding the memory block in which the number of required bytes is stored in the first sizeof(size_t)
bytes of that block.
I adopted Jonathon's Test
#include <iostream>
void test(size_t const size)
{
char * mem = new char[size];
std::cout << "Number of allocated bytes at " << (size_t)mem;
std::cout << " is: " << *(size_t*)(mem-16) << std::endl;
delete [] mem;
}
void main()
{
test(1U);
test(40U);
test(256);
test(6666);
test(57005);
system("pause");
}
Giving me
Number of allocated bytes at 101044204016 is: 1 Number of allocated bytes at 101044242832 is: 40 Number of allocated bytes at 101044242832 is: 256 Number of allocated bytes at 101044244064 is: 6666 Number of allocated bytes at 101044244064 is: 57005 Drücken Sie eine beliebige Taste . . .
Where
101044204016 / 16 = 6315262751
101044242832 / 16 = 6315265177
101044244064 / 16 = 6315265254
Als see C++ allocates abnormally large amout memory for variables
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.