Skip to content

Commit

Permalink
pythongh-111971: Make _PyUnicode_FromId thread-safe in --disable-gil
Browse files Browse the repository at this point in the history
  • Loading branch information
corona10 committed Dec 26, 2023
1 parent 36adc79 commit 4644f71
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 5 deletions.
6 changes: 5 additions & 1 deletion Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,17 @@ typedef struct _Py_Identifier {
// Index in PyInterpreterState.unicode.ids.array. It is process-wide
// unique and must be initialized to -1.
Py_ssize_t index;
// Hidden PyMutex struct for non free-threaded build.
struct {
uint8_t v;
} mutex;
} _Py_Identifier;

#ifndef Py_BUILD_CORE
// For now we are keeping _Py_IDENTIFIER for continued use
// in non-builtin extensions (and naughty PyPI modules).

#define _Py_static_string_init(value) { .string = (value), .index = -1 }
#define _Py_static_string_init(value) { .string = (value), .index = -1, mutex = 0 }
#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)

Expand Down
11 changes: 7 additions & 4 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1897,6 +1897,7 @@ PyUnicode_FromString(const char *u)
PyObject *
_PyUnicode_FromId(_Py_Identifier *id)
{
PyMutex_Lock((PyMutex *)&id->mutex);
PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_unicode_ids *ids = &interp->unicode.ids;

Expand All @@ -1923,14 +1924,14 @@ _PyUnicode_FromId(_Py_Identifier *id)
obj = ids->array[index];
if (obj) {
// Return a borrowed reference
return obj;
goto end;
}
}

obj = PyUnicode_DecodeUTF8Stateful(id->string, strlen(id->string),
NULL, NULL);
if (!obj) {
return NULL;
goto end;
}
PyUnicode_InternInPlace(&obj);

Expand All @@ -1941,7 +1942,8 @@ _PyUnicode_FromId(_Py_Identifier *id)
PyObject **new_array = PyMem_Realloc(ids->array, new_size * item_size);
if (new_array == NULL) {
PyErr_NoMemory();
return NULL;
obj = NULL;
goto end;
}
memset(&new_array[ids->size], 0, (new_size - ids->size) * item_size);
ids->array = new_array;
Expand All @@ -1951,11 +1953,12 @@ _PyUnicode_FromId(_Py_Identifier *id)
// The array stores a strong reference
ids->array[index] = obj;

end:
PyMutex_Unlock((PyMutex *)&id->mutex);
// Return a borrowed reference
return obj;
}


static void
unicode_clear_identifiers(struct _Py_unicode_state *state)
{
Expand Down
1 change: 1 addition & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,7 @@ static int test_unicode_id_init(void)
static _Py_Identifier PyId_test_unicode_id_init = {
.string = "test_unicode_id_init",
.index = -1,
.mutex = 0,
};

// Initialize Python once without using the identifier
Expand Down

0 comments on commit 4644f71

Please sign in to comment.