#3643 add a few more checks to _testcapi to prevent segfaults

Author: Victor Stinner
Reviewer: Benjamin Peterson
This commit is contained in:
Benjamin Peterson 2008-08-23 20:27:43 +00:00
parent 7161cbfcba
commit 37346b2b9b
2 changed files with 26 additions and 4 deletions

View File

@ -25,6 +25,12 @@ Library
- Fixed two format strings in the _collections module. - 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? What's New in Python 2.6 beta 3?
================================ ================================

View File

@ -600,6 +600,10 @@ raise_exception(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "Oi:raise_exception", if (!PyArg_ParseTuple(args, "Oi:raise_exception",
&exc, &num_args)) &exc, &num_args))
return NULL; return NULL;
if (!PyExceptionClass_Check(exc)) {
PyErr_Format(PyExc_TypeError, "an exception class is required");
return NULL;
}
exc_args = PyTuple_New(num_args); exc_args = PyTuple_New(num_args);
if (exc_args == NULL) if (exc_args == NULL)
@ -628,14 +632,17 @@ raise_exception(PyObject *self, PyObject *args)
*/ */
static PyThread_type_lock thread_done = NULL; static PyThread_type_lock thread_done = NULL;
static void static int
_make_call(void *callable) _make_call(void *callable)
{ {
PyObject *rc; PyObject *rc;
int success;
PyGILState_STATE s = PyGILState_Ensure(); PyGILState_STATE s = PyGILState_Ensure();
rc = PyObject_CallFunction((PyObject *)callable, ""); rc = PyObject_CallFunction((PyObject *)callable, "");
success = (rc != NULL);
Py_XDECREF(rc); Py_XDECREF(rc);
PyGILState_Release(s); PyGILState_Release(s);
return success;
} }
/* Same thing, but releases `thread_done` when it returns. This variant /* Same thing, but releases `thread_done` when it returns. This variant
@ -652,10 +659,17 @@ static PyObject *
test_thread_state(PyObject *self, PyObject *args) test_thread_state(PyObject *self, PyObject *args)
{ {
PyObject *fn; PyObject *fn;
int success = 1;
if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn))
return NULL; 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 */ /* Ensure Python is set up for threading */
PyEval_InitThreads(); PyEval_InitThreads();
thread_done = PyThread_allocate_lock(); thread_done = PyThread_allocate_lock();
@ -666,10 +680,10 @@ test_thread_state(PyObject *self, PyObject *args)
/* Start a new thread with our callback. */ /* Start a new thread with our callback. */
PyThread_start_new_thread(_make_call_from_thread, fn); PyThread_start_new_thread(_make_call_from_thread, fn);
/* Make the callback with the thread lock held by this thread */ /* 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 */ /* Do it all again, but this time with the thread-lock released */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
_make_call(fn); success &= _make_call(fn);
PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
@ -679,7 +693,7 @@ test_thread_state(PyObject *self, PyObject *args)
*/ */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
PyThread_start_new_thread(_make_call_from_thread, fn); 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 */ PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
@ -687,6 +701,8 @@ test_thread_state(PyObject *self, PyObject *args)
PyThread_release_lock(thread_done); PyThread_release_lock(thread_done);
PyThread_free_lock(thread_done); PyThread_free_lock(thread_done);
if (!success)
return NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
#endif #endif