realloc() invalid old size
Asked Answered
C

5

9

I am doing an exercise for fun from KandR C programming book. The program is for finding the longest line from a set of lines entered by the user and then prints it.

Here is what I have written (partially, some part is taken from the book directly):-

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

int MAXLINE =  10;
int INCREMENT = 10;

void copy(char longest[], char line[]){
    int i=0;

    while((longest[i] = line[i]) != '\0'){
        ++i;
    }
}

int _getline(char s[]){
    int i,c;

    for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
        if(i == MAXLINE - 1){
            s = (char*)realloc(s,MAXLINE + INCREMENT);

            if(s == NULL){
                printf("%s","Unable to allocate memory");
                //  goto ADDNULL;
                exit(1);
            }

            MAXLINE = MAXLINE + INCREMENT;
        }
        s[i] = c;
    }

    if(c == '\n'){
        s[i] = c;
        ++i;
    }

ADDNULL:
    s[i]= '\0';
    return i;
} 

int main(){
    int max=0, len;

    char line[MAXLINE], longest[MAXLINE];

    while((len = _getline(line)) > 0){
        printf("%d", MAXLINE);
        if(len > max){
            max = len;
            copy(longest, line);
        }
    }

    if(max>0){
        printf("%s",longest);
    }

    return 0;
}

The moment I input more than 10 characters in a line, the program crashes and displays:-

*** Error in `./a.out': realloc(): invalid old size: 0x00007fff26502ed0 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3d6a07bbe7]
/lib64/libc.so.6[0x3d6a07f177]
/lib64/libc.so.6(realloc+0xd2)[0x3d6a0805a2]
./a.out[0x400697]
./a.out[0x40083c]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x3d6a021b45]
./a.out[0x400549]

I also checked realloc invalid old size but could not follow the logic of passing a pointer to a pointer to the function modifying the array.

Crape answered 4/7, 2014 at 19:1 Comment(4)
Amongst other errors in the program (use parens to assure meaning in calculations and elsewhere) the program is writing 'int' size values to the 's' array, but only allocating char size increments.Inceptive
The function name '_getline' will conflict with the C library function name. rather use something like 'myGetLine'Inceptive
The parameter passed to _getline is NOT a pointer to a malloc'd area, rather it the first address of an area on the stack. Therefore, trying to realloc() that pointer is an error. Suggest getting initial pointer for the _getline parameter as "line = (MAXSIZE*sizeof(int));"Inceptive
When performing the realloc, use a second parameter of ((MAXLINE + INCREMENT)*sizeof(int))Inceptive
M
13

realloc call will re-allocate memory by taking a pointer to a storage area on the heap i.e a dynamically allocated memory result of a call to malloc.

In your case the problem is that you are allocating memory on the stack and not dynamically by a call to malloc which results memory allocation on the heap. And, passing the pointer of the automatic character array line to _getline which uses it for call to realloc. So, you got the error.

Try dynamically allocating the character array line :

char* line  = (char *) malloc(MAXLINE); 
char* longest = ( char *) malloc(MAXLINE);
Mohr answered 4/7, 2014 at 19:17 Comment(5)
So then my _getline function would be something like _getline(char* s)?Crape
@Karan, no keep the _getline as it is, in C array names are automatically decayed to the pointers to their first elements.Mohr
@Karan, See https://mcmap.net/q/17745/-what-is-array-to-pointer-conversion-aka-decay for array decaying.Mohr
Thanks. However, on large inputs, i get another error related to realloc: *** Error in `./a.out': realloc(): invalid next size: 0x00000000009ce010 *** Segmentation fault (core dumped)Crape
@Karan, Segmentation faults are common in C and occurs when you allocate less size than your input. In the problem context you are allocating less memory on the heap and trying to overwrite memory from the large buffer data you entered so you are getting the error.See en.wikipedia.org/wiki/Segmentation_fault for more.Mohr
M
6

You get an invalid old size error when your code writes the memory that malloc/realloc allocated for "housekeeping information". This is where they store the "old" allocated size. This also happens when the pointer that you pass to realloc has not been properly initialized, i.e. it's neither a NULL nor a pointer previously returned from malloc/calloc/realloc.

In your case, the pointer passed to realloc is actually an array allocated in automatic memory - i.e. it's not a valid pointer. To fix, change the declarations of line and longest as follows:

char *line = malloc(MAXLINE), *longest = malloc(MAXLINE);

To avoid memory leaks, make sure that you call free(line) and free(longest) at the end of your program.

Mcdougald answered 4/7, 2014 at 19:9 Comment(0)
U
1

if _getline() reads 10 or more characters, it will call realloc() on memory that was not allocated with malloc(). This is undefined behavior.

Additionally, the memory allocated from realloc() will be leaked at the end of the call to _getline().

Additionally, let's assume that the input string is "0123456789\n". Then you will attempt to write to longest that value, but you will never call realloc() before you do that, which is required.

Unbonnet answered 4/7, 2014 at 19:7 Comment(0)
L
1

You are trying to realloc() memory that was not allocated dynamically with malloc(). You cannot do that.

Also, if realloc() fails, the original memory is still allocated, and thus still needs to be freed with free(). So do not assign the return value of realloc() to the original pointer unless it is not NULL, otherwise you are leaking the original memory. Assign the return value of realloc() to a temp variable first, check its value, and then assign to the original pointer only if realloc() was successful.

Larghetto answered 4/7, 2014 at 19:7 Comment(0)
I
0

Your error is here:

int _getline(char s[])

It means _getline is a function returning int getting a pointer to char by value.

You actually want to pass that pointer (which must point to memory allocated with malloc() or be NULL) by reference.

That means, you need to pass a pointer to a pointer to char.

Correcting that error will force you to correct all follow-on errors too.

Only use free / realloc on NULL resp. on pointers returned from malloc, calloc, realloc or a function specified to return such a pointer.

Indented answered 4/7, 2014 at 19:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.