strncmp("aa", "ab", -1)

Khem Raj raj.khem at gmail.com
Thu Sep 25 07:31:26 UTC 2008


On Wed, Sep 24, 2008 at 4:17 PM, Tobias Poschwatta <tp at fonz.de> wrote:
> On Wed, Sep 24, 2008 at 01:33:52PM -0700, Khem Raj wrote:
>> I can not reproduce it on a eabi system and there has been few changes
>> in this file. I do not have oabi system to test against. Can you try
>> same on eabi system ?
>
> Unfortunately, I don't have an eabi system to test. However, I had a
> closer look in gdb. This is what I found:
>
> I order to debug the strncmp function, I had to create another test
> program, because in the first version strncmp was inlined and the code
> somehow reduced to 'printf("%d", 0);'. The new test program is:
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> int main(int argc, char **argv)
> {
>        const char *s1 = "aa";
>        const char *s2 = "ab";
>        printf("%s <=> %s => %d\n", s1, s2, strncmp(s1, s2, -1));
>        exit(0);
> }
>
>
> readelf -s now shows a reference to strncmp.
>
> Using gdb to disassemble strncmp gives:
>
> (gdb) disass strncmp
> Dump of assembler code for function strncmp:
> 0x400398e0 <strncmp+0>: cmp     r2, #0  ; 0x0
> 0x400398e4 <strncmp+4>: moveq   r0, #0  ; 0x0
> 0x400398e8 <strncmp+8>: moveq   pc, lr
> 0x400398ec <strncmp+12>:        subs    r2, r2, #1      ; 0x1
> 0x400398f0 <strncmp+16>:        add     r12, r0, r2
> 0x400398f4 <strncmp+20>:        ldrb    r2, [r0], #1
> 0x400398f8 <strncmp+24>:        ldrb    r3, [r1], #1
> 0x400398fc <strncmp+28>:        cmp     r12, r0
> 0x40039900 <strncmp+32>:        cmpcs   r2, #1  ; 0x1
> 0x40039904 <strncmp+36>:        cmpcs   r2, r3
> 0x40039908 <strncmp+40>:        beq     0x400398f4 <strncmp+20>
> 0x4003990c <strncmp+44>:        sub     r0, r2, r3
> 0x40039910 <strncmp+48>:        mov     pc, lr
> End of assembler dump.
>
> This matches the non-thumb version in libc/string/arm/strncmp.S
> (__USE_BX__ undefined).
>
> When reaching the strncmp, the parameters r0, r1 and r2 have the
> expected values:
>
> Breakpoint 1, 0x400398e0 in strncmp () from /ffp/lib/libc.so.0
>
> (gdb) x/4c $r0
> 0x84e4 <_fini+20>:      97 'a'  97 'a'  0 '\0'  0 '\0'
> (gdb) x/4c $r1
> 0x84e8 <_fini+24>:      97 'a'  98 'b'  0 '\0'  0 '\0'
> (gdb) p $r2
> $13 = 4294967295
>
> Now, stepping through the function with 'si' doesn't loop at
>  0x40039908 <strncmp+40>:        beq     0x400398f4 <strncmp+20>
> but continues although r2 == r3 == 'a'.
>
> At line
>  0x400398f0 <strncmp+16>:        add     r12, r0, r2
> register r12 (ip) is set to r0 + r2. Because r2 is UINT_MAX - 1 at
> this point, r12 ends up being r0 - 2.
>
> The comparison
>  0x400398fc <strncmp+28>:        cmp     r12, r0
> clears carry, so the two cmpcs are not executed, zero is not set,
> and the branch not taken.
>
> Unless I got this completely wrong, this looks like a bug.

You analysis looks ok. The current implementation assumes that size
parameter will not overflow. I dont see an easy way to fix the current
implementation. I think it would be better to use a C algorithm.

>
> Tobias
>
>
>
>
>
>
>
>
>
>
>
>
>
>



More information about the uClibc mailing list