Skip to content

Commit c9bc716

Browse files
luke-gruberjhawthorn
authored andcommitted
Get String#crypt working with multi-ractor in cases where !HAVE_CRYPT_R
In commit 12f7ba5, ractor safety was added to String#crypt, however in certain cases it can cause a deadlock. When we lock a native mutex, we cannot allocate ruby objects because they might trigger GC which starts a VM barrier. If the barrier is triggered and other native threads are waiting on this mutex, they will not be able to be woken up in order to join the barrier. To fix this, we don't allocate ruby objects when we hold the lock. The following could reproduce the problem: ```ruby strings = [] 10_000.times do |i| strings << "my string #{i}" end STRINGS = Ractor.make_shareable(strings) rs = [] 100.times do rs << Ractor.new do STRINGS.each do |s| s.dup.crypt(s.dup) end end end while rs.any? r, obj = Ractor.select(*rs) rs.delete(r) end ``` I will not be adding tests because I am almost finished a PR to enable running test-all test cases inside many ractors at once, which is how I found the issue. Co-authored-by: jhawthorn <john@hawthorn.email>
1 parent 7c35d85 commit c9bc716

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

string.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11262,8 +11262,15 @@ rb_str_crypt(VALUE str, VALUE salt)
1126211262
CRYPT_END();
1126311263
rb_syserr_fail(err, "crypt");
1126411264
}
11265-
result = rb_str_new_cstr(res);
11265+
11266+
size_t res_size = strlen(res)+1;
11267+
char *dup = malloc(res_size); // need to hold onto lock while duplicating a potentially static buffer
11268+
memcpy(dup, res, res_size);
1126611269
CRYPT_END();
11270+
// Don't allocate a ruby object while holding this lock, we could hit a VM barrier, which
11271+
// causes a deadlock if other ractors are waiting on this lock.
11272+
result = rb_str_new_cstr(dup);
11273+
free(dup);
1126711274
return result;
1126811275
}
1126911276

0 commit comments

Comments
 (0)