[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.