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.