Skip to content

Commit f006940

Browse files
Issue #20440: Massive replacing unsafe attribute setting code with special
macro Py_SETREF.
2 parents 2bd58e3 + 5a57ade commit f006940

28 files changed

+92
-120
lines changed

Include/object.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,32 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
846846
Py_DECREF(_py_xdecref_tmp); \
847847
} while (0)
848848

849+
#ifndef Py_LIMITED_API
850+
/* Safely decref `op` and set `op` to `op2`.
851+
*
852+
* As in case of Py_CLEAR "the obvious" code can be deadly:
853+
*
854+
* Py_XDECREF(op);
855+
* op = op2;
856+
*
857+
* The safe way is:
858+
*
859+
* Py_SETREF(op, op2);
860+
*
861+
* That arranges to set `op` to `op2` _before_ decref'ing, so that any code
862+
* triggered as a side-effect of `op` getting torn down no longer believes
863+
* `op` points to a valid object.
864+
*/
865+
866+
#define Py_SETREF(op, op2) \
867+
do { \
868+
PyObject *_py_tmp = (PyObject *)(op); \
869+
(op) = (op2); \
870+
Py_XDECREF(_py_tmp); \
871+
} while (0)
872+
873+
#endif /* ifndef Py_LIMITED_API */
874+
849875
/*
850876
These are provided as conveniences to Python runtime embedders, so that
851877
they can have object code that is not dependent on Python compilation flags.

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Release date: tba
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #20440: Massive replacing unsafe attribute setting code with special
14+
macro Py_SETREF.
15+
1316
- Issue #25766: Special method __bytes__() now works in str subclasses.
1417

1518
- Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size.

Modules/_csv.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,8 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
276276
else {
277277
if (PyUnicode_READY(src) == -1)
278278
return -1;
279-
Py_XDECREF(*target);
280279
Py_INCREF(src);
281-
*target = src;
280+
Py_SETREF(*target, src);
282281
}
283282
}
284283
return 0;
@@ -784,8 +783,7 @@ parse_process_char(ReaderObj *self, Py_UCS4 c)
784783
static int
785784
parse_reset(ReaderObj *self)
786785
{
787-
Py_XDECREF(self->fields);
788-
self->fields = PyList_New(0);
786+
Py_SETREF(self->fields, PyList_New(0));
789787
if (self->fields == NULL)
790788
return -1;
791789
self->field_len = 0;

Modules/_ctypes/_ctypes.c

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,7 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
391391
Py_DECREF((PyObject *)dict);
392392
return NULL;
393393
}
394-
Py_DECREF(result->tp_dict);
395-
result->tp_dict = (PyObject *)dict;
394+
Py_SETREF(result->tp_dict, (PyObject *)dict);
396395
dict->format = _ctypes_alloc_format_string(NULL, "B");
397396
if (dict->format == NULL) {
398397
Py_DECREF(result);
@@ -871,8 +870,7 @@ PyCPointerType_SetProto(StgDictObject *stgdict, PyObject *proto)
871870
return -1;
872871
}
873872
Py_INCREF(proto);
874-
Py_XDECREF(stgdict->proto);
875-
stgdict->proto = proto;
873+
Py_SETREF(stgdict->proto, proto);
876874
return 0;
877875
}
878876

@@ -962,8 +960,7 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
962960
Py_DECREF((PyObject *)stgdict);
963961
return NULL;
964962
}
965-
Py_DECREF(result->tp_dict);
966-
result->tp_dict = (PyObject *)stgdict;
963+
Py_SETREF(result->tp_dict, (PyObject *)stgdict);
967964

968965
return (PyObject *)result;
969966
}
@@ -1406,8 +1403,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
14061403
/* replace the class dict by our updated spam dict */
14071404
if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict))
14081405
goto error;
1409-
Py_DECREF(result->tp_dict);
1410-
result->tp_dict = (PyObject *)stgdict; /* steal the reference */
1406+
Py_SETREF(result->tp_dict, (PyObject *)stgdict); /* steal the reference */
14111407
stgdict = NULL;
14121408

14131409
/* Special case for character arrays.
@@ -1820,8 +1816,7 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
18201816
Py_DECREF((PyObject *)stgdict);
18211817
return NULL;
18221818
}
1823-
Py_DECREF(result->tp_dict);
1824-
result->tp_dict = (PyObject *)stgdict;
1819+
Py_SETREF(result->tp_dict, (PyObject *)stgdict);
18251820

18261821
return (PyObject *)result;
18271822
}
@@ -1949,8 +1944,7 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
19491944
Py_DECREF((PyObject *)stgdict);
19501945
return NULL;
19511946
}
1952-
Py_DECREF(result->tp_dict);
1953-
result->tp_dict = (PyObject *)stgdict;
1947+
Py_SETREF(result->tp_dict, (PyObject *)stgdict);
19541948

19551949
/* Install from_param class methods in ctypes base classes.
19561950
Overrides the PyCSimpleType_from_param generic method.
@@ -2313,8 +2307,7 @@ PyCFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
23132307
Py_DECREF((PyObject *)stgdict);
23142308
return NULL;
23152309
}
2316-
Py_DECREF(result->tp_dict);
2317-
result->tp_dict = (PyObject *)stgdict;
2310+
Py_SETREF(result->tp_dict, (PyObject *)stgdict);
23182311

23192312
if (-1 == make_funcptrtype_dict(stgdict)) {
23202313
Py_DECREF(result);
@@ -2458,8 +2451,7 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep)
24582451
return -1;
24592452
}
24602453
if (ob->b_objects == NULL || !PyDict_CheckExact(ob->b_objects)) {
2461-
Py_XDECREF(ob->b_objects);
2462-
ob->b_objects = keep; /* refcount consumed */
2454+
Py_SETREF(ob->b_objects, keep); /* refcount consumed */
24632455
return 0;
24642456
}
24652457
key = unique_key(target, index);
@@ -2962,9 +2954,8 @@ PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob)
29622954
"the errcheck attribute must be callable");
29632955
return -1;
29642956
}
2965-
Py_XDECREF(self->errcheck);
29662957
Py_XINCREF(ob);
2967-
self->errcheck = ob;
2958+
Py_SETREF(self->errcheck, ob);
29682959
return 0;
29692960
}
29702961

@@ -2993,9 +2984,8 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob)
29932984
return -1;
29942985
}
29952986
Py_XDECREF(self->checker);
2996-
Py_XDECREF(self->restype);
29972987
Py_INCREF(ob);
2998-
self->restype = ob;
2988+
Py_SETREF(self->restype, ob);
29992989
self->checker = PyObject_GetAttrString(ob, "_check_retval_");
30002990
if (self->checker == NULL)
30012991
PyErr_Clear();
@@ -3033,11 +3023,9 @@ PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob)
30333023
converters = converters_from_argtypes(ob);
30343024
if (!converters)
30353025
return -1;
3036-
Py_XDECREF(self->converters);
3037-
self->converters = converters;
3038-
Py_XDECREF(self->argtypes);
3026+
Py_SETREF(self->converters, converters);
30393027
Py_INCREF(ob);
3040-
self->argtypes = ob;
3028+
Py_SETREF(self->argtypes, ob);
30413029
}
30423030
return 0;
30433031
}
@@ -5164,9 +5152,8 @@ comerror_init(PyObject *self, PyObject *args, PyObject *kwds)
51645152
return -1;
51655153

51665154
bself = (PyBaseExceptionObject *)self;
5167-
Py_DECREF(bself->args);
5168-
bself->args = args;
5169-
Py_INCREF(bself->args);
5155+
Py_INCREF(args);
5156+
Py_SETREF(bself->args, args);
51705157

51715158
return 0;
51725159
}

Modules/_curses_panel.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,8 @@ PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args)
312312
PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
313313
return NULL;
314314
}
315-
Py_DECREF(po->wo);
316-
po->wo = temp;
317-
Py_INCREF(po->wo);
315+
Py_INCREF(temp);
316+
Py_SETREF(po->wo, temp);
318317
Py_INCREF(Py_None);
319318
return Py_None;
320319
}

Modules/_io/bytesio.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -969,8 +969,7 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
969969
if (initvalue && initvalue != Py_None) {
970970
if (PyBytes_CheckExact(initvalue)) {
971971
Py_INCREF(initvalue);
972-
Py_XDECREF(self->buf);
973-
self->buf = initvalue;
972+
Py_SETREF(self->buf, initvalue);
974973
self->string_size = PyBytes_GET_SIZE(initvalue);
975974
}
976975
else {

Modules/_sqlite/connection.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ void pysqlite_flush_statement_cache(pysqlite_Connection* self)
204204
node = node->next;
205205
}
206206

207-
Py_DECREF(self->statement_cache);
208-
self->statement_cache = (pysqlite_Cache*)PyObject_CallFunction((PyObject*)&pysqlite_CacheType, "O", self);
207+
Py_SETREF(self->statement_cache,
208+
(pysqlite_Cache *)PyObject_CallFunction((PyObject *)&pysqlite_CacheType, "O", self));
209209
Py_DECREF(self);
210210
self->statement_cache->decref_factory = 0;
211211
}
@@ -318,9 +318,8 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args,
318318
_pysqlite_drop_unused_cursor_references(self);
319319

320320
if (cursor && self->row_factory != Py_None) {
321-
Py_XDECREF(((pysqlite_Cursor*)cursor)->row_factory);
322321
Py_INCREF(self->row_factory);
323-
((pysqlite_Cursor*)cursor)->row_factory = self->row_factory;
322+
Py_SETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory);
324323
}
325324

326325
return cursor;
@@ -795,8 +794,7 @@ static void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self
795794
}
796795
}
797796

798-
Py_DECREF(self->statements);
799-
self->statements = new_list;
797+
Py_SETREF(self->statements, new_list);
800798
}
801799

802800
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
@@ -827,8 +825,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
827825
}
828826
}
829827

830-
Py_DECREF(self->cursors);
831-
self->cursors = new_list;
828+
Py_SETREF(self->cursors, new_list);
832829
}
833830

834831
PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)

Modules/_sqlite/cursor.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
170170
return 0;
171171
}
172172

173-
Py_XDECREF(self->row_cast_map);
174-
self->row_cast_map = PyList_New(0);
173+
Py_SETREF(self->row_cast_map, PyList_New(0));
175174

176175
for (i = 0; i < sqlite3_column_count(self->statement->st); i++) {
177176
converter = NULL;
@@ -510,9 +509,8 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
510509
goto error;
511510

512511
/* reset description and rowcount */
513-
Py_DECREF(self->description);
514512
Py_INCREF(Py_None);
515-
self->description = Py_None;
513+
Py_SETREF(self->description, Py_None);
516514
self->rowcount = -1L;
517515

518516
func_args = PyTuple_New(1);
@@ -537,8 +535,8 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
537535
}
538536

539537
if (self->statement->in_use) {
540-
Py_DECREF(self->statement);
541-
self->statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
538+
Py_SETREF(self->statement,
539+
PyObject_New(pysqlite_Statement, &pysqlite_StatementType));
542540
if (!self->statement) {
543541
goto error;
544542
}
@@ -654,8 +652,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
654652
numcols = sqlite3_column_count(self->statement->st);
655653
Py_END_ALLOW_THREADS
656654

657-
Py_DECREF(self->description);
658-
self->description = PyTuple_New(numcols);
655+
Py_SETREF(self->description, PyTuple_New(numcols));
659656
if (!self->description) {
660657
goto error;
661658
}

Modules/_sre.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,8 +753,7 @@ deepcopy(PyObject** object, PyObject* memo)
753753
if (!copy)
754754
return 0;
755755

756-
Py_DECREF(*object);
757-
*object = copy;
756+
Py_SETREF(*object, copy);
758757

759758
return 1; /* success */
760759
}

Modules/_ssl.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,8 +1589,7 @@ static int PySSL_set_context(PySSLSocket *self, PyObject *value,
15891589
return -1;
15901590
#else
15911591
Py_INCREF(value);
1592-
Py_DECREF(self->ctx);
1593-
self->ctx = (PySSLContext *) value;
1592+
Py_SETREF(self->ctx, (PySSLContext *)value);
15941593
SSL_set_SSL_CTX(self->ssl, self->ctx->ctx);
15951594
#endif
15961595
} else {
@@ -1647,8 +1646,7 @@ PySSL_get_owner(PySSLSocket *self, void *c)
16471646
static int
16481647
PySSL_set_owner(PySSLSocket *self, PyObject *value, void *c)
16491648
{
1650-
Py_XDECREF(self->owner);
1651-
self->owner = PyWeakref_NewRef(value, NULL);
1649+
Py_SETREF(self->owner, PyWeakref_NewRef(value, NULL));
16521650
if (self->owner == NULL)
16531651
return -1;
16541652
return 0;

0 commit comments

Comments
 (0)