黑客C ++动态数组大小 [英] Hacking C++ dynamic array size

查看:149
本文介绍了黑客C ++动态数组大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

纯粹的好奇心,不用于生产,因为显然可能会导致重大问题。



使用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开销)

这些都是很好的线索。有两件事情可能发生:


  1. 您所请求的分配大小正在与下一个对齐大小对齐。

  2. 最低位(由于上述对齐而不使用)用于此状态信息。

所以我们添加代码以显示与这些规则玩耍的数字:

  #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>


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:

  1. Your requested allocation sizes are being aligned up to the next alignment size.
  2. 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:

这篇关于黑客C ++动态数组大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆