glibc detected freeing invalid pointer on ash... might be a bug, but I'm not sure

Denis Vlasenko vda.linux at googlemail.com
Thu Mar 15 00:39:05 UTC 2007


Hi,

Thanks for your effort.

On Wednesday 14 March 2007 02:29, Franklin wrote:
> I got some free time today and dig ash.c more.
> 
> I found that the mark->stackp was always cleared to NULL at this point:
> 
> evalbltin():
> if ((i = setjmp(jmploc.loc)))
> 	goto cmddone;
> 
> You can see the log file attached in this mail.  I passed the &smark to 
> evalbltin(), and print the mark and mark->stackp value.  You can search for 
> keywork "(nil)", and you can find that it was always cleared to NULL after 
> calling setjmp().

setjmp is "magic". It marks the point (CPU state) to which you
can return later with longjmp (by reloading CPU state into CPU).
(more info on their manpages)

However, this does not explain how mark->stackp managed to
mysteriously change to NULL here:

evalbltin 2: mark=0x7fe7b890, mark->stackp=0x100821a8. call setjmp(jmploc.loc)
evalbltin 4: mark=0x7fe7b890, mark->stackp=(nil)

The code:

fprintf(stderr, "evalbltin 2: mark=%p, mark->stackp=%p. call setjmp(jmploc.loc)\n", mark, mark->stackp);
        if ((i = setjmp(jmploc.loc))) {
fprintf(stderr, "evalbltin 3: mark=%p, mark->stackp=%p. i=%d, goto cmddone\n", mark, mark->stackp, i);
                goto cmddone;
        }
        savehandler = handler;
fprintf(stderr, "evalbltin 4: mark=%p, mark->stackp=%p\n", mark, mark->stackp);

If setjmp returned 0, it means that no jump occurred. setjmp just
saved CPU state to jmploc.loc, if() didn't trigger and you arrived to '4'.

But why this changed mark->stackp???

This is really strange. Can you do

make shell/ash.s
objdump -dr shell/ash.o

and also

objdump -dr busibox_unstripped if you do static build.
I'm interested in setjmp assembly. For example, mine is:
080543f8 <_setjmp>:
 80543f8:       31 c0                   xor    %eax,%eax
 80543fa:       8b 54 24 04             mov    0x4(%esp),%edx
 80543fe:       89 1a                   mov    %ebx,(%edx)
 8054400:       89 72 04                mov    %esi,0x4(%edx)
 8054403:       89 7a 08                mov    %edi,0x8(%edx)
 8054406:       8d 4c 24 04             lea    0x4(%esp),%ecx
 805440a:       89 4a 10                mov    %ecx,0x10(%edx)
 805440d:       8b 0c 24                mov    (%esp),%ecx
 8054410:       89 4a 14                mov    %ecx,0x14(%edx)
 8054413:       89 6a 0c                mov    %ebp,0xc(%edx)
 8054416:       89 42 18                mov    %eax,0x18(%edx)
 8054419:       c3                      ret
 805441a:       90                      nop
 805441b:       90                      nop

What I am trying to understand - whether setjmp corrupts
mark->stackp by using wrong stack slot (fetching mark and using
it as a pointer to something else).

Indirect way to test this theory:

struct stackmark {
+	char BOGOBUFFER[16];
        struct stack_block *stackp;
        char *stacknxt;
        size_t stacknleft;
        struct stackmark *marknext;
};

This will make stackp inaccessible by just storing a word at *mark.

Thanks!
--
vda



More information about the busybox mailing list