我有两个应用程序实例,输入和执行顺序相同。因此,其中一个实例是冗余的,并用于将内存中的数据与另一个实例进行比较,作为一种错误检测机制。
现在,我希望在这两个进程中,所有内存分配和释放都以完全相同的方式发生。最简单的方法是什么?编写自己的malloc和free函数吗?那么使用其他函数(如mmap)分配的内存怎么办?
现在,我希望在这两个进程中,所有内存分配和释放都以完全相同的方式发生。最简单的方法是什么?编写自己的malloc和free函数吗?那么使用其他函数(如mmap)分配的内存怎么办?
您可以通过以下方式禁用它:
echo 0 > /proc/sys/kernel/randomize_va_space
作为root用户,或通过sysctl。
如果您不禁用地址空间布局随机化,则无法进行操作。
您之前曾问过类似的问题(链接),在那里我解释了您的malloc
并不总是确定性的。
我仍然认为对于某些实际应用,malloc
无法是确定性的。例如,想象一下一个程序具有哈希表,以其正在启动的子进程的pid
为键。该表中的冲突在所有进程中都不同等等。
因此,我认为您无法使malloc
在您的意义上是确定性的,无论您尝试什么(除非您将自己限制在一个非常狭窄的可检查点应用程序类别中,那么这样的软件将不会非常实用)。
sbrk
,但我相信是的。据我所知,ASLR需要禁用root
权限(否则这是一个巨大的安全漏洞)。 - Basile Starynkevitchpid
索引哈希表会如何使malloc
不确定性。这将使进程在使用malloc
时不确定性,但该函数本身仍然是确定性的。我曾经参与了一个需要确定性的项目,只要注意不从外部引入非确定性(如你所说的来自其他进程的pid
或使用指针的哈希),并且不使用x87 FPU(而是使用SSE),那么你的程序就可以是确定性的。 - Sylvain Defresnemalloc()
返回的内存将是确定性的,这假设您的系统实现不具有某种调用random()
或类似功能的方式。如果您不确定,请阅读您的系统malloc
的代码或文档。personality(2)
系统调用和ADDR_NO_RANDOMIZE参数禁用它。有关个性化的更多信息,请参见此处。gcc -fno-pie -no-pie
)中,静态缓冲区每次都会具有相同的地址。对于 PIE 可执行文件,您可以禁用内核的地址空间布局随机化以加载程序。在共享库中,禁用 ASLR 并两次运行相同的程序应该导致动态链接器对映射库的位置做出相同的选择。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_addr = atoi(argv[++i]);
}
}
malloc_buffer = mmap((void*)buf_addr, buf_size, PROT_WRITE|PROT_READ,
MAP_FIXED|MAP_PRIVATE, 0, 0);
// editor's note: omit MAP_FIXED since you're checking the result anyway
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
,我们告诉内核替换与buf_addr
重叠的任何现有映射。MAP_FIXED
可能不是您想要的。将buf_addr
指定为提示而不是NULL
已经请求该地址(如果可能)。使用MAP_FIXED
,mmap
将返回错误或您提供的地址。 malloc_buffer!=(void *)but_addr
检查对于非FIXED
情况是有意义的,它不会替换代码或共享库或其他任何东西的现有映射。Linux 4.17引入了MAP_FIXED_NOREPLACE
,您可以使用它使mmap返回错误而不是在您不想使用的错误地址上分配内存。但仍然保留检查,以便您的代码适用于旧内核。)gcc -fno-pie -no-pie
**构建非PIE可执行文件。(现代发行版的GCC默认使用PIE)。请参见32位绝对地址在x86-64 Linux中不再允许?。但是,如果您的代码在共享库中,则需要使用内核sysctl或其他方法禁用ASLR。我认为动态链接只是使用mmap
,内核本身并不知道正在映射的是库。 - Peter Cordes在编写高可靠性代码时,通常的做法是避免使用malloc和其他动态内存分配。有时候采用的折衷方案是仅在系统初始化期间进行所有这些分配。
malloc
是确定性的,就像每个计算机算法一样。由于设计原因,计算机在生成非确定性(随机数)值方面表现非常糟糕。可能不确定的是匿名mmap
返回的内存。 - Sylvain Defresnemalloc
源代码(http://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=8608083adbe65c530a0d8ac3bbf547d85586b678;hb=HEAD)来看,该算法似乎是确定性的(不是随机的,也不会读取未初始化的内存)。但是,对于大块分配,它确实调用了`mmap`,这部分是不确定性的。 - Sylvain Defresne