0

This is the error I get when executing the .exe file built from the code below:

*** Error in `./test_bin.exe': realloc(): invalid old size: 0x00007ffc67d00cf0 ***

I don't understand why realloc() throws an error when I'm using it as intended. I have tried casting before realloc() call, but that doesn't work either.

int main{

    double *test;
    double arr1[5] = {1.0,2.0,3.0,4.0,5.0};
    double arr2[2] = {1.0,2.0};
    int     i;


    test = (double*)malloc(5*sizeof(double));
    test = arr1;
    for(i=0;i<5;i++) printf("%lf ",test[i]);

    printf("\n");

    test = realloc(test,2*sizeof(double));
    test = arr2;
    for(i=0;i<2;i++) printf("%lf ",test[i]);
    printf("\n");
    return 0;

}
wohlstad
  • 12,661
  • 10
  • 26
  • 39
astroguy
  • 45
  • 4
  • 1
    You can realloc only a heap pointer you get from malloc etc. After `test = arr` your pointer now points to an array on the stack. You cannot realloc it. – wohlstad Jul 21 '22 at 17:31
  • You have leaked your `malloc`ed memory right after it was allocated by overwriting the `test` pointer – Eugene Sh. Jul 21 '22 at 17:32
  • `test = (double*)malloc(5*sizeof(double)); test = <>.` is an instantaneous memory leak in just two lines. This mistake happens several times in your code. – WhozCraig Jul 21 '22 at 17:32
  • Thank you! This worked, I understand it better now. I will also stop casting, it was a practice I picked up when trying to understand malloc() – astroguy Jul 21 '22 at 17:40

3 Answers3

4

From the documentation of realloc (emphasis is mine):

Reallocates the given area of memory. It must be previously allocated by malloc(), calloc() or realloc() and not yet freed with a call to free or realloc. Otherwise, the results are undefined.

In your case this line:

test = arr1;

Makes the pointer now point to the array arr1 on the stack. It is not a pointer received from malloc/calloc/realloc and therefore this is undefined behavior (UB).

Moreover - the chunk of memory you got from malloc (1 line before assigning the pointer to arr1) is now leaked. You cannot have access to it or free it.


Edit:
To complete the answer:
The citation above is somewhat conflicting with the fact that you can use realloc with a NULL pointer. The same documentation link above also mentions further down that-

If ptr is NULL, the behavior is the same as calling malloc(new_size).

But anyway this case also does not appy to your code (as the address of array on the stack is not NULL).

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • Nice answer, but it is sometimes risky to cite `C++` documentation to describe a library function's behavior in a `C` implementation. Eg. calls such as `[m][c][re]alloc()` operate under slightly different rules in `C++` than when operating in `C`. Possibly related to this (I am not sure because I am very new to `C++`) is that in `C` [it is not a prerequisite that `[m][c]alloc` _must_ me called previously](https://stackoverflow.com/a/4459301/645128), as your cited documentation asserts. – ryyker Jul 21 '22 at 18:56
  • @ryyker the link I posted is indeed from cppreference.com, but it is under the "C" section (as makred at at the top). I was under the impression that it refers to pure C. Am I mistaken ? (this is the main page for the section: https://en.cppreference.com/w/c). – wohlstad Jul 21 '22 at 19:07
  • @ryyker also my citation includes `realloc` in the group (see above in the second line of the citation). – wohlstad Jul 21 '22 at 19:13
  • 1
    @wohlstad no you are not misstaken. That section is for C only. (And a good one at that.) – Fredrik Jul 21 '22 at 19:14
  • No, your location for citing could be fine, except for it claiming the pre-requisite that `[c][m]alloc()` _must_ be called first. – ryyker Jul 21 '22 at 19:15
  • 2
    @ryyker further down the page of the link it actually says: "If ptr is NULL, the behavior is the same as calling malloc(new_size). ". – wohlstad Jul 21 '22 at 19:19
  • Do you at least see the conflict with the segment you cited? :) As I said before, good answer (+1) (I mean the word _must_ is just shy of the word _shall_ in most spec speak. both make it sound imperative that one of the other allocation calls is _required_ prior to using this one, which is not true of course, by it own admission further down in the link.) – ryyker Jul 21 '22 at 19:23
  • 1
    @ryyker yes I do. Thanks. Adding an update to the question. – wohlstad Jul 21 '22 at 19:25
2

You passed the pointer converted from arr1, which is not allocated via malloc() family, to realloc(). This invokes undefined behavior.

You can use memcpy() to copy contents of arrays instead of assigning pointers.

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

int main(void){

    double *test;
    double arr1[5] = {1.0,2.0,3.0,4.0,5.0};
    double arr2[2] = {1.0,2.0};
    int     i;


    test = malloc(5*sizeof(double));
    /* test = arr1; */
    memcpy(test, arr1, sizeof(arr1));
    for(i=0;i<5;i++) printf("%lf ",test[i]);

    printf("\n");

    test = realloc(test,2*sizeof(double));
    /* test = arr2; */
    memcpy(test, arr2, sizeof(arr2));
    for(i=0;i<2;i++) printf("%lf ",test[i]);
    printf("\n");
    return 0;

}

Also note that casting results of malloc() family is considered as a bad practice.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
2

These statements

test = (double*)malloc(5*sizeof(double));
test = arr1;

results in a memory leak because at first memory was allocated and its address was assigned to the pointer test and then the pointer test was reassigned with the address of the first element of the array arr1. So the address of the allocated memory was lost.

And you may reallocate only memory that early was dynamically allocated using malloc, calloc or realloc.

Arrays do not have the assignment operator. You need to copy elements from one array to another. For example

test = (double*)malloc(5*sizeof(double));
memcpy( test, arr1, 5 * sizeof( double ) );
for(i=0;i<5;i++) printf("%lf ",test[i]);

Your program can look the following way

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

int main( void )
{
    double arr1[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
    const size_t N1 = sizeof( arr1 ) / sizeof( *arr1 );
    double arr2[] = { 1.0, 2.0 };
    const size_t N2 = sizeof( arr2 ) / sizeof( *arr2 );

    double *test = malloc( sizeof( arr1 ) );

    if ( test != NULL )
    {
        memcpy( test, arr1, sizeof( arr1 ) );
        for ( size_t i = 0; i < N1; i++ )
        {
            printf( "%f ", test[i] );
        } 
        putchar( '\n' );

        double *tmp = realloc( test, sizeof( arr2 ) );

        if ( tmp != NULL )
        {
            test = tmp;

            memcpy( test, arr2, sizeof( arr2 ) );
            for ( size_t i = 0; i < N2; i++ )
            {
                printf( "%f ", test[i] );
            } 
            putchar( '\n' );
        }

        free( test );
    }
}

The program output is

1.000000 2.000000 3.000000 4.000000 5.000000 
1.000000 2.000000 

Pay attention to that you need to use an intermediate pointer to reallocate memory. Otherwise again there can be a memory leak if the memory will not be reallocated successfully.

And the length modifier l in the format string "%lf" in the calls of printf is redundant and has no effect,

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335