[SNIP different usage of strncat()]

> Or just:
>
>  strncat(name, d->d_name, strlen(d->d_name)+1);
>
> in the first place.  It isn't the access to the final null that is the
> problem, after all, it that strcat has some bug that causes it to access
> memory _beyond_ the terminating null.

 Since 'strncat(name, d->d_name, strlen(d->d_name)+1)' (or
'strcpy(d+strlen(d), s)') should have the exact same effect as a simple
strcat()-call so I suggest you use that instead. Please note that the
standard says that "The null character at the end of s1. A terminating null
character is always appended to the result./121/ ", footnote /121/: "Thus
the maximum number of characters that end up in the array pointed to by s1
is strlen(s1)+n+1." (statements to the same effect appear in the libc.info
manual.) Thus any fears that {name} wouldn't be properly '\0'-terminated are
unfounded (ISTR someone brought this up a couple of mails ago).

 What does the code that segfaults look like? This is the sctrcat() loop on
my computer (using libc5):

        <strcat+32>:  mov    (%ecx),%dl
        <strcat+34>:  inc    %ecx
        <strcat+35>:  inc    %eax
        <strcat+36>:  mov    %dl,(%eax)
        <strcat+38>:  test   %dl,%dl
        <strcat+40>:  jne    0x804ca20 <strcat+32>

on my computer. But the dynamically linked libc.so.5 (libc.so.5.3.12 on my
system, 5.4.13 in tomsrtbt) contains a much more elaborate version that
tries to move 32-bit words at a time. This code does seem to get it wrong,
accessing up to 3 bytes beyond the terminating '\0'. Probably not standard
compliant(? can't find it in the standard right now). Example:

/*code*/ {
        char d[5] = "", *s = "0123";

        strcat(d, s);
}

after the first unravelled loop {d} contains { '0', '1', '2', '3' } and all
thats needed is a '\0' terminator but the next step in the unravelled loop
loads EAX and gets '0x20794d00' with 0x20, 0x79 and 0x4d being 'garbage'
from the stack:

        (gdb) x /20bx $3
        0x80485e9 <_fini+9>: 0x30 0x31 0x32 0x33 0x00 0x4d 0x79 0x20

(The extra three bytes of garbage isn't stored.)

 I tried this with the tomsrtbt libc5 version using different combinations
of 'export LD_LIBRARY_PATH=/usr/i586-pc-linux-tomsrtbt/lib' and (in gdb)
'set auto-solib-add 0' but none of the loaded versions av strcat() resembles
what

        $ objdump --dynamic-syms libc.so.5.4.13|grep strcat
0006f520 g    DF .text  000001aa strcat
        $ objdump --disassemble --start-add=0x6f520 libc.so.5.4.13|less
0006f520 <.text+0x5d690>:
   6f520:       57                      pushl  %edi
   6f521:       8b 54 24 08             movl   0x8(%esp,1),%edx
   6f525:       8b 4c 24 0c             movl   0xc(%esp,1),%ecx
   6f529:       f6 01 ff                testb  $0xff,(%ecx)
   6f52c:       0f 84 92 01 00 00       je     0x6f6c4
   6f532:       f6 c2 03                testb  $0x3,%dl
   6f535:       74 3c                   je     0x6f573
   6f537:       f6 02 ff                testb  $0xff,(%edx)
   6f53a:       0f 84 a9 00 00 00       je     0x6f5e9
...

 gives me. I'm not sure why.

 I'd be interested to know if anyone else could verify my findings.


Disclaimer: I haven't done Linux development for more than two year.
(Fifteen+ years of x86 embedded C development.)


//Bj�rnen.


Reply via email to