summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorNARUSE, Yui <naruse@airemix.jp>2021-02-01 21:42:11 +0900
committerNARUSE, Yui <naruse@airemix.jp>2021-02-01 21:42:11 +0900
commit74f90b46a9f21e8ef6e01bebad9dc00f420f8cec (patch)
treeecf34fd502c5d7a2c30168c06a0570a76898c11a /compile.c
parentd1fb0a39537d4536869921383ee2a223cc6dfac9 (diff)
merge revision(s) efcdf68e6443ab70fbff1703b9dabbfc5090df31,5e26619660f20272a53c7f839dde36cce034bb35: [Backport #17539]
Guard callinfo Callinfo was being written in to an array and the GC would not see the reference on the stack. `new_insn_send` creates a new callinfo object, then it calls `new_insn_core`. `new_insn_core` allocates a new INSN linked list item, which can end up calling `xmalloc` which will trigger a GC: https://github.com/ruby/ruby/blob/70cd351c7c71c48ee18d7c01e851a89614086f8f/compile.c#L968-L969 Since the callinfo object isn't on the stack, the GC won't see it, and it can get collected. This patch just refactors `new_insn_send` to keep the object on the stack Co-authored-by: John Hawthorn <john@hawthorn.email> --- compile.c | 7 +++++-- test/ruby/test_gc.rb | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) Fix WB for callinfo The WB for callinfo needs to be executed *after* the reference is written. Otherwise we get a WB miss. --- compile.c | 1 + 1 file changed, 1 insertion(+)
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/compile.c b/compile.c
index c29d42e433..c62deafd23 100644
--- a/compile.c
+++ b/compile.c
@@ -1302,12 +1302,16 @@ static INSN *
new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
{
VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
- operands[0] = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
+ VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
+ operands[0] = ci;
operands[1] = (VALUE)blockiseq;
if (blockiseq) {
RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
}
- return new_insn_core(iseq, line_no, BIN(send), 2, operands);
+ INSN *insn = new_insn_core(iseq, line_no, BIN(send), 2, operands);
+ RB_OBJ_WRITTEN(iseq, Qundef, ci);
+ RB_GC_GUARD(ci);
+ return insn;
}
static rb_iseq_t *