mirror of
https://github.com/python/cpython
synced 2024-09-06 03:03:36 +00:00
![Gregory P. Smith](/assets/img/avatar_default.png)
Fix clang ubsan (undefined behavior sanitizer) warnings in dictobject.c by adjusting how the internal struct _dictkeysobject shared keys structure is declared. This remains ABI compatible. We get rid of the union at the end of the struct being used for conveinence to avoid typecasting in favor of char[] variable length array at the end of a struct. This is known to clang to be used for variable sized objects and will not cause an undefined behavior problem. Similarly, char arrays do not have strict aliasing undefined behavior when cast. PEP-007 does not currently list variable length arrays (VLAs) as allowed in our subset of C99. If this turns out to be a problem, the fix to this is to change the char `dk_indices[]` into `dk_indices[1]` and restore the three size computation subtractions this change removes: `- Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)` If this works as is I'll make a separate PR to update PEP-007.
69 lines
2.2 KiB
C
69 lines
2.2 KiB
C
#ifndef Py_DICT_COMMON_H
|
|
#define Py_DICT_COMMON_H
|
|
|
|
typedef struct {
|
|
/* Cached hash code of me_key. */
|
|
Py_hash_t me_hash;
|
|
PyObject *me_key;
|
|
PyObject *me_value; /* This field is only meaningful for combined tables */
|
|
} PyDictKeyEntry;
|
|
|
|
/* dict_lookup_func() returns index of entry which can be used like DK_ENTRIES(dk)[index].
|
|
* -1 when no entry found, -3 when compare raises error.
|
|
*/
|
|
typedef Py_ssize_t (*dict_lookup_func)
|
|
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
|
|
|
|
#define DKIX_EMPTY (-1)
|
|
#define DKIX_DUMMY (-2) /* Used internally */
|
|
#define DKIX_ERROR (-3)
|
|
|
|
/* See dictobject.c for actual layout of DictKeysObject */
|
|
struct _dictkeysobject {
|
|
Py_ssize_t dk_refcnt;
|
|
|
|
/* Size of the hash table (dk_indices). It must be a power of 2. */
|
|
Py_ssize_t dk_size;
|
|
|
|
/* Function to lookup in the hash table (dk_indices):
|
|
|
|
- lookdict(): general-purpose, and may return DKIX_ERROR if (and
|
|
only if) a comparison raises an exception.
|
|
|
|
- lookdict_unicode(): specialized to Unicode string keys, comparison of
|
|
which can never raise an exception; that function can never return
|
|
DKIX_ERROR.
|
|
|
|
- lookdict_unicode_nodummy(): similar to lookdict_unicode() but further
|
|
specialized for Unicode string keys that cannot be the <dummy> value.
|
|
|
|
- lookdict_split(): Version of lookdict() for split tables. */
|
|
dict_lookup_func dk_lookup;
|
|
|
|
/* Number of usable entries in dk_entries. */
|
|
Py_ssize_t dk_usable;
|
|
|
|
/* Number of used entries in dk_entries. */
|
|
Py_ssize_t dk_nentries;
|
|
|
|
/* Actual hash table of dk_size entries. It holds indices in dk_entries,
|
|
or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
|
|
|
|
Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).
|
|
|
|
The size in bytes of an indice depends on dk_size:
|
|
|
|
- 1 byte if dk_size <= 0xff (char*)
|
|
- 2 bytes if dk_size <= 0xffff (int16_t*)
|
|
- 4 bytes if dk_size <= 0xffffffff (int32_t*)
|
|
- 8 bytes otherwise (int64_t*)
|
|
|
|
Dynamically sized, SIZEOF_VOID_P is minimum. */
|
|
char dk_indices[]; /* char is required to avoid strict aliasing. */
|
|
|
|
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
|
|
see the DK_ENTRIES() macro */
|
|
};
|
|
|
|
#endif
|