cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: Possible memory leak with FTP and curl_easy_perform() ?

From: Jean-François Lavoie <lavoiejeff_at_videotron.ca>
Date: Wed, 15 Oct 2008 10:17:10 -0400

Hello Daniel,

    thanks for writing back. Since I am using Visual Studio, I could
not find any package for version 7.19 and that is why I am still using
7.18.

    Here is the code with which I can reproduce the leak. As you will
see, it is the ftpget.c example included in the curl package, which I
modified to get a smaller file so that it iterates more often. I also
added a while loop around the curl_easy_perforrm() call. When you run
this program, after a few iterations (maybe 20), you will notice that
the process will take 8 KB more memory, and after a few other
iterations, 8 KB more again, and so on.. Is that behavior normal and
everything will be cleaned after the 1000th iteration on the
curl_easy_cleanup() call ?

    My application constantly gets small files from a ftp server and
that is the reason I noticed that memory usage was slowly going up.

Here is my platform information again :

platform : MS windows XP SP2
libcurl version : 7.18.00 win32 no SSL vc6 (downloaded from
http://curl.haxx.se/download/libcurl-7.18.0-win32-msvc.zip )
compiler : MS visual studio 2005

    Thank you for any help !

Jeff

----------------------------

/*****************************************************************************
 * _ _ ____ _
 * Project ___| | | | _ \| |
 * / __| | | | |_) | |
 * | (__| |_| | _ <| |___
 * \___|\___/|_| \_\_____|
 *
 * $Id: ftpget.c,v 1.8 2008-05-22 21:20:09 danf Exp $
 */

#include <stdio.h>

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

/*
 * This is an example showing how to get a single file from an FTP server.
 * It delays the actual destination file creation until the first write
 * callback so that it won't create an empty file in case the remote file
 * doesn't exist or something else fails.
 */

struct FtpFile {
  const char *filename;
  FILE *stream;
};

static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
  struct FtpFile *out=(struct FtpFile *)stream;
  if(out && !out->stream) {
    /* open file for writing */
    out->stream=fopen(out->filename, "wb");
    if(!out->stream)
      return -1; /* failure, can't open file to write */
  }
  return fwrite(buffer, size, nmemb, out->stream);
}

int main(void)
{
  int i = 0;
  CURL *curl;
  CURLcode res;
  struct FtpFile ftpfile={
    "curl.tar.gz", /* name to store the file as if succesful */
    NULL
  };

  curl_global_init(CURL_GLOBAL_DEFAULT);

  while(1)
  {
     curl = curl_easy_init();
  if(curl) {
    /*
     * Get curl 7.9.2 from sunet.se's FTP site. curl 7.9.2 is most likely not
     * present there by the time you read this, so you'd better replace the
     * URL with one that works!
     */
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://ftp.sunet.se/pub/www/utilities/curl/curl-6.0-win32.zip");
    /* Define our callback to get called when there's data to be written */
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
    /* Set a pointer to our struct to pass to the callback */
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);

    /* Switch on full protocol/debug output */
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    i = 0;
    while(i<1000)
    {
       res = curl_easy_perform(curl);
       i++;
    }
    /* always cleanup */
    curl_easy_cleanup(curl);

    if(CURLE_OK != res) {
      /* we failed */
      fprintf(stderr, "curl told us %d\n", res);
    }
  }

  if(ftpfile.stream)
  {
    fclose(ftpfile.stream); /* close the local file */
    ftpfile.stream = 0;
  }
}

  curl_global_cleanup();

  return 0;
}

----------------------------

curl-library-request_at_cool.haxx.se a écrit :
> Send curl-library mailing list submissions to
> curl-library_at_cool.haxx.se
>
> To subscribe or unsubscribe via the World Wide Web, visit
> http://cool.haxx.se/cgi-bin/mailman/listinfo/curl-library
> or, via email, send a message with subject or body 'help' to
> curl-library-request_at_cool.haxx.se
>
> You can reach the person managing the list at
> curl-library-owner_at_cool.haxx.se
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of curl-library digest..."
>
>
> Today's Topics:
>
> 1. Possible memory leak with FTP and curl_easy_perform() ?
> (Jean-Fran?ois Lavoie)
> 2. Re: curl_multi_perform slow (timeout) (Daniel Stenberg)
> 3. Re: Possible memory leak with FTP and curl_easy_perform() ?
> (Daniel Stenberg)
> 4. Re: libcurl issue with IPv6 and c-ares (Daniel Stenberg)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Fri, 10 Oct 2008 15:41:14 -0400
> From: Jean-Fran?ois Lavoie <lavoiejeff_at_videotron.ca>
> Subject: Possible memory leak with FTP and curl_easy_perform() ?
> To: curl-library_at_cool.haxx.se
> Message-ID: <48EFAFDA.6060904_at_videotron.ca>
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
>
> Hi,
>
> I am a new libcurl user and I think I may have found a memory leak
> in repeated FTP transfers using the same curl handle. Maybe I am just
> using the library in a way it is not intented for.
>
> Here is my platform information :
>
> platform : MS windows XP SP2
> libcurl version : 7.18.00 win32 no SSL vc6 (downloaded from
> http://curl.haxx.se/download/libcurl-7.18.0-win32-msvc.zip )
> compiler : MS visual studio 2005
>
> The problem I found can be easily reproduced by taking the ftpget.c
> example file (included in the docs/example folder ) and adding a while
> (true) instruction to make the curl_easy_perform() call repeatedly.
> Doing this, without changing any curl options between the
> curl_easy_perform() calls makes the ftpget program take more and more
> memory over time, which can be seen with the task manager in windows. I
> tested it and it does not take more and more memory using the same
> function call order in HTTP mode instead of FTP.
>
> this will cause the leak :
>
> program 1
> {
> curl_global_init()
> curl_easy_init()
> curl_easy_setopt()...
>
> while (true)
> {
> curl_easy_perform()
> }
>
> curl_easy_cleanup()
> curl_global_cleanup()
> }
>
> It seems the documentation recommends re-using the same handle so I
> would guess it is perfectly normal to use the library this way for
> multiple sequential FTP transfers.
>
> The following program does the same thing, but will not take more
> and more memory over time. It calls curl_easy_init() and
> curl_easy_cleanup() for each FTP transfer.
>
> this will NOT cause the leak :
>
> program 2
> {
> curl_global_init()
>
> while(true)
> {
> curl_easy_init()
> curl_easy_setopt()...
>
> curl_easy_perform()
>
> curl_easy_cleanup()
> }
>
> curl_global_cleanup()
> }
>
> Please let me know if it is a problem from the library or if I am
> just using the library in a wrong way.
>
> Thank you very much, and many thanks for the great work, CURL is
> wonderful !
>
> Jeff
>
>
> ------------------------------
>
> Message: 2
> Date: Fri, 10 Oct 2008 23:08:24 +0200 (CEST)
> From: Daniel Stenberg <daniel_at_haxx.se>
> Subject: Re: curl_multi_perform slow (timeout)
> To: libcurl development <curl-library_at_cool.haxx.se>
> Message-ID: <alpine.LRH.1.10.0810102115470.17954_at_yvahk3.pbagnpgbe.fr>
> Content-Type: TEXT/PLAIN; format=flowed; charset=US-ASCII
>
> On Fri, 10 Oct 2008, Dino Puller wrote:
>
>
>> err = curl_multi_perform(_this->multi_handle, &running_handles);
>> if (err == CURLM_CALL_MULTI_PERFORM)
>> err = curl_multi_perform(_this->multi_handle, &running_handles);
>>
>
> So what if this second call also returns CURLM_CALL_MULTI_PERFORM? I suggest
> you loop as long as it returns that, like our example sources do.
>
>
>> libcurl version tested: 7.19.0 and 7.18.2
>>
>
> On what platform?
>
>
Received on 2008-10-15