gpt4 book ai didi

c++ - 破解 C++ 动态数组大小

转载 作者:太空宇宙 更新时间:2023-11-04 15:42:08 26 4
gpt4 key购买 nike

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

对于 C++,当您分配新内存 (var *ch = new char[x]) 时,大小基本上存储在 ch[-1] 中,根据C++ 规范。

问题是,有没有办法得到那个值?我试过:

char* ptr = ch;
--ptr
cout << *ptr;

// AND

cout << ch[-sizeof(char)];

那么有没有办法破解这个?同样,纯粹的好奇心。

最佳答案

免责声明:永远不要指望这项工作。仅将此视为“玩具代码”,切勿在“真实”软件中使用它!

通常,new 运算符最终会调用 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("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;
}

请注意,我首先将 p 转换为 size_t*,然后减去 1(等于 sizeof(size_t) 字节).

输出:

$ ./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)

所以输出是close


查看来自 glibc 的 malloc/malloc.c,我们看到以下注释:

  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)

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

  1. 您请求的分配大小正在与下一个对齐大小对齐。
  2. 最低位(由于上述对齐而未使用)用于此“状态信息”。

因此我们添加代码以显示“符合”这些规则的数字:

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

大小还包括 SIZE,并且必须至少为 16。然后将此值与下一个 2*SIZE 的倍数对齐。我们读出的结果将低 2 位 AND 运算掉。这些是“状态信息。结果:

$ ./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

好了!


请注意,我正在使用:

$ uname
CYGWIN_NT-6.1-WOW64

$ g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)

同样,这是高度特定于实现的,永远不应该被信任。然而,许多分配器确实在实际内存块之前存储分配大小。


另见:

关于c++ - 破解 C++ 动态数组大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21471814/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com