Skip to content

Commit 1da0901

Browse files
authored
gh-111178: fix UBSan failures in Python/context.c (GH-128242)
* fix UBSan failures for `PyContext` * fix UBSan failures for `PyContextVar` * fix UBSan failures for `PyContextToken` * fix UBSan failures for `_PyContextTokenMissing`
1 parent c22302e commit 1da0901

File tree

1 file changed

+68
-53
lines changed

1 file changed

+68
-53
lines changed

Python/context.c

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ class _contextvars.Context "PyContext *" "&PyContext_Type"
419419
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/
420420

421421

422+
#define _PyContext_CAST(op) ((PyContext *)(op))
423+
424+
422425
static inline PyContext *
423426
_context_alloc(void)
424427
{
@@ -513,37 +516,40 @@ context_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
513516
}
514517

515518
static int
516-
context_tp_clear(PyContext *self)
519+
context_tp_clear(PyObject *op)
517520
{
521+
PyContext *self = _PyContext_CAST(op);
518522
Py_CLEAR(self->ctx_prev);
519523
Py_CLEAR(self->ctx_vars);
520524
return 0;
521525
}
522526

523527
static int
524-
context_tp_traverse(PyContext *self, visitproc visit, void *arg)
528+
context_tp_traverse(PyObject *op, visitproc visit, void *arg)
525529
{
530+
PyContext *self = _PyContext_CAST(op);
526531
Py_VISIT(self->ctx_prev);
527532
Py_VISIT(self->ctx_vars);
528533
return 0;
529534
}
530535

531536
static void
532-
context_tp_dealloc(PyContext *self)
537+
context_tp_dealloc(PyObject *self)
533538
{
534539
_PyObject_GC_UNTRACK(self);
535-
536-
if (self->ctx_weakreflist != NULL) {
537-
PyObject_ClearWeakRefs((PyObject*)self);
540+
PyContext *ctx = _PyContext_CAST(self);
541+
if (ctx->ctx_weakreflist != NULL) {
542+
PyObject_ClearWeakRefs(self);
538543
}
539544
(void)context_tp_clear(self);
540545

541546
_Py_FREELIST_FREE(contexts, self, Py_TYPE(self)->tp_free);
542547
}
543548

544549
static PyObject *
545-
context_tp_iter(PyContext *self)
550+
context_tp_iter(PyObject *op)
546551
{
552+
PyContext *self = _PyContext_CAST(op);
547553
return _PyHamt_NewIterKeys(self->ctx_vars);
548554
}
549555

@@ -575,18 +581,20 @@ context_tp_richcompare(PyObject *v, PyObject *w, int op)
575581
}
576582

577583
static Py_ssize_t
578-
context_tp_len(PyContext *self)
584+
context_tp_len(PyObject *op)
579585
{
586+
PyContext *self = _PyContext_CAST(op);
580587
return _PyHamt_Len(self->ctx_vars);
581588
}
582589

583590
static PyObject *
584-
context_tp_subscript(PyContext *self, PyObject *key)
591+
context_tp_subscript(PyObject *op, PyObject *key)
585592
{
586593
if (context_check_key_type(key)) {
587594
return NULL;
588595
}
589596
PyObject *val = NULL;
597+
PyContext *self = _PyContext_CAST(op);
590598
int found = _PyHamt_Find(self->ctx_vars, key, &val);
591599
if (found < 0) {
592600
return NULL;
@@ -599,12 +607,13 @@ context_tp_subscript(PyContext *self, PyObject *key)
599607
}
600608

601609
static int
602-
context_tp_contains(PyContext *self, PyObject *key)
610+
context_tp_contains(PyObject *op, PyObject *key)
603611
{
604612
if (context_check_key_type(key)) {
605613
return -1;
606614
}
607615
PyObject *val = NULL;
616+
PyContext *self = _PyContext_CAST(op);
608617
return _PyHamt_Find(self->ctx_vars, key, &val);
609618
}
610619

@@ -701,7 +710,7 @@ _contextvars_Context_copy_impl(PyContext *self)
701710

702711

703712
static PyObject *
704-
context_run(PyContext *self, PyObject *const *args,
713+
context_run(PyObject *self, PyObject *const *args,
705714
Py_ssize_t nargs, PyObject *kwnames)
706715
{
707716
PyThreadState *ts = _PyThreadState_GET();
@@ -712,14 +721,14 @@ context_run(PyContext *self, PyObject *const *args,
712721
return NULL;
713722
}
714723

715-
if (_PyContext_Enter(ts, (PyObject *)self)) {
724+
if (_PyContext_Enter(ts, self)) {
716725
return NULL;
717726
}
718727

719728
PyObject *call_result = _PyObject_VectorcallTstate(
720729
ts, args[0], args + 1, nargs - 1, kwnames);
721730

722-
if (_PyContext_Exit(ts, (PyObject *)self)) {
731+
if (_PyContext_Exit(ts, self)) {
723732
Py_XDECREF(call_result);
724733
return NULL;
725734
}
@@ -739,21 +748,12 @@ static PyMethodDef PyContext_methods[] = {
739748
};
740749

741750
static PySequenceMethods PyContext_as_sequence = {
742-
0, /* sq_length */
743-
0, /* sq_concat */
744-
0, /* sq_repeat */
745-
0, /* sq_item */
746-
0, /* sq_slice */
747-
0, /* sq_ass_item */
748-
0, /* sq_ass_slice */
749-
(objobjproc)context_tp_contains, /* sq_contains */
750-
0, /* sq_inplace_concat */
751-
0, /* sq_inplace_repeat */
751+
.sq_contains = context_tp_contains
752752
};
753753

754754
static PyMappingMethods PyContext_as_mapping = {
755-
(lenfunc)context_tp_len, /* mp_length */
756-
(binaryfunc)context_tp_subscript, /* mp_subscript */
755+
.mp_length = context_tp_len,
756+
.mp_subscript = context_tp_subscript
757757
};
758758

759759
PyTypeObject PyContext_Type = {
@@ -763,13 +763,13 @@ PyTypeObject PyContext_Type = {
763763
.tp_methods = PyContext_methods,
764764
.tp_as_mapping = &PyContext_as_mapping,
765765
.tp_as_sequence = &PyContext_as_sequence,
766-
.tp_iter = (getiterfunc)context_tp_iter,
767-
.tp_dealloc = (destructor)context_tp_dealloc,
766+
.tp_iter = context_tp_iter,
767+
.tp_dealloc = context_tp_dealloc,
768768
.tp_getattro = PyObject_GenericGetAttr,
769769
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
770770
.tp_richcompare = context_tp_richcompare,
771-
.tp_traverse = (traverseproc)context_tp_traverse,
772-
.tp_clear = (inquiry)context_tp_clear,
771+
.tp_traverse = context_tp_traverse,
772+
.tp_clear = context_tp_clear,
773773
.tp_new = context_tp_new,
774774
.tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist),
775775
.tp_hash = PyObject_HashNotImplemented,
@@ -909,6 +909,9 @@ class _contextvars.ContextVar "PyContextVar *" "&PyContextVar_Type"
909909
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/
910910

911911

912+
#define _PyContextVar_CAST(op) ((PyContextVar *)(op))
913+
914+
912915
static PyObject *
913916
contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
914917
{
@@ -926,8 +929,9 @@ contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
926929
}
927930

928931
static int
929-
contextvar_tp_clear(PyContextVar *self)
932+
contextvar_tp_clear(PyObject *op)
930933
{
934+
PyContextVar *self = _PyContextVar_CAST(op);
931935
Py_CLEAR(self->var_name);
932936
Py_CLEAR(self->var_default);
933937
#ifndef Py_GIL_DISABLED
@@ -939,30 +943,33 @@ contextvar_tp_clear(PyContextVar *self)
939943
}
940944

941945
static int
942-
contextvar_tp_traverse(PyContextVar *self, visitproc visit, void *arg)
946+
contextvar_tp_traverse(PyObject *op, visitproc visit, void *arg)
943947
{
948+
PyContextVar *self = _PyContextVar_CAST(op);
944949
Py_VISIT(self->var_name);
945950
Py_VISIT(self->var_default);
946951
return 0;
947952
}
948953

949954
static void
950-
contextvar_tp_dealloc(PyContextVar *self)
955+
contextvar_tp_dealloc(PyObject *self)
951956
{
952957
PyObject_GC_UnTrack(self);
953958
(void)contextvar_tp_clear(self);
954959
Py_TYPE(self)->tp_free(self);
955960
}
956961

957962
static Py_hash_t
958-
contextvar_tp_hash(PyContextVar *self)
963+
contextvar_tp_hash(PyObject *op)
959964
{
965+
PyContextVar *self = _PyContextVar_CAST(op);
960966
return self->var_hash;
961967
}
962968

963969
static PyObject *
964-
contextvar_tp_repr(PyContextVar *self)
970+
contextvar_tp_repr(PyObject *op)
965971
{
972+
PyContextVar *self = _PyContextVar_CAST(op);
966973
// Estimation based on the shortest name and default value,
967974
// but maximize the pointer size.
968975
// "<ContextVar name='a' at 0x1234567812345678>"
@@ -1106,15 +1113,15 @@ PyTypeObject PyContextVar_Type = {
11061113
sizeof(PyContextVar),
11071114
.tp_methods = PyContextVar_methods,
11081115
.tp_members = PyContextVar_members,
1109-
.tp_dealloc = (destructor)contextvar_tp_dealloc,
1116+
.tp_dealloc = contextvar_tp_dealloc,
11101117
.tp_getattro = PyObject_GenericGetAttr,
11111118
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1112-
.tp_traverse = (traverseproc)contextvar_tp_traverse,
1113-
.tp_clear = (inquiry)contextvar_tp_clear,
1119+
.tp_traverse = contextvar_tp_traverse,
1120+
.tp_clear = contextvar_tp_clear,
11141121
.tp_new = contextvar_tp_new,
11151122
.tp_free = PyObject_GC_Del,
1116-
.tp_hash = (hashfunc)contextvar_tp_hash,
1117-
.tp_repr = (reprfunc)contextvar_tp_repr,
1123+
.tp_hash = contextvar_tp_hash,
1124+
.tp_repr = contextvar_tp_repr,
11181125
};
11191126

11201127

@@ -1129,6 +1136,9 @@ class _contextvars.Token "PyContextToken *" "&PyContextToken_Type"
11291136
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/
11301137

11311138

1139+
#define _PyContextToken_CAST(op) ((PyContextToken *)(op))
1140+
1141+
11321142
static PyObject *
11331143
token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
11341144
{
@@ -1138,34 +1148,37 @@ token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
11381148
}
11391149

11401150
static int
1141-
token_tp_clear(PyContextToken *self)
1151+
token_tp_clear(PyObject *op)
11421152
{
1153+
PyContextToken *self = _PyContextToken_CAST(op);
11431154
Py_CLEAR(self->tok_ctx);
11441155
Py_CLEAR(self->tok_var);
11451156
Py_CLEAR(self->tok_oldval);
11461157
return 0;
11471158
}
11481159

11491160
static int
1150-
token_tp_traverse(PyContextToken *self, visitproc visit, void *arg)
1161+
token_tp_traverse(PyObject *op, visitproc visit, void *arg)
11511162
{
1163+
PyContextToken *self = _PyContextToken_CAST(op);
11521164
Py_VISIT(self->tok_ctx);
11531165
Py_VISIT(self->tok_var);
11541166
Py_VISIT(self->tok_oldval);
11551167
return 0;
11561168
}
11571169

11581170
static void
1159-
token_tp_dealloc(PyContextToken *self)
1171+
token_tp_dealloc(PyObject *self)
11601172
{
11611173
PyObject_GC_UnTrack(self);
11621174
(void)token_tp_clear(self);
11631175
Py_TYPE(self)->tp_free(self);
11641176
}
11651177

11661178
static PyObject *
1167-
token_tp_repr(PyContextToken *self)
1179+
token_tp_repr(PyObject *op)
11681180
{
1181+
PyContextToken *self = _PyContextToken_CAST(op);
11691182
PyUnicodeWriter *writer = PyUnicodeWriter_Create(0);
11701183
if (writer == NULL) {
11711184
return NULL;
@@ -1195,14 +1208,16 @@ token_tp_repr(PyContextToken *self)
11951208
}
11961209

11971210
static PyObject *
1198-
token_get_var(PyContextToken *self, void *Py_UNUSED(ignored))
1211+
token_get_var(PyObject *op, void *Py_UNUSED(ignored))
11991212
{
1213+
PyContextToken *self = _PyContextToken_CAST(op);
12001214
return Py_NewRef(self->tok_var);;
12011215
}
12021216

12031217
static PyObject *
1204-
token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored))
1218+
token_get_old_value(PyObject *op, void *Py_UNUSED(ignored))
12051219
{
1220+
PyContextToken *self = _PyContextToken_CAST(op);
12061221
if (self->tok_oldval == NULL) {
12071222
return get_token_missing();
12081223
}
@@ -1211,8 +1226,8 @@ token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored))
12111226
}
12121227

12131228
static PyGetSetDef PyContextTokenType_getsetlist[] = {
1214-
{"var", (getter)token_get_var, NULL, NULL},
1215-
{"old_value", (getter)token_get_old_value, NULL, NULL},
1229+
{"var", token_get_var, NULL, NULL},
1230+
{"old_value", token_get_old_value, NULL, NULL},
12161231
{NULL}
12171232
};
12181233

@@ -1228,15 +1243,15 @@ PyTypeObject PyContextToken_Type = {
12281243
sizeof(PyContextToken),
12291244
.tp_methods = PyContextTokenType_methods,
12301245
.tp_getset = PyContextTokenType_getsetlist,
1231-
.tp_dealloc = (destructor)token_tp_dealloc,
1246+
.tp_dealloc = token_tp_dealloc,
12321247
.tp_getattro = PyObject_GenericGetAttr,
12331248
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1234-
.tp_traverse = (traverseproc)token_tp_traverse,
1235-
.tp_clear = (inquiry)token_tp_clear,
1249+
.tp_traverse = token_tp_traverse,
1250+
.tp_clear = token_tp_clear,
12361251
.tp_new = token_tp_new,
12371252
.tp_free = PyObject_GC_Del,
12381253
.tp_hash = PyObject_HashNotImplemented,
1239-
.tp_repr = (reprfunc)token_tp_repr,
1254+
.tp_repr = token_tp_repr,
12401255
};
12411256

12421257
static PyContextToken *
@@ -1270,7 +1285,7 @@ context_token_missing_tp_repr(PyObject *self)
12701285
}
12711286

12721287
static void
1273-
context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self))
1288+
context_token_missing_tp_dealloc(PyObject *Py_UNUSED(self))
12741289
{
12751290
#ifdef Py_DEBUG
12761291
/* The singleton is statically allocated. */
@@ -1285,7 +1300,7 @@ PyTypeObject _PyContextTokenMissing_Type = {
12851300
PyVarObject_HEAD_INIT(&PyType_Type, 0)
12861301
"Token.MISSING",
12871302
sizeof(_PyContextTokenMissing),
1288-
.tp_dealloc = (destructor)context_token_missing_tp_dealloc,
1303+
.tp_dealloc = context_token_missing_tp_dealloc,
12891304
.tp_getattro = PyObject_GenericGetAttr,
12901305
.tp_flags = Py_TPFLAGS_DEFAULT,
12911306
.tp_repr = context_token_missing_tp_repr,

0 commit comments

Comments
 (0)