summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2024-11-03 09:27:59 +0100
committerJean Boussier <[email protected]>2024-11-05 18:00:36 +0100
commited22e6837941b429538cff5c8110b2caf2634474 (patch)
tree5c086bcd4f9f867e0579a8a7c76fc54202efec93
parent241a03483c7eecfba008500df78716eb083d808b (diff)
[ruby/json] JSON::Ext::Parser mark the name cache entries when not on the heap
This is somewhat dead code as unless you are using `JSON::Parser.new` direcltly we never allocate `JSON::Ext::Parser` anymore. But still, we should mark all its reference in case some code out there uses that. Followup: #675 https://github.com/ruby/json/commit/8bf74a977b
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12003
-rw-r--r--ext/json/parser/extconf.rb5
-rw-r--r--ext/json/parser/parser.c15
-rw-r--r--ext/json/parser/parser.rl15
-rw-r--r--test/json/json_ext_parser_test.rb20
-rw-r--r--test/json/test_helper.rb18
5 files changed, 70 insertions, 3 deletions
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index 8705884127..c3c23d2cb4 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,9 +1,8 @@
# frozen_string_literal: true
require 'mkmf'
-have_func("rb_enc_raise", "ruby.h")
-have_func("rb_enc_interned_str", "ruby.h")
-
+have_func("rb_enc_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
+have_func("rb_gc_mark_locations") # Missing on TruffleRuby
append_cflags("-std=c99")
create_makefile 'json/ext/parser'
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index cdf8983a77..758dba4694 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -2115,6 +2115,19 @@ case 9:
}
}
+#ifndef HAVE_RB_GC_MARK_LOCATIONS
+// For TruffleRuby
+void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
+{
+ VALUE *value = start;
+
+ while (value < end) {
+ rb_gc_mark(*value);
+ value++;
+ }
+}
+#endif
+
static void JSON_mark(void *ptr)
{
JSON_Parser *json = ptr;
@@ -2124,6 +2137,8 @@ static void JSON_mark(void *ptr)
rb_gc_mark(json->array_class);
rb_gc_mark(json->decimal_class);
rb_gc_mark(json->match_string);
+ const VALUE *name_cache_entries = &json->name_cache.entries[0];
+ rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length);
}
static void JSON_free(void *ptr)
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 3301f1608c..15ec2b6843 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -875,6 +875,19 @@ static VALUE cParser_parse(VALUE self)
}
}
+#ifndef HAVE_RB_GC_MARK_LOCATIONS
+// For TruffleRuby
+void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
+{
+ VALUE *value = start;
+
+ while (value < end) {
+ rb_gc_mark(*value);
+ value++;
+ }
+}
+#endif
+
static void JSON_mark(void *ptr)
{
JSON_Parser *json = ptr;
@@ -884,6 +897,8 @@ static void JSON_mark(void *ptr)
rb_gc_mark(json->array_class);
rb_gc_mark(json->decimal_class);
rb_gc_mark(json->match_string);
+ const VALUE *name_cache_entries = &json->name_cache.entries[0];
+ rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length);
}
static void JSON_free(void *ptr)
diff --git a/test/json/json_ext_parser_test.rb b/test/json/json_ext_parser_test.rb
index ff6598f490..9db8ae772f 100644
--- a/test/json/json_ext_parser_test.rb
+++ b/test/json/json_ext_parser_test.rb
@@ -27,6 +27,26 @@ class JSONExtParserTest < Test::Unit::TestCase
assert_equal "unexpected token at 'NaN'", ex.message
end
+ if GC.respond_to?(:stress=)
+ def test_gc_stress_parser_new
+ payload = JSON.dump([{ foo: 1, bar: 2, baz: 3, egg: { spam: 4 } }] * 10)
+
+ previous_stress = GC.stress
+ JSON::Parser.new(payload).parse
+ ensure
+ GC.stress = previous_stress
+ end
+
+ def test_gc_stress
+ payload = JSON.dump([{ foo: 1, bar: 2, baz: 3, egg: { spam: 4 } }] * 10)
+
+ previous_stress = GC.stress
+ JSON.parse(payload)
+ ensure
+ GC.stress = previous_stress
+ end
+ end
+
def parse(json)
JSON::Ext::Parser.new(json).parse
end
diff --git a/test/json/test_helper.rb b/test/json/test_helper.rb
index 7bff9b3391..6fcb76edf8 100644
--- a/test/json/test_helper.rb
+++ b/test/json/test_helper.rb
@@ -19,6 +19,24 @@ begin
rescue LoadError
end
+if GC.respond_to?(:verify_compaction_references)
+ # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
+ # move objects around, helping to find object movement bugs.
+ begin
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
+ rescue NotImplementedError
+ # Some platforms don't support compaction
+ end
+end
+
+if GC.respond_to?(:auto_compact=)
+ begin
+ GC.auto_compact = true
+ rescue NotImplementedError
+ # Some platforms don't support compaction
+ end
+end
+
unless defined?(Test::Unit::CoreAssertions)
require "core_assertions"
Test::Unit::TestCase.include Test::Unit::CoreAssertions