You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
642 lines
16 KiB
642 lines
16 KiB
/* |
|
* C Extension module to test Python interpreter C APIs. |
|
* |
|
* The 'test_*' functions exported by this module are run as part of the |
|
* standard Python regression test, via Lib/test/test_capi.py. |
|
*/ |
|
|
|
#include "Python.h" |
|
|
|
#ifdef WITH_THREAD |
|
#include "pythread.h" |
|
#endif /* WITH_THREAD */ |
|
|
|
static PyObject *TestError; /* set to exception object in init */ |
|
|
|
/* Raise TestError with test_name + ": " + msg, and return NULL. */ |
|
|
|
static PyObject * |
|
raiseTestError(const char* test_name, const char* msg) |
|
{ |
|
char buf[2048]; |
|
|
|
if (strlen(test_name) + strlen(msg) > sizeof(buf) - 50) |
|
PyErr_SetString(TestError, "internal error msg too large"); |
|
else { |
|
PyOS_snprintf(buf, sizeof(buf), "%s: %s", test_name, msg); |
|
PyErr_SetString(TestError, buf); |
|
} |
|
return NULL; |
|
} |
|
|
|
/* Test #defines from pyconfig.h (particularly the SIZEOF_* defines). |
|
|
|
The ones derived from autoconf on the UNIX-like OSes can be relied |
|
upon (in the absence of sloppy cross-compiling), but the Windows |
|
platforms have these hardcoded. Better safe than sorry. |
|
*/ |
|
static PyObject* |
|
sizeof_error(const char* fatname, const char* typename, |
|
int expected, int got) |
|
{ |
|
char buf[1024]; |
|
PyOS_snprintf(buf, sizeof(buf), |
|
"%.200s #define == %d but sizeof(%.200s) == %d", |
|
fatname, expected, typename, got); |
|
PyErr_SetString(TestError, buf); |
|
return (PyObject*)NULL; |
|
} |
|
|
|
static PyObject* |
|
test_config(PyObject *self) |
|
{ |
|
#define CHECK_SIZEOF(FATNAME, TYPE) \ |
|
if (FATNAME != sizeof(TYPE)) \ |
|
return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE)) |
|
|
|
CHECK_SIZEOF(SIZEOF_SHORT, short); |
|
CHECK_SIZEOF(SIZEOF_INT, int); |
|
CHECK_SIZEOF(SIZEOF_LONG, long); |
|
CHECK_SIZEOF(SIZEOF_VOID_P, void*); |
|
CHECK_SIZEOF(SIZEOF_TIME_T, time_t); |
|
#ifdef HAVE_LONG_LONG |
|
CHECK_SIZEOF(SIZEOF_LONG_LONG, PY_LONG_LONG); |
|
#endif |
|
|
|
#undef CHECK_SIZEOF |
|
|
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
static PyObject* |
|
test_list_api(PyObject *self) |
|
{ |
|
PyObject* list; |
|
int i; |
|
|
|
/* SF bug 132008: PyList_Reverse segfaults */ |
|
#define NLIST 30 |
|
list = PyList_New(NLIST); |
|
if (list == (PyObject*)NULL) |
|
return (PyObject*)NULL; |
|
/* list = range(NLIST) */ |
|
for (i = 0; i < NLIST; ++i) { |
|
PyObject* anint = PyInt_FromLong(i); |
|
if (anint == (PyObject*)NULL) { |
|
Py_DECREF(list); |
|
return (PyObject*)NULL; |
|
} |
|
PyList_SET_ITEM(list, i, anint); |
|
} |
|
/* list.reverse(), via PyList_Reverse() */ |
|
i = PyList_Reverse(list); /* should not blow up! */ |
|
if (i != 0) { |
|
Py_DECREF(list); |
|
return (PyObject*)NULL; |
|
} |
|
/* Check that list == range(29, -1, -1) now */ |
|
for (i = 0; i < NLIST; ++i) { |
|
PyObject* anint = PyList_GET_ITEM(list, i); |
|
if (PyInt_AS_LONG(anint) != NLIST-1-i) { |
|
PyErr_SetString(TestError, |
|
"test_list_api: reverse screwed up"); |
|
Py_DECREF(list); |
|
return (PyObject*)NULL; |
|
} |
|
} |
|
Py_DECREF(list); |
|
#undef NLIST |
|
|
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
static int |
|
test_dict_inner(int count) |
|
{ |
|
int pos = 0, iterations = 0, i; |
|
PyObject *dict = PyDict_New(); |
|
PyObject *v, *k; |
|
|
|
if (dict == NULL) |
|
return -1; |
|
|
|
for (i = 0; i < count; i++) { |
|
v = PyInt_FromLong(i); |
|
PyDict_SetItem(dict, v, v); |
|
Py_DECREF(v); |
|
} |
|
|
|
while (PyDict_Next(dict, &pos, &k, &v)) { |
|
PyObject *o; |
|
iterations++; |
|
|
|
i = PyInt_AS_LONG(v) + 1; |
|
o = PyInt_FromLong(i); |
|
if (o == NULL) |
|
return -1; |
|
if (PyDict_SetItem(dict, k, o) < 0) { |
|
Py_DECREF(o); |
|
return -1; |
|
} |
|
Py_DECREF(o); |
|
} |
|
|
|
Py_DECREF(dict); |
|
|
|
if (iterations != count) { |
|
PyErr_SetString( |
|
TestError, |
|
"test_dict_iteration: dict iteration went wrong "); |
|
return -1; |
|
} else { |
|
return 0; |
|
} |
|
} |
|
|
|
static PyObject* |
|
test_dict_iteration(PyObject* self) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < 200; i++) { |
|
if (test_dict_inner(i) < 0) { |
|
return NULL; |
|
} |
|
} |
|
|
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
|
|
/* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG) |
|
PyLong_{As, From}{Unsigned,}LongLong(). |
|
|
|
Note that the meat of the test is contained in testcapi_long.h. |
|
This is revolting, but delicate code duplication is worse: "almost |
|
exactly the same" code is needed to test PY_LONG_LONG, but the ubiquitous |
|
dependence on type names makes it impossible to use a parameterized |
|
function. A giant macro would be even worse than this. A C++ template |
|
would be perfect. |
|
|
|
The "report an error" functions are deliberately not part of the #include |
|
file: if the test fails, you can set a breakpoint in the appropriate |
|
error function directly, and crawl back from there in the debugger. |
|
*/ |
|
|
|
#define UNBIND(X) Py_DECREF(X); (X) = NULL |
|
|
|
static PyObject * |
|
raise_test_long_error(const char* msg) |
|
{ |
|
return raiseTestError("test_long_api", msg); |
|
} |
|
|
|
#define TESTNAME test_long_api_inner |
|
#define TYPENAME long |
|
#define F_S_TO_PY PyLong_FromLong |
|
#define F_PY_TO_S PyLong_AsLong |
|
#define F_U_TO_PY PyLong_FromUnsignedLong |
|
#define F_PY_TO_U PyLong_AsUnsignedLong |
|
|
|
#include "testcapi_long.h" |
|
|
|
static PyObject * |
|
test_long_api(PyObject* self) |
|
{ |
|
return TESTNAME(raise_test_long_error); |
|
} |
|
|
|
#undef TESTNAME |
|
#undef TYPENAME |
|
#undef F_S_TO_PY |
|
#undef F_PY_TO_S |
|
#undef F_U_TO_PY |
|
#undef F_PY_TO_U |
|
|
|
#ifdef HAVE_LONG_LONG |
|
|
|
static PyObject * |
|
raise_test_longlong_error(const char* msg) |
|
{ |
|
return raiseTestError("test_longlong_api", msg); |
|
} |
|
|
|
#define TESTNAME test_longlong_api_inner |
|
#define TYPENAME PY_LONG_LONG |
|
#define F_S_TO_PY PyLong_FromLongLong |
|
#define F_PY_TO_S PyLong_AsLongLong |
|
#define F_U_TO_PY PyLong_FromUnsignedLongLong |
|
#define F_PY_TO_U PyLong_AsUnsignedLongLong |
|
|
|
#include "testcapi_long.h" |
|
|
|
static PyObject * |
|
test_longlong_api(PyObject* self) |
|
{ |
|
return TESTNAME(raise_test_longlong_error); |
|
} |
|
|
|
#undef TESTNAME |
|
#undef TYPENAME |
|
#undef F_S_TO_PY |
|
#undef F_PY_TO_S |
|
#undef F_U_TO_PY |
|
#undef F_PY_TO_U |
|
|
|
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG |
|
for both long and int arguments. The test may leak a little memory if |
|
it fails. |
|
*/ |
|
static PyObject * |
|
test_L_code(PyObject *self) |
|
{ |
|
PyObject *tuple, *num; |
|
PY_LONG_LONG value; |
|
|
|
tuple = PyTuple_New(1); |
|
if (tuple == NULL) |
|
return NULL; |
|
|
|
num = PyLong_FromLong(42); |
|
if (num == NULL) |
|
return NULL; |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) |
|
return NULL; |
|
if (value != 42) |
|
return raiseTestError("test_L_code", |
|
"L code returned wrong value for long 42"); |
|
|
|
Py_DECREF(num); |
|
num = PyInt_FromLong(42); |
|
if (num == NULL) |
|
return NULL; |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) |
|
return NULL; |
|
if (value != 42) |
|
return raiseTestError("test_L_code", |
|
"L code returned wrong value for int 42"); |
|
|
|
Py_DECREF(tuple); |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
#endif /* ifdef HAVE_LONG_LONG */ |
|
|
|
/* Functions to call PyArg_ParseTuple with integer format codes, |
|
and return the result. |
|
*/ |
|
static PyObject * |
|
getargs_b(PyObject *self, PyObject *args) |
|
{ |
|
unsigned char value; |
|
if (!PyArg_ParseTuple(args, "b", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLong((unsigned long)value); |
|
} |
|
|
|
static PyObject * |
|
getargs_B(PyObject *self, PyObject *args) |
|
{ |
|
unsigned char value; |
|
if (!PyArg_ParseTuple(args, "B", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLong((unsigned long)value); |
|
} |
|
|
|
static PyObject * |
|
getargs_H(PyObject *self, PyObject *args) |
|
{ |
|
unsigned short value; |
|
if (!PyArg_ParseTuple(args, "H", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLong((unsigned long)value); |
|
} |
|
|
|
static PyObject * |
|
getargs_I(PyObject *self, PyObject *args) |
|
{ |
|
unsigned int value; |
|
if (!PyArg_ParseTuple(args, "I", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLong((unsigned long)value); |
|
} |
|
|
|
static PyObject * |
|
getargs_k(PyObject *self, PyObject *args) |
|
{ |
|
unsigned long value; |
|
if (!PyArg_ParseTuple(args, "k", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLong(value); |
|
} |
|
|
|
static PyObject * |
|
getargs_i(PyObject *self, PyObject *args) |
|
{ |
|
int value; |
|
if (!PyArg_ParseTuple(args, "i", &value)) |
|
return NULL; |
|
return PyLong_FromLong((long)value); |
|
} |
|
|
|
static PyObject * |
|
getargs_l(PyObject *self, PyObject *args) |
|
{ |
|
long value; |
|
if (!PyArg_ParseTuple(args, "l", &value)) |
|
return NULL; |
|
return PyLong_FromLong(value); |
|
} |
|
|
|
#ifdef HAVE_LONG_LONG |
|
static PyObject * |
|
getargs_L(PyObject *self, PyObject *args) |
|
{ |
|
PY_LONG_LONG value; |
|
if (!PyArg_ParseTuple(args, "L", &value)) |
|
return NULL; |
|
return PyLong_FromLongLong(value); |
|
} |
|
|
|
static PyObject * |
|
getargs_K(PyObject *self, PyObject *args) |
|
{ |
|
unsigned PY_LONG_LONG value; |
|
if (!PyArg_ParseTuple(args, "K", &value)) |
|
return NULL; |
|
return PyLong_FromUnsignedLongLong(value); |
|
} |
|
#endif |
|
|
|
/* This function not only tests the 'k' getargs code, but also the |
|
PyInt_AsUnsignedLongMask() and PyInt_AsUnsignedLongMask() functions. */ |
|
static PyObject * |
|
test_k_code(PyObject *self) |
|
{ |
|
PyObject *tuple, *num; |
|
unsigned long value; |
|
|
|
tuple = PyTuple_New(1); |
|
if (tuple == NULL) |
|
return NULL; |
|
|
|
/* a number larger than ULONG_MAX even on 64-bit platforms */ |
|
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); |
|
if (num == NULL) |
|
return NULL; |
|
|
|
value = PyInt_AsUnsignedLongMask(num); |
|
if (value != ULONG_MAX) |
|
return raiseTestError("test_k_code", |
|
"PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) |
|
return NULL; |
|
if (value != ULONG_MAX) |
|
return raiseTestError("test_k_code", |
|
"k code returned wrong value for long 0xFFF...FFF"); |
|
|
|
Py_DECREF(num); |
|
num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); |
|
if (num == NULL) |
|
return NULL; |
|
|
|
value = PyInt_AsUnsignedLongMask(num); |
|
if (value != (unsigned long)-0x42) |
|
return raiseTestError("test_k_code", |
|
"PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); |
|
|
|
PyTuple_SET_ITEM(tuple, 0, num); |
|
|
|
value = -1; |
|
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) |
|
return NULL; |
|
if (value != (unsigned long)-0x42) |
|
return raiseTestError("test_k_code", |
|
"k code returned wrong value for long -0xFFF..000042"); |
|
|
|
Py_DECREF(tuple); |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
#ifdef Py_USING_UNICODE |
|
|
|
/* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case |
|
of an error. |
|
*/ |
|
static PyObject * |
|
test_u_code(PyObject *self) |
|
{ |
|
PyObject *tuple, *obj; |
|
Py_UNICODE *value; |
|
int len; |
|
|
|
tuple = PyTuple_New(1); |
|
if (tuple == NULL) |
|
return NULL; |
|
|
|
obj = PyUnicode_Decode("test", strlen("test"), |
|
"ascii", NULL); |
|
if (obj == NULL) |
|
return NULL; |
|
|
|
PyTuple_SET_ITEM(tuple, 0, obj); |
|
|
|
value = 0; |
|
if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0) |
|
return NULL; |
|
if (value != PyUnicode_AS_UNICODE(obj)) |
|
return raiseTestError("test_u_code", |
|
"u code returned wrong value for u'test'"); |
|
value = 0; |
|
if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0) |
|
return NULL; |
|
if (value != PyUnicode_AS_UNICODE(obj) || |
|
len != PyUnicode_GET_SIZE(obj)) |
|
return raiseTestError("test_u_code", |
|
"u# code returned wrong values for u'test'"); |
|
|
|
Py_DECREF(tuple); |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
#endif |
|
|
|
/* Simple test of _PyLong_NumBits and _PyLong_Sign. */ |
|
static PyObject * |
|
test_long_numbits(PyObject *self) |
|
{ |
|
struct triple { |
|
long input; |
|
size_t nbits; |
|
int sign; |
|
} testcases[] = {{0, 0, 0}, |
|
{1L, 1, 1}, |
|
{-1L, 1, -1}, |
|
{2L, 2, 1}, |
|
{-2L, 2, -1}, |
|
{3L, 2, 1}, |
|
{-3L, 2, -1}, |
|
{4L, 3, 1}, |
|
{-4L, 3, -1}, |
|
{0x7fffL, 15, 1}, /* one Python long digit */ |
|
{-0x7fffL, 15, -1}, |
|
{0xffffL, 16, 1}, |
|
{-0xffffL, 16, -1}, |
|
{0xfffffffL, 28, 1}, |
|
{-0xfffffffL, 28, -1}}; |
|
int i; |
|
|
|
for (i = 0; i < sizeof(testcases) / sizeof(struct triple); ++i) { |
|
PyObject *plong = PyLong_FromLong(testcases[i].input); |
|
size_t nbits = _PyLong_NumBits(plong); |
|
int sign = _PyLong_Sign(plong); |
|
|
|
Py_DECREF(plong); |
|
if (nbits != testcases[i].nbits) |
|
return raiseTestError("test_long_numbits", |
|
"wrong result for _PyLong_NumBits"); |
|
if (sign != testcases[i].sign) |
|
return raiseTestError("test_long_numbits", |
|
"wrong result for _PyLong_Sign"); |
|
} |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
static PyObject * |
|
raise_exception(PyObject *self, PyObject *args) |
|
{ |
|
PyObject *exc; |
|
PyObject *exc_args, *v; |
|
int num_args, i; |
|
|
|
if (!PyArg_ParseTuple(args, "Oi:raise_exception", |
|
&exc, &num_args)) |
|
return NULL; |
|
|
|
exc_args = PyTuple_New(num_args); |
|
if (exc_args == NULL) |
|
return NULL; |
|
for (i = 0; i < num_args; ++i) { |
|
v = PyInt_FromLong(i); |
|
if (v == NULL) { |
|
Py_DECREF(exc_args); |
|
return NULL; |
|
} |
|
PyTuple_SET_ITEM(exc_args, i, v); |
|
} |
|
PyErr_SetObject(exc, exc_args); |
|
return NULL; |
|
} |
|
|
|
#ifdef WITH_THREAD |
|
|
|
void _make_call(void *callable) |
|
{ |
|
PyObject *rc; |
|
PyGILState_STATE s = PyGILState_Ensure(); |
|
rc = PyObject_CallFunction(callable, ""); |
|
Py_XDECREF(rc); |
|
PyGILState_Release(s); |
|
} |
|
|
|
static PyObject * |
|
test_thread_state(PyObject *self, PyObject *args) |
|
{ |
|
PyObject *fn; |
|
if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) |
|
return NULL; |
|
/* Ensure Python is setup for threading */ |
|
PyEval_InitThreads(); |
|
/* Start a new thread for our callback. */ |
|
PyThread_start_new_thread( _make_call, fn); |
|
/* Make the callback with the thread lock held by this thread */ |
|
_make_call(fn); |
|
/* Do it all again, but this time with the thread-lock released */ |
|
Py_BEGIN_ALLOW_THREADS |
|
_make_call(fn); |
|
Py_END_ALLOW_THREADS |
|
/* And once more with and without a thread |
|
XXX - should use a lock and work out exactly what we are trying |
|
to test <wink> |
|
*/ |
|
Py_BEGIN_ALLOW_THREADS |
|
PyThread_start_new_thread( _make_call, fn); |
|
_make_call(fn); |
|
Py_END_ALLOW_THREADS |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
#endif |
|
|
|
static PyMethodDef TestMethods[] = { |
|
{"raise_exception", raise_exception, METH_VARARGS}, |
|
{"test_config", (PyCFunction)test_config, METH_NOARGS}, |
|
{"test_list_api", (PyCFunction)test_list_api, METH_NOARGS}, |
|
{"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, |
|
{"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, |
|
{"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS}, |
|
{"test_k_code", (PyCFunction)test_k_code, METH_NOARGS}, |
|
|
|
{"getargs_b", (PyCFunction)getargs_b, METH_VARARGS}, |
|
{"getargs_B", (PyCFunction)getargs_B, METH_VARARGS}, |
|
{"getargs_H", (PyCFunction)getargs_H, METH_VARARGS}, |
|
{"getargs_I", (PyCFunction)getargs_I, METH_VARARGS}, |
|
{"getargs_k", (PyCFunction)getargs_k, METH_VARARGS}, |
|
{"getargs_i", (PyCFunction)getargs_i, METH_VARARGS}, |
|
{"getargs_l", (PyCFunction)getargs_l, METH_VARARGS}, |
|
#ifdef HAVE_LONG_LONG |
|
{"getargs_L", (PyCFunction)getargs_L, METH_VARARGS}, |
|
{"getargs_K", (PyCFunction)getargs_K, METH_VARARGS}, |
|
{"test_longlong_api", (PyCFunction)test_longlong_api, METH_NOARGS}, |
|
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS}, |
|
#endif |
|
#ifdef Py_USING_UNICODE |
|
{"test_u_code", (PyCFunction)test_u_code, METH_NOARGS}, |
|
#endif |
|
#ifdef WITH_THREAD |
|
{"_test_thread_state", (PyCFunction)test_thread_state, METH_VARARGS}, |
|
#endif |
|
{NULL, NULL} /* sentinel */ |
|
}; |
|
|
|
#define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);} |
|
|
|
PyMODINIT_FUNC |
|
init_testcapi(void) |
|
{ |
|
PyObject *m; |
|
|
|
m = Py_InitModule("_testcapi", TestMethods); |
|
|
|
PyModule_AddObject(m, "UCHAR_MAX", PyInt_FromLong(UCHAR_MAX)); |
|
PyModule_AddObject(m, "USHRT_MAX", PyInt_FromLong(USHRT_MAX)); |
|
PyModule_AddObject(m, "UINT_MAX", PyLong_FromUnsignedLong(UINT_MAX)); |
|
PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX)); |
|
PyModule_AddObject(m, "INT_MIN", PyInt_FromLong(INT_MIN)); |
|
PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN)); |
|
PyModule_AddObject(m, "INT_MAX", PyInt_FromLong(INT_MAX)); |
|
PyModule_AddObject(m, "LONG_MAX", PyInt_FromLong(LONG_MAX)); |
|
|
|
TestError = PyErr_NewException("_testcapi.error", NULL, NULL); |
|
Py_INCREF(TestError); |
|
PyModule_AddObject(m, "error", TestError); |
|
}
|
|
|