cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: Memory leak if FTP server responds "530 Login incorrect"

From: Alexey Simak <alexeysimak_at_gmail.com>
Date: Mon, 11 Dec 2006 19:46:13 +0200

> I then run the example and use 'memanalyze.pl' to check for leaks:
> $ memanalyze.pl memdump
>$

> Ie, it finds none. I even did a make clean and rebuild just to be extra
sure
> my build has nothing "weird" in it, but still no leak.

> It makes me interested in what the difference is between your
build/version
> and mine!

Actually to find memory leaks I'm using some memory profiler tool on Win,
not your memdebug module. So unfortunately I cannot say why leaks are not
detected in your environment.

To prove that there are memory leaks I modified a test program to run
a lot of FTP fetches sequentially. Then I ran it with performance monitor.
Attached you can see a chart <memoryleak.pdf> which shows memory usage
of test program during execution of 10 000 000 FTP fetches.

Here is a code of test program:
//--------------------------------------------------------------------------
-
#include "curl/curl.h"

#ifndef TRUE
#define TRUE 1
#endif

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

int 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 test( const char * cszURL )
{
    CURL* handle;
    CURLM* multi_handle;
    int still_running; /* keep number of running handles */

    struct FtpFile ftpfile={
    "test.txt", /* name to store the file as if succesful */
    NULL
    };

    multi_handle = curl_multi_init();
    handle = curl_easy_init();
    CURLMcode code = curl_multi_add_handle( multi_handle, handle );

    curl_easy_setopt(handle, CURLOPT_URL, cszURL);
    /* Define our callback to get called when there's data to be written */
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_fwrite);
    /* Set a pointer to our struct to pass to the callback */
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &ftpfile);
    /* Switch on full protocol/debug output */
    curl_easy_setopt(handle, CURLOPT_VERBOSE, FALSE);
    // speed up the test
    curl_easy_setopt(handle, CURLOPT_NOBODY, TRUE);

    /* 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);

        /* In a real-world program you OF COURSE check the return code of
the
           function calls, *and* you make sure that maxfd is bigger than -1
so
           that the call to select() below makes sense! */

        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, handle );
    curl_easy_cleanup( handle );
    curl_multi_cleanup( multi_handle );

    if(ftpfile.stream)
        fclose(ftpfile.stream); /* close the local file */

    return 0;
}

int main(int argc, char* argv[])
{
    int nCount = 1;
    if ( argc > 1 ) {
        nCount = atoi(argv[1]);
    }

    curl_global_init(CURL_GLOBAL_DEFAULT);

    printf("Performing %d iteration(s)...\n", nCount);

    for (int i = 0; i < nCount; i++) {
        test(
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.9.2.tar.gz" );
    }

    printf("Done\n");

    curl_global_cleanup();

    return 0;
}
//--------------------------------------------------------------------------
-

Received on 2006-12-11