Skip to content

Commit ed74a25

Browse files
Fix Tools/gdb/libpython.py
Backport 11659d0 into this change instead of leaving it a separate followup change.
1 parent 2173bb8 commit ed74a25

4 files changed

Lines changed: 18 additions & 25 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed clang ubsan (undefined behavior sanitizer) warnings in dictobject.c by
2+
adjusting how the internal struct _dictkeysobject shared keys structure is
3+
declared.

Objects/dict-common.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,8 @@ struct _dictkeysobject {
5959
- 4 bytes if dk_size <= 0xffffffff (int32_t*)
6060
- 8 bytes otherwise (int64_t*)
6161
62-
Dynamically sized, 8 is minimum. */
63-
union {
64-
int8_t as_1[8];
65-
int16_t as_2[4];
66-
int32_t as_4[2];
67-
#if SIZEOF_VOID_P > 4
68-
int64_t as_8[1];
69-
#endif
70-
} dk_indices;
62+
Dynamically sized, SIZEOF_VOID_P is minimum. */
63+
char dk_indices[]; /* char is required to avoid strict aliasing. */
7164

7265
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
7366
see the DK_ENTRIES() macro */

Objects/dictobject.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ PyDict_Fini(void)
300300
2 : sizeof(int32_t))
301301
#endif
302302
#define DK_ENTRIES(dk) \
303-
((PyDictKeyEntry*)(&(dk)->dk_indices.as_1[DK_SIZE(dk) * DK_IXSIZE(dk)]))
303+
((PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)]))
304304

305305
#define DK_DEBUG_INCREF _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA
306306
#define DK_DEBUG_DECREF _Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA
@@ -318,21 +318,21 @@ dk_get_index(PyDictKeysObject *keys, Py_ssize_t i)
318318
Py_ssize_t ix;
319319

320320
if (s <= 0xff) {
321-
int8_t *indices = keys->dk_indices.as_1;
321+
int8_t *indices = (int8_t*)(keys->dk_indices);
322322
ix = indices[i];
323323
}
324324
else if (s <= 0xffff) {
325-
int16_t *indices = keys->dk_indices.as_2;
325+
int16_t *indices = (int16_t*)(keys->dk_indices);
326326
ix = indices[i];
327327
}
328328
#if SIZEOF_VOID_P > 4
329329
else if (s > 0xffffffff) {
330-
int64_t *indices = keys->dk_indices.as_8;
330+
int64_t *indices = (int64_t*)(keys->dk_indices);
331331
ix = indices[i];
332332
}
333333
#endif
334334
else {
335-
int32_t *indices = keys->dk_indices.as_4;
335+
int32_t *indices = (int32_t*)(keys->dk_indices);
336336
ix = indices[i];
337337
}
338338
assert(ix >= DKIX_DUMMY);
@@ -348,23 +348,23 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
348348
assert(ix >= DKIX_DUMMY);
349349

350350
if (s <= 0xff) {
351-
int8_t *indices = keys->dk_indices.as_1;
351+
int8_t *indices = (int8_t*)(keys->dk_indices);
352352
assert(ix <= 0x7f);
353353
indices[i] = (char)ix;
354354
}
355355
else if (s <= 0xffff) {
356-
int16_t *indices = keys->dk_indices.as_2;
356+
int16_t *indices = (int16_t*)(keys->dk_indices);
357357
assert(ix <= 0x7fff);
358358
indices[i] = (int16_t)ix;
359359
}
360360
#if SIZEOF_VOID_P > 4
361361
else if (s > 0xffffffff) {
362-
int64_t *indices = keys->dk_indices.as_8;
362+
int64_t *indices = (int64_t*)(keys->dk_indices);
363363
indices[i] = ix;
364364
}
365365
#endif
366366
else {
367-
int32_t *indices = keys->dk_indices.as_4;
367+
int32_t *indices = (int32_t*)(keys->dk_indices);
368368
assert(ix <= 0x7fffffff);
369369
indices[i] = (int32_t)ix;
370370
}
@@ -424,8 +424,8 @@ static PyDictKeysObject empty_keys_struct = {
424424
lookdict_split, /* dk_lookup */
425425
0, /* dk_usable (immutable) */
426426
0, /* dk_nentries */
427-
.dk_indices = { .as_1 = {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
428-
DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}},
427+
{DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
428+
DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
429429
};
430430

431431
static PyObject *empty_values[1] = { NULL };
@@ -533,7 +533,6 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
533533
}
534534
else {
535535
dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
536-
- Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
537536
+ es * size
538537
+ sizeof(PyDictKeyEntry) * usable);
539538
if (dk == NULL) {
@@ -546,7 +545,7 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
546545
dk->dk_usable = usable;
547546
dk->dk_lookup = lookdict_unicode_nodummy;
548547
dk->dk_nentries = 0;
549-
memset(&dk->dk_indices.as_1[0], 0xff, es * size);
548+
memset(&dk->dk_indices[0], 0xff, es * size);
550549
memset(DK_ENTRIES(dk), 0, sizeof(PyDictKeyEntry) * usable);
551550
return dk;
552551
}
@@ -3086,7 +3085,6 @@ _PyDict_SizeOf(PyDictObject *mp)
30863085
in the type object. */
30873086
if (mp->ma_keys->dk_refcnt == 1)
30883087
res += (sizeof(PyDictKeysObject)
3089-
- Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
30903088
+ DK_IXSIZE(mp->ma_keys) * size
30913089
+ sizeof(PyDictKeyEntry) * usable);
30923090
return res;
@@ -3096,7 +3094,6 @@ Py_ssize_t
30963094
_PyDict_KeysSize(PyDictKeysObject *keys)
30973095
{
30983096
return (sizeof(PyDictKeysObject)
3099-
- Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
31003097
+ DK_IXSIZE(keys) * DK_SIZE(keys)
31013098
+ USABLE_FRACTION(DK_SIZE(keys)) * sizeof(PyDictKeyEntry));
31023099
}

Tools/gdb/libpython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ def _get_entries(self, keys):
736736
else:
737737
offset = 8 * dk_size
738738

739-
ent_addr = keys['dk_indices']['as_1'].address
739+
ent_addr = keys['dk_indices'].address
740740
ent_addr = ent_addr.cast(_type_unsigned_char_ptr()) + offset
741741
ent_ptr_t = gdb.lookup_type('PyDictKeyEntry').pointer()
742742
ent_addr = ent_addr.cast(ent_ptr_t)

0 commit comments

Comments
 (0)