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
The problem is that you read memory that has not been initialized after
malloc
/realloc
. It’s because you usearr->capacity
instead ofarr->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 valgrind notices is in the loop where you push data up after the insertion point in
insertArr
. Simply switch toarr->items
instead ofarr->capacity - 1
:Note that the
continue
part is most likely wrong. Why shouldn’t0
s be moved too?You have the same issue in
printArr
:And twice in
sortArr
: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)
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 andgdb
thentarget 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")
and
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 usememmove()
.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.