C语言 将 getpid() 与 clone() 一起使用会导致 SIGSEGV



我正在尝试使用下一个代码运行一个简单的clone()

#define _GNU_SOURCE  
#include <linux/sched.h>
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int child_func(void* arg) {
//  printf("Child is running with PID %dn", getpid());
printf("Child is runningn");
return 0;  
} 
int main() {
printf("main() startedn");
pid_t child_pid = clone(child_func, malloc(4096), SIGCHLD, NULL);
pid_t parent_pid = getpid();
printf("Parent pid: %lun", parent_pid);
printf("Child pid: %lun", child_pid);
}

这里一切都很好:

$ ./clone_example 
main() started
Parent pid: 9200
Child pid: 9201
Child is running

直到我通过添加getpid()执行来更改child_func()

...
int child_func(void* arg) {
printf("Child is running with PID %dn", getpid());
//  printf("Child is runningn");
return 0;  
} 
...

重新编译此代码后 -child_func()开始失败。

控制台输出如下所示:

$ ./clone_example 
main() started
Parent pid: 11085
Child pid: 11086

如果使用strace运行:

$ strace -o clone_example.log -ff ./clone_example 
main() started
Parent pid: 11655
Child pid: 11656

在线程的日志clone_example.log.11656中,我看到了下一个:

>     --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x562696b1dff8} ---
>     +++ killed by SIGSEGV (core dumped) +++

为什么会这样? 我在这里做错了什么?

man 2 clone

child_stack参数指定子进程使用的堆栈的位置。 自从孩子和 调用进程可以共享内存,子进程不可能在与 调用进程。 因此,调用进程必须为子堆栈设置内存空间并传递 指向此空间的指针指向clone()堆栈在所有运行 Linux 的处理器上向下增长(HP PA 除外( 处理器(,因此child_stack通常指向为子级设置的内存空间的最顶层地址 叠。

您的孩子遇到了分段错误,因为堆栈向下增长,并且您正在传递指向新分配的内存区域开头的指针,而您应该传递指向该区域末尾的指针。这只发生在你添加另一个函数调用(getpid()(时,因为没有这个调用,你的子进程就不会使用那么多的堆栈。

正确的调用是:

pid_t child_pid = clone(child_func, ((uint8_t*)malloc(4096)) + 4095, SIGCHLD, NULL);

PS:我猜对malloc()的内联调用只是为了简化示例,但是您应该在将malloc()传递给孩子之前检查其返回值。

最新更新