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 13:27:55 +0200

>> I've now committed a fix that stops the leak for me. I also added a test
>> case that repeats the scenario.

Thanks for the quick resolution. I've checked your fix and the memory leak
I've reported has gone. But now we have some other two leaks when
login and password are OK:

1) ftp.c,v 1.384 2006/12/11 09:32:58 bagder, line 2557:
       char *dir = (char *)malloc(nread+1);

2) escape.c,v 1.38 2006-10-17 21:32:56 bagder, line 123:
       char *ns = malloc(alloc);

Please note that there are no these leaks if your last fix is not applied.

Here is a simple program to reproduce the problem:

//------------------------------------------------------------------------
#include "curl.h"

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 main(int argc, char* argv[])
{
    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
    };

    curl_global_init(CURL_GLOBAL_DEFAULT);

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

    curl_easy_setopt(handle, CURLOPT_URL,
"ftp://ftp.univ.kiev.ua/pub/incoming/test.txt");
    /* 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, 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 */

    curl_global_cleanup();

    return 0;
}

//------------------------------------------------------------------------
Received on 2006-12-11