[3.13] gh-130851: Don't crash when deduping unusual code constants (GH-130853) (#130880)

The bytecode compiler only generates a few different types of constants,
like str, int, tuple, slices, etc. Users can construct code objects with
various unusual constants, including ones that are not hashable or not
even constant.

The free threaded build previously crashed with a fatal error when
confronted with these constants. Instead, treat distinct objects of
otherwise unhandled types as not equal for the purposes of deduplication.
(cherry picked from commit 2905690a91)

Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-03-05 21:22:57 +01:00 committed by GitHub
parent 39f7b06d35
commit e285232c76
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 6 deletions

View file

@ -2527,6 +2527,7 @@ intern_one_constant(PyObject *op)
_Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(consts, op);
if (entry == NULL) {
if (_Py_hashtable_set(consts, op, op) != 0) {
PyErr_NoMemory();
return NULL;
}
@ -2548,7 +2549,8 @@ intern_one_constant(PyObject *op)
}
static int
compare_constants(const void *key1, const void *key2) {
compare_constants(const void *key1, const void *key2)
{
PyObject *op1 = (PyObject *)key1;
PyObject *op2 = (PyObject *)key2;
if (op1 == op2) {
@ -2608,8 +2610,8 @@ compare_constants(const void *key1, const void *key2) {
Py_complex c2 = ((PyComplexObject *)op2)->cval;
return memcmp(&c1, &c2, sizeof(Py_complex)) == 0;
}
_Py_FatalErrorFormat("unexpected type in compare_constants: %s",
Py_TYPE(op1)->tp_name);
// gh-130851: Treat instances of unexpected types as distinct if they are
// not the same object.
return 0;
}
@ -2629,9 +2631,13 @@ hash_const(const void *key)
}
Py_hash_t h = PyObject_Hash(op);
if (h == -1) {
// This should never happen: all the constants we support have
// infallible hash functions.
Py_FatalError("code: hash failed");
// gh-130851: Other than slice objects, every constant that the
// bytecode compiler generates is hashable. However, users can
// provide their own constants, when constructing code objects via
// types.CodeType(). If the user-provided constant is unhashable, we
// use the memory address of the object as a fallback hash value.
PyErr_Clear();
return (Py_uhash_t)(uintptr_t)key;
}
return (Py_uhash_t)h;
}