简体   繁体   中英

Segmentation fault on simple quick sort implementation

So I've been trying to create a generic recursive quick sort implementation in C. For it to be generic, I am using a comparison function pointer. Also, since we can use either Lomuto or Hoare partitioning, I'm using a function pointer to two separate functions, one for each partitioning. Right now I've only finished the Lomuto part. Now of course, the comparison function is not used in the quicksort function itself, but on the partition functions, so I'm passing the function pointer. Should be simple, but I'm desperate for some help, as I keep getting a segmentation fault when trying to call the function:

quicksort_recursive(array, 0, 8, sizeof(int), &cmpnum, &partition_lomuto);

Here's the comparison function:

int cmpnum(const void* s1, const void* s2)
{
    int *a = (int*)s1;
    int *b = (int*)s2;
    if ((*a) > (*b))
        return 1;
    else if ((*a) < (*b))
        return -1;
    else
        return 0;
}

And here's the array:

int array[] = [3, 7, 8, 5, 2, 1, 9, 5, 4];

Perpetrator is in here somewhere:

void swap(void *a, void *b, size_t size)
{
    char buffer[size];
    memcpy(buffer, a, size);
    memcpy(a, b, size);
    memcpy(b, buffer, size);
    return;
}

void *get(void *const array, size_t index, size_t size)
{
    return ((char *)array) + (index * size);
}

size_t partition_lomuto(void *const array, size_t low, size_t high, size_t size, __compar_fn_t compare)
{
    void *pivot = get(array, high, size);
    size_t i = low;
    for (size_t j = low; j <= high - 1; j++)
    {
        if(compare(get(array, j, size), pivot) <= 0)
        {
            i++;
            swap(get(array, i, size), get(array, j, size), size);
        }
    }
    swap(get(array, i + 1, size), get(array, high, size), size);
    return (i + 1);
}

void quicksort_recursive(void *const array, size_t low, size_t high, size_t size, __compar_fn_t compare, size_t (*partition)(void *const array, size_t low, size_t high, size_t size, __compar_fn_t compare))
{
    if (low < high)
    {
        size_t partition_index = partition(array, low, high, size, compare);
        quicksort_recursive(array, low, partition_index - 1, size, compare, partition);
        quicksort_recursive(array, low, partition_index + 1, size, compare, partition);
    }
    return;
}

Building your program with gcc -fsanitize=address ... and running it results in the following error:

=================================================================
==89==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff14f51124 at pc 0x7f766a029dd3 bp 0x7fff14f50f10 sp 0x7fff14f506c0
READ of size 4 at 0x7fff14f51124 thread T0
    #0 0x7f766a029dd2 in __interceptor_memcpy (/lib64/libasan.so.6+0x39dd2)
    #1 0x401381 in swap /tmp/t.c:19
    #2 0x401527 in partition_lomuto /tmp/t.c:44
    #3 0x401584 in quicksort_recursive /tmp/t.c:52
    #4 0x4018e0 in main /tmp/t.c:64
    #5 0x7f7669e4d1e1 in __libc_start_main (/lib64/libc.so.6+0x281e1)
    #6 0x4010dd in _start (/tmp/a.out+0x4010dd)

Address 0x7fff14f51124 is located in stack of thread T0 at offset 84 in frame
    #0 0x4015fc in main /tmp/t.c:60

  This frame has 1 object(s):
    [48, 84) 'array' (line 61) <== Memory access at offset 84 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/lib64/libasan.so.6+0x39dd2) in __interceptor_memcpy
Shadow bytes around the buggy address:
  0x1000629e21d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e21e0: 00 00 00 00 ca ca ca ca 04 cb cb cb cb cb cb cb
  0x1000629e21f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2210: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f1 f1
=>0x1000629e2220: 00 00 00 00[04]f3 f3 f3 f3 f3 00 00 00 00 00 00
  0x1000629e2230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000629e2270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==89==ABORTING

Looks like the bug is here:

    swap(get(array, i + 1, size), get(array, high, size), size);

While you know that i <= high , i + 1 could get out of bounds.

PS You have low and high as inclusive (closed) interval. If is often easier to reason about algorithms using half-open intervals.

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