-
Notifications
You must be signed in to change notification settings - Fork 5.6k
[Bug #20998] Check if the string is frozen in rb_str_locktmp() & rb_str_unlocktmp() #13615
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
Conversation
|
I have reviewed the usages in CRuby, and all seem fine in that they should raise FrozenError anyway if given a frozen String. Except the usage in Line 499 in 32737f8
IO::Buffer.for("str".freeze) { p 1 } gives FrozenError when it was fine before, so I'll change the code to skip the rb_str_locktmp() if the string is frozen.I ran both test-all and test-spec and neither found this, so it seems IO::Buffer lacks some test coverage. cc @ioquatix |
|
Actually I'm not sure what is the right behavior there, is there a valid use case to use |
…locktmp in that case
|
I need some time to review this change. |
|
OK, FWIW, I'm confident this change in IO::Buffer is correct, because the only thing that locking a string does is prevent mutations, e.g. as tested in ruby/test/ruby/test_io_buffer.rb Lines 114 to 122 in c88c231
But a frozen string already cannot be mutated, so freezing is stronger than locking and the locking is then redundant. |
|
Ah I've seen https://bugs.ruby-lang.org/issues/20998#note-16. Maybe there is an explicit function to mark a String as shouldn't be moved by GC? |
|
In
The entire point is to prevent another thread from causing the string to be reallocated (tampering the receiver). |
If you want to avoid GC compaction moving the string, you have to pin it. To do that |
|
@ioquatix The way I read that comment, it says the freeze mechanism (= .freeze) is as good as rb_str_locktmp().
Freezing already prevents that, it prevents all mutations.
|
|
I would like to know under which circumstances the For example the char* of a String cannot move "at any time", most C extension code relies on it not moving, and the GC is not able to patch the I guess the only cases the char* of a String can change are:
In our case for IO::Buffer it refers directly to the char* in Line 53 in 0ca2b8e
without getting it out of the String at usages. So relying on the String VALUE to be on stack doesn't work.
In my understanding, I'm not changing anything about GC compaction here, IO::Buffer and |
|
I think with that last comment it's clear that GC compaction + IO::Buffer is an orthogonal issue to this change, and this change doesn't make it any worse. In short, It's good that made us think about GC compaction though, there might be a pre-existing bug there, and if so it would be worth opening an issue to track and fix it. |
That is correct.
Any allocation my trigger GC, regardless if whether it was triggered from C or Ruby code.
Yes, in general any mutating
That is correct too. |
https://bugs.ruby-lang.org/issues/20998