0

I wrote function - malloc, free and realloc The malloc function work fine. The problem is in the function of the realloc it returns me Segmentation fault and I do not know why this is happening. I would be happy if you help me to Understand why this is happening שand how I can fix it.

My code -

#include <unistd.h>
#include <stdio.h>

void *malloc (size_t size);
void *realloc (void *ptr, size_t size);
void free (void *ptr);

typedef struct metadata_block *p_block;
struct metadata_block
{
  size_t size;
  p_block next;
  int free;
};

p_block head = NULL;

int
main ()
{
  char *str;
  int *a;
  a = (int *) malloc (4);
  scanf ("%d", a);
  printf ("String = %d\n", *a);
  a = (int *) realloc (str, 25);
  scanf ("%d", a);
  printf ("String = %d\n", *a);

  return 0;
}

void *
malloc (size_t size)
{
  void *my_malloc;
  p_block tmp;

  if (size <= 0)
    {
      return NULL;
    }

  if (head == NULL)
    {
      head = (void *) sbrk (size + sizeof (struct metadata_block));
      head->size = size;
      head->free = 0;
      head->next = NULL;
      return (void *) head + sizeof (struct metadata_block);
    }
  else
    {
      p_block tmp = head;
      while (tmp->next != NULL)
        {
          tmp = tmp->next;
        }
      tmp->next = (void *) sbrk (size + sizeof (struct metadata_block));
      tmp->size = size;
      tmp->free = 1;
      tmp->next = NULL;
      return (void *) size + sizeof (struct metadata_block);
    }
}

void *
realloc (void *ptr, size_t size)
{
  void *newptr;

  if (ptr == NULL)
    {
      return malloc (size);
    }
  if (size == 0)
    {
      return (ptr);
    }

  newptr = malloc (size);
  return (newptr);

}

void
free (void *ptr)
{
  p_block tmp;

  if (tmp->free == 1)
    {
      tmp = 0;
    }
  ptr = NULL;
}
Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
  • 4
    Your implementation of `realloc` neither frees the previous block nor copies the contents of the previous block into the new block. – abligh Dec 22 '14 at 11:16
  • 6
    standard warning : Please use differnt function names while re-implementing _standard library_ function. Good practice. – Sourav Ghosh Dec 22 '14 at 11:18
  • You are calling `realloc(str, 25)` with uninitialized `str`!!! What's the purpose of that??? – barak manos Dec 22 '14 at 11:19
  • 1
    As @abligh said, there are issues with your implementation of `realloc` and one more, it expects ther first argument to be `NULL` or to be a valid pointer, you are passing `str` uninintialized, it's ok with your implementation, but with the standard library function, SEGMENTATION FAULT. The purpose of the first argument is to try to return the same address if possible, you are doing that only if `size == 0` in that case `realloc` actually acts like `free`. – Iharob Al Asimi Dec 22 '14 at 11:19
  • So how do you suggest I fix it, what's the best way to do this? – dan gold Dec 22 '14 at 11:24

3 Answers3

1

You realloc should behave like this:

  • If ptr == NULL, then just malloc
  • If ptr != NULL :
    • malloc new pointer (newPtr) of new size
    • memcpy contents from ptr to newPtr
    • free ptr
    • return newPtr

Remember that realloc needs a pointer which was given from call to malloc (or NULL).

IMHO, implementing behaviour of realloc, which tries to return the same address if possible is too complicated for your task.

zoska
  • 1,684
  • 11
  • 23
0

OP's realloc(), let's call it realloc_gold() ( and malloc_gold() free_gold()), needs to copy the data contents and other fixes.

void *realloc_gold(void *ptr, size_t size) {

  if (ptr == NULL) {
    return malloc_gold(size);
  }

When the size is 0, free the current ptr and best to handle the same way as malloc_gold(0)

  if (size == 0) {
    free_gold(ptr);
    return malloc_gold(ptr);
  }

Detect OOM and copy data contents. Of course this leads to the problem, what is oldsize? the C standard malloc(), realloc() saves that info somehow, but user code, in general, does not have access to that info. So this code needs to save it. The usual solution is to allocate the size requested + the size of a size_t, and put the size info right before the returned pointer. Assume malloc_gold() does that.

  void *newptr = malloc_gold(size);
  if (newptr != NULL) {
    true
    size_t oldsize = ((struct metadata_block *) ptr)[-1].size;
    memcpy(newptr, ptr, size < oldsize : size : oldsize);
    free_gold(ptr);
  }

  return (newptr);
}

malloc_gold() and free_gold() need to account for the leading size - so some work left for OP.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I did as you said but I get segmentation fault in the memcpy() function. Do you know why and how I can fix it ? – dan gold Dec 22 '14 at 19:47
  • @dan gold 1) I reviewed the details of your `malloc_gold()` and updated my `oldsize` code. Is this what you did? 2) for debug purposes, temporarily do no have have `free_gold()` actually delete anything. – chux - Reinstate Monica Dec 22 '14 at 20:17
  • yes my malloc work ! and the free is not relevant now the problem is the size in the memcpy() function becuse this size not the size what i need. and I don't no how can I fix it. because all this I need your help to fix it, there is no second way to do this work. – dan gold Dec 22 '14 at 20:41
  • @dan gold `malloc_gold()` works different from the 1st time to the 2nd time. Maybe `tmp->next = (void *) sbrk (size + sizeof (struct metadata_block)); tmp = tmp->next; tmp->size = size; tmp->free = 1; tmp->next = NULL; return (void *) tmp + sizeof (struct metadata_block);` (advance tmp and change return value.) – chux - Reinstate Monica Dec 22 '14 at 20:54
  • I checked the function and it works the problem is the size of the realloc() function when you do the memcpy() function you send wrong value you need to send the old size. so if what I say true THE QUESTION IS; how I can get the old size (the size of the organ) If you can write me more clearly what is the right way to you I would be happy to know this. thank you – dan gold Dec 22 '14 at 21:17
  • @dan gold `malloc_gold()` is faulty. Try this at the beginning of `main()` `printf("%lu\n", (long) malloc_gold()); printf("%lu\n", (long) malloc_gold());` and report those 2 values. `realloc_gold()` is failing because of earlier failed calls to `malloc_gold()`. – chux - Reinstate Monica Dec 22 '14 at 21:51
  • The code `true` in my post is a typo error - I will take out later. – chux - Reinstate Monica Dec 22 '14 at 21:52
  • I add the printf("%lu\n", (long) malloc_gold()); and I am get the number 16 ? what now ? It still return me the segmentation fault after all your changes – dan gold Dec 23 '14 at 13:03
  • @dan gold 16 is really the result of the first call to `malloc_gold()`?? 16 is likely an invalid address coming from `malloc_gold()` Suggest debugging that. Call `printf("%lu\n", (long) malloc_gold());` and check that you are getting reasonable values. At this end I am running out of ideas. – chux - Reinstate Monica Dec 23 '14 at 15:39
-1
The following is close to what you want, however, read all the commentary.

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

void *myMalloc  (size_t size);
void *myRealloc (void *ptr, size_t size);
void  myFree    (void *ptr);

//typedef struct metadata_block *p_block;
struct metadata_block
{
    size_t size;
    //p_block next;
    struct metadata_block * next;
    int free;
};

//p_block head = NULL;
struct metadata_block *head = NULL;

int main ()
{
    //char *str;
    char * str = NULL;
    int *a;

    //a = (int *) malloc (4);
    // following is not correct because myMalloc
    // returns parameter*sizeof(struct meta_block)
    // probably should call system malloc() instead of myMalloc()
    if( NULL == (a = myMalloc( sizeof(int) ) ) ) 
    { // myMalloc failed
        perror("myMalloc failed");
        exit( EXIT_FAILURE );
    }

    // implied else, myMalloc successful

    //scanf ("%d", a);
    if( 1 != scanf(" %d", a) ) 
    { // scanf failed
        perror("scanf 1 failed" );
        myFree( a );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    printf ("String = %d\n", *a);

    //a = (int *) realloc (str, 25);
    int * b;
    if( NULL == (b = myRealloc( str, 25 ) ) )
    { // then, myRealloc failed
        perror( "myRealloc failed" );
        myFree(a);
        exit( EXIT_FAILURE );
    }

    // implied else, myRealloc successful

    a = b;

    //scanf ("%d", a);
    if( 1 != scanf(" %d", a ) )
    { // then, scanf failed
        perror( "scanf 2 failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    printf ("String = %d\n", *a);

    // <-- added following line so no memory leaks
    myFree( a );

    return 0;
} // end function: main


void *myMalloc (size_t size)
{
    //void *my_malloc;
    //p_block tmp;

    if (size <= 0)
    {
        return NULL;
    }

    if (head == NULL)
    {
        if( NULL == (head = malloc(sizeof(struct metadata_block)*(size))) )
        { // then, malloc failed
            perror( "malloc failed" );
            exit( EXIT_FAILURE);
        }

        // implied else, malloc successful

        head->size = size;
        head->free = 0;
        head->next = NULL;
        return (void *) head + sizeof (struct metadata_block);
    }

    else
    {
        struct metadata_block* tmp = head;

        // step through existing linked list
        while (tmp->next != NULL)
        {
            tmp = tmp->next;
        }

        // initialize new metadata_block instance
        //tmp->next = (void *) sbrk (size + sizeof (struct metadata_block));
        tmp->next = malloc(sizeof(struct metadata_block)*(size+1));
        tmp->size = size;
        tmp->free = 1;
        tmp->next = NULL;
        return (void *) size + sizeof (struct metadata_block);
    }
} // end function: myMalloc


void *realloc (void *ptr, size_t size)
{
    void *newptr;

    if (ptr == NULL)
    {
        return malloc (size);
    }

    if (size == 0)
    {
        return (ptr);
    }

    newptr = malloc (size);
    return (newptr);
} // end function: realloc


// <-- the function myFree fails to actually free anything
//     and tmp is being used without first being set to something
void myFree (void *ptr)
{
    //p_block tmp;
    struct metadata_block *tmp = ptr;

    if (tmp->free == 1)
    {
        tmp = 0; // <-- this looses the allocated memory pointer
                 //     without actually freeing the allocated memory
    }

    ptr = NULL;  // <-- this has no effect on the rest of the program allocated memory
                 //     because C passes by value, not by reference
} // end function: myFree
user3629249
  • 16,402
  • 1
  • 16
  • 17