如何实现确定性malloc

说我有一个应用程序的两个实例,具有相同的input和相同的执行顺序。 因此,一个实例是冗余实例,用于将内存中的数据与另一实例进行比较,作为一种错误检测机制。

现在,我希望所有内存分配和释放在两个进程中以完全相同的方式发生。 什么是最简单的方法来实现呢? 写我自己的malloc和免费的? 那么如何分配与其他function,如mmap的内存?

我想知道你在做什么。 如果你的过程是确定性的,那么分配/释放模式应该是相同的。

唯一可能的区别可能是malloc返回的地址。 但是你可能不应该依赖它们(最简单的方法是不使用指针作为键映射或其他数据结构)。 即使如此,如果分配不通过sbrk (glibc使用匿名mmap进行大分配),或者如果使用mmap (默认情况下地址由内核选择),那么应该只有区别。

如果你真的想拥有完全相同的地址,一个选择是有一个大的静态缓冲区,并写一个自定义的分配器,使用这个缓冲区的内存。 这有一个缺点,迫使你事先知道你需要的最大内存量。 如果您使用内核地址空间布局随机化 ,这可能会中断。

如果您事先不知道要使用的最大内存大小,或者如果每次增加此大小时不想重新编译,则还可以使用mmap将固定地址上的大型匿名缓冲区映射。 只需将缓冲区的大小和地址作为参数传递给进程,然后使用返回的内存在其上实现自己的malloc

 static void* malloc_buffer = NULL; static size_t malloc_buffer_len = 0; void* malloc(size_t size) { // Use malloc_buffer & malloc_buffer_len to implement your // own allocator. If you don't read uninitialized memory, // it can be deterministic. return memory; } int main(int argc, char** argv) { size_t buf_size = 0; uintptr_t buf_addr = 0; for (int i = 0; i < argv; ++i) { if (strcmp(argv[i], "--malloc-size") == 0) { buf_size = atoi(argv[++i]); } if (strcmp(argv[i], "--malloc-addr") == 0) { buf_size = atoi(argv[++i]); } } malloc_buffer = mmap((void*)buf_addr, buf_size, PROT_WRITE|PROT_READ, MAP_FIXED|MAP_PRIVATE, 0, 0); if (malloc_buffer == MAP_FAILED || malloc_buffer != (void*)but_addr) { // Could not get requested memory block, fail. exit(1); } malloc_size = buf_size; } 

通过使用[MAP_FIXED][2] ,我们要求有一个所需大小的内存块,并从给定的地址开始。 如果使用此块来实现自己的malloc,并且不要在代码中使用其他非确定性操作,则可以完全控制指针值。

这假设你的malloc / free的模式使用是确定性的。 而且你不使用非确定性的库。

不过,我认为一个更简单的解决方案是保持算法的确定性,而不是依赖于地址。 这个有可能。 我曾经在一个大型项目上工作,多台计算机必须确定性地更新状态(以便每个程序具有相同的状态,而只有传输输入)。 如果除了引用对象之外,不使用指针来引用其他东西(最重要的是从不使用指针值作为散列,而不是用作映射中的键),那么你的状态将保持确定性。

除非你想要做的是能够快照整个进程内存,并做一个二进制差异来发现分歧。 我认为这是一个糟糕的主意,因为你怎么知道他们在计算中达到了同一个点呢? 比较输出要容易得多,或者让进程能够计算状态的哈希值,并使用它来检查它们是否同步,因为您可以控制何时完成(因此也变得确定,否则你的测量是非确定性的)。

就像其他人所说的那样:如果程序指令的执行是确定性的,那么malloc()返回的malloc()将是确定性的。 这假定你的系统的实现没有一些调用random()或者这个效果。 如果您不确定,请阅读系统的malloc的代码或文档。

正如其他人也指出的那样,ASLR可能是个例外。 如果您没有root权限,则可以通过personality(2)系统调用和ADDR_NO_RANDOMIZE参数禁用每个进程。 在这里看到更多关于个性的信息。

编辑:我也应该说,如果你不知道:你在做什么叫做互模拟 ,是一个研究得很好的技术。 如果您不知道术语,可能有助于使用该关键字进行搜索。

编写高可靠性代码时,通常的做法是避免malloc和其他动态内存分配。 有时使用的折衷办法是仅在系统初始化期间进行所有这样的分配。

什么是不确定性的不仅是malloc而且是mmap (获取更多内存空间的基本系统调用;它不是一个函数,它是一个系统调用,所以从应用程序的角度来看是基本的或原子的;所以你不能在应用程序)因为在Linux上的地址空间布局随机化 。

你可以用它来禁用它

  echo 0 > /proc/sys/kernel/randomize_va_space 

作为根,或通过sysctl 。

如果你不禁用地址空间布局随机化,你卡住了。

你以前也曾经问过类似的问题,我解释过你的malloc -s并不总是确定的。

我仍然认为对于一些实际应用, malloc不能是确定性的。 想象一下,例如一个程序有一个由它所启动的子进程的pid -s键入的散列表。 该表中的碰撞在所有的过程中不会相同

所以我相信,无论你想要什么(除非你将自己的应用程序限制在一个非常狭窄的应用程序类别中,因此你的软件将不会非常有用),你不会成功地在你的意义上确定malloc确定性。

您可以使用共享内存来存储您的数据。 它可以从两个进程访问,你可以用确定的方式填写它。