Skip to content

Commit 354ad9e

Browse files
committed
[GR-11888] Fix arity checking and NULL arguments to rb_scan_args to match MRI.
PullRequest: truffleruby/732
2 parents 344d8ea + 1879477 commit 354ad9e

File tree

5 files changed

+47
-22
lines changed

5 files changed

+47
-22
lines changed

lib/cext/include/truffleruby/truffleruby.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ MUST_INLINE int rb_tr_scan_args(int argc, VALUE *argv, const char *format, VALUE
228228
const char *formatp = format;
229229
int pre = 0;
230230
int optional = 0;
231+
int n_mand = 0;
232+
int n_opt = 0;
231233
bool rest;
232234
int post = 0;
233235
bool kwargs;
@@ -281,6 +283,9 @@ MUST_INLINE int rb_tr_scan_args(int argc, VALUE *argv, const char *format, VALUE
281283
rb_raise(rb_eArgError, "not enough arguments for required");
282284
}
283285

286+
n_mand = pre + post;
287+
n_opt = optional;
288+
284289
// Read arguments
285290

286291
int argn = 0;
@@ -360,26 +365,30 @@ MUST_INLINE int rb_tr_scan_args(int argc, VALUE *argv, const char *format, VALUE
360365
// Don't assign the correct v to a temporary VALUE* and then assign arg to it - this doesn't optimise well
361366

362367
switch (valuen) {
363-
case 1: *v1 = arg; break;
364-
case 2: *v2 = arg; break;
365-
case 3: *v3 = arg; break;
366-
case 4: *v4 = arg; break;
367-
case 5: *v5 = arg; break;
368-
case 6: *v6 = arg; break;
369-
case 7: *v7 = arg; break;
370-
case 8: *v8 = arg; break;
371-
case 9: *v9 = arg; break;
372-
case 10: *v10 = arg; break;
368+
case 1: if (v1 != NULL) { *v1 = arg; } break;
369+
case 2: if (v2 != NULL) { *v2 = arg; } break;
370+
case 3: if (v3 != NULL) { *v3 = arg; } break;
371+
case 4: if (v4 != NULL) { *v4 = arg; } break;
372+
case 5: if (v5 != NULL) { *v5 = arg; } break;
373+
case 6: if (v6 != NULL) { *v6 = arg; } break;
374+
case 7: if (v7 != NULL) { *v7 = arg; } break;
375+
case 8: if (v8 != NULL) { *v8 = arg; } break;
376+
case 9: if (v9 != NULL) { *v9 = arg; } break;
377+
case 10: if (v10 != NULL) { *v10 = arg; } break;
373378
}
374379

375380
valuen++;
376381
}
377382

378383
if (found_kwargs) {
379-
return argc - 1;
380-
} else {
381-
return argc;
384+
argc = argc - 1;
382385
}
386+
387+
if (argn < argc) {
388+
rb_error_arity(argc, n_mand, rest ? UNLIMITED_ARGUMENTS : n_mand + n_opt);
389+
}
390+
391+
return argc;
383392
}
384393

385394
#if defined(__cplusplus)

lib/truffle/truffle/cext.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,10 @@ def rb_check_arity(arg_count, min, max)
11421142
Truffle::Type.check_arity arg_count, min, max
11431143
end
11441144

1145+
def rb_arity_error_string(arg_count, min, max)
1146+
Truffle::Type.arity_error_string(arg_count, min, max)
1147+
end
1148+
11451149
def rb_raise(object, name)
11461150
raise 'not implemented'
11471151
end

spec/ruby/optional/capi/util_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
lambda { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError)
2424
end
2525

26+
it "raises an ArgumentError if there are too many arguments" do
27+
lambda { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should raise_error(ArgumentError)
28+
end
29+
2630
it "assigns the required and optional arguments scanned" do
2731
@o.rb_scan_args([1, 2], "11", 2, @acc).should == 2
2832
ScratchPad.recorded.should == [1, 2]

src/main/c/cext/ruby.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3468,6 +3468,11 @@ VALUE rb_enum_values_pack(int argc, const VALUE *argv) {
34683468
rb_tr_error("rb_enum_values_pack not implemented");
34693469
}
34703470

3471+
3472+
NORETURN(void rb_error_arity(int argc, int min, int max)) {
3473+
rb_exc_raise(rb_exc_new3(rb_eArgError, rb_tr_wrap(polyglot_invoke(RUBY_CEXT, "rb_arity_error_string", argc, min, max))));
3474+
}
3475+
34713476
void rb_error_untrusted(VALUE obj) {
34723477
rb_tr_error("rb_error_untrusted not implemented");
34733478
}

src/main/ruby/core/type.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -611,15 +611,18 @@ def self.object_respond_to_marshal_load?(obj)
611611

612612
def self.check_arity(arg_count, min, max)
613613
if arg_count < min || (max != -1 && arg_count > max)
614-
error_message = case
615-
when min == max
616-
'wrong number of arguments (given %d, expected %d)' % [arg_count, min]
617-
when max == -1
618-
'wrong number of arguments (given %d, expected %d+)' % [arg_count, min]
619-
else
620-
'wrong number of arguments (given %d, expected %d..%d)' % [arg_count, min, max]
621-
end
622-
raise ArgumentError, error_message
614+
raise ArgumentError, arity_error_string(arg_count, min, max)
615+
end
616+
end
617+
618+
def self.arity_error_string(arg_count, min, max)
619+
case
620+
when min == max
621+
'wrong number of arguments (given %d, expected %d)' % [arg_count, min]
622+
when max == -1
623+
'wrong number of arguments (given %d, expected %d+)' % [arg_count, min]
624+
else
625+
'wrong number of arguments (given %d, expected %d..%d)' % [arg_count, min, max]
623626
end
624627
end
625628

0 commit comments

Comments
 (0)