cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: 7.15.4 introduced crash problem

From: Ingmar Runge <ingmar_at_irsoft.de>
Date: Tue, 04 Jul 2006 15:26:42 +0200

Hi,

The release I upgraded from was 7.15.3.

I have been able to work around the issue. I realized that the multi
interface doesn't use my host cache share anyway, from what I grasped.
So I completely removed the share interface calls.

Anyway, a crash remains a crash so I will try to help to fix it anyway:
I attached a modified version of the multi-single.c example to reproduce
the crash. Note lines 57/58. Another screenshot made while debugging the
demo's crash is also attached. The demo app crash seems to take, like, a
somehow different route than in my real app. It crashes after
curl_share_cleanup has been called, not after a curl_multi_add_handle
call... both end up in Curl_hash_destroy calls and finally a crash in
free() though...

Maybe the moment I add my easy handle to the multi stack, the easy
handle's host cache is freed and replaced by the multi interface's share
handle. Later, after returning from the multi processing, I try to free
the original share handle. It has already been freed previously though
which could lead to a crash.
In my main app, there are several easy handles processed during some
multi calls. All use the same share handle. When the first one is added
to the multi stack, my share is freed and replaced. Then, when the
second easy handle is added, libcurl tries to free its share handle
again, as the pointer is not NULL, but pointing to where the already
freed share handle has been.
This sounds like it perfectly made sense and could explain the crashes.
It's only an assumption, I can't right now prove it with code parts
though. What do you think?

~
Ingmar Runge

PS. My English isn't so good, so please excuse any mistakes and ask if I
described something inaccurately or something ;-)

/*****************************************************************************
 * _ _ ____ _
 * Project ___| | | | _ \| |
 * / __| | | | |_) | |
 * | (__| |_| | _ <| |___
 * \___|\___/|_| \_\_____|
 *
 * $Id: multi-single.c,v 1.5 2004/05/24 15:16:29 bagder Exp $
 *
 * This is a very simple example using the multi interface.
 */

#include <stdio.h>
#include <string.h>

/* curl stuff */
#include "..\..\include\curl\curl.h"

void curlsh_lock_function(CURL *handle, curl_lock_data data, curl_lock_access access, void *userptr)
{
  /* does nothing in this example :O */
}

void curlsh_unlock_function(CURL *handle, curl_lock_data data, void *userptr)
{
  /* does nothing in this example :O */
}

/*
 * Simply download a HTTP file.
 */
int main(int argc, char **argv)
{
  CURL *http_handle;
  CURLM *multi_handle;
  
  CURLSH *hCURLShare;

  int still_running; /* keep number of running handles */

  curl_global_init(CURL_GLOBAL_ALL);

  hCURLShare = curl_share_init();
  
  curl_share_setopt(hCURLShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
  
  curl_share_setopt(hCURLShare, CURLSHOPT_LOCKFUNC, &curlsh_lock_function);
  curl_share_setopt(hCURLShare, CURLSHOPT_UNLOCKFUNC, &curlsh_unlock_function);

  http_handle = curl_easy_init();

  /* set the options (I left out a few, you'll get the point anyway) */
  curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.haxx.se/");
  

  /******************************************************/
  /* no crash without the following line, crash with it */
  curl_easy_setopt(http_handle, CURLOPT_SHARE, hCURLShare);
  /******************************************************/

  curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1);
  curl_easy_setopt(http_handle, CURLOPT_DNS_CACHE_TIMEOUT, -1); // cache forever
  curl_easy_setopt(http_handle, CURLOPT_DNS_USE_GLOBAL_CACHE, 0); // disable, we use curl_share* for caching
  curl_easy_setopt(http_handle, CURLOPT_AUTOREFERER, 1);
  curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10);
  curl_easy_setopt(http_handle, CURLOPT_CRLF, 1);
  curl_easy_setopt(http_handle, CURLOPT_CONNECTTIMEOUT, 60);
  curl_easy_setopt(http_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  curl_easy_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(http_handle, CURLOPT_SSL_VERIFYHOST, 0);
  curl_easy_setopt(http_handle, CURLOPT_NOPROGRESS, 1);
  curl_easy_setopt(http_handle, CURLOPT_UNRESTRICTED_AUTH, 1);
  
  /* init a multi stack */
  multi_handle = curl_multi_init();

  /* add the individual transfers */
  curl_multi_add_handle(multi_handle, http_handle);

  /* we start some action by calling perform right away */
  while(CURLM_CALL_MULTI_PERFORM ==
        curl_multi_perform(multi_handle, &still_running));

  while(still_running) {
    struct timeval timeout;
    int rc; /* select() return code */

    fd_set fdread;
    fd_set fdwrite;
    fd_set fdexcep;
    int maxfd;

    FD_ZERO(&fdread);
    FD_ZERO(&fdwrite);
    FD_ZERO(&fdexcep);

    /* set a suitable timeout to play around with */
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    /* get file descriptors from the transfers */
    curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);

    rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);

    switch(rc) {
    case -1:
      /* select error */
      still_running = 0;
      printf("select() returns error, this is badness\n");
      break;
    case 0:
    default:
      /* timeout or readable/writable sockets */
      while(CURLM_CALL_MULTI_PERFORM ==
            curl_multi_perform(multi_handle, &still_running));
      break;
    }
  }
  
  curl_multi_remove_handle(multi_handle, http_handle);
  
  curl_multi_cleanup(multi_handle);

  curl_easy_cleanup(http_handle);
  
  curl_share_cleanup(hCURLShare);
  curl_global_cleanup();

  return 0;
}

demo-app-crash.png
Received on 2006-07-04