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

Reply via email to