Commit dcf7310b authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

fixed curl_easy_duphandle() to properly clean up all memory if any memory

function fails and it returns NULL
parent c2e8ba0f
Loading
Loading
Loading
Loading
+84 −57
Original line number Diff line number Diff line
@@ -420,24 +420,16 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
 */
CURL *curl_easy_duphandle(CURL *incurl)
{
  bool fail = TRUE;
  struct SessionHandle *data=(struct SessionHandle *)incurl;

  struct SessionHandle *outcurl = (struct SessionHandle *)
    malloc(sizeof(struct SessionHandle));
    calloc(sizeof(struct SessionHandle), 1);

  if(NULL == outcurl)
    return NULL; /* failure */

  /* start with clearing the entire new struct */
  memset(outcurl, 0, sizeof(struct SessionHandle));

#ifdef USE_ARES
  /* If we use ares, we need to setup a new ares channel for the new handle */
  if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel)) {
    free(outcurl);
    return NULL;
  }
#endif
  do {

    /*
     * We setup a few buffers we need. We should probably make them
@@ -446,8 +438,7 @@ CURL *curl_easy_duphandle(CURL *incurl)
     */
    outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
    if(!outcurl->state.headerbuff) {
    free(outcurl); /* free the memory again */
    return NULL;
      break;
    }
    outcurl->state.headersize=HEADERSIZE;

@@ -458,37 +449,73 @@ CURL *curl_easy_duphandle(CURL *incurl)
      malloc(sizeof(struct connectdata *) * outcurl->state.numconnects);

    if(!outcurl->state.connects) {
    free(outcurl->state.headerbuff);
    free(outcurl);
    return NULL;
      break;
    }

    memset(outcurl->state.connects, 0,
           sizeof(struct connectdata *)*outcurl->state.numconnects);

    outcurl->progress.flags    = data->progress.flags;
    outcurl->progress.callback = data->progress.callback;

  if(data->cookies)
    if(data->cookies) {
      /* If cookies are enabled in the parent handle, we enable them
         in the clone as well! */
      outcurl->cookies = Curl_cookie_init(data,
                                            data->cookies->filename,
                                            outcurl->cookies,
                                            data->set.cookiesession);
      if(!outcurl->cookies) {
        break;
      }
    }

    /* duplicate all values in 'change' */
    if(data->change.url) {
      outcurl->change.url = strdup(data->change.url);
      if(!outcurl->change.url)
        break;
      outcurl->change.url_alloc = TRUE;
    }
    if(data->change.proxy) {
      outcurl->change.proxy = strdup(data->change.proxy);
      if(!outcurl->change.proxy)
        break;
      outcurl->change.proxy_alloc = TRUE;
    }
    if(data->change.referer) {
      outcurl->change.referer = strdup(data->change.referer);
      if(!outcurl->change.referer)
        break;
      outcurl->change.referer_alloc = TRUE;
    }

#ifdef USE_ARES
    /* If we use ares, we setup a new ares channel for the new handle */
    if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
      break;
#endif

    fail = FALSE; /* we reach this point and thus we are OK */

  } while(0);

  if(fail) {
    if(outcurl) {
      if(outcurl->state.connects)
        free(outcurl->state.connects);
      if(outcurl->state.headerbuff)
        free(outcurl->state.headerbuff);
      if(outcurl->change.proxy)
        free(outcurl->change.proxy);
      if(outcurl->change.url)
        free(outcurl->change.url);
      if(outcurl->change.referer)
        free(outcurl->change.referer);
      free(outcurl); /* free the memory again */
      outcurl = NULL;
    }
  }

  return outcurl;
}