]> granicus.if.org Git - python/commitdiff
#3643 add a few more checks to _testcapi to prevent segfaults
authorBenjamin Peterson <benjamin@python.org>
Sat, 23 Aug 2008 20:27:43 +0000 (20:27 +0000)
committerBenjamin Peterson <benjamin@python.org>
Sat, 23 Aug 2008 20:27:43 +0000 (20:27 +0000)
Author: Victor Stinner
Reviewer: Benjamin Peterson

Misc/NEWS
Modules/_testcapimodule.c

index 07fc1f35043191038fb5154be7117bd2e6bc9781..2ae121a244a7ce3871eb21c301afed7c7495c98f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,12 @@ Library
 
 - Fixed two format strings in the _collections module.
 
+Extension Modules
+-----------------
+
+- Issue #3643: Added a few more checks to _testcapi to prevent segfaults by
+  exploitation of poor argument checking.
+
 
 What's New in Python 2.6 beta 3?
 ================================
index 2ed81aa5b844ac7cfe5955ac48d4720752c8838d..f3a9f5ce9d043db57f752c75141d3df859ea13f6 100644 (file)
@@ -600,6 +600,10 @@ raise_exception(PyObject *self, PyObject *args)
        if (!PyArg_ParseTuple(args, "Oi:raise_exception",
                              &exc, &num_args))
                return NULL;
+       if (!PyExceptionClass_Check(exc)) {
+               PyErr_Format(PyExc_TypeError, "an exception class is required");
+               return NULL;
+       }
 
        exc_args = PyTuple_New(num_args);
        if (exc_args == NULL)
@@ -628,14 +632,17 @@ raise_exception(PyObject *self, PyObject *args)
  */
 static PyThread_type_lock thread_done = NULL;
 
-static void
+static int
 _make_call(void *callable)
 {
        PyObject *rc;
+       int success;
        PyGILState_STATE s = PyGILState_Ensure();
        rc = PyObject_CallFunction((PyObject *)callable, "");
+       success = (rc != NULL);
        Py_XDECREF(rc);
        PyGILState_Release(s);
+       return success;
 }
 
 /* Same thing, but releases `thread_done` when it returns.  This variant
@@ -652,10 +659,17 @@ static PyObject *
 test_thread_state(PyObject *self, PyObject *args)
 {
        PyObject *fn;
+       int success = 1;
 
        if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn))
                return NULL;
 
+       if (!PyCallable_Check(fn)) {
+               PyErr_Format(PyExc_TypeError, "'%s' object is not callable",
+                       fn->ob_type->tp_name);
+               return NULL;
+       }
+
        /* Ensure Python is set up for threading */
        PyEval_InitThreads();
        thread_done = PyThread_allocate_lock();
@@ -666,10 +680,10 @@ test_thread_state(PyObject *self, PyObject *args)
        /* Start a new thread with our callback. */
        PyThread_start_new_thread(_make_call_from_thread, fn);
        /* Make the callback with the thread lock held by this thread */
-       _make_call(fn);
+       success &= _make_call(fn);
        /* Do it all again, but this time with the thread-lock released */
        Py_BEGIN_ALLOW_THREADS
-       _make_call(fn);
+       success &= _make_call(fn);
        PyThread_acquire_lock(thread_done, 1);  /* wait for thread to finish */
        Py_END_ALLOW_THREADS
 
@@ -679,7 +693,7 @@ test_thread_state(PyObject *self, PyObject *args)
        */
        Py_BEGIN_ALLOW_THREADS
        PyThread_start_new_thread(_make_call_from_thread, fn);
-       _make_call(fn);
+       success &= _make_call(fn);
        PyThread_acquire_lock(thread_done, 1);  /* wait for thread to finish */
        Py_END_ALLOW_THREADS
 
@@ -687,6 +701,8 @@ test_thread_state(PyObject *self, PyObject *args)
        PyThread_release_lock(thread_done);
 
        PyThread_free_lock(thread_done);
+       if (!success)
+               return NULL;
        Py_RETURN_NONE;
 }
 #endif