1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
From 3e07c20277cda90941953426f7bddc71d009388a Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Tue, 16 Jul 2024 15:42:49 +0200
Subject: [PATCH] [3.12] gh-113993: For string interning, do not rely on (or
assert) _Py_IsImmortal (GH-121358) (GH-121851)
gh-113993: For string interning, do not rely on (or assert) _Py_IsImmortal (GH-121358)
Older stable ABI extensions are allowed to make immortal objects mortal.
Instead, use `_PyUnicode_STATE` (`interned` and `statically_allocated`).
(cherry picked from commit 956270d08d5c23f59937e2f29f8e0b7f63d68afd)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
---
...024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst | 2 ++
Objects/unicodeobject.c | 16 ++++++++++------
2 files changed, 12 insertions(+), 6 deletions(-)
create mode 100644 Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 815747e1b1ed9c..7bd4b221c83cf7 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -257,7 +257,8 @@ _PyUnicode_InternedSize_Immortal(void)
// value, to help detect bugs in optimizations.
while (PyDict_Next(dict, &pos, &key, &value)) {
- if (_Py_IsImmortal(key)) {
+ assert(PyUnicode_CHECK_INTERNED(key) != SSTATE_INTERNED_IMMORTAL_STATIC);
+ if (PyUnicode_CHECK_INTERNED(key) == SSTATE_INTERNED_IMMORTAL) {
count++;
}
}
@@ -691,10 +692,14 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
/* Check interning state */
#ifdef Py_DEBUG
+ // Note that we do not check `_Py_IsImmortal(op)`, since stable ABI
+ // extensions can make immortal strings mortal (but with a high enough
+ // refcount).
+ // The other way is extremely unlikely (worth a potential failed assertion
+ // in a debug build), so we do check `!_Py_IsImmortal(op)`.
switch (PyUnicode_CHECK_INTERNED(op)) {
case SSTATE_NOT_INTERNED:
if (ascii->state.statically_allocated) {
- CHECK(_Py_IsImmortal(op));
// This state is for two exceptions:
// - strings are currently checked before they're interned
// - the 256 one-latin1-character strings
@@ -710,11 +715,9 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
break;
case SSTATE_INTERNED_IMMORTAL:
CHECK(!ascii->state.statically_allocated);
- CHECK(_Py_IsImmortal(op));
break;
case SSTATE_INTERNED_IMMORTAL_STATIC:
CHECK(ascii->state.statically_allocated);
- CHECK(_Py_IsImmortal(op));
break;
default:
Py_UNREACHABLE();
@@ -1899,7 +1902,8 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index,
static PyObject*
get_latin1_char(Py_UCS1 ch)
{
- return Py_NewRef(LATIN1(ch));
+ PyObject *o = LATIN1(ch);
+ return o;
}
static PyObject*
@@ -15015,7 +15019,7 @@ intern_common(PyInterpreterState *interp, PyObject *s /* stolen */,
{
PyObject *r = (PyObject *)_Py_hashtable_get(INTERNED_STRINGS, s);
if (r != NULL) {
- assert(_Py_IsImmortal(r));
+ assert(_PyUnicode_STATE(r).statically_allocated);
assert(r != s); // r must be statically_allocated; s is not
Py_DECREF(s);
return Py_NewRef(r);
|