zoukankan      html  css  js  c++  java
  • gdb多进程 clone系统调用 received signal SIGBUS, Bus error

    #define _GNU_SOURCE
    #include<sched.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<errno.h>
    #include<string.h>
    
    static char child_stack[2048];
    
    int x = 10;
    
    static int child_fn() {
        printf("Pid: %ld
    ", (long) getpid());
        return 0;
    }
    
    int main() {
        printf("before= %d
    ", x);
        errno = 0;
        pid_t child_pid = clone(&child_fn, (void *) child_stack+1024, CLONE_NEWPID | SIGCHLD, NULL);
        if(child_pid == -1) {
            printf("%s
    ", strerror(errno));
            return 0;
        } else {
            printf("clone()= %ld
    ", (long) child_pid);
            printf("after= %d
    ", x);
    
            while(waitpid(-1, NULL, 0) < 0 && errno == EINTR) {
                printf("waiting
    ");
                continue;
            }
    
            return 0;
        }
    }
    



    我得到的输出是:

    before= 10
    clone()= 16
    after= 10
    



    这意味着child_fn确实分配了一个Pid,即child_pid。但是printf中的child_fn是不是没有执行,或者可能是在其他stdout范围内打印?无论哪种方式,这可能是什么原因,以及如何对其进行调试。我只是从名称空间开始,所以对它们了解不多。

    如果我使用gdb运行原始代码,则会发现它失败并显示SIGSEGV

    $ gcc -o clone clone.c
    $ sudo gdb ./clone
    (gdb) set follow-fork-mode child
    (gdb) run
    Starting program: /home/lars/tmp/clone 
    before= 10
    [New process 10768]
    clone()= 10768
    after= 10
    
    Thread 2.1 "clone" received signal SIGSEGV, Segmentation fault.
    [Switching to process 10768]
    0x00007ffff7a5e9de in vfprintf () from /lib64/libc.so.6
    



    我怀疑您的child_stack太小。您分配了2048个字节,但只使用了一半。如果我将clone调用修改为如下所示:

    pid_t child_pid = clone(&child_fn, (void *) child_stack+2048, CLONE_NEWPID | SIGCHLD, NULL);
    



    然后在我的系统上似乎可以正常运行:

    $ sudo gdb ./clone
    (gdb) set follow-fork-mode child
    (gdb) run
    Starting program: /home/lars/tmp/clone 
    Missing separate debuginfos, use: dnf debuginfo-install glibc-2.24-9.fc25.x86_64
    before= 10
    [New process 10807]
    clone()= 10807
    after= 10
    Pid: 1
    [Inferior 2 (process 10807) exited normally]
    root@cloud:/nsexec# gcc simple.c  -o simple
    root@cloud:/nsexec# ./simple 
    clone() = 58961
    root@cloud:/nsexec# gdb ./clone
    GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
    Copyright (C) 2018 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "aarch64-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from ./clone...(no debugging symbols found)...done.
    (gdb) set follow-fork-mode child
    (gdb) run
    Starting program: /nsexec/clone 
    [New process 58985]
    clone() = 58985
    
    Thread 2.1 "clone" received signal SIGBUS, Bus error.
    [Switching to process 58985]
    0x0000aaaaaaaaa8d8 in child_func ()
    (gdb) 

    From man 2 clone:

    The child_stack argument specifies the location of the stack used by the child process. Since the child and calling process may share memory, it is not possible for the child process to execute in the same stack as the calling process. The calling process must therefore set up memory space for the child stack and pass a pointer to this space to clone()Stacks grow downward on all processors that run Linux (except the HP PA processors), so child_stack usually points to the topmost address of the memory space set up for the child stack.

    Your child is running into segmentation fault because the stack grows down and you are passing a pointer to the start of a newly allocated memory area, when you should pass a pointer to the end of such area. This only happens when you add another function call (getpid()) because without that call your child process is not using as much stack.

    Correct call would be:

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

    PS: I'm guessing that inline call to malloc() was just to simplify the example, but you should check the return value of malloc() before passing it to the child.

  • 相关阅读:
    语言及其文法
    编译原理绪论
    数据库系统绪论
    Flask系列-模板
    进程调度
    Flask系列-程序基本结构
    针对博客园上传md文件有点麻烦的解决方案
    博客样式存档二 (目前样式)
    [省选联考 2020 A 卷] 组合数问题
    退役划水(2)
  • 原文地址:https://www.cnblogs.com/dream397/p/14098918.html
Copyright © 2011-2022 走看看