出于调试目的,我希望malloc
在每次执行程序时都返回相同的地址,但在MSVC中情况并非如此。例如:
#include <stdlib.h>
#include <stdio.h>
int main() {
int test = 5;
printf("Stack: %p\n", &test);
printf("Heap: %p\n", malloc(4));
return 0;
}
用cygwin的gcc编译,每次都得到相同的堆栈地址和堆地址,而用MSVC编译时关闭了ASLR...
cl t.c /link /DYNAMICBASE:NO /NXCOMPAT:NO
...I每次都会获得相同的堆栈地址,但是堆地址会发生变化。
我已经尝试添加注册表值HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\MoveImages
,但它不起作用。
发布于 2020-05-12 06:45:24
malloc()
每次返回的堆栈地址和指针都可能不同。事实上,当程序在Mac/OS上多次编译和运行时,两者是不同的。
编译器和/或OS可能会导致此行为尝试并使其更难利用软件缺陷。在某些情况下,可能有一种方法可以防止这种情况,但如果您的目标是重放同一系列malloc()
地址,其他因素可能会更改地址,例如时间敏感行为、文件系统副作用,更不用说不确定的线程行为。您应该尝试并避免在测试中依赖于此。
还要注意,&test
应该转换为(void *)
,因为%p
需要一个void
指针,但不能保证它具有与int *
相同的表示形式。
发布于 2020-05-12 07:45:58
事实证明,您可能无法从MSVC运行时库中获得确定性行为。C/C++运行时库的调试版本和生产版本最终都调用了一个名为_malloc_base()
的函数,该函数又调用了Win32 API函数HeapAlloc()。不幸的是,无论是HeapAlloc()
还是提供其堆的函数HeapCreate()都没有记录标志或其他方式来获得确定性行为。
您可以按照@Enosh_Cohen的建议,在VirtualAlloc()
之上构建自己的分配方案,但是这样就会失去MSVC分配函数提供的debug functionality。
发布于 2021-04-03 14:40:38
Diomidis' answer建议在VirtualAlloc
之上创建一个新的malloc
,所以我就这么做了。事实证明这有些挑战,因为VirtualAlloc
本身不是确定性的,所以我记录了我使用的过程。
首先,获取Doug Lea's malloc。(指向源代码的ftp链接已断开;请使用this http alternative。)
然后,将win32mmap
函数替换为以下代码(因此将其放入公共领域,就像Doug Lea的malloc本身一样):
static void* win32mmap(size_t size) {
/* Where to ask for the next address from VirtualAlloc. */
static char *next_address = (char*)(0x1000000);
/* Return value from VirtualAlloc. */
void *ptr = 0;
/* Number of calls to VirtualAlloc we have made. */
int tries = 0;
while (!ptr && tries < 100) {
ptr = VirtualAlloc(next_address, size,
MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!ptr) {
/* Perhaps the requested address is already in use. Try again
* after moving the pointer. */
next_address += 0x1000000;
tries++;
}
else {
/* Advance the request boundary. */
next_address += size;
}
}
/* Either we got a non-NULL result, or we exceeded the retry limit
* and are going to return MFAIL. */
return (ptr != 0)? ptr: MFAIL;
}
现在编译并将生成的malloc.c
与您的程序链接,从而覆盖MSVCRT分配器。
这样,我现在可以获得一致的malloc
地址。
但是要当心
0x1000000
是通过使用VirtualQuery
枚举我的地址空间来查找大的、持续可用的空洞来选择的。地址空间布局似乎具有一些不可避免的不确定性,即使禁用了ASLR也是如此。您可能需要调整该值。https://stackoverflow.com/questions/61740028
复制相似问题