0
votes

so, today I was implementing a insertion sort algorithm in C and I found myself with THIS (video) strange bug.

the integer variable arraySize simply change it's own value during a loop, and it doesn't even occur everytime, it's completely random and the ONLY time I change the arraySize value is at the start of the code, when I initialize with the value 10.

Code:

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


int main () {
  int y = 0, arraySize = 10, array[1000];
  srand(time(NULL));
  for (int i = 0; i < arraySize; i++) {
    array[i] = rand() % 1000;
  }
  for (int i = 1; i < arraySize; i++) {
    for (int j = i; array[j] <= array[j - 1]; j--) {
      y = array[j - 1];
      array[j - 1] = array[j];
      array[j] = y;
    }
    printf("for externo i = %d, arraySize = %d \n", i, arraySize);
  }
  for (int i = 0; i < arraySize; i++) {
    printf("%d. i = %d ", array[i], i);
  }
  printf("\n");
  return 0;
}

Example of outputs this exact program gave-me after being compiled with a simple "gcc insertionSort.c"

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 5 
10. i = 0 22. i = 1 233. i = 2 343. i = 3 592. i = 4

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 10 
for externo i = 5, arraySize = 10 
for externo i = 6, arraySize = 10 
for externo i = 7, arraySize = 10 
for externo i = 8, arraySize = 10 
for externo i = 9, arraySize = 10 
54. i = 0 239. i = 1 312. i = 2 313. i = 3 438. i = 4 465. i = 5 827. i = 6 839. i = 7 874. i = 8 935. i = 9

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 10 
for externo i = 5, arraySize = 10 
for externo i = 6, arraySize = 10 
for externo i = 7, arraySize = 10 
for externo i = 8, arraySize = 10 
for externo i = 9, arraySize = 6 
10. i = 0 58. i = 1 135. i = 2 316. i = 3 411. i = 4 442. i = 5

I'm using xubuntu 16.04 and those are my gcc configs:

Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

2
This has to be the first time someone has posted a video to demonstrate the error. So congrats on that!Ajay Brahmakshatriya
for (int j = i; array[j] <= array[j - 1]; j--) This is the culprit.Ajay Brahmakshatriya
When you decrease j, you must take care that j - 1 cannot drop below 0.M Oehm

2 Answers

1
votes

In this line -

for (int j = i; array[j] <= array[j - 1]; j--)  

j can potentially go less than 0, which would cause an out of bound access leading to Undefined Behavior.

I don't want to make sense out of UB but what happens is you end up changing other values on the stack like arraySize.

One simple fix for this would be -

for (int j = i; j > 0 && array[j] <= array[j - 1] ; j--) //Short circuiting prevents UB here. 

instead of the line mentioned above.

Now whether this condition is appropriate for your logic, that is for you to figure out.

0
votes

This loop:

for (int j = i; array[j] <= array[j - 1]; j--) {

can run off the beginning of the array (j becomes less than 0), resulting in undefined behavior. Evaluating the loop termination condition causes UB all by itself even when j is exactly zero, but the most likely culprit for the change to another variable's value is the out-of-bounds modifications to the array performed in the loop body.

You need to ensure that your sort stops at the beginning of the array.