Skip to content

Commit 3550148

Browse files
committed
Fix usage of rb_struct_initialize() to pass an Array of members values and not a Hash
* rb_struct_initialize() does not accept a Hash, and it's very brittle to pass `[{...}]` and to rely on that C function using rb_keyword_given_p(). It basically worked accidentally, by having **members in the caller of the caller. Such logic when Struct#initialize is defined in Ruby (as in TruffleRuby) is basically impossible to implement, because it's incorrectly treating positional arguments as keyword arguments. * rb_struct_initialize() is used in CRuby to set members of Data instances in marshal.c (there is no rb_data_initialize() yet). There, the code passes an Array of members values for Data (and for Struct which are not `keyword_init: true`): https://github.com/ruby/ruby/blob/48c7f349f68846e10d60ae77ad299a38ee014479/marshal.c#L2150-L2176 So we should do the same in psych. * Rename to init_data since it's only used for Data. * See #692 (comment).
1 parent 0297c55 commit 3550148

File tree

3 files changed

+6
-8
lines changed

3 files changed

+6
-8
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
2727
os: [ ubuntu-latest, macos-latest, windows-latest ]
2828
include:
29-
# jruby is broken with "undefined method 'init_struct'"
29+
# jruby is broken with "undefined method 'init_data'"
3030
# https://github.com/ruby/psych/actions/runs/15434465445/job/43438083198?pr=734
3131
- { os: windows-latest, ruby: jruby-head }
3232
- { os: macos-latest, ruby: jruby-head }

ext/psych/psych_to_ruby.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@ static VALUE path2class(VALUE self, VALUE path)
2424
return rb_path_to_class(path);
2525
}
2626

27-
static VALUE init_struct(VALUE self, VALUE data, VALUE attrs)
27+
static VALUE init_data(VALUE self, VALUE data, VALUE values)
2828
{
29-
VALUE args = rb_ary_new2(1);
30-
rb_ary_push(args, attrs);
31-
rb_struct_initialize(data, args);
32-
29+
rb_struct_initialize(data, values);
3330
return data;
3431
}
3532

@@ -42,7 +39,7 @@ void Init_psych_to_ruby(void)
4239
VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
4340
cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
4441

45-
rb_define_private_method(cPsychVisitorsToRuby, "init_struct", init_struct, 2);
42+
rb_define_private_method(cPsychVisitorsToRuby, "init_data", init_data, 2);
4643
rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
4744
rb_define_private_method(class_loader, "path2class", path2class, 1);
4845
}

lib/psych/visitors/to_ruby.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ def visit_Psych_Nodes_Mapping o
219219
revive_data_members(members, o)
220220
end
221221
data ||= allocate_anon_data(o, members)
222-
init_struct(data, **members)
222+
values = data.members.map { |m| members[m] }
223+
init_data(data, values)
223224
data.freeze
224225
data
225226

0 commit comments

Comments
 (0)