Skip to content Skip to footer

c++ - 为什么 system() 失败并显示错误代码 127?

在 Linux 系统上,我试图通过调用在运行时调用程序system()。系统调用以不等于零的返回码退出。

调用WEXITSTATUS错误代码给出“127”。

根据系统的手册页,此代码表明/bin/sh无法调用:

如果/bin/sh无法执行,退出状态将是执行的命令的状态exit(127)。

我检查了:/bin/sh是一个链接bash。bash在那儿。我可以从外壳执行它。

现在,我怎样才能找出为什么/bin/sh不能被调用?任何内核历史或什么?

编辑:

在非常有用的提示(见下文)之后,我strace -f -p 的过程。这是我在system通话期间得到的:

Process 16080 detached

[pid 11779] <... select resumed> ) = ? ERESTARTNOHAND (To be restarted)

[pid 11774] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 127}], 0, NULL) = 16080

[pid 11779] --- SIGCHLD (Child exited) @ 0 (0) ---

[pid 11779] rt_sigaction(SIGCHLD, {0x2ae0ff898ae2, [CHLD], SA_RESTORER|SA_RESTART, 0x32dd2302d0},

[pid 11774] rt_sigaction(SIGINT, {0x2ae1042070f0, [], SA_RESTORER|SA_SIGINFO, 0x32dd2302d0},

[pid 11779] <... rt_sigaction resumed> {0x2ae0ff898ae2, [CHLD], SA_RESTORER|SA_RESTART, 0x32dd2302d0}, 8) = 0

[pid 11779] sendto(5, "a", 1, 0, NULL, 0

[pid 11774] <... rt_sigaction resumed> NULL, 8) = 0

[pid 11779] <... sendto resumed> ) = 1

[pid 11779] rt_sigreturn(0x2

[pid 11774] rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x32dd2302d0},

[pid 11779] <... rt_sigreturn resumed> ) = -1 EINTR (Interrupted system call)

[pid 11779] select(16, [9 15], [], NULL, NULL

[pid 11774] <... rt_sigaction resumed> NULL, 8) = 0

[pid 11774] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

[pid 11774] write(1, "Problems calling nvcc jitter: ex"..., 49) = 49

[pid 11774] rt_sigaction(SIGINT, {0x1, [], SA_RESTORER, 0x32dd2302d0}, {0x2ae1042070f0, [], SA_RESTORER|SA_SIGINFO, 0x32dd2302d0}, 8) = 0

[pid 11774] rt_sigaction(SIGQUIT, {0x1, [], SA_RESTORER, 0x32dd2302d0}, {SIG_DFL, [], SA_RESTORER, 0x32dd2302d0}, 8) = 0

[pid 11774] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0

[pid 11774] clone(Process 16081 attached (waiting for parent)

Process 16081 resumed (parent 11774 ready)

child_stack=0, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7fff0177ab68) = 16081

[pid 16081] rt_sigaction(SIGINT, {0x2ae1042070f0, [], SA_RESTORER|SA_SIGINFO, 0x32dd2302d0},

[pid 11774] wait4(16081, Process 11774 suspended

[pid 16081] <... rt_sigaction resumed> NULL, 8) = 0

[pid 16081] rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x32dd2302d0}, NULL, 8) = 0

[pid 16081] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

[pid 16081] execve("/bin/sh", ["sh", "-c", 0xdda1d98], [/* 58 vars */]) = -1 EFAULT (Bad address)

[pid 16081] exit_group(127) = ?

Process 11774 resumed

当谈到调用/bin/sh它说坏地址。为什么 ?

编辑:

这里涉及失败的整个部分system(这里已经安全复制到缓冲区):

std::ostringstream jit_command;

jit_command << string(CUDA_DIR) << "/bin/nvcc -v --ptxas-options=-v ";

jit_command << "-arch=" << string(GPUARCH);

jit_command << " -m64 --compiler-options -fPIC,-shared -link ";

jit_command << fname_src << " -I$LIB_PATH/include -o " << fname_dest;

string gen = jit_command.str();

cout << gen << endl;

char* cmd = new(nothrow) char[gen.size()+1];

if (!cmd) ___error_exit("no memory for jitter command");

strcpy(cmd,gen.c_str());

int ret;

if (ret=system(cmd)) {

cout << "Problems calling nvcc jitter: ";

if (WIFEXITED(ret)) {

printf("exited, status=%d\n", WEXITSTATUS(ret));

} else if (WIFSIGNALED(ret)) {

printf("killed by signal %d\n", WTERMSIG(ret));

} else if (WIFSTOPPED(ret)) {

printf("stopped by signal %d\n", WSTOPSIG(ret));

} else if (WIFCONTINUED(ret)) {

printf("continued\n");

} else {

printf("not recognized\n");

}

cout << "Checking shell.. ";

if(system(NULL))

cout << "ok!\n";

else

cout << "nope!\n";

__error_exit("Nvcc error\n");

}

delete[] cmd;

return true;

输出:

/usr/local/cuda/bin/nvcc -v --ptxas-options=-v -arch=sm_20 -m64 --compiler-options -fPIC,-shared -link bench_cudp_Oku2fm.cu -I$LIB_PATH/include -o bench_cudp_Oku2fm.o

Problems calling nvcc jitter: exited, status=127

Checking shell.. ok!

编辑(代码的第一个版本):

string gen = jit_command.str();

cout << gen << endl;

int ret;

if (ret=system(gen.c_str())) {

....

字符串创建的复杂性不是这里的问题。如图strace所示,“错误地址”是问题所在。它是一个合法的字符串。不应出现“错误地址”。

据我所知,std::string::c_str()返回的 aconst char *可能指向 libc++ 的暂存空间,其中可能保留字符串的只读副本。

不幸的是,该错误并不是真正可重现的。在失败之前调用system成功多次。

我不想仓促,但它闻起来像是内核、libc 或硬件中的错误。

编辑:

我为失败的系统调用生成了更详细的strace输出 ( ):strace -f -v -s 2048 -e trace=process -p $!execve

首先是一个成功的调用:

[pid 2506] execve("/bin/sh", ["sh", "-c", "/usr/local/cuda/bin/nvcc -v --ptxas-options=-v -arch=sm_20 -m64 --compiler-options -fPIC,-shared -link /home/user/toolchain/kernels-empty/bench_cudp_U11PSy.cu -I$LIB_PATH/include -o /home/user/toolchain/kernels-empty/bench_cudp_U11PSy.o"], ["MODULE_VERSION_STACK=3.2.8", ... ]) = 0

现在失败的一个:

[pid 17398] execve("/bin/sh", ["sh", "-c", 0x14595af0], ) = -1 EFAULT (Bad address)

这里是相同的。似乎它不是导致错误地址的环境变量列表。正如 Chris Dodd 提到的 execve 的第三个参数是原始指针 0x14595af0,strace 认为(并且内核同意)是无效的。strace不将其识别为字符串(因此它打印十六进制值而不是字符串)。

编辑:

我从指针值中插入打印出来,cmd看看父进程中这个指针的值是什么:

string gen = jit_command.str();

cout << gen << endl;

char* cmd = new(nothrow) char[gen.size()+1];

if (!cmd) __error_exit("no memory for jitter command");

strcpy(cmd,gen.c_str());

cout << "cmd = " << (void*)cmd << endl;

int ret;

if (ret=system(cmd)) {

cout << "failed cmd = " << (void*)cmd << endl;

cout << "Problems calling nvcc jitter: ";

输出(对于失败的调用):

cmd = 0x14595af0

failed cmd = 0x14595af0

Problems calling nvcc jitter: exited, status=127

Checking shell.. ok!

它的指针值与来自 的第三个参数相同strace。(我更新了strace上面的输出)。

关于指针的 32 位外观cmd:我检查了cmd指针的值以进行后续调用。看不出结构上有什么区别。cmd这是thensystem调用成功时的值之一:

cmd = 0x145d4f20

所以,在system调用之前指针是有效的。正如strace上面的输出表明子进程(在调用之后fork)接收到正确的指针值。但是,由于某种原因,指针值在子进程中被标记为无效。

现在我们认为它要么:

libc/内核错误

硬件问题

编辑:

同时让我发布一个解决方法。被迫实施这样的事情真是太愚蠢了……但它确实有效。system因此,如果调用失败,将执行以下代码块。它分配新的命令字符串并重试直到成功(不是无限期地)。

list listPtr;

int maxtry=1000;

do{

char* tmp = new(nothrow) char[gen.size()+1];

if (!tmp) __error_exit("no memory for jitter command");

strcpy(tmp,gen.c_str());

listPtr.push_back( tmp );

} while ((ret=system(listPtr.back())) && (--maxtry>0));

while(listPtr.size()) {

delete[] listPtr.back();

listPtr.pop_back();

}

编辑:

我刚刚看到这种解决方法在一次特定的运行中不起作用。它一路走来,1000 次尝试,全部使用新分配的cmd命令字符串。1000 次全部失败。不仅如此。我尝试了不同的 Linux 主机(相同的 Linux/软件配置)。

考虑到这一点,可能会排除硬件问题。(然后必须在 2 个物理上不同的主机上)。仍然是内核错误??

编辑:

torek,我将尝试安装修改后的system呼叫。给我一些时间。

Copyright © 2088 世界杯德国巴西_世界杯为什么四年一次 - lynzzx.com All Rights Reserved.
友情链接