【问题标题】:Calling "clone()" on linux but it seems to malfunction在 linux 上调用“clone()”,但似乎出现故障
【发布时间】:2017-05-25 16:31:45
【问题描述】:

一个简单的测试程序,我希望它会“克隆”一个子进程,每个进程都可以执行到结束

#include<stdio.h>
#include<sched.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
}
char buf[1024];
int main()
{
    printf("before clone\n");
    int pid=clone(f,buf,CLONE_VM|CLONE_VFORK,NULL);
    if(pid==-1){
        printf("%d\n",errno);
        return 1;
    }
    waitpid(pid,NULL,0);
    printf("after clone\n");
    printf("father pid=%d\n",getpid());
    return 0;
}

算了:

$g++ testClone.cpp && ./a.out
before clone

它没有打印出我所期望的。似乎在“克隆”后程序处于未知状态然后退出。我尝试了 gdb 并打印:

Breakpoint 1, main () at testClone.cpp:15
(gdb) n-
before clone
(gdb) n-
waiting for new child: No child processes.
(gdb) n-
Single stepping until exit from function clone@plt,-
which has no line number information.

如果我删除“waitpid”这一行,那么 gdb 会打印另一种奇怪的信息。

(gdb) n-
before clone
(gdb) n-
Detaching after fork from child process 26709.
warning: Unexpected waitpid result 000000 when waiting for vfork-done
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x00007fb18a446bf1 in clone () from /lib64/libc.so.6
ptrace: No such process.

我的程序哪里出错了?

【问题讨论】:

    标签: linux gcc process gdb clone


    【解决方案1】:

    您永远不应该在用户级程序中调用clone——在cloned 进程中允许您执行的操作有太多限制。

    特别是,调用任何libc 函数(例如printf)是完全禁止的(因为libc 不知道您的clone 存在,并且没有对其执行任何设置) .

    正如 K. A. Buhr 指出的那样,你也传递了太小的筹码,而且它的末端是错误的。您的堆栈也未正确对齐。

    简而言之,尽管 K. A. Buhr 的修改看起来有效,但实际上并没有。

    TL;DR: clone,只是不要使用它。

    【讨论】:

      【解决方案2】:

      clone 的第二个参数是一个指向子堆栈的指针。根据clone(2) 的手册页:

      所有运行 Linux 的处理器(HP PA 处理器除外)上的堆栈都向下增长,因此 child_stack 通常指向为子堆栈设置的内存空间的最高地址。

      此外,1024 字节对于堆栈来说是微不足道的。您的程序的以下修改版本似乎可以正常运行:

      // #define _GNU_SOURCE   // may be needed if compiled as C instead of C++
      #include <stdio.h>
      #include <sched.h>
      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/wait.h>
      #include <errno.h>
      
      int f(void*arg)
      {
          pid_t pid=getpid();
          printf("child pid=%d\n",pid);
          return 0;
      }
      char buf[1024*1024];   // *** allocate more stack ***
      int main()
      {
          printf("before clone\n");
          int pid=clone(f,buf+sizeof(buf),CLONE_VM|CLONE_VFORK,NULL);
               // *** in previous line: pointer is to *end* of stack ***
          if(pid==-1){
              printf("%d\n",errno);
              return 1;
          }
          waitpid(pid,NULL,0);
          printf("after clone\n");
          printf("father pid=%d\n",getpid());
          return 0;
      }
      

      另外,@Employed Russian 是对的——除非你想找点乐子,否则你可能不应该使用 clone。无论forkvfork 是满足您需求时clone 的更明智的接口。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-14
        • 1970-01-01
        • 1970-01-01
        • 2022-06-22
        • 2011-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多