首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何使用MSVC让malloc每次都返回相同的地址?

如何使用MSVC让malloc每次都返回相同的地址?
EN

Stack Overflow用户
提问于 2020-05-12 05:51:24
回答 3查看 382关注 0票数 2

出于调试目的,我希望malloc在每次执行程序时都返回相同的地址,但在MSVC中情况并非如此。例如:

代码语言:javascript
代码运行次数:0
运行
复制
#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...

代码语言:javascript
代码运行次数:0
运行
复制
cl t.c /link /DYNAMICBASE:NO /NXCOMPAT:NO

...I每次都会获得相同的堆栈地址,但是堆地址会发生变化。

我已经尝试添加注册表值HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\MoveImages,但它不起作用。

EN

回答 3

Stack Overflow用户

发布于 2020-05-12 14:45:24

malloc()每次返回的堆栈地址和指针都可能不同。事实上,当程序在Mac/OS上多次编译和运行时,两者是不同的。

编译器和/或OS可能会导致此行为尝试并使其更难利用软件缺陷。在某些情况下,可能有一种方法可以防止这种情况,但如果您的目标是重放同一系列malloc()地址,其他因素可能会更改地址,例如时间敏感行为、文件系统副作用,更不用说不确定的线程行为。您应该尝试并避免在测试中依赖于此。

还要注意,&test应该转换为(void *),因为%p需要一个void指针,但不能保证它具有与int *相同的表示形式。

票数 2
EN

Stack Overflow用户

发布于 2020-05-12 15:45:58

事实证明,您可能无法从MSVC运行时库中获得确定性行为。C/C++运行时库的调试版本和生产版本最终都调用了一个名为_malloc_base()的函数,该函数又调用了Win32 API函数HeapAlloc()。不幸的是,无论是HeapAlloc()还是提供其堆的函数HeapCreate()都没有记录标志或其他方式来获得确定性行为。

您可以按照@Enosh_Cohen的建议,在VirtualAlloc()之上构建自己的分配方案,但是这样就会失去MSVC分配函数提供的debug functionality

票数 2
EN

Stack Overflow用户

发布于 2021-04-03 22:40:38

Diomidis' answer建议在VirtualAlloc之上创建一个新的malloc,所以我就这么做了。事实证明这有些挑战,因为VirtualAlloc本身不是确定性的,所以我记录了我使用的过程。

首先,获取Doug Lea's malloc。(指向源代码的ftp链接已断开;请使用this http alternative。)

然后,将win32mmap函数替换为以下代码(因此将其放入公共领域,就像Doug Lea的malloc本身一样):

代码语言:javascript
代码运行次数:0
运行
复制
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也是如此。您可能需要调整该值。

  • 我证实,在我的特殊情况下,在100次连续运行中获得相同的地址是可行的。对于我想做的调试来说,这已经足够好了,但是在足够多的迭代之后,或者在重启之后,这些值可能会发生变化。

  • 此修改不应用于生产代码,仅用于调试。重试限制是一个错误,我没有做任何事情来跟踪堆何时缩小。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61740028

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档