summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Valentine-House <matt@eightbitraptor.com>2022-09-28 14:45:43 +0100
committerPeter Zhu <peter@peterzhu.ca>2022-09-29 09:22:14 -0400
commit892f350a7db4d2cc99c5061d2e74498dfc4809ca (patch)
treeffd0183981305e3de2bd339e4363e6e5471ef7dc
parent4ced7bfb235353aacd24e3d40cd832af59df6e97 (diff)
[Bug #19029] Don't start GC during compaction
RARRAY_PTR when called with a transient array detransients the array before returning its pointer which allocates in the heap. Because RARRAY_PTR was being used during compaction (when re-embedding arrays that have moved between size pools) this introduces the possibility that we can hit a malloc threshold, triggering GC, while in the middle of compaction. We should avoid this by using safer functions to get hold of the pointer. Since we know that the array is not embedded here, we can use ARY_HEAP_PTR and ARY_EMBED_PTR directly
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6466
-rw-r--r--array.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/array.c b/array.c
index 793a53f17b..cacc549a24 100644
--- a/array.c
+++ b/array.c
@@ -505,15 +505,19 @@ rb_ary_make_embedded(VALUE ary)
{
assert(rb_ary_embeddable_p(ary));
if (!ARY_EMBED_P(ary)) {
- VALUE *buf = RARRAY_PTR(ary);
- long len = RARRAY_LEN(ary);
+ const VALUE *buf = ARY_HEAP_PTR(ary);
+ long len = ARY_HEAP_LEN(ary);
+ bool was_transient = RARRAY_TRANSIENT_P(ary);
+ // FL_SET_EMBED also unsets the transient flag
FL_SET_EMBED(ary);
ARY_SET_EMBED_LEN(ary, len);
- RARY_TRANSIENT_UNSET(ary);
- memmove(RARRAY_PTR(ary), buf, len * sizeof(VALUE));
- ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ MEMCPY((void *)ARY_EMBED_PTR(ary), (void *)buf, VALUE, len);
+
+ if (!was_transient) {
+ ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ }
}
}