зеркало из https://github.com/github/ruby.git
Make io_fwrite safe for compaction
[Bug #20169] Embedded strings are not safe for system calls without the GVL because compaction can cause pages to be locked causing the operation to fail with EFAULT. This commit changes io_fwrite to use rb_str_tmp_frozen_no_embed_acquire, which guarantees that the return string is not embedded.
This commit is contained in:
Родитель
02c88477ce
Коммит
5e0c171451
|
@ -57,6 +57,7 @@ static inline VALUE rb_str_eql_internal(const VALUE str1, const VALUE str2);
|
|||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
/* string.c (export) */
|
||||
VALUE rb_str_tmp_frozen_acquire(VALUE str);
|
||||
VALUE rb_str_tmp_frozen_no_embed_acquire(VALUE str);
|
||||
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp);
|
||||
VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc);
|
||||
VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE);
|
||||
|
|
2
io.c
2
io.c
|
@ -1975,7 +1975,7 @@ io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
|
|||
if (converted)
|
||||
OBJ_FREEZE(str);
|
||||
|
||||
tmp = rb_str_tmp_frozen_acquire(str);
|
||||
tmp = rb_str_tmp_frozen_no_embed_acquire(str);
|
||||
RSTRING_GETMEM(tmp, ptr, len);
|
||||
n = io_binwrite(tmp, ptr, len, fptr, nosync);
|
||||
rb_str_tmp_frozen_release(str, tmp);
|
||||
|
|
36
string.c
36
string.c
|
@ -1341,6 +1341,42 @@ rb_str_tmp_frozen_acquire(VALUE orig)
|
|||
return str_new_frozen_buffer(0, orig, FALSE);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_str_tmp_frozen_no_embed_acquire(VALUE orig)
|
||||
{
|
||||
if (OBJ_FROZEN_RAW(orig) && !STR_EMBED_P(orig) && !rb_str_reembeddable_p(orig)) return orig;
|
||||
if (STR_SHARED_P(orig) && !STR_EMBED_P(RSTRING(orig)->as.heap.aux.shared)) return rb_str_tmp_frozen_acquire(orig);
|
||||
|
||||
VALUE str = str_alloc_heap(0);
|
||||
OBJ_FREEZE(str);
|
||||
/* Always set the STR_SHARED_ROOT to ensure it does not get re-embedded. */
|
||||
FL_SET(str, STR_SHARED_ROOT);
|
||||
|
||||
size_t capa = str_capacity(orig, TERM_LEN(orig));
|
||||
|
||||
/* If the string is embedded then we want to create a copy that is heap
|
||||
* allocated. If the string is shared then the shared root must be
|
||||
* embedded, so we want to create a copy. If the string is a shared root
|
||||
* then it must be embedded, so we want to create a copy. */
|
||||
if (STR_EMBED_P(orig) || FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT)) {
|
||||
RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(sizeof(char), capa, sizeof(char), TERM_LEN(orig));
|
||||
memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), capa);
|
||||
}
|
||||
else {
|
||||
/* orig must be heap allocated and not shared, so we can safely transfer
|
||||
* the pointer to str. */
|
||||
RSTRING(str)->as.heap.ptr = RSTRING(orig)->as.heap.ptr;
|
||||
RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
|
||||
RBASIC(orig)->flags &= ~STR_NOFREE;
|
||||
STR_SET_SHARED(orig, str);
|
||||
}
|
||||
|
||||
RSTRING(str)->len = RSTRING(orig)->len;
|
||||
RSTRING(str)->as.heap.aux.capa = capa;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче