mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-93649: Move _testcapi tests to specific files (#129544)
Move many functions from _testcapimodule.c into more specific files in Modules/_testcapi/. In moved code: * Replace get_testerror() with PyExc_AssertionError. * Replace raiseTestError() with PyErr_Format(PyExc_AssertionError, ...).
This commit is contained in:
parent
7d0521d5fc
commit
71ae93374d
9 changed files with 651 additions and 646 deletions
|
@ -403,42 +403,6 @@ class CAPITest(unittest.TestCase):
|
|||
def test_buildvalue_N(self):
|
||||
_testcapi.test_buildvalue_N()
|
||||
|
||||
def check_negative_refcount(self, code):
|
||||
# bpo-35059: Check that Py_DECREF() reports the correct filename
|
||||
# when calling _Py_NegativeRefcount() to abort Python.
|
||||
code = textwrap.dedent(code)
|
||||
rc, out, err = assert_python_failure('-c', code)
|
||||
self.assertRegex(err,
|
||||
br'_testcapimodule\.c:[0-9]+: '
|
||||
br'_Py_NegativeRefcount: Assertion failed: '
|
||||
br'object has negative ref count')
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
|
||||
'need _testcapi.negative_refcount()')
|
||||
def test_negative_refcount(self):
|
||||
code = """
|
||||
import _testcapi
|
||||
from test import support
|
||||
|
||||
with support.SuppressCrashReport():
|
||||
_testcapi.negative_refcount()
|
||||
"""
|
||||
self.check_negative_refcount(code)
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'),
|
||||
'need _testcapi.decref_freed_object()')
|
||||
@support.skip_if_sanitizer("use after free on purpose",
|
||||
address=True, memory=True, ub=True)
|
||||
def test_decref_freed_object(self):
|
||||
code = """
|
||||
import _testcapi
|
||||
from test import support
|
||||
|
||||
with support.SuppressCrashReport():
|
||||
_testcapi.decref_freed_object()
|
||||
"""
|
||||
self.check_negative_refcount(code)
|
||||
|
||||
def test_trashcan_subclass(self):
|
||||
# bpo-35983: Check that the trashcan mechanism for "list" is NOT
|
||||
# activated when its tp_dealloc is being called by a subclass
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import enum
|
||||
import textwrap
|
||||
import unittest
|
||||
from test import support
|
||||
from test.support import import_helper
|
||||
from test.support import os_helper
|
||||
from test.support import threading_helper
|
||||
from test.support.script_helper import assert_python_failure
|
||||
|
||||
|
||||
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
|
||||
_testcapi = import_helper.import_module('_testcapi')
|
||||
|
@ -170,5 +173,42 @@ class EnableDeferredRefcountingTest(unittest.TestCase):
|
|||
self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list))
|
||||
|
||||
|
||||
class CAPITest(unittest.TestCase):
|
||||
def check_negative_refcount(self, code):
|
||||
# bpo-35059: Check that Py_DECREF() reports the correct filename
|
||||
# when calling _Py_NegativeRefcount() to abort Python.
|
||||
code = textwrap.dedent(code)
|
||||
rc, out, err = assert_python_failure('-c', code)
|
||||
self.assertRegex(err,
|
||||
br'object\.c:[0-9]+: '
|
||||
br'_Py_NegativeRefcount: Assertion failed: '
|
||||
br'object has negative ref count')
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
|
||||
'need _testcapi.negative_refcount()')
|
||||
def test_negative_refcount(self):
|
||||
code = """
|
||||
import _testcapi
|
||||
from test import support
|
||||
|
||||
with support.SuppressCrashReport():
|
||||
_testcapi.negative_refcount()
|
||||
"""
|
||||
self.check_negative_refcount(code)
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'),
|
||||
'need _testcapi.decref_freed_object()')
|
||||
@support.skip_if_sanitizer("use after free on purpose",
|
||||
address=True, memory=True, ub=True)
|
||||
def test_decref_freed_object(self):
|
||||
code = """
|
||||
import _testcapi
|
||||
from test import support
|
||||
|
||||
with support.SuppressCrashReport():
|
||||
_testcapi.decref_freed_object()
|
||||
"""
|
||||
self.check_negative_refcount(code)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -181,6 +181,83 @@ dict_popstring_null(PyObject *self, PyObject *args)
|
|||
RETURN_INT(PyDict_PopString(dict, key, NULL));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
test_dict_inner(PyObject *self, int count)
|
||||
{
|
||||
Py_ssize_t pos = 0, iterations = 0;
|
||||
int i;
|
||||
PyObject *dict = PyDict_New();
|
||||
PyObject *v, *k;
|
||||
|
||||
if (dict == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
v = PyLong_FromLong(i);
|
||||
if (v == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItem(dict, v, v) < 0) {
|
||||
Py_DECREF(v);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
|
||||
k = v = UNINITIALIZED_PTR;
|
||||
while (PyDict_Next(dict, &pos, &k, &v)) {
|
||||
PyObject *o;
|
||||
iterations++;
|
||||
|
||||
assert(k != UNINITIALIZED_PTR);
|
||||
assert(v != UNINITIALIZED_PTR);
|
||||
i = PyLong_AS_LONG(v) + 1;
|
||||
o = PyLong_FromLong(i);
|
||||
if (o == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItem(dict, k, o) < 0) {
|
||||
Py_DECREF(o);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(o);
|
||||
k = v = UNINITIALIZED_PTR;
|
||||
}
|
||||
assert(k == UNINITIALIZED_PTR);
|
||||
assert(v == UNINITIALIZED_PTR);
|
||||
|
||||
Py_DECREF(dict);
|
||||
|
||||
if (iterations != count) {
|
||||
PyErr_SetString(
|
||||
PyExc_AssertionError,
|
||||
"test_dict_iteration: dict iteration went wrong ");
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
error:
|
||||
Py_DECREF(dict);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 200; i++) {
|
||||
if (test_dict_inner(self, i) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"dict_containsstring", dict_containsstring, METH_VARARGS},
|
||||
{"dict_getitemref", dict_getitemref, METH_VARARGS},
|
||||
|
@ -191,6 +268,7 @@ static PyMethodDef test_methods[] = {
|
|||
{"dict_pop_null", dict_pop_null, METH_VARARGS},
|
||||
{"dict_popstring", dict_popstring, METH_VARARGS},
|
||||
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
|
||||
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -99,9 +99,68 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data,
|
|||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
|
||||
/* Test PyOS_string_to_double. */
|
||||
static PyObject *
|
||||
test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
double result;
|
||||
const char *msg;
|
||||
|
||||
#define CHECK_STRING(STR, expected) \
|
||||
do { \
|
||||
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||
if (result == -1.0 && PyErr_Occurred()) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (result != (double)expected) { \
|
||||
msg = "conversion of " STR " to float failed"; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_INVALID(STR) \
|
||||
do { \
|
||||
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||
if (result == -1.0 && PyErr_Occurred()) { \
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) { \
|
||||
PyErr_Clear(); \
|
||||
} \
|
||||
else { \
|
||||
return NULL; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
msg = "conversion of " STR " didn't raise ValueError"; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
CHECK_STRING("0.1", 0.1);
|
||||
CHECK_STRING("1.234", 1.234);
|
||||
CHECK_STRING("-1.35", -1.35);
|
||||
CHECK_STRING(".1e01", 1.0);
|
||||
CHECK_STRING("2.e-2", 0.02);
|
||||
|
||||
CHECK_INVALID(" 0.1");
|
||||
CHECK_INVALID("\t\n-3");
|
||||
CHECK_INVALID(".123 ");
|
||||
CHECK_INVALID("3\n");
|
||||
CHECK_INVALID("123abc");
|
||||
|
||||
Py_RETURN_NONE;
|
||||
fail:
|
||||
PyErr_Format(PyExc_AssertionError, "test_string_to_double: %s", msg);
|
||||
return NULL;
|
||||
#undef CHECK_STRING
|
||||
#undef CHECK_INVALID
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
_TESTCAPI_FLOAT_PACK_METHODDEF
|
||||
_TESTCAPI_FLOAT_UNPACK_METHODDEF
|
||||
{"test_string_to_double", test_string_to_double, METH_NOARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -60,22 +60,61 @@ list_extend(PyObject* Py_UNUSED(module), PyObject *args)
|
|||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
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 = PyLong_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 (PyLong_AS_LONG(anint) != NLIST-1-i) {
|
||||
PyErr_SetString(PyExc_AssertionError,
|
||||
"test_list_api: reverse screwed up");
|
||||
Py_DECREF(list);
|
||||
return (PyObject*)NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(list);
|
||||
#undef NLIST
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"list_get_size", list_get_size, METH_O},
|
||||
{"list_get_item", list_get_item, METH_VARARGS},
|
||||
{"list_set_item", list_set_item, METH_VARARGS},
|
||||
{"list_clear", list_clear, METH_O},
|
||||
{"list_extend", list_extend, METH_VARARGS},
|
||||
|
||||
{"test_list_api", test_list_api, METH_NOARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestCapi_Init_List(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PyModule_AddFunctions(m, test_methods);
|
||||
}
|
||||
|
|
|
@ -584,6 +584,106 @@ tracemalloc_untrack(PyObject *self, PyObject *args)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tracemalloc_track_race_thread(void *data)
|
||||
{
|
||||
PyTraceMalloc_Track(123, 10, 1);
|
||||
PyTraceMalloc_Untrack(123, 10);
|
||||
|
||||
PyThread_type_lock lock = (PyThread_type_lock)data;
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
|
||||
// gh-128679: Test fix for tracemalloc.stop() race condition
|
||||
static PyObject *
|
||||
tracemalloc_track_race(PyObject *self, PyObject *args)
|
||||
{
|
||||
#define NTHREAD 50
|
||||
PyObject *tracemalloc = NULL;
|
||||
PyObject *stop = NULL;
|
||||
PyThread_type_lock locks[NTHREAD];
|
||||
memset(locks, 0, sizeof(locks));
|
||||
|
||||
// Call tracemalloc.start()
|
||||
tracemalloc = PyImport_ImportModule("tracemalloc");
|
||||
if (tracemalloc == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *start = PyObject_GetAttrString(tracemalloc, "start");
|
||||
if (start == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *res = PyObject_CallNoArgs(start);
|
||||
Py_DECREF(start);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
stop = PyObject_GetAttrString(tracemalloc, "stop");
|
||||
Py_CLEAR(tracemalloc);
|
||||
if (stop == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Start threads
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = PyThread_allocate_lock();
|
||||
if (!lock) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
locks[i] = lock;
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
|
||||
unsigned long thread;
|
||||
thread = PyThread_start_new_thread(tracemalloc_track_race_thread,
|
||||
(void*)lock);
|
||||
if (thread == (unsigned long)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "can't start new thread");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// Call tracemalloc.stop() while threads are running
|
||||
res = PyObject_CallNoArgs(stop);
|
||||
Py_CLEAR(stop);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
// Wait until threads complete with the GIL released
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
// Free threads locks
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
Py_CLEAR(tracemalloc);
|
||||
Py_CLEAR(stop);
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
if (lock) {
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#undef NTHREAD
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"pymem_api_misuse", pymem_api_misuse, METH_NOARGS},
|
||||
{"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS},
|
||||
|
@ -602,6 +702,7 @@ static PyMethodDef test_methods[] = {
|
|||
// Tracemalloc tests
|
||||
{"tracemalloc_track", tracemalloc_track, METH_VARARGS},
|
||||
{"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS},
|
||||
{"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -185,6 +185,292 @@ test_py_try_inc_ref(PyObject *self, PyObject *unused)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
_test_incref(PyObject *ob)
|
||||
{
|
||||
return Py_NewRef(ob);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_XINCREF(_test_incref(obj));
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_INCREF(_test_incref(obj));
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
Py_XDECREF(PyLong_FromLong(0));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
Py_DECREF(PyLong_FromLong(0));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_IncRef(obj);
|
||||
Py_DecRef(obj);
|
||||
Py_DecRef(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef Py_REF_DEBUG
|
||||
static PyObject *
|
||||
negative_refcount(PyObject *self, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyObject *obj = PyUnicode_FromString("negative_refcount");
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(Py_REFCNT(obj) == 1);
|
||||
|
||||
Py_SET_REFCNT(obj, 0);
|
||||
/* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */
|
||||
Py_DECREF(obj);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyObject *obj = PyUnicode_FromString("decref_freed_object");
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(Py_REFCNT(obj) == 1);
|
||||
|
||||
// Deallocate the memory
|
||||
Py_DECREF(obj);
|
||||
// obj is a now a dangling pointer
|
||||
|
||||
// gh-109496: If Python is built in debug mode, Py_DECREF() must call
|
||||
// _Py_NegativeRefcount() and abort Python.
|
||||
Py_DECREF(obj);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Test Py_CLEAR() macro
|
||||
static PyObject*
|
||||
test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
// simple case with a variable
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
assert(obj == NULL);
|
||||
|
||||
// gh-98724: complex case, Py_CLEAR() argument has a side effect
|
||||
PyObject* array[1];
|
||||
array[0] = PyList_New(0);
|
||||
if (array[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p = array;
|
||||
Py_CLEAR(*p++);
|
||||
assert(array[0] == NULL);
|
||||
assert(p == array + 1);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear()
|
||||
static PyObject*
|
||||
test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
// Py_SETREF() simple case with a variable
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_SETREF(obj, NULL);
|
||||
assert(obj == NULL);
|
||||
|
||||
// Py_XSETREF() simple case with a variable
|
||||
PyObject *obj2 = PyList_New(0);
|
||||
if (obj2 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_XSETREF(obj2, NULL);
|
||||
assert(obj2 == NULL);
|
||||
// test Py_XSETREF() when the argument is NULL
|
||||
Py_XSETREF(obj2, NULL);
|
||||
assert(obj2 == NULL);
|
||||
|
||||
// gh-98724: complex case, Py_SETREF() argument has a side effect
|
||||
PyObject* array[1];
|
||||
array[0] = PyList_New(0);
|
||||
if (array[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p = array;
|
||||
Py_SETREF(*p++, NULL);
|
||||
assert(array[0] == NULL);
|
||||
assert(p == array + 1);
|
||||
|
||||
// gh-98724: complex case, Py_XSETREF() argument has a side effect
|
||||
PyObject* array2[1];
|
||||
array2[0] = PyList_New(0);
|
||||
if (array2[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p2 = array2;
|
||||
Py_XSETREF(*p2++, NULL);
|
||||
assert(array2[0] == NULL);
|
||||
assert(p2 == array2 + 1);
|
||||
|
||||
// test Py_XSETREF() when the argument is NULL
|
||||
p2 = array2;
|
||||
Py_XSETREF(*p2++, NULL);
|
||||
assert(array2[0] == NULL);
|
||||
assert(p2 == array2 + 1);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_REFCOUNT() \
|
||||
do { \
|
||||
PyObject *obj = PyList_New(0); \
|
||||
if (obj == NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
assert(Py_REFCNT(obj) == 1); \
|
||||
\
|
||||
/* test Py_NewRef() */ \
|
||||
PyObject *ref = Py_NewRef(obj); \
|
||||
assert(ref == obj); \
|
||||
assert(Py_REFCNT(obj) == 2); \
|
||||
Py_DECREF(ref); \
|
||||
\
|
||||
/* test Py_XNewRef() */ \
|
||||
PyObject *xref = Py_XNewRef(obj); \
|
||||
assert(xref == obj); \
|
||||
assert(Py_REFCNT(obj) == 2); \
|
||||
Py_DECREF(xref); \
|
||||
\
|
||||
assert(Py_XNewRef(NULL) == NULL); \
|
||||
\
|
||||
Py_DECREF(obj); \
|
||||
Py_RETURN_NONE; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Test Py_NewRef() and Py_XNewRef() macros
|
||||
static PyObject*
|
||||
test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_REFCOUNT();
|
||||
}
|
||||
|
||||
#undef Py_NewRef
|
||||
#undef Py_XNewRef
|
||||
|
||||
// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros.
|
||||
static PyObject*
|
||||
test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_REFCOUNT();
|
||||
}
|
||||
|
||||
|
||||
// Test Py_Is() function
|
||||
#define TEST_PY_IS() \
|
||||
do { \
|
||||
PyObject *o_none = Py_None; \
|
||||
PyObject *o_true = Py_True; \
|
||||
PyObject *o_false = Py_False; \
|
||||
PyObject *obj = PyList_New(0); \
|
||||
if (obj == NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
/* test Py_Is() */ \
|
||||
assert(Py_Is(obj, obj)); \
|
||||
assert(!Py_Is(obj, o_none)); \
|
||||
\
|
||||
/* test Py_None */ \
|
||||
assert(Py_Is(o_none, o_none)); \
|
||||
assert(!Py_Is(obj, o_none)); \
|
||||
\
|
||||
/* test Py_True */ \
|
||||
assert(Py_Is(o_true, o_true)); \
|
||||
assert(!Py_Is(o_false, o_true)); \
|
||||
assert(!Py_Is(obj, o_true)); \
|
||||
\
|
||||
/* test Py_False */ \
|
||||
assert(Py_Is(o_false, o_false)); \
|
||||
assert(!Py_Is(o_true, o_false)); \
|
||||
assert(!Py_Is(obj, o_false)); \
|
||||
\
|
||||
Py_DECREF(obj); \
|
||||
Py_RETURN_NONE; \
|
||||
} while (0)
|
||||
|
||||
// Test Py_Is() macro
|
||||
static PyObject*
|
||||
test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_PY_IS();
|
||||
}
|
||||
|
||||
#undef Py_Is
|
||||
|
||||
// Test Py_Is() function, after undefining its macro.
|
||||
static PyObject*
|
||||
test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_PY_IS();
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
clear_managed_dict(PyObject *self, PyObject *obj)
|
||||
{
|
||||
PyObject_ClearManagedDict(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
|
||||
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
|
||||
|
@ -193,15 +479,27 @@ static PyMethodDef test_methods[] = {
|
|||
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
|
||||
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
|
||||
{"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS},
|
||||
{"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS},
|
||||
{"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS},
|
||||
{"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS},
|
||||
{"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS},
|
||||
{"test_incref_decref_API", test_incref_decref_API, METH_NOARGS},
|
||||
#ifdef Py_REF_DEBUG
|
||||
{"negative_refcount", negative_refcount, METH_NOARGS},
|
||||
{"decref_freed_object", decref_freed_object, METH_NOARGS},
|
||||
#endif
|
||||
{"test_py_clear", test_py_clear, METH_NOARGS},
|
||||
{"test_py_setref", test_py_setref, METH_NOARGS},
|
||||
{"test_refcount_macros", test_refcount_macros, METH_NOARGS},
|
||||
{"test_refcount_funcs", test_refcount_funcs, METH_NOARGS},
|
||||
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
|
||||
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
|
||||
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestCapi_Init_Object(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PyModule_AddFunctions(m, test_methods);
|
||||
}
|
||||
|
|
|
@ -8,18 +8,37 @@ set_get_size(PyObject *self, PyObject *obj)
|
|||
RETURN_SIZE(PySet_GET_SIZE(obj));
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that following tests don't modify the object,
|
||||
// to ensure that Py_DECREF() will not crash.
|
||||
assert(Py_TYPE(obj) == &PyList_Type);
|
||||
assert(Py_SIZE(obj) == 0);
|
||||
|
||||
// bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions.
|
||||
Py_SET_TYPE(obj, &PyList_Type);
|
||||
Py_SET_SIZE(obj, 0);
|
||||
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"set_get_size", set_get_size, METH_O},
|
||||
|
||||
{"test_set_type_size", test_set_type_size, METH_NOARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestCapi_Init_Set(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PyModule_AddFunctions(m, test_methods);
|
||||
}
|
||||
|
|
|
@ -163,124 +163,6 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
#endif
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
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 = PyLong_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 (PyLong_AS_LONG(anint) != NLIST-1-i) {
|
||||
PyErr_SetString(get_testerror(self),
|
||||
"test_list_api: reverse screwed up");
|
||||
Py_DECREF(list);
|
||||
return (PyObject*)NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(list);
|
||||
#undef NLIST
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_dict_inner(PyObject *self, int count)
|
||||
{
|
||||
Py_ssize_t pos = 0, iterations = 0;
|
||||
int i;
|
||||
PyObject *dict = PyDict_New();
|
||||
PyObject *v, *k;
|
||||
|
||||
if (dict == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
v = PyLong_FromLong(i);
|
||||
if (v == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItem(dict, v, v) < 0) {
|
||||
Py_DECREF(v);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
|
||||
k = v = UNINITIALIZED_PTR;
|
||||
while (PyDict_Next(dict, &pos, &k, &v)) {
|
||||
PyObject *o;
|
||||
iterations++;
|
||||
|
||||
assert(k != UNINITIALIZED_PTR);
|
||||
assert(v != UNINITIALIZED_PTR);
|
||||
i = PyLong_AS_LONG(v) + 1;
|
||||
o = PyLong_FromLong(i);
|
||||
if (o == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItem(dict, k, o) < 0) {
|
||||
Py_DECREF(o);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(o);
|
||||
k = v = UNINITIALIZED_PTR;
|
||||
}
|
||||
assert(k == UNINITIALIZED_PTR);
|
||||
assert(v == UNINITIALIZED_PTR);
|
||||
|
||||
Py_DECREF(dict);
|
||||
|
||||
if (iterations != count) {
|
||||
PyErr_SetString(
|
||||
get_testerror(self),
|
||||
"test_dict_iteration: dict iteration went wrong ");
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
error:
|
||||
Py_DECREF(dict);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PyObject*
|
||||
test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 200; i++) {
|
||||
if (test_dict_inner(self, i) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* Issue #4701: Check that PyObject_Hash implicitly calls
|
||||
* PyType_Ready if it hasn't already been called
|
||||
*/
|
||||
|
@ -755,61 +637,6 @@ pending_threadfunc(PyObject *self, PyObject *arg, PyObject *kwargs)
|
|||
return PyLong_FromUnsignedLong((unsigned long)num_added);
|
||||
}
|
||||
|
||||
/* Test PyOS_string_to_double. */
|
||||
static PyObject *
|
||||
test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) {
|
||||
double result;
|
||||
const char *msg;
|
||||
|
||||
#define CHECK_STRING(STR, expected) \
|
||||
do { \
|
||||
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||
if (result == -1.0 && PyErr_Occurred()) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (result != (double)expected) { \
|
||||
msg = "conversion of " STR " to float failed"; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_INVALID(STR) \
|
||||
do { \
|
||||
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||
if (result == -1.0 && PyErr_Occurred()) { \
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) { \
|
||||
PyErr_Clear(); \
|
||||
} \
|
||||
else { \
|
||||
return NULL; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
msg = "conversion of " STR " didn't raise ValueError"; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
CHECK_STRING("0.1", 0.1);
|
||||
CHECK_STRING("1.234", 1.234);
|
||||
CHECK_STRING("-1.35", -1.35);
|
||||
CHECK_STRING(".1e01", 1.0);
|
||||
CHECK_STRING("2.e-2", 0.02);
|
||||
|
||||
CHECK_INVALID(" 0.1");
|
||||
CHECK_INVALID("\t\n-3");
|
||||
CHECK_INVALID(".123 ");
|
||||
CHECK_INVALID("3\n");
|
||||
CHECK_INVALID("123abc");
|
||||
|
||||
Py_RETURN_NONE;
|
||||
fail:
|
||||
return raiseTestError(self, "test_string_to_double", msg);
|
||||
#undef CHECK_STRING
|
||||
#undef CHECK_INVALID
|
||||
}
|
||||
|
||||
|
||||
/* Coverage testing of capsule objects. */
|
||||
|
||||
static const char *capsule_name = "capsule name";
|
||||
|
@ -1391,48 +1218,6 @@ static PyMethodDef ml = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
_test_incref(PyObject *ob)
|
||||
{
|
||||
return Py_NewRef(ob);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_XINCREF(_test_incref(obj));
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_INCREF(_test_incref(obj));
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
Py_XDECREF(PyLong_FromLong(0));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
Py_DECREF(PyLong_FromLong(0));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_structseq_newtype_doesnt_leak(PyObject *Py_UNUSED(self),
|
||||
PyObject *Py_UNUSED(args))
|
||||
|
@ -1479,16 +1264,6 @@ test_structseq_newtype_null_descr_doc(PyObject *Py_UNUSED(self),
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyLong_FromLong(0);
|
||||
Py_IncRef(obj);
|
||||
Py_DecRef(obj);
|
||||
Py_DecRef(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyThread_type_lock start_event;
|
||||
PyThread_type_lock exit_event;
|
||||
|
@ -1906,45 +1681,6 @@ bad_get(PyObject *module, PyObject *args)
|
|||
}
|
||||
|
||||
|
||||
#ifdef Py_REF_DEBUG
|
||||
static PyObject *
|
||||
negative_refcount(PyObject *self, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyObject *obj = PyUnicode_FromString("negative_refcount");
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(Py_REFCNT(obj) == 1);
|
||||
|
||||
Py_SET_REFCNT(obj, 0);
|
||||
/* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */
|
||||
Py_DECREF(obj);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyObject *obj = PyUnicode_FromString("decref_freed_object");
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(Py_REFCNT(obj) == 1);
|
||||
|
||||
// Deallocate the memory
|
||||
Py_DECREF(obj);
|
||||
// obj is a now a dangling pointer
|
||||
|
||||
// gh-109496: If Python is built in debug mode, Py_DECREF() must call
|
||||
// _Py_NegativeRefcount() and abort Python.
|
||||
Py_DECREF(obj);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Functions for testing C calling conventions (METH_*) are named meth_*,
|
||||
* e.g. "meth_varargs" for METH_VARARGS.
|
||||
*
|
||||
|
@ -2048,208 +1784,6 @@ pynumber_tobase(PyObject *module, PyObject *args)
|
|||
return PyNumber_ToBase(obj, base);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that following tests don't modify the object,
|
||||
// to ensure that Py_DECREF() will not crash.
|
||||
assert(Py_TYPE(obj) == &PyList_Type);
|
||||
assert(Py_SIZE(obj) == 0);
|
||||
|
||||
// bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions.
|
||||
Py_SET_TYPE(obj, &PyList_Type);
|
||||
Py_SET_SIZE(obj, 0);
|
||||
|
||||
Py_DECREF(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Test Py_CLEAR() macro
|
||||
static PyObject*
|
||||
test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
// simple case with a variable
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
assert(obj == NULL);
|
||||
|
||||
// gh-98724: complex case, Py_CLEAR() argument has a side effect
|
||||
PyObject* array[1];
|
||||
array[0] = PyList_New(0);
|
||||
if (array[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p = array;
|
||||
Py_CLEAR(*p++);
|
||||
assert(array[0] == NULL);
|
||||
assert(p == array + 1);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear()
|
||||
static PyObject*
|
||||
test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
// Py_SETREF() simple case with a variable
|
||||
PyObject *obj = PyList_New(0);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_SETREF(obj, NULL);
|
||||
assert(obj == NULL);
|
||||
|
||||
// Py_XSETREF() simple case with a variable
|
||||
PyObject *obj2 = PyList_New(0);
|
||||
if (obj2 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_XSETREF(obj2, NULL);
|
||||
assert(obj2 == NULL);
|
||||
// test Py_XSETREF() when the argument is NULL
|
||||
Py_XSETREF(obj2, NULL);
|
||||
assert(obj2 == NULL);
|
||||
|
||||
// gh-98724: complex case, Py_SETREF() argument has a side effect
|
||||
PyObject* array[1];
|
||||
array[0] = PyList_New(0);
|
||||
if (array[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p = array;
|
||||
Py_SETREF(*p++, NULL);
|
||||
assert(array[0] == NULL);
|
||||
assert(p == array + 1);
|
||||
|
||||
// gh-98724: complex case, Py_XSETREF() argument has a side effect
|
||||
PyObject* array2[1];
|
||||
array2[0] = PyList_New(0);
|
||||
if (array2[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **p2 = array2;
|
||||
Py_XSETREF(*p2++, NULL);
|
||||
assert(array2[0] == NULL);
|
||||
assert(p2 == array2 + 1);
|
||||
|
||||
// test Py_XSETREF() when the argument is NULL
|
||||
p2 = array2;
|
||||
Py_XSETREF(*p2++, NULL);
|
||||
assert(array2[0] == NULL);
|
||||
assert(p2 == array2 + 1);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_REFCOUNT() \
|
||||
do { \
|
||||
PyObject *obj = PyList_New(0); \
|
||||
if (obj == NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
assert(Py_REFCNT(obj) == 1); \
|
||||
\
|
||||
/* test Py_NewRef() */ \
|
||||
PyObject *ref = Py_NewRef(obj); \
|
||||
assert(ref == obj); \
|
||||
assert(Py_REFCNT(obj) == 2); \
|
||||
Py_DECREF(ref); \
|
||||
\
|
||||
/* test Py_XNewRef() */ \
|
||||
PyObject *xref = Py_XNewRef(obj); \
|
||||
assert(xref == obj); \
|
||||
assert(Py_REFCNT(obj) == 2); \
|
||||
Py_DECREF(xref); \
|
||||
\
|
||||
assert(Py_XNewRef(NULL) == NULL); \
|
||||
\
|
||||
Py_DECREF(obj); \
|
||||
Py_RETURN_NONE; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Test Py_NewRef() and Py_XNewRef() macros
|
||||
static PyObject*
|
||||
test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_REFCOUNT();
|
||||
}
|
||||
|
||||
#undef Py_NewRef
|
||||
#undef Py_XNewRef
|
||||
|
||||
// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros.
|
||||
static PyObject*
|
||||
test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_REFCOUNT();
|
||||
}
|
||||
|
||||
|
||||
// Test Py_Is() function
|
||||
#define TEST_PY_IS() \
|
||||
do { \
|
||||
PyObject *o_none = Py_None; \
|
||||
PyObject *o_true = Py_True; \
|
||||
PyObject *o_false = Py_False; \
|
||||
PyObject *obj = PyList_New(0); \
|
||||
if (obj == NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
/* test Py_Is() */ \
|
||||
assert(Py_Is(obj, obj)); \
|
||||
assert(!Py_Is(obj, o_none)); \
|
||||
\
|
||||
/* test Py_None */ \
|
||||
assert(Py_Is(o_none, o_none)); \
|
||||
assert(!Py_Is(obj, o_none)); \
|
||||
\
|
||||
/* test Py_True */ \
|
||||
assert(Py_Is(o_true, o_true)); \
|
||||
assert(!Py_Is(o_false, o_true)); \
|
||||
assert(!Py_Is(obj, o_true)); \
|
||||
\
|
||||
/* test Py_False */ \
|
||||
assert(Py_Is(o_false, o_false)); \
|
||||
assert(!Py_Is(o_true, o_false)); \
|
||||
assert(!Py_Is(obj, o_false)); \
|
||||
\
|
||||
Py_DECREF(obj); \
|
||||
Py_RETURN_NONE; \
|
||||
} while (0)
|
||||
|
||||
// Test Py_Is() macro
|
||||
static PyObject*
|
||||
test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_PY_IS();
|
||||
}
|
||||
|
||||
#undef Py_Is
|
||||
|
||||
// Test Py_Is() function, after undefining its macro.
|
||||
static PyObject*
|
||||
test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
TEST_PY_IS();
|
||||
}
|
||||
|
||||
|
||||
/* We only use 2 in test_capi/test_misc.py. */
|
||||
#define NUM_BASIC_STATIC_TYPES 2
|
||||
static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = {
|
||||
|
@ -2608,14 +2142,6 @@ settrace_to_error(PyObject *self, PyObject *list)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
clear_managed_dict(PyObject *self, PyObject *obj)
|
||||
{
|
||||
PyObject_ClearManagedDict(obj);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_macros(PyObject *self, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
|
@ -2969,124 +2495,18 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
tracemalloc_track_race_thread(void *data)
|
||||
{
|
||||
PyTraceMalloc_Track(123, 10, 1);
|
||||
PyTraceMalloc_Untrack(123, 10);
|
||||
|
||||
PyThread_type_lock lock = (PyThread_type_lock)data;
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
|
||||
// gh-128679: Test fix for tracemalloc.stop() race condition
|
||||
static PyObject *
|
||||
tracemalloc_track_race(PyObject *self, PyObject *args)
|
||||
{
|
||||
#define NTHREAD 50
|
||||
PyObject *tracemalloc = NULL;
|
||||
PyObject *stop = NULL;
|
||||
PyThread_type_lock locks[NTHREAD];
|
||||
memset(locks, 0, sizeof(locks));
|
||||
|
||||
// Call tracemalloc.start()
|
||||
tracemalloc = PyImport_ImportModule("tracemalloc");
|
||||
if (tracemalloc == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *start = PyObject_GetAttrString(tracemalloc, "start");
|
||||
if (start == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *res = PyObject_CallNoArgs(start);
|
||||
Py_DECREF(start);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
stop = PyObject_GetAttrString(tracemalloc, "stop");
|
||||
Py_CLEAR(tracemalloc);
|
||||
if (stop == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Start threads
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = PyThread_allocate_lock();
|
||||
if (!lock) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
locks[i] = lock;
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
|
||||
unsigned long thread;
|
||||
thread = PyThread_start_new_thread(tracemalloc_track_race_thread,
|
||||
(void*)lock);
|
||||
if (thread == (unsigned long)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "can't start new thread");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// Call tracemalloc.stop() while threads are running
|
||||
res = PyObject_CallNoArgs(stop);
|
||||
Py_CLEAR(stop);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
// Wait until threads complete with the GIL released
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
// Free threads locks
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
Py_CLEAR(tracemalloc);
|
||||
Py_CLEAR(stop);
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
if (lock) {
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#undef NTHREAD
|
||||
}
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
{"set_errno", set_errno, METH_VARARGS},
|
||||
{"test_config", test_config, METH_NOARGS},
|
||||
{"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS},
|
||||
{"test_list_api", test_list_api, METH_NOARGS},
|
||||
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
|
||||
{"test_lazy_hash_inheritance", test_lazy_hash_inheritance,METH_NOARGS},
|
||||
{"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS},
|
||||
{"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS},
|
||||
{"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS},
|
||||
{"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS},
|
||||
{"test_structseq_newtype_doesnt_leak",
|
||||
test_structseq_newtype_doesnt_leak, METH_NOARGS},
|
||||
{"test_structseq_newtype_null_descr_doc",
|
||||
test_structseq_newtype_null_descr_doc, METH_NOARGS},
|
||||
{"test_incref_decref_API", test_incref_decref_API, METH_NOARGS},
|
||||
{"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS},
|
||||
{"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS},
|
||||
{"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS},
|
||||
{"test_string_to_double", test_string_to_double, METH_NOARGS},
|
||||
{"test_capsule", (PyCFunction)test_capsule, METH_NOARGS},
|
||||
{"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS},
|
||||
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__)
|
||||
|
@ -3145,10 +2565,6 @@ static PyMethodDef TestMethods[] = {
|
|||
#endif
|
||||
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
|
||||
{"bad_get", bad_get, METH_VARARGS},
|
||||
#ifdef Py_REF_DEBUG
|
||||
{"negative_refcount", negative_refcount, METH_NOARGS},
|
||||
{"decref_freed_object", decref_freed_object, METH_NOARGS},
|
||||
#endif
|
||||
{"meth_varargs", meth_varargs, METH_VARARGS},
|
||||
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},
|
||||
{"meth_o", meth_o, METH_O},
|
||||
|
@ -3157,13 +2573,6 @@ static PyMethodDef TestMethods[] = {
|
|||
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS},
|
||||
{"pycfunction_call", test_pycfunction_call, METH_VARARGS},
|
||||
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
|
||||
{"test_set_type_size", test_set_type_size, METH_NOARGS},
|
||||
{"test_py_clear", test_py_clear, METH_NOARGS},
|
||||
{"test_py_setref", test_py_setref, METH_NOARGS},
|
||||
{"test_refcount_macros", test_refcount_macros, METH_NOARGS},
|
||||
{"test_refcount_funcs", test_refcount_funcs, METH_NOARGS},
|
||||
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
|
||||
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
|
||||
{"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL},
|
||||
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
|
||||
{"gen_get_code", gen_get_code, METH_O, NULL},
|
||||
|
@ -3172,14 +2581,12 @@ static PyMethodDef TestMethods[] = {
|
|||
{"settrace_to_error", settrace_to_error, METH_O, NULL},
|
||||
{"settrace_to_record", settrace_to_record, METH_O, NULL},
|
||||
{"test_macros", test_macros, METH_NOARGS, NULL},
|
||||
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
||||
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
|
||||
{"function_set_warning", function_set_warning, METH_NOARGS},
|
||||
{"test_critical_sections", test_critical_sections, METH_NOARGS},
|
||||
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
|
||||
{"test_atexit", test_atexit, METH_NOARGS},
|
||||
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
|
||||
{"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue