• 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.

  • 相关阅读:
    declare handler 声明异常处理的语法
    mysql存储过程获取sqlstate message_text
    mongoTemplate操作内嵌文档
    mysql索引之七:组合索引中选择合适的索引列顺序
    mongoDB的操作总结
    explain之三:MYSQL EXPLAIN语句的extended 选项学习体会,分析诊断工具之二
    状态模式
    代码重构----使用java有限状态机来消除太多的if else判断
    断路器(CircuitBreaker)设计模式
    断路器之一:Hystrix 使用与分析
  • 原文地址:https://www.cnblogs.com/dream397/p/14098918.html
Copyright © 2020-2023  润新知