[前][次][番号順一覧][スレッド一覧]

ruby-changes:65970

From: Yusuke <ko1@a...>
Date: Mon, 26 Apr 2021 22:47:12 +0900 (JST)
Subject: [ruby-changes:65970] 2c7d3b3a72 (master): node.c (rb_ast_new): imemo_ast is WB-unprotected

https://git.ruby-lang.org/ruby.git/commit/?id=2c7d3b3a72

From 2c7d3b3a722c4636ab1e9d289cbca47ddd168d3e Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@r...>
Date: Mon, 26 Apr 2021 18:11:46 +0900
Subject: node.c (rb_ast_new): imemo_ast is WB-unprotected

Previously imemo_ast was handled as WB-protected which caused a segfault
of the following code:

    # shareable_constant_value: literal
    M0 = {}
    M1 = {}
    ...
    M100000 = {}

My analysis is here: `shareable_constant_value: literal` creates many
Hash instances during parsing, and add them to node_buffer of imemo_ast.
However, the contents are missed because imemo_ast is incorrectly
WB-protected.

This changeset makes imemo_ast as WB-unprotected.
---
 gc.c                 | 7 +++++++
 internal/imemo.h     | 1 +
 node.c               | 2 +-
 test/ruby/test_gc.rb | 7 +++++++
 4 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/gc.c b/gc.c
index 4d78b85..c7e9754 100644
--- a/gc.c
+++ b/gc.c
@@ -2435,6 +2435,13 @@ rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0) https://github.com/ruby/ruby/blob/trunk/gc.c#L2435
     return newobj_of(v0, flags, v1, v2, v3, TRUE);
 }
 
+rb_ast_t *
+rb_imemo_ast_new(VALUE node_buffer)
+{
+    VALUE flags = T_IMEMO | (imemo_ast << FL_USHIFT);
+    return (rb_ast_t *)newobj_of(node_buffer, flags, 0, 0, 0, FALSE);
+}
+
 static VALUE
 rb_imemo_tmpbuf_new(VALUE v1, VALUE v2, VALUE v3, VALUE v0)
 {
diff --git a/internal/imemo.h b/internal/imemo.h
index a9e2136..102356c 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -130,6 +130,7 @@ struct MEMO { https://github.com/ruby/ruby/blob/trunk/internal/imemo.h#L130
 
 typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
 VALUE rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0);
+struct rb_ast_struct *rb_imemo_ast_new(VALUE node_buffer);
 rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
 struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
 void rb_strterm_mark(VALUE obj);
diff --git a/node.c b/node.c
index bef9d7b..2392d5b 100644
--- a/node.c
+++ b/node.c
@@ -1299,7 +1299,7 @@ rb_ast_t * https://github.com/ruby/ruby/blob/trunk/node.c#L1299
 rb_ast_new(void)
 {
     node_buffer_t *nb = rb_node_buffer_new();
-    rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, (VALUE)nb);
+    rb_ast_t *ast = rb_imemo_ast_new((VALUE)nb);
     return ast;
 }
 
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index 1f75a34..f10946b 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -494,4 +494,11 @@ class TestGc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_gc.rb#L494
     b = 1000.times.map { Object.new.object_id }
     assert_empty(a & b)
   end
+
+  def test_ast_node_buffer
+    # https://github.com/ruby/ruby/pull/4416
+    Module.new.class_eval do
+      eval((["# shareable_constant_value: literal"] + (0..100000).map {|i| "M#{ i } = {}" }).join("\n"))
+    end
+  end
 end
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]