hush for non-mmu system

Denys Vlasenko vda.linux at googlemail.com
Sun Aug 31 21:15:41 UTC 2014


On Sun, Aug 31, 2014 at 3:54 PM, Waldemar Brodkorb
<mail at waldemar-brodkorb.de> wrote:
> Hi Denys,
> Denys Vlasenko wrote,
>
>> > mmap2(NULL, 197, PROT_READ|PROT_WRITE,
>> These many tiny mmaps are the result of your uclibc
>> .config having MALLOC_SIMPLE=y.
>> Try using
>> MALLOC_STANDARD=y
>> MALLOC_GLIBC_COMPAT=y
>> instead
>
> Okay, changed. But did not result in a working hush.
>
>> > vfork()                                 = 29
>> > munmap(0x419f8000, 197)                 = 0
>> > wait4(-1, bin    dev    lib    mnt    root   sys    usr
>> > boot   etc    media  proc   sbin   tmp    var
>> > [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED, NULL) = 29
>> > --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=29,
>> > si_status=0, si_utime=0, si_stime=0} ---
>> > sigreturn() (mask [HUP TRAP])           = 29
>> > rt_sigreturn()                          = 0
>> > --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
>> > +++ killed by SIGSEGV +++
>> >
>> > After that the system is unresponsible. It is unimportant which
>> > command is executed. (ps, ls, ..)
>>
>> I did not try to reproduce it with exactly your version/.config of uclibc.
>>
>> I did try your busybox .config, against glibc and uclibc.
>> In each case, it worked. My strace looks like this:
>
> On which architecture or target? With or without MMU?

x86 with FORCE_NOMMU=y (actually, with exactly your bbox .config)


>  'ls'
>     : pipe member 'ls' '(null)'...
>     execing 'ls'
>   run_pipe return -1 (1 children started)
>   checkjobs 0x41d96a44
> bin      dev      lib      media    proc     sbin     tmp      var
> boot     etc      linuxrc  mnt      root     sys      usr
> />

Thanks. Looks like we do succeed in vforking a child,
then parent reaches checkjobs() function and there it waits
for any child to terminate:

 wait_more:
        while (1) {
                int i;
                int dead;

                childpid = waitpid(-1, &status, attributes);  <<< HERE
                if (childpid <= 0) {
                        if (childpid && errno != ECHILD)
                                bb_perror_msg("waitpid");
                        break;
                }
                dead = WIFEXITED(status) || WIFSIGNALED(status);

#if DEBUG_JOBS
                if (WIFSTOPPED(status))
                        debug_printf_jobs("pid %d stopped by sig %d
(exitcode %d)\n",
                                        childpid, WSTOPSIG(status),
WEXITSTATUS(status));
                if (WIFSIGNALED(status))
                        debug_printf_jobs("pid %d killed by sig %d
(exitcode %d)\n",
                                        childpid, WTERMSIG(status),
WEXITSTATUS(status));
                if (WIFEXITED(status))
                        debug_printf_jobs("pid %d exited, exitcode %d\n",
                                        childpid, WEXITSTATUS(status));
#endif

We do reach waitpid(-1) line - it is visible in strace.
However, in your debug build you aren't getting
"pid NNNNN exited, exitcode 0" message.
I do. So, the SIGSEGV happens somewhere between
"waitpid(-1)" and "#if DEBUG_JOBS" lines above.

The last thing your strace shows is

--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=29,
si_status=0, si_utime=0, si_stime=0} ---
sigreturn() (mask [HUP TRAP])           = 29
rt_sigreturn()                          = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---

It means that a signal handler was executed.
In this case, it should be a SIGCHLD handler,
which is a very simple function called record_pending_signo(),
it merely records a bit in a bitmask :

static void record_pending_signo(int sig)
{
        sigaddset(&G.pending_set, sig);
#if ENABLE_HUSH_FAST
        if (sig == SIGCHLD) {
                G.count_SIGCHLD++;
//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d
G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
        }
#endif
}

but it looks that at least return from sighandler didn't quite work.

(Just to be sure: you did not change "#define ENABLE_HUSH_FAST 0" to 1, right?)

Let's find out how far do you get in this code
Add two debug statements:

             childpid = waitpid(-1, &status, attributes);
             debug_printf("AFTER WAIT-1\n");   <<<THIS

static void record_pending_signo(int sig)
{
        debug_printf("IN SIGHANDLER\n");   <<< THIS
        sigaddset(&G.pending_set, sig);

rerun the test, and post the output.


More information about the busybox mailing list