Skip to content

[BUG]: pybind11's initialization of internals needs to be made more thread safe in the presence of free threading #5316

Open
@EthanSteinberg

Description

@EthanSteinberg

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

a1d0091

Problem description

PYBIND11_NOINLINE internals &get_internals() {
is not thread safe under free-threading.

internals is a global singleton struct shared across all pybind11 modules. get_internals() either retrieves that current global singleton or creates a new one.

The problem is double initialization, where two copies of internals would be created by multiple modules being imported/initalized in different threads.

if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) {
internals_pp = get_internals_pp_from_capsule(internals_obj);
}
if (internals_pp && *internals_pp) {
// We loaded the internals through `state_dict`, which means that our `error_already_set`
are the key problematic lines where we retrieve the current global, and initialize it if necessary.

The problem is that if two threads hit those lines at the same time, both threads could see that internals is null and both threads could initialize internals, which would lead to two copies.

Currently this is protected via the GIL (https://github.com/pybind/pybind11/blob/master/include/pybind11/detail/internals.h#L505), but that is problematic with the new python free threading setup.

In the short term this is still OK because the GIL is re-enabled during module import, but that is not a good long term strategy.

Reproducible example code

No response

Is this a regression? Put the last known working version here if it is.

Not a regression

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions