http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48758

           Summary: gcc miscompiles Emacs by incorrectly substituting
                    memcpy for memmove
           Product: gcc
           Version: 4.6.0
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: c
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: egg...@gnu.org
              Host: i686-pc-linux-gnu
            Target: i686-pc-linux-gnu
             Build: i686-pc-linux-gnu


Created attachment 24094
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=24094
Copy of the source code illustrating the problem

When compiling a test version of GNU Emacs with GCC 4.6.0 on Ubuntu
10.10 x86, the resulting Emacs usually works, but sometimes it
crashes.  It took me a while to debug the problem, but it turns out
that GCC 4.6.0 incorrectly substitutes memcpy for memmove,
and this invalid substitution crashes Emacs.
This is a regression from the GCC 4.4.5 that comes with Ubuntu.

Here's a stripped-down source file c.c illustrating the problem;
(I've also attached c.c for convenience.)

    typedef unsigned int size_t;

    extern void *memmove (void *__dest, __const void *__src, size_t __n)
         __attribute__ ((__nothrow__)) __attribute__ ((__nonnull__ (1, 2)));

    extern __inline __attribute__ ((__always_inline__)) __attribute__
((__artificial__)) void *
    __attribute__ ((__nothrow__)) memmove (void *__restrict __dest, __const
void *__restrict __src, size_t __len)

    {
      return __builtin___memmove_chk (__dest, __src, __len,
__builtin_object_size (__dest, 0));
    }

    void
    str_to_multibyte (unsigned char *str, int len, int bytes)
    {
      unsigned char *p = str, *endp = str + bytes;

      while (p < endp && *p < 0x80) p++;
      if (p == endp)
        return;
      bytes = endp - p;
      endp = str + len;
      memmove (endp - bytes, p, bytes);
    }

Here's the assembly language output from running 'gcc -S -O2'.
Notice that it invokes memcpy, not memmove.  But this is
an invalid optimization, because 'bytes' and 'len' are independent,
and it could well be that the target of memmove overlaps the source.

        .file    "c.c"
        .text
        .p2align 4,,15
        .globl    str_to_multibyte
        .type    str_to_multibyte, @function
    str_to_multibyte:
    .LFB1:
        .cfi_startproc
        pushl    %esi
        .cfi_def_cfa_offset 8
        .cfi_offset 6, -8
        pushl    %ebx
        .cfi_def_cfa_offset 12
        .cfi_offset 3, -12
        movl    12(%esp), %ebx
        movl    20(%esp), %ecx
        movl    16(%esp), %esi
        addl    %ebx, %ecx
        cmpl    %ecx, %ebx
        jae    .L2
        cmpb    $0, (%ebx)
        movl    %ebx, %edx
        jns    .L4
        jmp    .L2
        .p2align 4,,7
        .p2align 3
    .L9:
        cmpb    $0, 1(%edx)
        js    .L6
        movl    %eax, %edx
    .L4:
        leal    1(%edx), %eax
        cmpl    %ecx, %eax
        jne    .L9
    .L1:
        popl    %ebx
        .cfi_remember_state
        .cfi_def_cfa_offset 8
        .cfi_restore 3
        popl    %esi
        .cfi_def_cfa_offset 4
        .cfi_restore 6
        ret
    .L2:
        .cfi_restore_state
        cmpl    %ecx, %ebx
        je    .L1
        movl    %ebx, %eax
        .p2align 4,,7
        .p2align 3
    .L6:
        subl    %eax, %ecx
        addl    %esi, %ebx
        subl    %ecx, %ebx
        movl    %ecx, 20(%esp)
        movl    %eax, 16(%esp)
        movl    %ebx, 12(%esp)
        popl    %ebx
        .cfi_def_cfa_offset 8
        .cfi_restore 3
        popl    %esi
        .cfi_def_cfa_offset 4
        .cfi_restore 6
        jmp    memcpy
        .cfi_endproc
    .LFE1:
        .size    str_to_multibyte, .-str_to_multibyte
        .ident    "GCC: (GNU) 4.6.0"
        .section    .note.GNU-stack,"",@progbits


Here's the output of 'gcc -v -save-temps -S -O2 c.c':

    Using built-in specs.
    COLLECT_GCC=gcc
   
COLLECT_LTO_WRAPPER=/home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/4.6.0/lto-wrapper
    Target: i686-pc-linux-gnu
    Configured with: ../gcc-4.6.0/configure --prefix=/home/eggert/opt/gcc-4.6.0
--disable-nls
    Thread model: posix
    gcc version 4.6.0 (GCC) 
    COLLECT_GCC_OPTIONS='-v' '-save-temps' '-S' '-O2' '-mtune=generic'
'-march=pentiumpro'
     /home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/4.6.0/cc1 -E
-quiet -v c.c -mtune=generic -march=pentiumpro -O2 -fpch-preprocess -o c.i
    ignoring nonexistent directory
"/home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../i686-pc-linux-gnu/include"
    #include "..." search starts here:
    #include <...> search starts here:
     /home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/include
     /usr/local/include
     /home/eggert/opt/gcc-4.6.0/include
     /home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/include-fixed
     /usr/include
    End of search list.
    COLLECT_GCC_OPTIONS='-v' '-save-temps' '-S' '-O2' '-mtune=generic'
'-march=pentiumpro'
     /home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/4.6.0/cc1
-fpreprocessed c.i -quiet -dumpbase c.c -mtune=generic -march=pentiumpro
-auxbase c -O2 -version -o c.s
    GNU C (GCC) version 4.6.0 (i686-pc-linux-gnu)
        compiled by GNU C version 4.6.0, GMP version 4.3.2, MPFR version
3.0.0-p3, MPC version 0.8.2
    GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
    GNU C (GCC) version 4.6.0 (i686-pc-linux-gnu)
        compiled by GNU C version 4.6.0, GMP version 4.3.2, MPFR version
3.0.0-p3, MPC version 0.8.2
    GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
    Compiler executable checksum: fb2445fcd60a2e52fefc7ee16750c6b7
   
COMPILER_PATH=/home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/4.6.0/:/home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/4.6.0/:/home/eggert/opt/gcc-4.6.0/libexec/gcc/i686-pc-linux-gnu/:/home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/:/home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/
   
LIBRARY_PATH=/home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/:/home/eggert/opt/gcc-4.6.0/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../:/lib/:/usr/lib/
    COLLECT_GCC_OPTIONS='-v' '-save-temps' '-S' '-O2' '-mtune=generic'
'-march=pentiumpro'

Reply via email to