skip to Main Content

Recently, I was trying to make some functions that would give me the ability to interact with dynamically allocated arrays. I’m not considering the functions I wrote as something good, but it works. I tried to check whether my code has memory leaks or not with valgrind --tool=memcheck --leak-check=yes ./program and after running it gave me a lot of Conditional jump or move depends on unitialised value. I tried to run valgrind --track-origins=yes ./program but I didn’t really get something of it. I use Debian WSL. what exactly is that and why does this "error" even occur? I’d like to avoid anything that would ruin the hypothetical performance of my programs in the future.

program.c:

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

struct array {
    int* data;
    int items;
    int capacity;
    int space;
};
  
void removeArr(struct array *arr, int index);
void sortArr(struct array *arr, bool reverse);
void printArr(struct array *arr, int limit);
void appendArr(struct array *arr, int item);
void insertArr(struct array *arr, int index, int item);
  
int main() {
    struct array a1;
    int i = 0;
  
    a1.items = 0;
    a1.capacity = 10;
    a1.space = 5;
    a1.data = (int*)malloc(a1.capacity * sizeof(int));
    if(NULL == a1.data) {
        printf("Allocation for a1.data failedn");
        return 1;
    }
  
    // Filling up the array with 5 elements
    for(i = 0; i < a1.capacity - 5; i++) {
        a1.data[i] = i + 1;
        a1.items++;
    }
  
    // Testing appending, inserting and removing from an array
    appendArr(&a1, 6);
    appendArr(&a1, 7);
    insertArr(&a1, 1, 10);
    insertArr(&a1, a1.items, 3);
    removeArr(&a1, a1.items - 1);
    printf("Before For Loop: %d %dn", a1.capacity, a1.items);
    printArr(&a1, 5);
  
    // Testing appending inside the for loop
    for(i = 0; i < 2; i++) appendArr(&a1, i + 15);
    printf("After For Loop: %d %dn", a1.capacity, a1.items);
    printArr(&a1, 5);
  
    // Testing insert func when there's no free space in the array
    insertArr(&a1, 1, 100);
    printf("After insert with extra space: %d %dn", a1.capacity, a1.items);
    printArr(&a1, 5);
    // Testing reverse (bubble) sort
    putchar('n');
    sortArr(&a1, true);
    printArr(&a1, 5);
  
    // Testing standard (bubble) sort
    putchar('n');
    sortArr(&a1, false);
    printArr(&a1, 5);
  
    // Overwriting the entire array
    putchar('n');
    for(i = 0; i < a1.capacity; i++) {
        a1.data[i] = i + 1;
    }
    a1.items = a1.capacity;
  
    // Testing inserting inside the for loop
    for(i = 1; i <= 15; i++) {
        insertArr(&a1, i, i);
    }
    putchar('n');
    printArr(&a1, 5);
  
    // Check the curren capacity and items amount after all of the operations with the array
    printf("After Insert For Loop: %d %dn", a1.capacity, a1.items);
  
    // Freeing the dynamically allocated array
    free(a1.data);
    a1.data = NULL;
    return 0;
}
  
void removeArr(struct array *arr, int index) {
    if(0 >= index || index >= arr->capacity) {
        printf("ERROR: Index is incorrectn");
        exit(1);
    }
    for(int i = index; i < arr->capacity; i++) {
        if(0 == arr->data[i - 1] && 0 == arr->data[i]) {
            continue;
        }
        arr->data[i - 1] = arr->data[i];
    }
    arr->data[arr->capacity - 1] = 0;
    arr->items--;
}
  
void sortArr(struct array *arr, bool reverse) {
    int i = 0;
    bool swapped;
    if(false == reverse) {
        do {
            swapped = false;
            for(int j = 0; j < (arr->capacity - 1 - i); j++) {
                if(arr->data[j + 1] < arr->data[j]) {
                    int temp = arr->data[j];
                    arr->data[j] = arr->data[j + 1];
                    arr->data[j + 1] = temp;
                    swapped = true;
                }
            }
            i++;
        }
        while(swapped)
            ;
    }
  
    if(true == reverse) {
        do {
            swapped = false;
            for(int j = 0; j < (arr->capacity - 1 - i); j++) {
                if(arr->data[j + 1] > arr->data[j]) {
                    int temp = arr->data[j];
                    arr->data[j] = arr->data[j + 1];
                    arr->data[j + 1] = temp;
                    swapped = true;
                }
            }
            i++;
        }
        while(swapped)
            ;
    }
}
  
void printArr(struct array *arr, int limit) {
    int pos = 0;
    for(int i = 0; i < arr->capacity; i++) {
        if(pos < limit) {
            printf("%d ", arr->data[i]);
            pos++;
        }
        else {
            putchar('n');
            printf("%d ", arr->data[i]);
            pos = 1;
        }
    }
    putchar('n');
}
  
void appendArr(struct array *arr, int item) {
    if(arr->items == arr->capacity) {
        arr->capacity += arr->space;
        arr->data = (int*)realloc(arr->data, arr->capacity * sizeof(int));
        if(NULL == arr->data) {
            printf("Reallocation for arr->data failed while appending.n");
            exit(1);
        }
    }
    arr->data[arr->items] = item;
    arr->items++;
}
  
void insertArr(struct array *arr, int index, int item) {
    if(0 >= index || index >= arr->capacity) {
        printf("ERROR: Index is incorrectn");
        exit(1);
    }
    if(index == arr->items) {
        appendArr(arr, item);
    }
    else if(index > 0 && index < arr->capacity) {
        if(arr->items == arr->capacity) {
            arr->capacity += arr->space;
            arr->data = (int*)realloc(arr->data, arr->capacity * sizeof(int));
            if(NULL == arr->data) {
                printf("Reallocation for arr->data failed when inserting.n");
                exit(1);
            }
        }
        for(int i = arr->capacity - 1; i >= index; i--) {
            if(0 == arr->data[i] && 0 == arr->data[i - 1])
                continue;
  
            arr->data[i] = arr->data[i - 1];
        }
        arr->data[index - 1] = item;
        arr->items++;
    }
    else {
        printf("Unexpected error occured while insertion.n");
        exit(2);
    }
}

valgrind --tool=memcheck --leak-check=yes ./program output:

==14958== Memcheck, a memory error detector
==14958== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==14958== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==14958== Command: ./dev/test
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099BA: insertArr (test.c:192)
==14958==    by 0x109265: main (test.c:40)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099D8: insertArr (test.c:192)
==14958==    by 0x109265: main (test.c:40)
==14958== 
Before For Loop: 10 8
10 1 2 3 4 5 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1092BC: main (test.c:44)
==14958== 
==14958== Use of uninitialised value of size 8
==14958==    at 0x48ACAAB: _itoa_word (_itoa.c:177)
==14958==    by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1092BC: main (test.c:44)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48ACABC: _itoa_word (_itoa.c:177)
==14958==    by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1092BC: main (test.c:44)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1092BC: main (test.c:44)
==14958== 
6 3 0 0 
After For Loop: 10 10
10 1 2 3 4 5 
6 3 15 16 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099BA: insertArr (test.c:192)
==14958==    by 0x109326: main (test.c:52)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099D8: insertArr (test.c:192)
==14958==    by 0x109326: main (test.c:52)
==14958== 
After insert with extra space: 15 11
100 10 1 2 3 4 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x109353: main (test.c:54)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x109353: main (test.c:54)
==14958== 
5 6 3 15 16 0 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x109353: main (test.c:54)
==14958== 
==14958== Use of uninitialised value of size 8
==14958==    at 0x48ACAAB: _itoa_word (_itoa.c:177)
==14958==    by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x109353: main (test.c:54)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48ACABC: _itoa_word (_itoa.c:177)
==14958==    by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x109353: main (test.c:54)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x109353: main (test.c:54)
==14958== 
0 0 0 

==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x10969C: sortArr (test.c:129)
==14958==    by 0x10936E: main (test.c:58)
==14958== 
100 16 15 10 6 5 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x10937F: main (test.c:59)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x10937F: main (test.c:59)
==14958== 
4 3 3 2 1 0 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x10937F: main (test.c:59)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x1097C2: printArr (test.c:152)
==14958==    by 0x10937F: main (test.c:59)
==14958== 
0 0 0 

==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1095BB: sortArr (test.c:112)
==14958==    by 0x10939A: main (test.c:63)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1093AB: main (test.c:64)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958==    by 0x48AD65A: printf (printf.c:33)
==14958==    by 0x109786: printArr (test.c:147)
==14958==    by 0x1093AB: main (test.c:64)
==14958== 
0 0 0 0 1 2 
3 3 4 5 6 10 
15 16 100 

==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099BA: insertArr (test.c:192)
==14958==    by 0x109406: main (test.c:75)
==14958== 
==14958== Conditional jump or move depends on uninitialised value(s)
==14958==    at 0x1099D8: insertArr (test.c:192)
==14958==    by 0x109406: main (test.c:75)
==14958== 

1 2 3 4 5 6 
7 8 9 10 11 12 
13 14 15 1 2 3 
4 5 6 7 8 9 
10 11 12 13 14 15 
After Insert For Loop: 30 30
==14958== 
==14958== HEAP SUMMARY:
==14958==     in use at exit: 0 bytes in 0 blocks
==14958==   total heap usage: 6 allocs, 6 frees, 1,424 bytes allocated
==14958== 
==14958== All heap blocks were freed -- no leaks are possible
==14958== 
==14958== Use --track-origins=yes to see where uninitialised values come from
==14958== For lists of detected and suppressed errors, rerun with: -s
==14958== ERROR SUMMARY: 198 errors from 24 contexts (suppressed: 0 from 0)

I tried to research this exact problem, but I didn’t get something. And also the words that the other people were saying in their answers is not really what I was looking for.

2

Answers


  1. The problem is that you read memory that has not been initialized after malloc / realloc. It’s because you use arr->capacity instead of arr->items (the number of initialized entries in your allocated block) in your loops. The entries in your allocated memory that you haven’t assigned values to carry indederminate values and you shouldn’t read those since it makes your program have undefined behavior.

    The first place notices is in the loop where you push data up after the insertion point in insertArr. Simply switch to arr->items instead of arr->capacity - 1:

    void insertArr(struct array *arr, int index, int item) {
    //
            for(int i = arr->items; i >= index; i--) {      // not arr->capacity - 1
                // below is the conditional jump or move that depended on
                // uninitialised value(s):
                if(0 == arr->data[i] && 0 == arr->data[i - 1])
                    continue;
      
                arr->data[i] = arr->data[i - 1];
            }
    //
    }
    

    Note that the continue part is most likely wrong. Why shouldn’t 0s be moved too?

    You have the same issue in printArr:

    void printArr(struct array *arr, int limit) {
    //
        for(int i = 0; i < arr->items; i++) {                   // not arr->capacity
    //
    }
    

    And twice in sortArr:

    void sortArr(struct array *arr, bool reverse) {
    //
                for(int j = 0; j < (arr->items - 1 - i); j++) { // not arr->capacity
    //
    }
    
    Login or Signup to reply.
  2. Looking for leaks is not the first thing to do

    You used

    valgrind --tool=memcheck --leak-check=yes ./program

    --tool=memcheck is the default. You don’t need it.
    Fix your bugs first, then think of looking for leaks.

    Let’s track down the error

    ==95439== Conditional jump or move depends on uninitialised value(s)
    ==95439== at 0x202002: insertArr (so19.c:188)
    ==95439== by 0x201B93: main (so19.c:40)

    (gdb) list
    183                     printf("Reallocation for arr->data failed when inserting.n");
    184                     exit(1);
    185                 }
    186             }
    187             for(int i = arr->capacity - 1; i >= index; i--) {
    188                 if(0 == arr->data[i] && 0 == arr->data[i - 1])
    189                     continue;
    190       
    191                 arr->data[i] = arr->data[i - 1];
    192             }
    

    You are reading something that hasn’t been initialized. That will be either arr->data[i] or arr->data[i – 1].

    I ran

    valgrind --vgdb-error=0 ./program in one terminal and
    gdb then target remote | /usr/home/paulf/tools/valgrind/libexec/valgrind/../../bin/vgdb --pid=95439 in another (Valgrind will tell you the command to run in GDB).

    Then I used the "mc xb" command ("memcheck examine bytes")

    (gdb) mc xb &arr->data[i] sizeof(arr->data[i])
                      ff      ff      ff      ff
    0x5460064:      0x00    0x00    0x00    0x00
    

    and

    (gdb) mc xb &arr->data[i-1] sizeof(arr->data[i-1])
                      ff      ff      ff      ff
    0x5460060:      0x00    0x00    0x00    0x00
    

    That means that neither is initialized.

    Why are you checking that arr->data contains 0 values at the end? The easier way to do this is to work out the right indices and then use memmove().

    I also think that you would be much better using C++ for this. You could do the same thing with std::vector in much less code and also without the reinvent-the-wheel bugs.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search