-2
size_t writeFunctionHandler(char *contents,size_t size,size_t nmemb,void *userdata) {
  // size of the storedSize
  static size_t storedSize = 0;

  // the size of data available
  size_t realSize = size * nmemb;

  char *dataBuffer = (char *) userdata;

  // realloc the buffer buffer
  dataBuffer = realloc(dataBuffer,storedSize + realSize);

  if (dataBuffer == NULL) {
    printf("Could not allocate memory \n");
    return 0;
  }

  // store the contents of realSize from last storedSize
  memcpy(&(dataBuffer[storedSize]),contents,realSize);

  storedSize += realSize;
  return realSize;
}

I fail to understand as to why the above code return and error pointer being realloc'd was not allocated

And when I used this sample code

struct MemoryStruct {
  char *memory;
};

size_t writeFunctionHandler(char *contents,size_t size,size_t nmemb, void *userdata) {
  size_t realSize = size * nmemb;
  static size_t storedSize = 0;
  //char *dataBuffer = (char *)userdata;
  struct MemoryStruct *chunk = (struct MemoryStruct *)userdata;

  printf("print 1\n");
  chunk -> memory = realloc(chunk -> memory,storedSize + realSize);
  printf("print 2\n");

  if (chunk -> memory == NULL) {
    printf("Could not allocate memory\n");
    return 0;
  }

  memcpy(&(chunk -> memory[storedSize]),contents,realSize);
  storedSize += realSize;
  printf("print 3\n");

  return realSize;
}

All seem to work properly fine.

This above is a curl writeFunctionHandler

int main() {
   char *buffer = calloc(1,1);
   // struct MemoryStruct chunk;
   // chunk.memory = calloc(1,1);

   CURL *curl = curl_easy_init();

   curl_easy_setopt(curl, CURLOPT_URL, "http://stackoverflow.com");
   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunctionHandler);
   curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)buffer);
   // curl_easy_setopt(curl,CURLOPT_WRITEDATA, (void *) &chunk);

   free(buffer);
   //free(chunk.memory);
   curl_easy_cleanup(curl);

   return 0;
}

I fail to understand what difference between the 2 code except the fact that I'm using struct in the later case.

Ratatouille
  • 1,372
  • 5
  • 23
  • 50
  • Are you sure the **sample** function doesn't have anything between the last `curl_easy_setopt` and `free(chunk.memory)`? – StoryTeller - Unslander Monica Mar 26 '17 at 06:21
  • @StoryTeller Here how the actual code look like https://gist.github.com/anonymous/9274da0998124dc9576f28e52327af87 – Ratatouille Mar 26 '17 at 06:26
  • Sorry, but the link you gave is just a 404 – StoryTeller - Unslander Monica Mar 26 '17 at 06:27
  • https://gist.github.com/anonymous/9274da0998124dc9576f28e52327af87 – Sniper Mar 26 '17 at 06:28
  • 1
    [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Mar 26 '17 at 06:30
  • I see the code you posted doesn't have a call to `curl_easy_perform`. So I don't see when your callback can be executed, exactly. A [mcve] please. – StoryTeller - Unslander Monica Mar 26 '17 at 06:30
  • @StoryTeller https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html as soon as the CURL has data to write it calls the callback. – Ratatouille Mar 26 '17 at 06:32
  • @StoryTeller https://gist.github.com/anonymous/9274da0998124dc9576f28e52327af87#file-curl_easy-c-L55 – Ratatouille Mar 26 '17 at 06:32
  • Well `buffer` and `chunk-> memory` are 2 different example As I have mention earlier – Ratatouille Mar 26 '17 at 06:36
  • @SouravGhosh `char *dataBuffer = userdata;` use this instead of casting it correct. – Ratatouille Mar 26 '17 at 06:38
  • Oh, `dataBuffer = realloc(dataBuffer,storedSize + realSize);` That modifies a *local* variable. The original `userdata` pointer is unchanged. So next time your handler is called it will get the old `userdata` value not the `realloced` value. – kaylum Mar 26 '17 at 06:38
  • @kaylum I was assuming the same but how does it work with the struct example. I you can provide insight on that also that would be really helpful. – Ratatouille Mar 26 '17 at 06:39
  • `chunk->memory` is not a local variable. It is the same variable each time the handler is called. Which will work just fine as you have found. – kaylum Mar 26 '17 at 06:40
  • Well in case of `chunk->memory` `userdata` is a pointer to struct `MemoryStruct`. In case of `buffer` `userdata` is a pointer to `char buffer` both of which are created in main. So what the differences. – Ratatouille Mar 26 '17 at 06:44
  • 2
    Well, the differences is that the first example reallocates `userdata` each time. In the second example, `userdata` is unchanged. IN the first example, the `realloc` invalidates `userdata`. So it is a garbage pointer the next time the handler is called. In the second example, the `realloc` invalidates the old `chunk->memory` pointer but that is fine as it is correctly replaced with the new `realloc` value. – kaylum Mar 26 '17 at 06:45
  • @kaylum - You should post that as an answer. – StoryTeller - Unslander Monica Mar 26 '17 at 06:52
  • @kaylum what do you mean by userdata is unchanged. – Ratatouille Mar 26 '17 at 06:58
  • 1
    In the second example, `userdata` is set to `&chunk`. That values remains valid throughout the execution of the program. In the first example, `userdata` is set to `buffer`. But that becomes invalid on the first realloc (which frees the original `buffer` memory). – kaylum Mar 26 '17 at 07:11

1 Answers1

3

The point is that userdata points to struct containing a member memory and it is that member that is alloced from the heap.

Further, when the function returns, then memory may have been changed with the realloc, but in your version the change cannot be seen outside the function. That is because the value of the pointer was passed, not the address. If the address were passed (i.e. void **userdata), you would have realloced to that address (i.e. *userdata= realloc(..) and it would have become visible outside the function.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41