В системе Linux я пытаюсь вызвать программу во время выполнения с помощью вызова system()
.
Системный вызов завершается с кодом возврата, не равным нулю.
Вызов WEXITSTATUS
по коду ошибки дает "127".
Согласно справочной странице системы этот код указывает, что /bin/sh
не может быть вызван:
В случае, если /bin/sh
не может быть выполнен,
статус выхода будет таким, как у команды, которая выполняет exit(127)
.
Я проверил: /bin/sh
- это ссылка на bash
. bash
там. Я могу выполнить его из оболочки.
Теперь, как я могу узнать, почему /bin/sh
не может быть вызван?
Любая история ядра или что-то?
Edit:
После очень полезного совета (см. Ниже) я strace -f -p <PID>
процесс. Вот что я получаю во время 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}, <unfinished ...>
[pid 11774] rt_sigaction(SIGINT, {0x2ae1042070f0, [], SA_RESTORER|SA_SIGINFO, 0x32dd2302d0}, <unfinished ...>
[pid 11779] <... rt_sigaction resumed> {0x2ae0ff898ae2, [CHLD], SA_RESTORER|SA_RESTART, 0x32dd2302d0}, 8) = 0
[pid 11779] sendto(5, "a", 1, 0, NULL, 0 <unfinished ...>
[pid 11774] <... rt_sigaction resumed> NULL, 8) = 0
[pid 11779] <... sendto resumed> ) = 1
[pid 11779] rt_sigreturn(0x2 <unfinished ...>
[pid 11774] rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x32dd2302d0}, <unfinished ...>
[pid 11779] <... rt_sigreturn resumed> ) = -1 EINTR (Interrupted system call)
[pid 11779] select(16, [9 15], [], NULL, NULL <unfinished ...>
[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}, <unfinished ...>
[pid 11774] wait4(16081, Process 11774 suspended
<unfinished ...>
[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
, он говорит, что адрес плохой. Почему это?
Edit:
Здесь вся часть, которая включает сбой 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()
возвращает const char *
, который может указывать на пустое место в libc ++, где может храниться копия строки только для чтения.
К сожалению, ошибка на самом деле не воспроизводима. Вызов system
завершается успешно несколько раз, прежде чем происходит сбой.
Я не хочу быть поспешным, но пахнет как ошибка в ядре, libc или аппаратном обеспечении.
Edit:
Я произвел более подробный 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], <list of vars>) = -1 EFAULT (Bad address)
Здесь <list of vars>
идентично. Кажется, это не список переменных среды, которые вызывают неправильный адрес.
Как отметил Крис Додд, третий аргумент execve - это необработанный указатель 0x14595af0, который strace считает (и ядро соглашается) недопустимым. strace
не распознает его как строку (поэтому печатает шестнадцатеричное значение, а не строку).
Edit:
Я вставил print из значения указателя 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
, когда system
вызов завершается успешно:
cmd = 0x145d4f20
Итак, до вызова system
указатель действителен. Как показывает вывод strace
, указанный выше, дочерний процесс (после вызова fork
) получает правильное значение указателя. Но по какой-то причине значение указателя помечается как недопустимое в дочернем процессе.
Сейчас мы думаем, что либо:
- ошибка libc / kernel
- аппаратная проблема
Edit:
А пока позвольте мне опубликовать обходной путь. Так глупо быть вынужденным реализовать что-то подобное ... но это работает. Поэтому следующий кодовый блок выполняется в случае сбоя вызова system
. Он распределяет новые командные строки и повторяет попытки, пока не выполнится (ну, не бесконечно).
list<char*> 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();
}
Edit:
Я только что увидел, что этот обходной путь в одном конкретном прогоне не работал. Он прошел весь путь, 1000 попыток, все с недавно выделенными cmd
строками команд. Все 1000 провалились.
Не только это. Я пробовал на другом хосте Linux (та же конфигурация Linux / программного обеспечения).
Принимая это во внимание, можно исключить аппаратную проблему. (Должно быть на 2 физически разных хостах). Остается ошибка ядра ??
Edit:
Торек, я попытаюсь установить модифицированный system
вызов.Дай мне немного времени для этого.