Fix a race condition with interned strings sweeping.

[Bug #21172]

This fixes a rare CI failure.

The timeline of the race condition is:

- A `"foo" oid=1` string is interned.
- `"foo" oid=1` is no longer referenced and will be swept in the future.
- Another `"foo" oid=2` string is interned.
- `register_fstring` finds `"foo" oid=1`, but since it is about to be swept,
  removes it from `fstring_table` and insert `"foo" oid=2` instead.
- `"foo" oid=1` is swept, since it has the `RSTRING_FSTR` flag,
  a `st_delete` is issued in `fstring_table` which removes `"foo" oid=2`.

I don't know how to reproduce this bug consistently in a single test
case.
This commit is contained in:
Jean Boussier 2025-03-05 17:29:32 +01:00
parent 53579e5718
commit c224ca4fea
Notes: git 2025-03-05 17:57:39 +00:00

View File

@ -433,6 +433,10 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int exist
if (rb_objspace_garbage_object_p(str)) {
arg->fstr = Qundef;
// When RSTRING_FSTR strings are swept, they call `st_delete`.
// To avoid a race condition if an equivalent string was inserted
// we must remove the flag immediately.
FL_UNSET_RAW(str, RSTRING_FSTR);
return ST_DELETE;
}