self.assertTrue(globals["func1"]() is globals["func2"]())
+ @cpython_only
+ def test_unusual_constants(self):
+ # gh-130851: Code objects constructed with constants that are not
+ # types generated by the bytecode compiler should not crash the
+ # interpreter.
+ class Unhashable:
+ def __hash__(self):
+ raise TypeError("unhashable type")
+
+ class MyInt(int):
+ pass
+
+ code = compile("a = 1", "<string>", "exec")
+ code = code.replace(co_consts=(1, Unhashable(), MyInt(1), MyInt(1)))
+ self.assertIsInstance(code.co_consts[1], Unhashable)
+ self.assertEqual(code.co_consts[2], code.co_consts[3])
+
class CodeWeakRefTest(unittest.TestCase):
_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;
}
}
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) {
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;
}
}
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;
}