Package: python-tclink
Version: 3.4.0-1.1
Severity: normal

Python extensions written in C have a per-thread error indication.  If
an error happens, and an extension function doesn't check for the
error and convert it into an exception, then the error indication
stays set and some future extension function is likely to check for
and raise the error.  This can happen in a garbage collection and
cause Python to abort.  There are other scenarios that lead to a
segfault, but I don't understand that well enough to include an
example here.

Here's an example.  The version of tctest.py is the program from the
python-tclink source, modified so params["state"] is None.  This
provokes an error because PyString_AsString refuses to convert Py_None
to a string.

    [EMAIL PROTECTED]:/tmp$ cat tctest.py
    #!/usr/bin/python
    #
    # Test script for TCLink Python client.
    #

    import tclink

    print 'Using TCLink version', tclink.getVersion()

    params = {
        'custid':    'TestMerchant',
        'password':  'password',
        'action':    'preauth',
        'cc':        '4111111111111111',
        'exp':       '0404',
        'amount':    '100',
        'avs':       'n',
        'state':     None
    }

    result = tclink.send(params)

    if result['status'] == 'approved':
        print 'The transaction was approved!'
    elif result['status'] == 'decline':
        print 'The transaction was declined.'
    else:
        print 'There was an error.'

    print 'Here are the full details:'
    print result

    [EMAIL PROTECTED]:/tmp$ python tctest.py
    Using TCLink version 3.4-Python-Linux-i686
    The transaction was approved!
    Here are the full details:
    {'status': 'approved', 'transid': '011-0017158794', 'avs': 'N'}
    Exception exceptions.TypeError: 'expected string or Unicode object, 
NoneType found' in 'garbage collection' ignored
    Fatal Python error: unexpected exception during garbage collection
    Aborted
    [EMAIL PROTECTED]:/tmp$ 

Note that the exception message "expected string or Unicode object,
NoneType found" is correct, modulo poor English: something of type
NoneType really was encountered when something of type string was
appropriate, specifically the value of params["state"].  However,
because the exception happened later, it happened during a garbage
collection and python aborted.

Here's a patch:

--- py_tclink.c 2003-09-05 15:47:36.000000000 -0700
+++ /home/tim/ml/branches/tim/server/test/tclink-3.4-python-hacked/py_tclink.c  
2005-04-27 10:12:48.000000000 -0700
@@ -36,15 +36,23 @@
        TCLinkCon *c;
        param *p;
 
-
        if (!PyArg_ParseTuple(args, "O", &input))
                return (PyObject *)NULL;
 
        /* stuff the parameters */
        handle = TCLinkCreate();
 
-       while (PyDict_Next(input, &pos, &key, &value))
-               TCLinkPushParam(handle, PyString_AsString(key), 
PyString_AsString(value));
+       while (PyDict_Next(input, &pos, &key, &value) && !PyErr_Occurred()) {
+          char *k = PyString_AsString(key);
+          char *v;
+          if (!PyErr_Occurred()) v = PyString_AsString(value);
+          if (!PyErr_Occurred()) TCLinkPushParam(handle, k, v);
+        }
+
+        if (PyErr_Occurred()) {
+          TCLinkDestroy(handle);
+          return NULL;
+        }
 
        Py_BEGIN_ALLOW_THREADS
 
@@ -57,13 +65,18 @@
        c = (TCLinkCon *)handle;
        output = PyDict_New();
 
-       for (p = c->recv_param_list; p; p = p->next)
-               PyDict_SetItem(output, Py_BuildValue("s", p->name), 
Py_BuildValue("s", p->value));
+       for (p = c->recv_param_list; p && !PyErr_Occurred(); p = p->next)
+          PyDict_SetItem(output, Py_BuildValue("s", p->name),
+                         Py_BuildValue("s", p->value));
 
        TCLinkDestroy(handle);
 
-
-       return output;
+        if (PyErr_Occurred()) {
+          Py_DECREF(output);
+          return NULL;
+        } else {
+          return output;
+        }
 }
 
 #define TCLINKGETVERSION_DOC "Returns the module version string.\n"

And here's what happens when I run with the patched py_tclink.c.  The
point here is that python didn't abort, and the python stack trace
accurately points at the bad code.

    [EMAIL PROTECTED]:/tmp$ export 
PYTHONPATH=/home/tim/python-tclink-3.4.0/build/lib.linux-i686-2.3
    [EMAIL PROTECTED]:/tmp$ python tctest.py
    Using TCLink version 3.4-Python-Linux-i686
    Traceback (most recent call last):
      File "tctest.py", line 21, in ?
        result = tclink.send(params)
    TypeError: expected string or Unicode object, NoneType found
    [EMAIL PROTECTED]:/tmp$ 

-- System Information:
Debian Release: 3.1
  APT prefers testing
  APT policy: (1500, 'testing'), (500, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.4.26-treo
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages python-tclink depends on:
ii  python                        2.3.5-1    An interactive high-level object-o
ii  python2.3-tclink              3.4.0-1.1  TrustCommerce credit card processi

-- no debconf information


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to