Skip to content

Commit 5a13faa

Browse files
authored
gh-111178: fix UBSan failures in Modules/_pickle.c (#129787)
Fix UBSan failures for `Pdata`, `PicklerObject`, `UnpicklerObject`, `PicklerMemoProxyObject`, `UnpicklerMemoProxyObject` Indicate safe fast cast to avoid redundant future checks Use semantically correct parameter names
1 parent deac31d commit 5a13faa

File tree

1 file changed

+62
-39
lines changed

1 file changed

+62
-39
lines changed

Modules/_pickle.c

+62-39
Original file line numberDiff line numberDiff line change
@@ -410,24 +410,27 @@ typedef struct {
410410
Py_ssize_t allocated; /* number of slots in data allocated */
411411
} Pdata;
412412

413+
#define Pdata_CAST(op) ((Pdata *)(op))
414+
413415
static int
414-
Pdata_traverse(Pdata *self, visitproc visit, void *arg)
416+
Pdata_traverse(PyObject *self, visitproc visit, void *arg)
415417
{
416418
Py_VISIT(Py_TYPE(self));
417419
return 0;
418420
}
419421

420422
static void
421-
Pdata_dealloc(Pdata *self)
423+
Pdata_dealloc(PyObject *op)
422424
{
425+
Pdata *self = Pdata_CAST(op);
423426
PyTypeObject *tp = Py_TYPE(self);
424427
PyObject_GC_UnTrack(self);
425428
Py_ssize_t i = Py_SIZE(self);
426429
while (--i >= 0) {
427430
Py_DECREF(self->data[i]);
428431
}
429432
PyMem_Free(self->data);
430-
tp->tp_free((PyObject *)self);
433+
tp->tp_free(self);
431434
Py_DECREF(tp);
432435
}
433436

@@ -696,6 +699,11 @@ typedef struct {
696699
UnpicklerObject *unpickler;
697700
} UnpicklerMemoProxyObject;
698701

702+
#define PicklerObject_CAST(op) ((PicklerObject *)(op))
703+
#define UnpicklerObject_CAST(op) ((UnpicklerObject *)(op))
704+
#define PicklerMemoProxyObject_CAST(op) ((PicklerMemoProxyObject *)(op))
705+
#define UnpicklerMemoProxyObject_CAST(op) ((UnpicklerMemoProxyObject *)(op))
706+
699707
/* Forward declarations */
700708
static int save(PickleState *state, PicklerObject *, PyObject *, int);
701709
static int save_reduce(PickleState *, PicklerObject *, PyObject *, PyObject *);
@@ -4720,8 +4728,9 @@ static struct PyMethodDef Pickler_methods[] = {
47204728
};
47214729

47224730
static int
4723-
Pickler_clear(PicklerObject *self)
4731+
Pickler_clear(PyObject *op)
47244732
{
4733+
PicklerObject *self = PicklerObject_CAST(op);
47254734
Py_CLEAR(self->output_buffer);
47264735
Py_CLEAR(self->write);
47274736
Py_CLEAR(self->persistent_id);
@@ -4740,18 +4749,19 @@ Pickler_clear(PicklerObject *self)
47404749
}
47414750

47424751
static void
4743-
Pickler_dealloc(PicklerObject *self)
4752+
Pickler_dealloc(PyObject *self)
47444753
{
47454754
PyTypeObject *tp = Py_TYPE(self);
47464755
PyObject_GC_UnTrack(self);
47474756
(void)Pickler_clear(self);
4748-
tp->tp_free((PyObject *)self);
4757+
tp->tp_free(self);
47494758
Py_DECREF(tp);
47504759
}
47514760

47524761
static int
4753-
Pickler_traverse(PicklerObject *self, visitproc visit, void *arg)
4762+
Pickler_traverse(PyObject *op, visitproc visit, void *arg)
47544763
{
4764+
PicklerObject *self = PicklerObject_CAST(op);
47554765
Py_VISIT(Py_TYPE(self));
47564766
Py_VISIT(self->write);
47574767
Py_VISIT(self->persistent_id);
@@ -4822,7 +4832,7 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
48224832
{
48234833
/* In case of multiple __init__() calls, clear previous content. */
48244834
if (self->write != NULL)
4825-
(void)Pickler_clear(self);
4835+
(void)Pickler_clear((PyObject *)self);
48264836

48274837
if (_Pickler_SetProtocol(self, protocol, fix_imports) < 0)
48284838
return -1;
@@ -4974,27 +4984,29 @@ static PyMethodDef picklerproxy_methods[] = {
49744984
};
49754985

49764986
static void
4977-
PicklerMemoProxy_dealloc(PicklerMemoProxyObject *self)
4987+
PicklerMemoProxy_dealloc(PyObject *op)
49784988
{
4989+
PicklerMemoProxyObject *self = PicklerMemoProxyObject_CAST(op);
49794990
PyTypeObject *tp = Py_TYPE(self);
49804991
PyObject_GC_UnTrack(self);
49814992
Py_CLEAR(self->pickler);
4982-
tp->tp_free((PyObject *)self);
4993+
tp->tp_free(self);
49834994
Py_DECREF(tp);
49844995
}
49854996

49864997
static int
4987-
PicklerMemoProxy_traverse(PicklerMemoProxyObject *self,
4988-
visitproc visit, void *arg)
4998+
PicklerMemoProxy_traverse(PyObject *op, visitproc visit, void *arg)
49894999
{
5000+
PicklerMemoProxyObject *self = PicklerMemoProxyObject_CAST(op);
49905001
Py_VISIT(Py_TYPE(self));
49915002
Py_VISIT(self->pickler);
49925003
return 0;
49935004
}
49945005

49955006
static int
4996-
PicklerMemoProxy_clear(PicklerMemoProxyObject *self)
5007+
PicklerMemoProxy_clear(PyObject *op)
49975008
{
5009+
PicklerMemoProxyObject *self = PicklerMemoProxyObject_CAST(op);
49985010
Py_CLEAR(self->pickler);
49995011
return 0;
50005012
}
@@ -5032,15 +5044,17 @@ PicklerMemoProxy_New(PicklerObject *pickler)
50325044
/*****************************************************************************/
50335045

50345046
static PyObject *
5035-
Pickler_get_memo(PicklerObject *self, void *Py_UNUSED(ignored))
5047+
Pickler_get_memo(PyObject *op, void *Py_UNUSED(closure))
50365048
{
5049+
PicklerObject *self = PicklerObject_CAST(op);
50375050
return PicklerMemoProxy_New(self);
50385051
}
50395052

50405053
static int
5041-
Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
5054+
Pickler_set_memo(PyObject *op, PyObject *obj, void *Py_UNUSED(closure))
50425055
{
50435056
PyMemoTable *new_memo = NULL;
5057+
PicklerObject *self = PicklerObject_CAST(op);
50445058

50455059
if (obj == NULL) {
50465060
PyErr_SetString(PyExc_TypeError,
@@ -5050,7 +5064,7 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
50505064

50515065
PickleState *st = _Pickle_FindStateByType(Py_TYPE(self));
50525066
if (Py_IS_TYPE(obj, st->PicklerMemoProxyType)) {
5053-
PicklerObject *pickler =
5067+
PicklerObject *pickler = /* safe fast cast for 'obj' */
50545068
((PicklerMemoProxyObject *)obj)->pickler;
50555069

50565070
new_memo = PyMemoTable_Copy(pickler->memo);
@@ -5103,11 +5117,12 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
51035117
static PyObject *
51045118
Pickler_getattr(PyObject *self, PyObject *name)
51055119
{
5120+
PicklerObject *po = PicklerObject_CAST(self);
51065121
if (PyUnicode_Check(name)
51075122
&& PyUnicode_EqualToUTF8(name, "persistent_id")
5108-
&& ((PicklerObject *)self)->persistent_id_attr)
5123+
&& po->persistent_id_attr)
51095124
{
5110-
return Py_NewRef(((PicklerObject *)self)->persistent_id_attr);
5125+
return Py_NewRef(po->persistent_id_attr);
51115126
}
51125127

51135128
return PyObject_GenericGetAttr(self, name);
@@ -5119,8 +5134,9 @@ Pickler_setattr(PyObject *self, PyObject *name, PyObject *value)
51195134
if (PyUnicode_Check(name)
51205135
&& PyUnicode_EqualToUTF8(name, "persistent_id"))
51215136
{
5137+
PicklerObject *po = PicklerObject_CAST(self);
51225138
Py_XINCREF(value);
5123-
Py_XSETREF(((PicklerObject *)self)->persistent_id_attr, value);
5139+
Py_XSETREF(po->persistent_id_attr, value);
51245140
return 0;
51255141
}
51265142

@@ -5135,8 +5151,7 @@ static PyMemberDef Pickler_members[] = {
51355151
};
51365152

51375153
static PyGetSetDef Pickler_getsets[] = {
5138-
{"memo", (getter)Pickler_get_memo,
5139-
(setter)Pickler_set_memo},
5154+
{"memo", Pickler_get_memo, Pickler_set_memo},
51405155
{NULL}
51415156
};
51425157

@@ -7221,8 +7236,9 @@ static struct PyMethodDef Unpickler_methods[] = {
72217236
};
72227237

72237238
static int
7224-
Unpickler_clear(UnpicklerObject *self)
7239+
Unpickler_clear(PyObject *op)
72257240
{
7241+
UnpicklerObject *self = UnpicklerObject_CAST(op);
72267242
Py_CLEAR(self->readline);
72277243
Py_CLEAR(self->readinto);
72287244
Py_CLEAR(self->read);
@@ -7250,18 +7266,19 @@ Unpickler_clear(UnpicklerObject *self)
72507266
}
72517267

72527268
static void
7253-
Unpickler_dealloc(UnpicklerObject *self)
7269+
Unpickler_dealloc(PyObject *self)
72547270
{
72557271
PyTypeObject *tp = Py_TYPE(self);
7256-
PyObject_GC_UnTrack((PyObject *)self);
7272+
PyObject_GC_UnTrack(self);
72577273
(void)Unpickler_clear(self);
7258-
tp->tp_free((PyObject *)self);
7274+
tp->tp_free(self);
72597275
Py_DECREF(tp);
72607276
}
72617277

72627278
static int
7263-
Unpickler_traverse(UnpicklerObject *self, visitproc visit, void *arg)
7279+
Unpickler_traverse(PyObject *op, visitproc visit, void *arg)
72647280
{
7281+
UnpicklerObject *self = UnpicklerObject_CAST(op);
72657282
Py_VISIT(Py_TYPE(self));
72667283
Py_VISIT(self->readline);
72677284
Py_VISIT(self->readinto);
@@ -7322,7 +7339,7 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file,
73227339
{
73237340
/* In case of multiple __init__() calls, clear previous content. */
73247341
if (self->read != NULL)
7325-
(void)Unpickler_clear(self);
7342+
(void)Unpickler_clear((PyObject *)self);
73267343

73277344
if (_Unpickler_SetInputStream(self, file) < 0)
73287345
return -1;
@@ -7461,27 +7478,29 @@ static PyMethodDef unpicklerproxy_methods[] = {
74617478
};
74627479

74637480
static void
7464-
UnpicklerMemoProxy_dealloc(UnpicklerMemoProxyObject *self)
7481+
UnpicklerMemoProxy_dealloc(PyObject *op)
74657482
{
7483+
UnpicklerMemoProxyObject *self = UnpicklerMemoProxyObject_CAST(op);
74667484
PyTypeObject *tp = Py_TYPE(self);
74677485
PyObject_GC_UnTrack(self);
74687486
Py_CLEAR(self->unpickler);
7469-
tp->tp_free((PyObject *)self);
7487+
tp->tp_free(self);
74707488
Py_DECREF(tp);
74717489
}
74727490

74737491
static int
7474-
UnpicklerMemoProxy_traverse(UnpicklerMemoProxyObject *self,
7475-
visitproc visit, void *arg)
7492+
UnpicklerMemoProxy_traverse(PyObject *op, visitproc visit, void *arg)
74767493
{
7494+
UnpicklerMemoProxyObject *self = UnpicklerMemoProxyObject_CAST(op);
74777495
Py_VISIT(Py_TYPE(self));
74787496
Py_VISIT(self->unpickler);
74797497
return 0;
74807498
}
74817499

74827500
static int
7483-
UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self)
7501+
UnpicklerMemoProxy_clear(PyObject *op)
74847502
{
7503+
UnpicklerMemoProxyObject *self = UnpicklerMemoProxyObject_CAST(op);
74857504
Py_CLEAR(self->unpickler);
74867505
return 0;
74877506
}
@@ -7521,15 +7540,17 @@ UnpicklerMemoProxy_New(UnpicklerObject *unpickler)
75217540

75227541

75237542
static PyObject *
7524-
Unpickler_get_memo(UnpicklerObject *self, void *Py_UNUSED(ignored))
7543+
Unpickler_get_memo(PyObject *op, void *Py_UNUSED(closure))
75257544
{
7545+
UnpicklerObject *self = UnpicklerObject_CAST(op);
75267546
return UnpicklerMemoProxy_New(self);
75277547
}
75287548

75297549
static int
7530-
Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
7550+
Unpickler_set_memo(PyObject *op, PyObject *obj, void *Py_UNUSED(closure))
75317551
{
75327552
PyObject **new_memo;
7553+
UnpicklerObject *self = UnpicklerObject_CAST(op);
75337554
size_t new_memo_size = 0;
75347555

75357556
if (obj == NULL) {
@@ -7540,7 +7561,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored
75407561

75417562
PickleState *state = _Pickle_FindStateByType(Py_TYPE(self));
75427563
if (Py_IS_TYPE(obj, state->UnpicklerMemoProxyType)) {
7543-
UnpicklerObject *unpickler =
7564+
UnpicklerObject *unpickler = /* safe fast cast for 'obj' */
75447565
((UnpicklerMemoProxyObject *)obj)->unpickler;
75457566

75467567
new_memo_size = unpickler->memo_size;
@@ -7606,11 +7627,12 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored
76067627
static PyObject *
76077628
Unpickler_getattr(PyObject *self, PyObject *name)
76087629
{
7630+
UnpicklerObject *obj = UnpicklerObject_CAST(self);
76097631
if (PyUnicode_Check(name)
76107632
&& PyUnicode_EqualToUTF8(name, "persistent_load")
7611-
&& ((UnpicklerObject *)self)->persistent_load_attr)
7633+
&& obj->persistent_load_attr)
76127634
{
7613-
return Py_NewRef(((UnpicklerObject *)self)->persistent_load_attr);
7635+
return Py_NewRef(obj->persistent_load_attr);
76147636
}
76157637

76167638
return PyObject_GenericGetAttr(self, name);
@@ -7622,16 +7644,17 @@ Unpickler_setattr(PyObject *self, PyObject *name, PyObject *value)
76227644
if (PyUnicode_Check(name)
76237645
&& PyUnicode_EqualToUTF8(name, "persistent_load"))
76247646
{
7647+
UnpicklerObject *obj = UnpicklerObject_CAST(self);
76257648
Py_XINCREF(value);
7626-
Py_XSETREF(((UnpicklerObject *)self)->persistent_load_attr, value);
7649+
Py_XSETREF(obj->persistent_load_attr, value);
76277650
return 0;
76287651
}
76297652

76307653
return PyObject_GenericSetAttr(self, name, value);
76317654
}
76327655

76337656
static PyGetSetDef Unpickler_getsets[] = {
7634-
{"memo", (getter)Unpickler_get_memo, (setter)Unpickler_set_memo},
7657+
{"memo", Unpickler_get_memo, Unpickler_set_memo},
76357658
{NULL}
76367659
};
76377660

0 commit comments

Comments
 (0)