0

For whatever reason I am getting the following error when trying to free the 2D array I created:

Error in `./a.out': free(): invalid next size (fast): 0x0000000001759310 *** Aborted (core dumped)

I printed out the contents of the array and they are correct and I am able access all of the elements. However, I am yet to be able to free it. The error occurs when going through the freeing loop, i.e. freeing double *. Would appreciate any help.

Thanks!

Here is the code:

/*allocation*/
double **block_mat = (double **) malloc (sizeof(double *) * num_blocks);
int i;
for (i = 0; i <num_blocks; i++){
    block_mat[i] = (double *) malloc (sizeof(double) * s);
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free(block_mat[i]);
}

free(block_mat);

EDIT: The error was found! I under-allocated memory...So when I printed out my arrays they looked like everything was fine... I allocated arrays of sizes s, but used s^2 instead. Thank you everyone!

doubleOK
  • 353
  • 6
  • 19
  • 2
    The code as posted looks fine, apart from the redundant/dangerous casts - try to put together an [MCVE](http://stackoverflow.com/help/mcve). – Paul R Apr 26 '15 at 07:21
  • 1
    What is the type and value of `s`? – juanchopanza Apr 26 '15 at 07:21
  • s is an int... as I have said I can also access all the elements of the list. – doubleOK Apr 26 '15 at 07:23
  • Try using calloc to define your arrays, it's definitely more correct. – phil Apr 26 '15 at 07:23
  • 3
    By what definition, @rhubarbdog? – Ulrich Eckhardt Apr 26 '15 at 07:25
  • Could you please explain about the casts? I am just learning C and not sure I understand what you mean. Also the professor told us to use malloc, but I can try calloc as well... – doubleOK Apr 26 '15 at 07:25
  • The code looks correct. I tried it in a simple main(), with num_blocks = 50 and s = 100 and it doesn't crash. Try to post an entire program, with info on your platform (OS and libc version) because it might be a bug somewhere else than in your code. – Tobia Apr 26 '15 at 07:25
  • Also you should check the return value of all your malloc calls, because if one fails, then your program will crash. – Tobia Apr 26 '15 at 07:28
  • I updated the code... Looping over the elements of the block_mat I get all of the elements as they are supposed to be. – doubleOK Apr 26 '15 at 07:30
  • Also I've read all over SO about why you should never cast the returned result of malloc, can't remember the rationale but worth reading. – phil Apr 26 '15 at 07:30
  • Also consider a better compiler, I get a number of errors and warnings. – edmz Apr 26 '15 at 07:32
  • Unfortunately I cannot choose a compiler...we are using sagemathcloud... so I get what I get =( – doubleOK Apr 26 '15 at 07:33
  • What the... `strtol()` is a C++ function. You should clarify whether you're using C or C++. – CinchBlue Apr 26 '15 at 07:39
  • @Olga Kazakova. I think one problem may be that you should not use free(matrix) before to free its fields! – Sir Jo Black Apr 26 '15 at 07:40
  • strtol() can be used in C... http://www.tutorialspoint.com/c_standard_library/c_function_strtol.htm – doubleOK Apr 26 '15 at 07:41
  • @Olga Kazakova. Another comment that may remain my idea is that if you're using ** you have a "project" error! – Sir Jo Black Apr 26 '15 at 07:42
  • I actually initially did it the right way... but then I started moving things around in all possible combinations.. If comment out the freeing of block_mat[i] everything works fine – doubleOK Apr 26 '15 at 07:43
  • @SergioFormiggini could you please explain what you mean? – doubleOK Apr 26 '15 at 07:43
  • [Do I cast the result of malloc (in C)?](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Paul R Apr 26 '15 at 07:48
  • @Olga Kazakova. I understand you manage a bi-dimensional rectangular matrix! You might use a vector of double and manage it as a matrix! vector[x * ny+y]! You may use double * vector=malloc(nx * ny * sizeof(double)) ... etc, etc. – Sir Jo Black Apr 26 '15 at 07:49
  • Are you sure `block_index` doesn't get larger than `s`? This could lead to an out-of-bounds write –  Apr 26 '15 at 07:49
  • @Olga Kazakova. Regarding the issue relevant to block_mat[i], are you sure you don't use it after it's freed? – Sir Jo Black Apr 26 '15 at 07:51
  • 1
    @Mints97 nope... it gets to s*s as it should and the last time it writes is at [s*s-1] – doubleOK Apr 26 '15 at 07:55
  • 1
    @SergioFormiggini most definitely=) it is the last line of my code=) – doubleOK Apr 26 '15 at 07:56
  • @Mints97 - that you so much!!!! you were correct!!! I intended the size to be s^2 but allocated on s!!!! ERROR IS FOUND=) – doubleOK Apr 26 '15 at 08:13
  • 1
    @PaulR that you very much too! Putting an MCVE helped me see what I did wrong since I threw out everything I did not need! – doubleOK Apr 26 '15 at 08:14
  • @Mints97 ok then, if you write that as an answer, she can mark it as correct and you both get reputation points – Tobia Apr 27 '15 at 12:48
  • @Tobia: MOehm discovered the same problem and put it in his nice answer, which deserves to be accepted –  Apr 27 '15 at 12:52

4 Answers4

1

Are you sure that these pointers were all allocated with distinct mallocs?

free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);
for (i = 0; i < num_blocks; i++){
    free(block_mat[i]);
}
free(block_mat);

If two of them are the same pointer, then you are trying to free something twice.

Tobia
  • 17,856
  • 6
  • 74
  • 93
1

You allocate space for s doubles for each block_mat[i]. Later, you access

block_mat[i][block_index] = 0;
block_index++;

but you never check that block_index goes out of bounds, which it does.

If you write beyond the s allocated doubles, you might corrupt the internal control data for the subsequent pointer, which usually is placed before the pointer returned by malloc and which is required to be intact by free.

M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • Yes, I just discovered it literally a second before you posted=) Thank you though! That absolutely was THE problem – doubleOK Apr 26 '15 at 08:17
0

This is incorrect:

free(my_matrix);
free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);

The order should be at least like this:

free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);
tivn
  • 1,883
  • 14
  • 14
0

You have several problem that can impact allocation. The first, what if the call to strtol fails?

    s = (int)strtol(argv [3], &ptr, 10);

You should check the conversion:

#include <errno.h>
...
else {
    errno = 0;
    long tmp = strtol(argv [3], &ptr, 10);
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (ptr == argv[3]) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }
    s = (int)tmp;
}

Next, with your allocation and free, you were on the right track, but don't cast the return of malloc. Casting the return only increases the chance of a hard to debug error. When allocating a pointer-to-pointer-to-double, you need to allocate as many pointers as needed. (num_blocks) in your case. When computing the size of the allocation, you can simply dereference the variable being allocated which again lessens the chance of error:

int i;
double **block_mat = malloc (sizeof *block_mat * num_blocks);
/* check allocation for failure */

for (i = 0; i <num_blocks; i++){
    block_mat[i] = malloc (sizeof **block_mat * s);
    /* check allocation for failure */
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free (block_mat[i]);
}
free(block_mat);

Note: you must initialize all values in block_mat before you begin referencing the elements to prevent the deference of an unassigned value later. (e.g. double result = block_mat[i][j] * Pi;) Consider adding:

    block_mat[i] = malloc (sizeof **block_mat * s);
    /* check for failure */
    block_mat[i] = 0.0;

Note: When allocating numerical matricies, consider using calloc instead of malloc as it will initialize all values to '0' and prevent the inadvertent dereference of an unassigned valued -- which is undefined behavior. Using calloc you would have:

int i;
double **block_mat = calloc (num_blocks, sizeof *block_mat);
/* check allocation for failure */

for (i = 0; i <num_blocks; i++){
    block_mat[i] = calloc (s, sizeof **block_mat);
    /* check allocation for failure */
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free (block_mat[i]);
}
free(block_mat);

Note: when s is greater than 1, you will alloc space for more than one double at each pointer. Noting prevents you from doing that, but you are responsible for handling the offset to each value. (e.g. result = *(block_mat[i] + j + n * sizeof **block_mat) * Pi;, where n is 0 <= n < s) If you are storing multiple doubles in each pointer, consider using a pointer-to-struct instead. E.g.:

typedef struct point {
    double x;
    double y;
    double z;
} point;
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85