gh-111178: fix UBSan failures in Python/hamt.c
(GH-128247)
* fix UBSan failures for `PyHamtObject` * fix UBSan failures for `PyHamtNode_Array` * fix UBSan failures for `PyHamtNode_Collision` * fix UBSan failures for `PyHamtNode_Bitmap`
This commit is contained in:
parent
74a517181a
commit
c22302ecea
174
Python/hamt.c
174
Python/hamt.c
@ -319,6 +319,8 @@ typedef struct {
|
||||
Py_ssize_t a_count;
|
||||
} PyHamtNode_Array;
|
||||
|
||||
#define _PyHamtNode_Array_CAST(op) ((PyHamtNode_Array *)(op))
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_VAR_HEAD
|
||||
@ -326,6 +328,8 @@ typedef struct {
|
||||
PyObject *c_array[1];
|
||||
} PyHamtNode_Collision;
|
||||
|
||||
#define _PyHamtNode_Collision_CAST(op) ((PyHamtNode_Collision *)(op))
|
||||
|
||||
|
||||
static PyHamtObject *
|
||||
hamt_alloc(void);
|
||||
@ -479,6 +483,8 @@ error:
|
||||
#endif /* Py_DEBUG */
|
||||
/////////////////////////////////// Bitmap Node
|
||||
|
||||
#define _PyHamtNode_Bitmap_CAST(op) ((PyHamtNode_Bitmap *)(op))
|
||||
|
||||
|
||||
static PyHamtNode *
|
||||
hamt_node_bitmap_new(Py_ssize_t size)
|
||||
@ -1083,30 +1089,27 @@ hamt_node_bitmap_find(PyHamtNode_Bitmap *self,
|
||||
}
|
||||
|
||||
static int
|
||||
hamt_node_bitmap_traverse(PyHamtNode_Bitmap *self, visitproc visit, void *arg)
|
||||
hamt_node_bitmap_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
/* Bitmap's tp_traverse */
|
||||
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = Py_SIZE(self); --i >= 0; ) {
|
||||
PyHamtNode_Bitmap *self = _PyHamtNode_Bitmap_CAST(op);
|
||||
for (Py_ssize_t i = Py_SIZE(self); --i >= 0;) {
|
||||
Py_VISIT(self->b_array[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self)
|
||||
hamt_node_bitmap_dealloc(PyObject *self)
|
||||
{
|
||||
/* Bitmap's tp_dealloc */
|
||||
|
||||
Py_ssize_t len = Py_SIZE(self);
|
||||
Py_ssize_t i;
|
||||
PyHamtNode_Bitmap *node = _PyHamtNode_Bitmap_CAST(self);
|
||||
Py_ssize_t i, len = Py_SIZE(self);
|
||||
|
||||
if (Py_SIZE(self) == 0) {
|
||||
if (len == 0) {
|
||||
/* The empty node is statically allocated. */
|
||||
assert(self == &_Py_SINGLETON(hamt_bitmap_node_empty));
|
||||
assert(node == &_Py_SINGLETON(hamt_bitmap_node_empty));
|
||||
#ifdef Py_DEBUG
|
||||
_Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton");
|
||||
#else
|
||||
@ -1120,11 +1123,11 @@ hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self)
|
||||
if (len > 0) {
|
||||
i = len;
|
||||
while (--i >= 0) {
|
||||
Py_XDECREF(self->b_array[i]);
|
||||
Py_XDECREF(node->b_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
@ -1489,38 +1492,30 @@ hamt_node_collision_find(PyHamtNode_Collision *self,
|
||||
|
||||
|
||||
static int
|
||||
hamt_node_collision_traverse(PyHamtNode_Collision *self,
|
||||
visitproc visit, void *arg)
|
||||
hamt_node_collision_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
/* Collision's tp_traverse */
|
||||
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = Py_SIZE(self); --i >= 0; ) {
|
||||
PyHamtNode_Collision *self = _PyHamtNode_Collision_CAST(op);
|
||||
for (Py_ssize_t i = Py_SIZE(self); --i >= 0; ) {
|
||||
Py_VISIT(self->c_array[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hamt_node_collision_dealloc(PyHamtNode_Collision *self)
|
||||
hamt_node_collision_dealloc(PyObject *self)
|
||||
{
|
||||
/* Collision's tp_dealloc */
|
||||
|
||||
Py_ssize_t len = Py_SIZE(self);
|
||||
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc)
|
||||
|
||||
if (len > 0) {
|
||||
|
||||
PyHamtNode_Collision *node = _PyHamtNode_Collision_CAST(self);
|
||||
while (--len >= 0) {
|
||||
Py_XDECREF(self->c_array[len]);
|
||||
Py_XDECREF(node->c_array[len]);
|
||||
}
|
||||
}
|
||||
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
@ -1868,35 +1863,27 @@ hamt_node_array_find(PyHamtNode_Array *self,
|
||||
}
|
||||
|
||||
static int
|
||||
hamt_node_array_traverse(PyHamtNode_Array *self,
|
||||
visitproc visit, void *arg)
|
||||
hamt_node_array_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
/* Array's tp_traverse */
|
||||
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
|
||||
PyHamtNode_Array *self = _PyHamtNode_Array_CAST(op);
|
||||
for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
|
||||
Py_VISIT(self->a_array[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hamt_node_array_dealloc(PyHamtNode_Array *self)
|
||||
hamt_node_array_dealloc(PyObject *self)
|
||||
{
|
||||
/* Array's tp_dealloc */
|
||||
|
||||
Py_ssize_t i;
|
||||
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc)
|
||||
|
||||
for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
|
||||
Py_XDECREF(self->a_array[i]);
|
||||
PyHamtNode_Array *obj = _PyHamtNode_Array_CAST(self);
|
||||
for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
|
||||
Py_XDECREF(obj->a_array[i]);
|
||||
}
|
||||
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
@ -2605,6 +2592,8 @@ static PyObject *
|
||||
hamt_dump(PyHamtObject *self);
|
||||
#endif
|
||||
|
||||
#define _PyHamtObject_CAST(op) ((PyHamtObject *)(op))
|
||||
|
||||
|
||||
static PyObject *
|
||||
hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
@ -2613,24 +2602,27 @@ hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
}
|
||||
|
||||
static int
|
||||
hamt_tp_clear(PyHamtObject *self)
|
||||
hamt_tp_clear(PyObject *op)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
Py_CLEAR(self->h_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hamt_tp_traverse(PyHamtObject *self, visitproc visit, void *arg)
|
||||
hamt_tp_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
Py_VISIT(self->h_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hamt_tp_dealloc(PyHamtObject *self)
|
||||
hamt_tp_dealloc(PyObject *self)
|
||||
{
|
||||
if (self == _empty_hamt) {
|
||||
PyHamtObject *obj = _PyHamtObject_CAST(self);
|
||||
if (obj == _empty_hamt) {
|
||||
/* The empty one is statically allocated. */
|
||||
#ifdef Py_DEBUG
|
||||
_Py_FatalRefcountError("deallocating the empty hamt singleton");
|
||||
@ -2640,8 +2632,8 @@ hamt_tp_dealloc(PyHamtObject *self)
|
||||
}
|
||||
|
||||
PyObject_GC_UnTrack(self);
|
||||
if (self->h_weakreflist != NULL) {
|
||||
PyObject_ClearWeakRefs((PyObject*)self);
|
||||
if (obj->h_weakreflist != NULL) {
|
||||
PyObject_ClearWeakRefs(self);
|
||||
}
|
||||
(void)hamt_tp_clear(self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
@ -2673,16 +2665,18 @@ hamt_tp_richcompare(PyObject *v, PyObject *w, int op)
|
||||
}
|
||||
|
||||
static int
|
||||
hamt_tp_contains(PyHamtObject *self, PyObject *key)
|
||||
hamt_tp_contains(PyObject *op, PyObject *key)
|
||||
{
|
||||
PyObject *val;
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_Find(self, key, &val);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_tp_subscript(PyHamtObject *self, PyObject *key)
|
||||
hamt_tp_subscript(PyObject *op, PyObject *key)
|
||||
{
|
||||
PyObject *val;
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
hamt_find_t res = hamt_find(self, key, &val);
|
||||
switch (res) {
|
||||
case F_ERROR:
|
||||
@ -2698,19 +2692,21 @@ hamt_tp_subscript(PyHamtObject *self, PyObject *key)
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
hamt_tp_len(PyHamtObject *self)
|
||||
hamt_tp_len(PyObject *op)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_Len(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_tp_iter(PyHamtObject *self)
|
||||
hamt_tp_iter(PyObject *op)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_NewIterKeys(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_set(PyHamtObject *self, PyObject *args)
|
||||
hamt_py_set(PyObject *op, PyObject *args)
|
||||
{
|
||||
PyObject *key;
|
||||
PyObject *val;
|
||||
@ -2719,11 +2715,12 @@ hamt_py_set(PyHamtObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return (PyObject *)_PyHamt_Assoc(self, key, val);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_get(PyHamtObject *self, PyObject *args)
|
||||
hamt_py_get(PyObject *op, PyObject *args)
|
||||
{
|
||||
PyObject *key;
|
||||
PyObject *def = NULL;
|
||||
@ -2733,6 +2730,7 @@ hamt_py_get(PyHamtObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
PyObject *val = NULL;
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
hamt_find_t res = hamt_find(self, key, &val);
|
||||
switch (res) {
|
||||
case F_ERROR:
|
||||
@ -2750,67 +2748,63 @@ hamt_py_get(PyHamtObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_delete(PyHamtObject *self, PyObject *key)
|
||||
hamt_py_delete(PyObject *op, PyObject *key)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return (PyObject *)_PyHamt_Without(self, key);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_items(PyHamtObject *self, PyObject *args)
|
||||
hamt_py_items(PyObject *op, PyObject *args)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_NewIterItems(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_values(PyHamtObject *self, PyObject *args)
|
||||
hamt_py_values(PyObject *op, PyObject *args)
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_NewIterValues(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args))
|
||||
hamt_py_keys(PyObject *op, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return _PyHamt_NewIterKeys(self);
|
||||
}
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
static PyObject *
|
||||
hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args))
|
||||
hamt_py_dump(PyObject *op, PyObject *Py_UNUSED(args))
|
||||
{
|
||||
PyHamtObject *self = _PyHamtObject_CAST(op);
|
||||
return hamt_dump(self);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static PyMethodDef PyHamt_methods[] = {
|
||||
{"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL},
|
||||
{"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL},
|
||||
{"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL},
|
||||
{"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL},
|
||||
{"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL},
|
||||
{"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL},
|
||||
{"set", hamt_py_set, METH_VARARGS, NULL},
|
||||
{"get", hamt_py_get, METH_VARARGS, NULL},
|
||||
{"delete", hamt_py_delete, METH_O, NULL},
|
||||
{"items", hamt_py_items, METH_NOARGS, NULL},
|
||||
{"keys", hamt_py_keys, METH_NOARGS, NULL},
|
||||
{"values", hamt_py_values, METH_NOARGS, NULL},
|
||||
#ifdef Py_DEBUG
|
||||
{"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL},
|
||||
{"__dump__", hamt_py_dump, METH_NOARGS, NULL},
|
||||
#endif
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PySequenceMethods PyHamt_as_sequence = {
|
||||
0, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
0, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
(objobjproc)hamt_tp_contains, /* sq_contains */
|
||||
0, /* sq_inplace_concat */
|
||||
0, /* sq_inplace_repeat */
|
||||
.sq_contains = hamt_tp_contains,
|
||||
};
|
||||
|
||||
static PyMappingMethods PyHamt_as_mapping = {
|
||||
(lenfunc)hamt_tp_len, /* mp_length */
|
||||
(binaryfunc)hamt_tp_subscript, /* mp_subscript */
|
||||
.mp_length = hamt_tp_len,
|
||||
.mp_subscript = hamt_tp_subscript,
|
||||
};
|
||||
|
||||
PyTypeObject _PyHamt_Type = {
|
||||
@ -2820,13 +2814,13 @@ PyTypeObject _PyHamt_Type = {
|
||||
.tp_methods = PyHamt_methods,
|
||||
.tp_as_mapping = &PyHamt_as_mapping,
|
||||
.tp_as_sequence = &PyHamt_as_sequence,
|
||||
.tp_iter = (getiterfunc)hamt_tp_iter,
|
||||
.tp_dealloc = (destructor)hamt_tp_dealloc,
|
||||
.tp_iter = hamt_tp_iter,
|
||||
.tp_dealloc = hamt_tp_dealloc,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_richcompare = hamt_tp_richcompare,
|
||||
.tp_traverse = (traverseproc)hamt_tp_traverse,
|
||||
.tp_clear = (inquiry)hamt_tp_clear,
|
||||
.tp_traverse = hamt_tp_traverse,
|
||||
.tp_clear = hamt_tp_clear,
|
||||
.tp_new = hamt_tp_new,
|
||||
.tp_weaklistoffset = offsetof(PyHamtObject, h_weakreflist),
|
||||
.tp_hash = PyObject_HashNotImplemented,
|
||||
@ -2841,10 +2835,10 @@ PyTypeObject _PyHamt_ArrayNode_Type = {
|
||||
"hamt_array_node",
|
||||
sizeof(PyHamtNode_Array),
|
||||
0,
|
||||
.tp_dealloc = (destructor)hamt_node_array_dealloc,
|
||||
.tp_dealloc = hamt_node_array_dealloc,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)hamt_node_array_traverse,
|
||||
.tp_traverse = hamt_node_array_traverse,
|
||||
.tp_free = PyObject_GC_Del,
|
||||
.tp_hash = PyObject_HashNotImplemented,
|
||||
};
|
||||
@ -2854,10 +2848,10 @@ PyTypeObject _PyHamt_BitmapNode_Type = {
|
||||
"hamt_bitmap_node",
|
||||
sizeof(PyHamtNode_Bitmap) - sizeof(PyObject *),
|
||||
sizeof(PyObject *),
|
||||
.tp_dealloc = (destructor)hamt_node_bitmap_dealloc,
|
||||
.tp_dealloc = hamt_node_bitmap_dealloc,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)hamt_node_bitmap_traverse,
|
||||
.tp_traverse = hamt_node_bitmap_traverse,
|
||||
.tp_free = PyObject_GC_Del,
|
||||
.tp_hash = PyObject_HashNotImplemented,
|
||||
};
|
||||
@ -2867,10 +2861,10 @@ PyTypeObject _PyHamt_CollisionNode_Type = {
|
||||
"hamt_collision_node",
|
||||
sizeof(PyHamtNode_Collision) - sizeof(PyObject *),
|
||||
sizeof(PyObject *),
|
||||
.tp_dealloc = (destructor)hamt_node_collision_dealloc,
|
||||
.tp_dealloc = hamt_node_collision_dealloc,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)hamt_node_collision_traverse,
|
||||
.tp_traverse = hamt_node_collision_traverse,
|
||||
.tp_free = PyObject_GC_Del,
|
||||
.tp_hash = PyObject_HashNotImplemented,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user