Skip to content

Commit 900942f

Browse files
committed
Add two functions that check behaviour when using PyTuple_Set_Item() and PyList_Set_Item() with same value.
void dbg_PyTuple_SetItem_SIGSEGV_on_same_value(void); void dbg_PyList_SetItem_SIGSEGV_on_same_value(void); These do not actually SIGSEGV (Mac Mini B) but the behavior is certainly undefined (decref on deleted object).
1 parent c3727ed commit 900942f

3 files changed

Lines changed: 101 additions & 10 deletions

File tree

src/cpy/Containers/DebugContainers.c

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ static long debug_test_count = 0L;
1414

1515
PyObject *
1616
new_unique_string(const char *function_name, const char *suffix) {
17-
PyObject *value = NULL;
18-
if (suffix){
17+
PyObject *value = NULL;
18+
if (suffix) {
1919
value = PyUnicode_FromFormat("%s-%s-%ld", function_name, suffix, debug_test_count);
2020
} else {
2121
value = PyUnicode_FromFormat("%s-%ld", function_name, debug_test_count);
@@ -268,7 +268,7 @@ void dbg_PyTuple_SetItem_replace_with_same(void) {
268268
ref_count = Py_REFCNT(get_item);
269269
assert(ref_count == 1);
270270

271-
/* Increment the reference count from 1 so we can see it go to 1. */
271+
/* Increment the reference count from 1 so we can see it go back to 1 on Py_DECREF(container);. */
272272
Py_INCREF(value);
273273
Py_DECREF(container);
274274
/* Clean up. */
@@ -311,7 +311,7 @@ void dbg_PyTuple_SET_ITEM_replace_with_same(void) {
311311
ref_count = Py_REFCNT(get_item);
312312
assert(ref_count == 1);
313313

314-
/* Increment the reference count from 1 so we can see it go to 1. */
314+
/* Increment the reference count from 1 so we can see it go back to 1 on Py_DECREF(container);. */
315315
Py_INCREF(value);
316316
Py_DECREF(container);
317317
/* Clean up. */
@@ -858,7 +858,7 @@ void dbg_PyList_SetItem_replace_with_same(void) {
858858
ref_count = Py_REFCNT(get_item);
859859
assert(ref_count == 1);
860860

861-
/* Increment the reference count from 1 so we can see it go to 1. */
861+
/* Increment the reference count from 1 so we can see it go back to 1 on Py_DECREF(container);. */
862862
Py_INCREF(value);
863863
Py_DECREF(container);
864864
/* Clean up. */
@@ -901,7 +901,7 @@ void dbg_PyList_SET_ITEM_replace_with_same(void) {
901901
ref_count = Py_REFCNT(get_item);
902902
assert(ref_count == 1);
903903

904-
/* Increment the reference count from 1 so we can see it go to 1. */
904+
/* Increment the reference count from 1 so we can see it go back to 1 on Py_DECREF(container);. */
905905
Py_INCREF(value);
906906
Py_DECREF(container);
907907
/* Clean up. */
@@ -1661,6 +1661,90 @@ void dbg_PyDict_SetItem_fails_not_hashable(void) {
16611661

16621662
#if ACCEPT_SIGSEGV
16631663

1664+
void dbg_PyTuple_SetItem_SIGSEGV_on_same_value(void) {
1665+
printf("%s():\n", __FUNCTION__);
1666+
if (PyErr_Occurred()) {
1667+
fprintf(stderr, "%s(): On entry PyErr_Print() %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1668+
PyErr_Print();
1669+
return;
1670+
}
1671+
assert(!PyErr_Occurred());
1672+
Py_ssize_t ref_count;
1673+
1674+
PyObject *container = PyTuple_New(1);
1675+
assert(container);
1676+
1677+
ref_count = Py_REFCNT(container);
1678+
assert(ref_count == 1);
1679+
1680+
PyObject *value = new_unique_string(__FUNCTION__, NULL);
1681+
ref_count = Py_REFCNT(value);
1682+
assert(ref_count == 1);
1683+
1684+
int result = PyTuple_SetItem(container, 0, value);
1685+
assert(result == 0);
1686+
ref_count = Py_REFCNT(value);
1687+
assert(ref_count == 1);
1688+
1689+
PyObject *get_value = PyTuple_GetItem(container, 0);
1690+
assert(get_value == value);
1691+
ref_count = Py_REFCNT(value);
1692+
assert(ref_count == 1);
1693+
1694+
/* This causes value to be free'd. */
1695+
result = PyTuple_SetItem(container, 0, value);
1696+
assert(result == 0);
1697+
ref_count = Py_REFCNT(value);
1698+
assert(ref_count != 1);
1699+
1700+
fprintf(stderr, "%s(): Undefined behaviour, possible SIGSEGV %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1701+
/* This may cause a SIGSEGV. */
1702+
Py_DECREF(container);
1703+
fprintf(stderr, "%s(): SIGSEGV did not happen %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1704+
}
1705+
1706+
void dbg_PyList_SetItem_SIGSEGV_on_same_value(void) {
1707+
printf("%s():\n", __FUNCTION__);
1708+
if (PyErr_Occurred()) {
1709+
fprintf(stderr, "%s(): On entry PyErr_Print() %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1710+
PyErr_Print();
1711+
return;
1712+
}
1713+
assert(!PyErr_Occurred());
1714+
Py_ssize_t ref_count;
1715+
1716+
PyObject *container = PyList_New(1);
1717+
assert(container);
1718+
1719+
ref_count = Py_REFCNT(container);
1720+
assert(ref_count == 1);
1721+
1722+
PyObject *value = new_unique_string(__FUNCTION__, NULL);
1723+
ref_count = Py_REFCNT(value);
1724+
assert(ref_count == 1);
1725+
1726+
int result = PyList_SetItem(container, 0, value);
1727+
assert(result == 0);
1728+
ref_count = Py_REFCNT(value);
1729+
assert(ref_count == 1);
1730+
1731+
PyObject *get_value = PyList_GetItem(container, 0);
1732+
assert(get_value == value);
1733+
ref_count = Py_REFCNT(value);
1734+
assert(ref_count == 1);
1735+
1736+
/* This causes value to be free'd. */
1737+
result = PyList_SetItem(container, 0, value);
1738+
assert(result == 0);
1739+
ref_count = Py_REFCNT(value);
1740+
assert(ref_count != 1);
1741+
1742+
fprintf(stderr, "%s(): Undefined behaviour, possible SIGSEGV %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1743+
/* This may cause a SIGSEGV. */
1744+
Py_DECREF(container);
1745+
fprintf(stderr, "%s(): SIGSEGV did not happen %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
1746+
}
1747+
16641748
void dbg_PyDict_SetItem_SIGSEGV_on_key_NULL(void) {
16651749
printf("%s():\n", __FUNCTION__);
16661750
if (PyErr_Occurred()) {
@@ -1678,13 +1762,14 @@ void dbg_PyDict_SetItem_SIGSEGV_on_key_NULL(void) {
16781762
assert(ref_count == 1);
16791763

16801764
PyObject *key = NULL;
1681-
ref_count = Py_REFCNT(key);
1682-
assert(ref_count == 1);
16831765
PyObject *value = new_unique_string(__FUNCTION__, NULL);
16841766
ref_count = Py_REFCNT(value);
16851767
assert(ref_count == 1);
16861768

1769+
fprintf(stderr, "%s(): PyDict_SetItem() with NULL key causes SIGSEGV %s#%d:\n",
1770+
__FUNCTION__, __FILE_NAME__, __LINE__);
16871771
int result = PyDict_SetItem(container, key, value);
1772+
fprintf(stderr, "%s(): SIGSEGV did not happen %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
16881773
if (result) {
16891774
assert(PyErr_Occurred());
16901775
fprintf(stderr, "%s(): PyErr_Print() %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
@@ -1721,10 +1806,11 @@ void dbg_PyDict_SetItem_SIGSEGV_on_value_NULL(void) {
17211806
ref_count = Py_REFCNT(key);
17221807
assert(ref_count == 1);
17231808
PyObject *value = NULL;
1724-
ref_count = Py_REFCNT(value);
1725-
assert(ref_count == 1);
17261809

1810+
fprintf(stderr, "%s(): PyDict_SetItem() with NULL value causes SIGSEGV %s#%d:\n",
1811+
__FUNCTION__, __FILE_NAME__, __LINE__);
17271812
int result = PyDict_SetItem(container, key, value);
1813+
fprintf(stderr, "%s(): SIGSEGV did not happen %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);
17281814
if (result) {
17291815
assert(PyErr_Occurred());
17301816
fprintf(stderr, "%s(): PyErr_Print() %s#%d:\n", __FUNCTION__, __FILE_NAME__, __LINE__);

src/cpy/Containers/DebugContainers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ void dbg_PyDict_SetItem_increments(void);
5050
void dbg_PyDict_SetItem_fails_not_a_dict(void);
5151
void dbg_PyDict_SetItem_fails_not_hashable(void);
5252
#if ACCEPT_SIGSEGV
53+
void dbg_PyTuple_SetItem_SIGSEGV_on_same_value(void);
54+
void dbg_PyList_SetItem_SIGSEGV_on_same_value(void);
5355
void dbg_PyDict_SetItem_SIGSEGV_on_key_NULL(void);
5456
void dbg_PyDict_SetItem_SIGSEGV_on_value_NULL(void);
5557
#endif

src/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ int main(int argc, const char * argv[]) {
184184
dbg_PyDict_SetItem_fails_not_a_dict();
185185
dbg_PyDict_SetItem_fails_not_hashable();
186186
#if ACCEPT_SIGSEGV
187+
/* Comment out as desired. */
188+
dbg_PyTuple_SetItem_SIGSEGV_on_same_value();
189+
dbg_PyList_SetItem_SIGSEGV_on_same_value();
187190
dbg_PyDict_SetItem_SIGSEGV_on_key_NULL();
188191
dbg_PyDict_SetItem_SIGSEGV_on_value_NULL();
189192
#endif

0 commit comments

Comments
 (0)