简体   繁体   中英

GCC -O3 6.1.1, 5.3.1, 4.1.2 fails to compile a correct executable (recursive merge sort in C)

The following program is not compiled into a correct executable when using GCC (at least 6.1.1, 5.3.1, 4.1.2) and with optimization -O3 (and also -O2). GCC generates a correct executable with -O0 (and -O1).

The output should be (-O0):

Sorted array: 1.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000 9.00010.0009999.00012.00013.00014.00015.00016.00017.00018.0001                     9.00020.000

instead of (-O3):

Sorted array:11.00012.00013.00014.00015.00016.00017.00018.00019.00020.0009999.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000                      9.00010.000

Has anybody an idea of the reason? Is it a bug of GCC? Thanks!


#include <stdio.h>
#include <stdlib.h>

double arr[20] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};

int merge(double arr[],int l,int m,int h)
{
    double arr1[10],arr2[10];
    int n1,n2,i,j,k;

    n1=m-l+1; n2=h-m;
    for(i=0; i<n1; i++) arr1[i]=arr[l+i];
    for(j=0; j<n2; j++) arr2[j]=arr[m+j+1];

    arr1[i]=9999; arr2[j]=9999; i=0; j=0;

    for(k=l; k<=h; k++) {
        if(arr1[i]<=arr2[j])
            arr[k]=arr1[i++];
        else
            arr[k]=arr2[j++];
    }

return 0;
}

int merge_sort(double arr[],int low,int high)
{
    int mid;
    if(low<high) {
        mid=(low+high)/2;
        merge_sort(arr,low,mid);
        merge_sort(arr,mid+1,high);
        merge(arr,low,mid,high);
    }
    return 0;
}

int main()
{
    int i,n=20;

    merge_sort(arr,0,n-1);
    printf("Sorted array:");
    for(i=0; i<n; i++)
        printf("%6.3f",arr[i]);
    printf("\n");

    exit(0);
}

There is (at least) one bug.

In merge you have:

double arr1[10],arr2[10];

The work arrays needs to be one larger to fit the watch value ( 9999 ), so you need:

double arr1[11],arr2[11];

I see identical results between -O0 and -O3 on gcc 5.4.0:

evaitl@bb ~/se $ gcc -Wall -O0 -o foo foo.c
evaitl@bb ~/se $ ./foo 
Sorted array:11.000  12.000  13.000  14.000  15.000  16.000  17.000  18.000  19.000  20.000  9999.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000   9.000  10.000  
evaitl@bb ~/se $ gcc -Wall -O3 -o foo foo.c
evaitl@bb ~/se $ ./foo 
Sorted array:11.000  12.000  13.000  14.000  15.000  16.000  17.000  18.000  19.000  20.000  9999.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000   9.000  10.000 

Of course, the algorithm seems like it is doing strange things, but at least the compiler is consistent.

Check your own code before you assert it is correct and blame the compiler. ( The first rule of programming: it's always your fault )

AddressSanitizer shows the problem:

=================================================================
==13359==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff0e9e3f40 at pc 0x000000400c59 bp 0x7fff0e9e3e80 sp 0x7fff0e9e3e70
WRITE of size 8 at 0x7fff0e9e3f40 thread T0
    #0 0x400c58 in merge /tmp/sort.c:15
    #1 0x400f9f in merge_sort /tmp/sort.c:34
    #2 0x400fcc in main /tmp/sort.c:43
    #3 0x7f3d7416857f in __libc_start_main (/lib64/libc.so.6+0x2057f)
    #4 0x400928 in _start (/tmp/a.out+0x400928)

Address 0x7fff0e9e3f40 is located in stack of thread T0 at offset 112 in frame
    #0 0x400a05 in merge /tmp/sort.c:7

  This frame has 2 object(s):
    [32, 112) 'arr1' <== Memory access at offset 112 overflows this variable
    [160, 240) 'arr2'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM