Package: python-pycurl Version: 7.19.0-5 Severity: important Tags: patch Hi,
PyCurl segfault while invoking reset() function multiple times. Here is an example on how to reproduce the crash: $ printf "import pycurl\nc = pycurl.Curl()\nfor i in xrange(100000):\n\tc.reset()\n" | python This bug has been fixed upstream for ages[1][2]. Attached is a patch which includes the upstream fix reworked to apply cleanly on the Debian sources. Regards, [1] http://sourceforge.net/tracker/?func=detail&aid=2893665&group_id=28236&atid=392777 [2] http://pycurl.cvs.sourceforge.net/viewvc/pycurl/pycurl/src/pycurl.c?r1=1.148&r2=1.149 -- System Information: Debian Release: wheezy/sid APT prefers unstable APT policy: (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 3.2.0-3-amd64 (SMP w/2 CPU cores) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash
>From fd77939ffbd90f43c7749781b2f8ae5c9d86e91d Mon Sep 17 00:00:00 2001 From: Emmanuel Bouthenot <kol...@openics.org> Date: Wed, 10 Oct 2012 21:56:03 +0000 Subject: [PATCH] Fix refcount bug/segfault in reset() function --- debian/changelog | 8 ++ debian/patches/20_fix_refcount_bug.patch | 159 ++++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 168 insertions(+) create mode 100644 debian/patches/20_fix_refcount_bug.patch diff --git a/debian/changelog b/debian/changelog index 0aa84ab..df41cbf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +pycurl (7.19.0-5.1) unstable; urgency=low + + * Non-maintainer upload. + * Add a patch to fix refcount bug in reset() function which leads to + a segfault in some cases. + + -- Emmanuel Bouthenot <kol...@debian.org> Wed, 10 Oct 2012 21:45:56 +0000 + pycurl (7.19.0-5) unstable; urgency=low * debian/rules diff --git a/debian/patches/20_fix_refcount_bug.patch b/debian/patches/20_fix_refcount_bug.patch new file mode 100644 index 0000000..000e75e --- /dev/null +++ b/debian/patches/20_fix_refcount_bug.patch @@ -0,0 +1,159 @@ +Description: Fix refcount bug in reset() function which leads to a segfault in some cases +Forwarded: not-needed +Origin: upstream, http://pycurl.cvs.sourceforge.net/viewvc/pycurl/pycurl/src/pycurl.c?r1=1.148&r2=1.149 +Bug: http://sourceforge.net/tracker/?func=detail&aid=2893665&group_id=28236&atid=392777 +Author: Emmanuel Bouthenot <kol...@debian.org> +Last-Update: 2012-10-10 +--- a/src/pycurl.c ++++ b/src/pycurl.c +@@ -748,64 +748,84 @@ + } + + +-/* constructor - this is a module-level function returning a new instance */ +-static CurlObject * +-do_curl_new(PyObject *dummy) ++/* initializer - used to intialize curl easy handles for use with pycurl */ ++static int ++util_curl_init(CurlObject *self) + { +- CurlObject *self = NULL; + int res; + char *s = NULL; + +- UNUSED(dummy); +- +- /* Allocate python curl object */ +- self = util_curl_new(); +- if (self == NULL) +- return NULL; +- +- /* Initialize curl handle */ +- self->handle = curl_easy_init(); +- if (self->handle == NULL) +- goto error; +- + /* Set curl error buffer and zero it */ + res = curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->error); +- if (res != CURLE_OK) +- goto error; ++ if (res != CURLE_OK) { ++ return (-1); ++ } + memset(self->error, 0, sizeof(self->error)); + + /* Set backreference */ + res = curl_easy_setopt(self->handle, CURLOPT_PRIVATE, (char *) self); +- if (res != CURLE_OK) +- goto error; ++ if (res != CURLE_OK) { ++ return (-1); ++ } + + /* Enable NOPROGRESS by default, i.e. no progress output */ + res = curl_easy_setopt(self->handle, CURLOPT_NOPROGRESS, (long)1); +- if (res != CURLE_OK) +- goto error; ++ if (res != CURLE_OK) { ++ return (-1); ++ } + + /* Disable VERBOSE by default, i.e. no verbose output */ + res = curl_easy_setopt(self->handle, CURLOPT_VERBOSE, (long)0); +- if (res != CURLE_OK) +- goto error; ++ if (res != CURLE_OK) { ++ return (-1); ++ } + + /* Set FTP_ACCOUNT to NULL by default */ + res = curl_easy_setopt(self->handle, CURLOPT_FTP_ACCOUNT, NULL); +- if (res != CURLE_OK) +- goto error; ++ if (res != CURLE_OK) { ++ return (-1); ++ } + + /* Set default USERAGENT */ + s = (char *) malloc(7 + strlen(LIBCURL_VERSION) + 1); +- if (s == NULL) +- goto error; ++ if (s == NULL) { ++ return (-1); ++ } + strcpy(s, "PycURL/"); strcpy(s+7, LIBCURL_VERSION); + res = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, (char *) s); + if (res != CURLE_OK) { + free(s); +- goto error; ++ return (-1); + } ++ + self->options[ OPT_INDEX(CURLOPT_USERAGENT) ] = s; s = NULL; + ++ return (0); ++} ++ ++/* constructor - this is a module-level function returning a new instance */ ++static CurlObject * ++do_curl_new(PyObject *dummy) ++{ ++ CurlObject *self = NULL; ++ int res; ++ ++ UNUSED(dummy); ++ ++ /* Allocate python curl object */ ++ self = util_curl_new(); ++ if (self == NULL) ++ return NULL; ++ ++ /* Initialize curl handle */ ++ self->handle = curl_easy_init(); ++ if (self->handle == NULL) ++ goto error; ++ ++ res = util_curl_init(self); ++ if (res < 0) ++ goto error; ++ + /* Success - return new object */ + return self; + +@@ -1424,6 +1444,7 @@ + static PyObject* + do_curl_reset(CurlObject *self) + { ++ int res; + unsigned int i; + + curl_easy_reset(self->handle); +@@ -1452,6 +1473,14 @@ + } + } + ++ res = util_curl_init(self); ++ if (res < 0) { ++ Py_DECREF(self); /* this also closes self->handle */ ++ PyErr_SetString(ErrorObject, "resetting curl failed"); ++ return NULL; ++ } ++ ++ Py_INCREF(Py_None); + return Py_None; + } + +--- a/tests/test_internals.py ++++ b/tests/test_internals.py +@@ -245,6 +245,11 @@ + if opts.verbose >= 1: + print "Tracked objects:", len(gc.get_objects()) + ++# Ensure that the refcounting error in 'reset' is fixed ++if 1: ++ c = Curl() ++ for i in xrange(100000): ++ c.reset() + + # /*********************************************************************** + # // done diff --git a/debian/patches/series b/debian/patches/series index fdf6a58..8c3336a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ 10_setup.py.patch +20_fix_refcount_bug.patch -- 1.7.10.4