Skip to content

Commit f460ce7

Browse files
committed
Update rb_check_typeddata to check inherited types
1 parent 1e29461 commit f460ce7

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

spec/ruby/optional/capi/ext/typed_data_spec.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,18 @@ VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) {
148148
return Qnil;
149149
}
150150

151+
VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) {
152+
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
153+
}
154+
155+
VALUE sws_typed_rb_check_typeddata_same_type_parent(VALUE self, VALUE obj) {
156+
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_parent_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
157+
}
158+
159+
VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
160+
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
161+
}
162+
151163
void Init_typed_data_spec(void) {
152164
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
153165
rb_define_alloc_func(cls, sdaf_alloc_typed_func);
@@ -160,6 +172,9 @@ void Init_typed_data_spec(void) {
160172
rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1);
161173
rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1);
162174
rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2);
175+
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
176+
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
177+
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
163178
}
164179

165180
#ifdef __cplusplus

spec/ruby/optional/capi/typed_data_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,21 @@
5757
@s.typed_get_struct_data_ptr(a).should == 1024
5858
end
5959
end
60+
61+
describe "rb_check_typeddata" do
62+
it "returns data pointer when the struct has the given type" do
63+
a = @s.typed_wrap_struct(1024)
64+
@s.rb_check_typeddata_same_type(a).should == true
65+
end
66+
67+
it "returns data pointer when the parent struct has the given type" do
68+
a = @s.typed_wrap_struct(1024)
69+
@s.rb_check_typeddata_same_type_parent(a).should == true
70+
end
71+
72+
it "raises an error for different types" do
73+
a = @s.typed_wrap_struct(1024)
74+
-> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
75+
end
76+
end
6077
end

src/main/c/cext/data.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ VALUE rb_data_typed_object_make(VALUE ruby_class, const rb_data_type_t *type, vo
3636

3737
void *rb_check_typeddata(VALUE value, const rb_data_type_t *data_type) {
3838
struct RTypedData* typed_data = RTYPEDDATA(value);
39-
if (typed_data->type != data_type) {
40-
rb_raise(rb_eTypeError, "wrong argument type");
39+
// NOTE: this function is used on every access to typed data so it should remain fast.
40+
// RB_TYPE_P(value, T_DATA) is already checked by `RTYPEDDATA(value)`, see Truffle::CExt.RDATA().
41+
// RTYPEDDATA_P(value) is already checked implicitly by `typed_data->type` which would return `nil` if not `RTYPEDDATA_P`.
42+
if (!rb_typeddata_inherited_p(typed_data->type, data_type)) {
43+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)", rb_obj_class(value), data_type->wrap_struct_name);
4144
}
4245
return typed_data->data;
4346
}

0 commit comments

Comments
 (0)