-
Notifications
You must be signed in to change notification settings - Fork 1
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
Ruby assertion causing panic with shared strings #85
Comments
In the past, I thought a non-embedded string must have a non-NULL strbuf. But that may be a mistake. The old documentation said that So the policy of the
So the only case where |
This shouldn't happen. If the non-embedded string is not shared, or if it is shared but the shared root is not embedded, then it must have a non-null |
By the way, by default Immix does not move all objects. It only does "opportunistic" defragmentation, i.e. (1) it only does defragmentation if the heap is very full, and (2) even when doing defragmentation, it only moves the most fragmented blocks, and stop defragmenting if it has moved 2% of the full heap size. However, you can override this behavior and force Immix to do defragmentation in every GC and move as many objects as possible by hacking mmtk-core itself. See the instructions in https://github.com/mmtk/mmtk-core/blob/160b7702fccda133c9407234821ad35103623179/src/policy/immix/mod.rs#L20-L43 |
@wks this all makes sense. So indeed we're seeing a bug. @eileencodes it sounds like we should be able to add that assertion in the "update references" code. IOW, when we're updating references, if the string isn't embedded or it is pointing to a non-embedded root, it must have a reference to a tmpbuf reference. My guess is that somewhere we're making shared strings that don't have the tmpbuf set. Adding assertions like this should help us track it down. |
I found a special case. If a string is created using And if a string is shared, and the shared root has |
In CI (and locally) we were seeing a failed assertion for the `test_gem_remote_fetcher` test. After much debugging it was clear that for this test the strbuf was missing on `shared` so when `orig` moved, `shared` didn't follow`. This caused the offset to be very off. ``` Assertion Failed: string.c:1805:str_new_frozen_buffer:ofs >= 0 ruby 3.4.0dev (2024-08-09T19:42:38Z reproduction-for-s.. a5b29b5277) +MMTk(Immix) [arm64-darwin23] ``` With a `GC_ASSERT` we tracked down a missing `rb_mmtk_str_set_strbuf` in `rb_str_tmp_frozen_no_embed_acquire`. After fixing that case a standard string like `"hi"` would still fail the `GC_ASSERT`. This is because we also need to return early if the `new_root` of a shared object has the `STR_NOFREE` flag. In those cases, the object does not have a strbuf to copy. After these changes, both the `test_string.rb` and `test_gem_remote_fetcher.rb` tests pass. Fixes: #85
I've been debugging a panic that I can easily reproduce on my macos machine. I've whittled the reproduction down and what appears to be happening is that in
rb_mmtk_gc_ref_update_string
the original string is moved but shared string object stays put. In this scenario we've noticed that while the original object has it's underlying buffer the shared object entersrb_mmtk_gc_ref_update_string
with no buffer.After some more debugging and testing we also found that in other cases (unrelated to this particular test) that very often strings are missing their underlying buffer. So we're wondering, if a string is not embedded should it always have an underlying buffer? IE should this assertion always pass:
We're seeing this not true but aren't sure that the string should always have an underlying buffer (if it's not embedded).
Here's the test I've been running. Note I set the max heap to 1gb because it reproduces more often with a smaller amount of memory. This also only happens on Immix because the object is moving.
You can use this branch which has the test stripped down to the minimum https://github.com/mmtk/ruby/compare/mmtk...eileencodes:ruby:reproduction-for-str-size?expand=1
The assertion that's failing is here which expects the difference between
orig
andshared
to be equal to or greater than0
but instead we have a negative number (becauseorig
moved andshared
didn't follow:ruby/string.c
Lines 1775 to 1783 in 8082532
Here's some of the stacktrace with the debugging info (notes added by me):
cc/ @tenderlove @wks
The text was updated successfully, but these errors were encountered: