% cat segfault.c
#include <stdio.h>
int main()
{
char *s = "hello world";
*s = 'H';
printf("%s\n", s);
}
% CFLAGS=-g make segfault
gcc -g segfault.c -o segfault
O erro vem de algo executando uma chamada waitpid , geralmente o shell:
% ./segfault
zsh: bus error ./segfault
como aqui zsh caiu de um waitpid e, em seguida, percorreu algum caminho de código envolvendo WIFSIGNALED . (o macOS emite um erro de barramento em vez de um segfault (uma rosa por qualquer outro nome) e o erro exato da string irá variar dependendo do shell.)
O OpenSSH portable (a partir do commit ed7bd5d93fe14c7bd90febd29b858ea985d14d45) faz várias chamadas WIFSIGNALED(status) notavelmente em misc.c , session.c e sshd.c ; alguns desses return -1 que poderiam facilmente se transformar no status de saída 255 , embora eu precise adicionar depuração ou rastreio sshd para ver exatamente como esse caso acontece ( ssh -v -v -v não ajuda, nem o padrão sshd logs).
Como kluge, você pode forçar um waitpid a acontecer. Isso requer enganar um shell para não executar um exec simples para substituir a si mesmo, o que ele fará como uma otimização, se puder:
% ssh localhost 'sh -c ./segfault'
% ssh localhost ':; ./segfault'
% ssh localhost 'sh -c ":; ./segfault"'
sh: line 1: 9068 Bus error: 10 ./segfault
%
:; ... é complexo o suficiente para que sh não fork / exec e, em vez disso, termine waitpid on segfault e, em seguida, relate isso. Observe que o relatório de erros irá variar dependendo do sabor exato de sh .
% ssh localhost '/usr/local/bin/sh -c ":; ./segfault"'
Bus Error
Agora, se sh está causando o segfault (ou qualquer sinal inesperado), você precisará inspecionar o código de saída do SSH. Outra opção seria chamar um pequeno wrapper que faz o waitpid sem truques de shell:
#include <sys/wait.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int status;
pid_t pid;
if (argc < 2) {
fprintf(stderr, "Usage: waiter command [args ..]\n");
exit(1);
}
pid = fork();
if (pid < 0) {
err(1, "could not fork");
} else if (pid == 0) { /* child */
argv++;
execvp(*argv, argv);
err(1, "could not exec");
} else { /* parent */
if (waitpid(pid, &status, 0) < 0)
err(1, "could not waitpid");
if (WIFEXITED(status)) {
exit(WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
warnx("child exited with signal %d", WTERMSIG(status));
exit(128 + WTERMSIG(status));
} else {
err(1, "unknown waitpid condition?? status=%d", status);
}
}
exit(1);
}
... embora este wrapper também possa segfault (ou qualquer sinal), especialmente se o servidor tiver problemas de hardware, memória ruim, etc.
% ssh localhost ./waiter ./segfault
waiter: child exited with signal 10
No entanto, o wrapper tem muito menos código do que um típicosh% (~ 50 linhas versus ~ 10.000 para o shell bourne da herança) por isso deve ser menos provável que ele próprio cause uma condição de saída por sinal. (Você verificou o código de saída, certo?)