On Fri, 25 Oct 2019, Thorsten Glaser wrote:

> Using qemu-user-static in an m68k chroot:
> 
> # ./mksh -c '/bin/echo foo; echo bar'
> foo
> ^C^\
> 
> (it just hangs here, with qemu-user-static:i386; on the

This is really hard to debug, as neither strace nor gdb work under
qemu-user-static, and the broken FPU emulation means I also cannot
attach gdb-multiarch to qemu-user-static (FPU size 96 not supported,
gdbserver packet size mismatches).

I _believe_ SIGCHLD is never delivered. write(2)-to-stderr debugging
shows that it loops “forever” in jobs.c:j_waitj() in this loop:

        while (j->state == PRUNNING ||
            ((flags & JW_STOPPEDWAIT) && j->state == PSTOPPED)) {
                sigsuspend(&sm_default);
                if (fatal_trap)  // no, else is taken
                if ((flags & JW_INTERRUPT) && (rv = trap_pending())) // no, 
else is taken
        }

j->state is supposed to be changed by the SIGCHLD handler,
namely j_sigchld() in jobs.c, but it is never called.

I was not able to reproduce this in an MWE: all attempts still work
(I’m attaching it, in case someone else can make more sense out of it);
compiling it exactly the same as mksh with (the -D* are ignored, but
this is literally taking the mksh compile command line and changing
the filenames):

 klcc  -O2 -fno-lto -Wno-deprecated-declarations 
-fno-asynchronous-unwind-tables -fno-strict-aliasing -Wall -fwrapv -I. 
-I'../mksh'  -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN 
-DMKSH_NO_LIMITS -DHAVE_STRING_POOLING=2 -DHAVE_ATTRIBUTE_BOUNDED=0 
-DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 
-DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 
-DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=0 -DHAVE_SYS_BSDTYPES_H=0 
-DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 
-DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 
-DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_IO_H=0 
-DHAVE_LIBGEN_H=0 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 
-DHAVE_STRINGS_H=0 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 
-DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 
-DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=0 -Dsig_t=__sighandler_t -DHAVE_SIG_T=1 
-DHAVE_SYS_ERRLIST=1 -DHAVE_SYS_SIGNAME=0 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 
-DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 
-DHAVE_KILLPG=0 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 
-DHAVE_FTRUNCATE=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 
-DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=0 
-DHAVE_SETGROUPS=0 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 
-DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 
-DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=571 -c t.c
 klcc  -O2 -fno-lto -Wno-deprecated-declarations 
-fno-asynchronous-unwind-tables -fno-strict-aliasing -Wall -fwrapv -static 
-fno-lto -o t t.o

bye,
//mirabilos
-- 
tarent solutions GmbH
Rochusstraße 2-4, D-53123 Bonn • http://www.tarent.de/
Tel: +49 228 54881-393 • Fax: +49 228 54881-235
HRB 5168 (AG Bonn) • USt-ID (VAT): DE122264941
Geschäftsführer: Dr. Stefan Barth, Kai Ebenrett, Boris Esser, Alexander Steeg

**********

Mit der tarent Academy bieten wir auch Trainings und Schulungen in den
Bereichen Softwareentwicklung, Agiles Arbeiten und Zukunftstechnologien an.

Besuchen Sie uns auf www.tarent.de/academy. Wir freuen uns auf Ihren Kontakt.

**********
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static void handler(int);
static sigset_t sm_sigchld;
static sigset_t sm_default;
static volatile sig_atomic_t found = 0;

#define STKBUFSZ 80
static const char *stkbuf;

#define w(s) write(2, (s), strlen(s))

static void
handler(int signo)
{
	int save_errno = errno;
	struct rusage ru0;
	sigset_t omask;

	w("beg signal: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");

	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
	getrusage(RUSAGE_CHILDREN, &ru0);
	found = 1;
	sigprocmask(SIG_SETMASK, &omask, NULL);

	w("end signal: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");
	errno = save_errno;
}

static struct sigaction sa;
static pid_t pid;

static char newarg0[] = "/bin/sleep";
static char newarg1[] = "1";
static char *newarg[] = { newarg0, newarg1, NULL };

int
main(int argc, char *argv[], char *envp[])
{
	char buffer[STKBUFSZ];

	memset(buffer, 'b', STKBUFSZ);
	buffer[0] = 'a';
	buffer[STKBUFSZ - 1] = 'c';
	stkbuf = buffer;

	(void)sigemptyset(&sm_default);
	sigprocmask(SIG_SETMASK, &sm_default, NULL);

	(void)sigemptyset(&sm_sigchld);
	(void)sigaddset(&sm_sigchld, SIGCHLD);

	sa.sa_handler = handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;

	w("before cld: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");

	if ((pid = fork()) == -1) {
		fprintf(stderr, "cannot fork: %s\n", strerror(errno));
		return (1);
	} else if (!pid) {
		buffer[1] = 'd';
		w("inside cld: {");
		write(2, stkbuf, STKBUFSZ);
		w("}\n");

		execve(newarg0, newarg, envp);
		fprintf(stderr, "cannot exec: %s\n", strerror(errno));
		return (1);
	}

	w("before sig: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");

	if (sigaction(SIGCHLD, &sa, NULL)) {
		fprintf(stderr, "cannot sigaction: %s\n", strerror(errno));
		return (1);
	}

	while (!found) {
		w("before sus: <");
		write(2, stkbuf, STKBUFSZ);
		w(">\n");

		sigsuspend(&sm_default);
	}

	w(" after sus: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");

	errno = 0;
	if ((pid = waitpid(-1, NULL, WUNTRACED)) == 0) {
		fprintf(stderr, "wait would block: %s\n", strerror(errno));
		return (1);
	} else if (pid < 0) {
		fprintf(stderr, "wait no children or interrupted: %s\n", strerror(errno));
		return (1);
	}

	w("after wait: <");
	write(2, stkbuf, STKBUFSZ);
	w(">\n");

	return (0);
}

Reply via email to