Search code examples
cstructdynamic-memory-allocationrealloccallstack

Failed to dynamically allocate memory based on user's string; realloc(): invalid next size


I am attempting to minimize the memory allocation for the following program. The whole idea behind my attempt to dynamically allocate memory is

  1. Dynamically allocate memory for a user's string input with 30 bytes
  2. If the user's input is bigger than the allocated memory, call realloc() function to fit the string with 101 bytes
  3. If the user's input is bigger than 100 bytes, call exit() and terminate the program.

When I implemented realloc() function to check whether user input fits into dynamically allocated char array (line with calloc), my program fails with the following output:

realloc(): invalid next size
Aborted (core dumped)

I am not sure how to resolve it.

Code:

#include <stdio.h>  //gets() was removed from this library
#include <stdlib.h> //for calloc()
#include <string.h> //for strlen()
#include <unistd.h> //for sleep(2)
int len = 0;
struct item
{
    //i cant make sure pointer points to nothing because structures are only a templates.
    //i cant do operations here!!!!!!!
    char *itemName;
    int qty;
    float price;
    float amount;
};

int readItem(struct item *pProduct)

{
    printf("hey, what is the product name: ");
    gets(pProduct->itemName);

    //checking whether user's input fits into the allocated pointer size
    len = strlen(pProduct->itemName);
    printf("%d\n\n", len);

    if (len > 30)
    {
        //error here
        pProduct->itemName = (char *)realloc(pProduct->itemName, 101);

        printf("\nyour input is too big. re enter it\n");
        gets(pProduct->itemName);

        if (pProduct->itemName == NULL)
        {
            puts("memory is not avaible");
            exit(1);
        }
        len = strlen(pProduct->itemName);
        printf("%d\n\n", len);
        if (len > 100)
        {
            puts("memory is not avaible");
            exit(1);
        }
    }
    printf("\nEnter the product quantity: ");
    scanf("%d", &pProduct->qty);

    printf("\nEnter the product price: ");
    scanf("%f", &pProduct->price);

    //calculating the amount
    pProduct->amount = (float)pProduct->qty * pProduct->price;

    return 0;
}

void printItem(struct item *pProduct)
{
    puts("\n\nthe database:");
    sleep(1);

    printf("----------------------\n");
    printf("Name: \"%s\"\n", (*pProduct).itemName);
    printf("Price: %.2f\n", pProduct->price);
    printf("Quantity: %d\n", pProduct->qty);
    printf("Amount: %.2f\n", pProduct->amount);
    printf("----------------------\n");
}

int main()
{

    //assigning variable product and piinter pProduct to a tag name item,
    struct item product, *pProduct = NULL;
    //storing an address to a pointer pProduct
    //making a structure to a pointer
    pProduct = &product;

    //(char *) is casting char to a pointer type

    pProduct->itemName = (char *)calloc(30, sizeof(char));

    readItem(pProduct);
    printItem(pProduct);

    free(pProduct->itemName);
    pProduct->itemName = NULL;
    pProduct = NULL;

    return 0;
}

I know precisely REALLOC causes the trouble. To be more precise, if I enter 34 characters realloc seems to work, but if double it to 68, it throws the error despite the mentioned size in realloc

I have zero knowledge in call stack, but it might be useful for someone:


    libc.so.6!__GI_raise(int sig) (/build/glibc-YYA7BZ/glibc-2.31/sysdeps/unix/sysv/linux/raise.c:50)
     
    libc.so.6!__GI_abort() (/build/glibc-YYA7BZ/glibc-2.31/stdlib/abort.c:79)
     
    libc.so.6!__libc_message(enum __libc_message_action action, const char * fmt) (/build/glibc-YYA7BZ/glibc-2.31/sysdeps/posix/libc_fatal.c:155)
     
    libc.so.6!malloc_printerr(const char * str) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:5347)

    libc.so.6!_int_realloc(mstate av, mchunkptr oldp, size_t oldsize, size_t nb) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:4564)
     
    libc.so.6!__GI___libc_realloc(size_t bytes, void * oldmem) (/build/glibc-YYA7BZ/glibc-2.31/malloc/malloc.c:3226)
     
    libc.so.6!realloc_hook_ini(void * ptr, size_t sz, const void * caller) (/build/glibc-YYA7BZ/glibc-2.31/malloc/hooks.c:41)
     
    readItem(struct item * pProduct) (/home/max/My stuff/programming/Udemy/section 14, reading and wrinting files/test.c:22)
     
    main() (/home/max/My stuff/programming/Udemy/section 14, reading and wrinting files/test.c:72)

Solution

  • suggestions;

    allocate a long buffer, much longer than possibly ever needed. Then obtain the data via a call to fgets()

    char buffer[1024];
    fgets( buffer, sizof( buffer ), stdin );
    

    -OR-

    use the getline() function to read the data

    char *buffer = NULL;
    size_t byteCount;
    getline( &line, &byteCount, stdin );
    

    Note: I left error checking out of the above to make the illustration simple.