|
10 | 10 | #undef NDEBUG
|
11 | 11 |
|
12 | 12 | #include "Python.h"
|
13 |
| -#include "frameobject.h" |
14 | 13 | #include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
|
15 | 14 | #include "pycore_bitutils.h" // _Py_bswap32()
|
16 | 15 | #include "pycore_bytesobject.h" // _PyBytes_Find()
|
|
23 | 22 | #include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
24 | 23 | #include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
|
25 | 24 | #include "pycore_interp_id.h" // _PyInterpreterID_LookUp()
|
| 25 | +#include "pycore_object.h" // _PyObject_IsFreed() |
26 | 26 | #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal()
|
27 | 27 | #include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
|
28 | 28 | #include "pycore_pystate.h" // _PyThreadState_GET()
|
| 29 | + |
| 30 | +#include "frameobject.h" |
29 | 31 | #include "osdefs.h" // MAXPATHLEN
|
30 | 32 |
|
31 | 33 | #include "clinic/_testinternalcapi.c.h"
|
@@ -1446,6 +1448,77 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
|
1446 | 1448 | }
|
1447 | 1449 |
|
1448 | 1450 |
|
| 1451 | +static PyObject * |
| 1452 | +test_pyobject_is_freed(const char *test_name, PyObject *op) |
| 1453 | +{ |
| 1454 | + if (!_PyObject_IsFreed(op)) { |
| 1455 | + PyErr_SetString(PyExc_AssertionError, |
| 1456 | + "object is not seen as freed"); |
| 1457 | + return NULL; |
| 1458 | + } |
| 1459 | + Py_RETURN_NONE; |
| 1460 | +} |
| 1461 | + |
| 1462 | +static PyObject * |
| 1463 | +check_pyobject_null_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) |
| 1464 | +{ |
| 1465 | + PyObject *op = NULL; |
| 1466 | + return test_pyobject_is_freed("check_pyobject_null_is_freed", op); |
| 1467 | +} |
| 1468 | + |
| 1469 | + |
| 1470 | +static PyObject * |
| 1471 | +check_pyobject_uninitialized_is_freed(PyObject *self, |
| 1472 | + PyObject *Py_UNUSED(args)) |
| 1473 | +{ |
| 1474 | + PyObject *op = (PyObject *)PyObject_Malloc(sizeof(PyObject)); |
| 1475 | + if (op == NULL) { |
| 1476 | + return NULL; |
| 1477 | + } |
| 1478 | + /* Initialize reference count to avoid early crash in ceval or GC */ |
| 1479 | + Py_SET_REFCNT(op, 1); |
| 1480 | + /* object fields like ob_type are uninitialized! */ |
| 1481 | + return test_pyobject_is_freed("check_pyobject_uninitialized_is_freed", op); |
| 1482 | +} |
| 1483 | + |
| 1484 | + |
| 1485 | +static PyObject * |
| 1486 | +check_pyobject_forbidden_bytes_is_freed(PyObject *self, |
| 1487 | + PyObject *Py_UNUSED(args)) |
| 1488 | +{ |
| 1489 | + /* Allocate an incomplete PyObject structure: truncate 'ob_type' field */ |
| 1490 | + PyObject *op = (PyObject *)PyObject_Malloc(offsetof(PyObject, ob_type)); |
| 1491 | + if (op == NULL) { |
| 1492 | + return NULL; |
| 1493 | + } |
| 1494 | + /* Initialize reference count to avoid early crash in ceval or GC */ |
| 1495 | + Py_SET_REFCNT(op, 1); |
| 1496 | + /* ob_type field is after the memory block: part of "forbidden bytes" |
| 1497 | + when using debug hooks on memory allocators! */ |
| 1498 | + return test_pyobject_is_freed("check_pyobject_forbidden_bytes_is_freed", op); |
| 1499 | +} |
| 1500 | + |
| 1501 | + |
| 1502 | +static PyObject * |
| 1503 | +check_pyobject_freed_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) |
| 1504 | +{ |
| 1505 | + /* This test would fail if run with the address sanitizer */ |
| 1506 | +#ifdef _Py_ADDRESS_SANITIZER |
| 1507 | + Py_RETURN_NONE; |
| 1508 | +#else |
| 1509 | + PyObject *op = PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type); |
| 1510 | + if (op == NULL) { |
| 1511 | + return NULL; |
| 1512 | + } |
| 1513 | + Py_TYPE(op)->tp_dealloc(op); |
| 1514 | + /* Reset reference count to avoid early crash in ceval or GC */ |
| 1515 | + Py_SET_REFCNT(op, 1); |
| 1516 | + /* object memory is freed! */ |
| 1517 | + return test_pyobject_is_freed("check_pyobject_freed_is_freed", op); |
| 1518 | +#endif |
| 1519 | +} |
| 1520 | + |
| 1521 | + |
1449 | 1522 | static PyMethodDef module_functions[] = {
|
1450 | 1523 | {"get_configs", get_configs, METH_NOARGS},
|
1451 | 1524 | {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
@@ -1502,6 +1575,12 @@ static PyMethodDef module_functions[] = {
|
1502 | 1575 | {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
|
1503 | 1576 | {"_PyUnicode_TransformDecimalAndSpaceToASCII", unicode_transformdecimalandspacetoascii, METH_O},
|
1504 | 1577 | {"test_atexit", test_atexit, METH_NOARGS},
|
| 1578 | + {"check_pyobject_forbidden_bytes_is_freed", |
| 1579 | + check_pyobject_forbidden_bytes_is_freed, METH_NOARGS}, |
| 1580 | + {"check_pyobject_freed_is_freed", check_pyobject_freed_is_freed, METH_NOARGS}, |
| 1581 | + {"check_pyobject_null_is_freed", check_pyobject_null_is_freed, METH_NOARGS}, |
| 1582 | + {"check_pyobject_uninitialized_is_freed", |
| 1583 | + check_pyobject_uninitialized_is_freed, METH_NOARGS}, |
1505 | 1584 | {NULL, NULL} /* sentinel */
|
1506 | 1585 | };
|
1507 | 1586 |
|
|
0 commit comments