黑客C ++动态数组大小 [英] Hacking C++ dynamic array size
问题描述
使用C ++,当您分配新内存( var * ch = new char [x]
)时,根据C ++规范基本存储在 ch [-1]
中。
问题是,是否有获得这个价值的方法?我试过:
char * ptr = ch;
--ptr
cout<<< * PTR;
// AND
cout<<< CH [-sizeof(焦炭)];
那么有一种方法来破解吗?再次,纯粹的好奇心。
免责声明:永远不要指望这个工作。考虑这个只有玩具代码,从不在真正的软件中使用它!
通常,新
操作符结束向 malloc()
的调用权,这在众多libc版本中已经表现出这种行为。
你的代码的问题是你的指针是一个 char *
,但你之后的数据可能真的是一个 size_t
(32位系统上的4个字节)。
以下代码证明了您几乎 :
#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(分配:%d(0x%X)前缀值:%d(0x%X)\\\
,
size,size,result,result);
删除p;
}
int main(){
test(1);
test(40);
test(100);
test(0x100);
test(6666);
test(0xDEAD);
return 0;
}
请注意,我第一次投放 p
到
size_t *
,然后减去1(等于 sizeof(size_t)
bytes)
输出:
$ ./a.exe
分配:1(0x1)前缀值:19(0x13)
分配:40(0x28)前缀值:51(0x33)
分配:100(0x64)值:107(0x6B)
分配:256(0x100)前缀值:267(0x10B)
分配:6666(0x1A0A)前缀值:6675(0x1A13)
分配:57005(0xDEAD)前一个值:57019(0xDEBB)
所以输出是关闭 / p>
从glibc看 malloc / malloc.c
,我们看到以下注释:
对齐:2 * sizeof(size_t)(默认)
(即8字节对齐wi th 4byte size_t)。这就足够了
几乎所有当前的机器和C编译器。但是,如果需要,您可以
定义MALLOC_ALIGNMENT比此宽。
每个分配的块的最小开销:4或8个字节
每个错误的块有一个隐藏的开销,保持大小
和状态信息
最小分配大小:4字节ptrs:16字节(包括4个开销)
8字节ptrs:24/32字节(包括4/8开销)
这些都是很好的线索。有两件事情可能发生:
- 您所请求的分配大小正在与下一个对齐大小对齐。
- 最低位(由于上述对齐而不使用)用于此状态信息。
所以我们添加代码以显示与这些规则玩耍的数字:
#define SIZE sizeof(size_t)
(x)(x)+ 2 * SIZE-1)&(y)(x) ;〜(2 * SIZE-1))
#define mask(x)((x)&〜0x3)
printf(align(size)结果):0x%X\\\
\\\
,
align(MAX(size + SIZE,16)),mask(result));
大小还包括 SIZE
,并且必须至少为16.该值然后对齐到下一个2 * SIZE倍数,我们读出的结果具有底部2位关闭,这些是状态信息。结果:
$ ./a.exe
sizeof(size_t)= 4
size:1(0x1)result:19(0x13)
align(size):0x10 mask(result):0x10
size:40(0x28)结果:51(0x33)
align(size):0x30 mask(result):0x30
size:100(0x64)result:107(0x6B)
align :0x68 mask(result):0x68
size:256(0x100)result:267(0x10B)
align(size):0x108 mask(result):0x108
size:6666(0x1A0A)结果:6675(0x1A13)
align(size):0x1A10 mask(result):0x1A10
size:57005(0xDEAD)result:57019(0xDEBB)
align(size):0xDEB8 mask(result):0xDEB8
!
请注意,我正在使用:
$ uname
CYGWIN_NT-6.1-WOW64
$ g ++ --version
g ++(GCC)3.4.4 (cygming special,gdc 0.12,使用dmd 0.125)
同样,这是高度实现特定的,不应该被信任。然而,许多分配器确实存储在实际的内存块之前的分配大小。
另请参见: / p>
- malloc()/ free()存储分配的大小和地址在哪里?
- glibc
malloc / malloc.c
- 特别是malloc_chunk details
围绕第1119行
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:
- 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:
- Where Do malloc() / free() Store Allocated Sizes and Addresses?
- glibc
malloc/malloc.c
- especially "malloc_chunk details
" around line 1119
这篇关于黑客C ++动态数组大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!