Skip to content

Add locks around accesses/modifications to global encodings table #13600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

luke-gruber
Copy link
Contributor

@luke-gruber luke-gruber commented Jun 12, 2025

Add locks around accesses/modifications to global encodings table

This fixes segfaults and errors of the type "Encoding not found" when
using encoding-related methods and internal encoding c functions across
ractors.

Example of a possible segfault in release mode or assertion error in debug mode:

rs = []
100.times do
  rs << Ractor.new do
    "abc".force_encoding(Encoding.list.shuffle.first)
  end
end
while rs.any?
  r, obj = Ractor.select(*rs)
  rs.delete(r)
end

@zzak
Copy link
Member

zzak commented Jun 16, 2025

Could you add a test and/or reproduction case?

Was there a ticket associated with this PR?

@jhawthorn
Copy link
Member

Could you add a test and/or reproduction case?

It tends to be difficult to make reliable reproductions to concurrency issues, and at the moment all Ractor tests need an assert_separately, which is less than desirable. It's better to make things safe based on correct design and in this case it's pretty obvious that we'll need to hold a lock to read or write to a global st_table (and the ASSERT_GLOBAL_ENC_TABLE_LOCKED added ensure this won't regress)

Was there a ticket associated with this PR?

As Ractors are experimental and there are many issues we aren't necessarily filing tickets as the fixes will not be backported.

@zzak
Copy link
Member

zzak commented Jun 16, 2025

Cool just checking, I saw this and thought neat but there was no bug associated or other context, so wasn't sure if it was ready for review or not. 🙏

@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch from 7792937 to 79c7b72 Compare June 17, 2025 17:32
@luke-gruber
Copy link
Contributor Author

@zzak Sorry yeah, I added a test that is fairly reproducible.

@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch 3 times, most recently from 463dbb2 to 7311646 Compare June 17, 2025 18:17

This comment has been minimized.

@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch 2 times, most recently from cffea2b to 528cb55 Compare June 24, 2025 01:18
@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch 4 times, most recently from ede6622 to 1a546d6 Compare June 25, 2025 16:45
@luke-gruber
Copy link
Contributor Author

luke-gruber commented Jun 25, 2025

@jhawthorn This is ready for a review now 😅

@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch from 1a546d6 to 65a6473 Compare June 25, 2025 17:38
encoding.c Outdated
else {
return rb_locale_encoding();
rb_encoding *enc = NULL;
// TODO: make lock-free
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would it take to do this? I think we call these really a lot, and rb_enc_from_index only needs to lock in cases where the encoding is not one of the three fastpaths.

If it helps, I think it would be fine if we took a VM barrier to change internal or external encoding.

(ditto for internal encoding)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's called quite a bit. I don't think it should be hard, I'll try to do it in this PR. I'll add a new commit so you can review it easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhawthorn It's ready for review again. It turns out more than just the tbl->names stuff needs to be locked, because autoloading of encodings can happen inside ractors, which can call certain functions. However, the most-used encoding functions can still be without locks.

@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch from 57a7108 to 5cb6457 Compare June 30, 2025 16:03
This fixes segfaults and errors of the type "Encoding not found" when
using encoding-related methods and internal encoding c functions across
ractors.

Example of a possible segfault in release mode or assertion error in debug mode:

```ruby
rs = []
100.times do
  rs << Ractor.new do
    "abc".force_encoding(Encoding.list.shuffle.first)
  end
end
while rs.any?
  r, obj = Ractor.select(*rs)
  rs.delete(r)
end
```
@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch 2 times, most recently from eb0e332 to 3974143 Compare June 30, 2025 17:24
Also, make sure autoloading of encodings is safe across ractors.
@luke-gruber luke-gruber force-pushed the ractor_encoding_add_locks branch from 3974143 to 382c281 Compare June 30, 2025 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants