Lucas
Lucas

Reputation: 21

Why is my program leaking 12 bytes of memory and where are the uninitialised values coming from?

I ran valgrind on my program (which works as expected) but valgrind reports 12 bytes of memory leakage and a couple instances of uninitialised values that I just can't find in my code.

The program is a simple quadratic equation solver, the vast majority of the maths stuff takes place in quadSolver.c, whereas the input validation and returning the results to the user in a clean, presentable way is in main.c.

main.c:

#include <stdlib.h>
#include "quadSolver.h"

int main(int argv, char* args[]){
  if (argv != 4) {
    printf("Invalid arguments.\n");
    printf("Input: ./solve x y z\n");
    exit(0);
  } else if (!isNumber(args[1]) || !isNumber(args[2]) || !isNumber(args[3])) {
    printf("Invalid arguments.\n");
    printf("Arguments must be integers.\n");
    exit(0);
  }
  int* a = calloc(1, sizeof(int));
  int* b = calloc(1, sizeof(int));
  int* c = calloc(1, sizeof(int));
  *a = strtol(args[1], NULL, 10);
  *b = strtol(args[2], NULL, 10);
  *c = strtol(args[3], NULL, 10);
  double** roots = calloc(3, sizeof(int));
  roots = findRoots(*a, *b, *c);
  if(*roots[0] == 0) {
    printf("Roots are imaginary.\n");
  } else if(*roots[0] == 1) {
    printf("Roots are real and equal.\n");
    printf("Roots = %f\n", *roots[1]);
  } else {
    printf("Roots are real and unequal.\n");
    printf("Root A = %f\n", *roots[1]);
    printf("Root B = %f\n", *roots[2]);
  }
  free(a);
  free(b);
  free(c);
  free(roots);
}

quadSolver.c:

#include "quadSolver.h"

bool isNumber(char* input) {
  int i = 0;
  if (input[0] == '-') {
    i = 1;
  }
  for (i; input[i] != '\0'; i++) {
    if(!isdigit(input[i])) {
      return false;
    }
  }
  return true;
}

int determineNumberOfRoots(int a, int b, int c) {
  if ((square(b)-4*a*c) > 0) {
    return 2;
  } else if ((square(b)-4*a*c) == 0) {
    return 1;
  } else {
    return 0;
  }
}

int square(int x) {
  int answer = x * x;
  return answer;
}

double** findRoots(int a, int b, int c) {
  if (determineNumberOfRoots(a, b, c) == 0) {
    double** result = calloc(1, sizeof(double));
    double num = 0;
    result[0] = &num;
    return result;
  } else if (determineNumberOfRoots(a, b, c) == 1) {
    double* root = calloc(1, sizeof(double));
    *root = (-b)/(2*a);
    double** result = calloc(2, sizeof(double));
    double num = 1.0;
    result[0] = &num;
    result[1] = root;
    return result;
  } else {
    double* rootPos = calloc(1, sizeof(double));
    double* rootNeg = calloc(1, sizeof(double));
    *rootPos = (double) ((-b) + sqrt((double)(square(b)-(4*a*c))))/(2*a);
    *rootNeg = (double) ((-b) - sqrt((double)(square(b)-(4*a*c))))/(2*a);
    double** result = calloc(3, sizeof(double));
    double num = 2.0;
    result[0] = &num;
    result[1] = rootPos;
    result[2] = rootNeg;
    return result;
  }
}

Valgrind says:

==34332== Conditional jump or move depends on uninitialised value(s)
==34332==    at 0x1093E1: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332==  Uninitialised value was created by a stack allocation
==34332==    at 0x1093CA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== 
==34332== Conditional jump or move depends on uninitialised value(s)
==34332==    at 0x1093EB: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332==  Uninitialised value was created by a stack allocation
==34332==    at 0x1093CA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== HEAP SUMMARY:
==34332==     in use at exit: 12 bytes in 1 blocks
==34332==   total heap usage: 6 allocs, 5 frees, 1,056 bytes allocated
==34332== 
==34332== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==34332==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34332==    by 0x1093AA: main (in /home/lugehr/Documents/Programming Practice/C/QuadraticSolver/solve)
==34332== 
==34332== LEAK SUMMARY:
==34332==    definitely lost: 12 bytes in 1 blocks
==34332==    indirectly lost: 0 bytes in 0 blocks
==34332==      possibly lost: 0 bytes in 0 blocks
==34332==    still reachable: 0 bytes in 0 blocks
==34332==         suppressed: 0 bytes in 0 blocks
==34332== 

Upvotes: 0

Views: 198

Answers (1)

vmt
vmt

Reputation: 860

You're leaking the memory in main() at:
double **roots = calloc(3, sizeof(int)));

The call to findRoots() on the next line, allocates memory inside itself, and overwrites the value of roots when it returns, in the end you leak the 3*sizeof(int) (allocated inside main) bytes which is now unreachable due to the overwrite previously mentioned.

Your program however, is riddled with other kinds of bugs, as mentioned in the comments, but the scope of this answer is to address the memory leak.

EDIT: For future reference, when debugging, you should compile your programs with debug information (e.g. gcc/clang -g ...) so that valgrind has more context to work with and it becomes easier to figure out the leaks when you can e.g. get line numbers directly in the output.

Upvotes: 2

Related Questions