diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-07-11 19:20:53 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-07-11 20:04:29 +0900 |
commit | 3e7d002118a92fad5934e11c75be6768a1476c1b (patch) | |
tree | e9f437327b5c743622a97c092ddadc2d99cb0bc5 | |
parent | cd069df36596d9bf7a6db8aaa0dcefdafb233a91 (diff) |
Check exception flag as a bool [Bug #15987]
-rw-r--r-- | complex.c | 8 | ||||
-rw-r--r-- | ext/bigdecimal/bigdecimal.c | 12 | ||||
-rw-r--r-- | ext/bigdecimal/extconf.rb | 1 | ||||
-rw-r--r-- | internal.h | 4 | ||||
-rw-r--r-- | io.c | 36 | ||||
-rw-r--r-- | object.c | 29 | ||||
-rw-r--r-- | rational.c | 8 | ||||
-rw-r--r-- | test/ruby/test_complex.rb | 6 | ||||
-rw-r--r-- | test/ruby/test_float.rb | 6 | ||||
-rw-r--r-- | test/ruby/test_integer.rb | 6 | ||||
-rw-r--r-- | test/ruby/test_io.rb | 12 | ||||
-rw-r--r-- | test/ruby/test_rational.rb | 6 |
12 files changed, 92 insertions, 42 deletions
@@ -477,13 +477,7 @@ nucomp_f_complex(int argc, VALUE *argv, VALUE klass) a2 = Qundef; } if (!NIL_P(opts)) { - static ID kwds[1]; - VALUE exception; - if (!kwds[0]) { - kwds[0] = idException; - } - rb_get_kwargs(opts, kwds, 0, 1, &exception); - raise = (exception != Qfalse); + raise = rb_opts_exception_p(opts, raise); } return nucomp_convert(rb_cComplex, a1, a2, raise); } diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index da1b24a631..430707a4d6 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -2560,6 +2560,10 @@ BigDecimal_clone(VALUE self) return self; } +#ifdef HAVE_RB_OPTS_EXCEPTION_P +int rb_opts_exception_p(VALUE opts, int default_value); +#define opts_exception_p(opts) rb_opts_exception_p((opts), 1) +#else static int opts_exception_p(VALUE opts) { @@ -2569,8 +2573,16 @@ opts_exception_p(VALUE opts) kwds[0] = rb_intern_const("exception"); } rb_get_kwargs(opts, kwds, 0, 1, &exception); + switch (exception) { + case Qtrue: case Qfalse: + break; + default: + rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE, + flagname, obj); + } return exception != Qfalse; } +#endif static Real * BigDecimal_new(int argc, VALUE *argv) diff --git a/ext/bigdecimal/extconf.rb b/ext/bigdecimal/extconf.rb index a6a36304cc..7a7af10a2d 100644 --- a/ext/bigdecimal/extconf.rb +++ b/ext/bigdecimal/extconf.rb @@ -27,6 +27,7 @@ have_func("rb_rational_num", "ruby.h") have_func("rb_rational_den", "ruby.h") have_func("rb_array_const_ptr", "ruby.h") have_func("rb_sym2str", "ruby.h") +have_func("rb_opts_exception_p", "ruby.h") if File.file?(File.expand_path('../lib/bigdecimal.rb', __FILE__)) bigdecimal_rb = "$(srcdir)/lib/bigdecimal.rb" diff --git a/internal.h b/internal.h index f2c9e9a814..4f9c5b1475 100644 --- a/internal.h +++ b/internal.h @@ -1891,6 +1891,7 @@ VALUE rb_immutable_obj_clone(int, VALUE *, VALUE); VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); VALUE rb_convert_type_with_id(VALUE,int,const char*,ID); VALUE rb_check_convert_type_with_id(VALUE,int,const char*,ID); +int rb_bool_expected(VALUE, const char *); struct RBasicRaw { VALUE flags; @@ -2349,6 +2350,9 @@ void rb_write_error_str(VALUE mesg); /* numeric.c (export) */ VALUE rb_int_positive_pow(long x, unsigned long y); +/* object.c (export) */ +int rb_opts_exception_p(VALUE opts, int default_value); + /* process.c (export) */ int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen); rb_pid_t rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds, char *errmsg, size_t errmsg_buflen); @@ -171,7 +171,6 @@ VALUE rb_default_rs; static VALUE argf; -#define id_exception idException static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding; static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args; static VALUE sym_textmode, sym_binmode, sym_autoclose; @@ -2793,18 +2792,10 @@ read_internal_locktmp(VALUE str, struct io_internal_read_struct *iis) return (long)rb_str_locktmp_ensure(str, read_internal_call, (VALUE)iis); } -static int -no_exception_p(VALUE opts) -{ - VALUE except; - ID id = id_exception; - - rb_get_kwargs(opts, &id, 0, 1, &except); - return except == Qfalse; -} +#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE) static VALUE -io_getpartial(int argc, VALUE *argv, VALUE io, VALUE opts, int nonblock) +io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock) { rb_io_t *fptr; VALUE length, str; @@ -2846,7 +2837,7 @@ io_getpartial(int argc, VALUE *argv, VALUE io, VALUE opts, int nonblock) if (!nonblock && fptr_wait_readable(fptr)) goto again; if (nonblock && (e == EWOULDBLOCK || e == EAGAIN)) { - if (no_exception_p(opts)) + if (no_exception) return sym_wait_readable; else rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, @@ -2940,9 +2931,9 @@ io_readpartial(int argc, VALUE *argv, VALUE io) } static VALUE -io_nonblock_eof(VALUE opts) +io_nonblock_eof(int no_exception) { - if (!no_exception_p(opts)) { + if (!no_exception) { rb_eof_error(); } return Qnil; @@ -2963,6 +2954,8 @@ io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex) shrinkable = io_setstrbuf(&str, len); OBJ_TAINT(str); + rb_bool_expected(ex, "exception"); + GetOpenFile(io, fptr); rb_io_check_byte_readable(fptr); @@ -2981,7 +2974,7 @@ io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex) if (n < 0) { int e = errno; if ((e == EWOULDBLOCK || e == EAGAIN)) { - if (ex == Qfalse) return sym_wait_readable; + if (!ex) return sym_wait_readable; rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "read would block"); } @@ -2991,7 +2984,7 @@ io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex) io_set_read_length(str, n, shrinkable); if (n == 0) { - if (ex == Qfalse) return Qnil; + if (!ex) return Qnil; rb_eof_error(); } @@ -3007,6 +3000,7 @@ io_write_nonblock(VALUE io, VALUE str, VALUE ex) if (!RB_TYPE_P(str, T_STRING)) str = rb_obj_as_string(str); + rb_bool_expected(ex, "exception"); io = GetWriteIO(io); GetOpenFile(io, fptr); @@ -3022,7 +3016,7 @@ io_write_nonblock(VALUE io, VALUE str, VALUE ex) if (n < 0) { int e = errno; if (e == EWOULDBLOCK || e == EAGAIN) { - if (ex == Qfalse) { + if (!ex) { return sym_wait_writable; } else { @@ -12193,12 +12187,14 @@ static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock) { VALUE tmp, str, length; + int no_exception; rb_scan_args(argc, argv, "11", &length, &str); if (!NIL_P(str)) { StringValue(str); argv[1] = str; } + no_exception = no_exception_p(opts); if (!next_argv()) { if (!NIL_P(str)) { @@ -12215,16 +12211,16 @@ argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock) RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0); } else { - tmp = io_getpartial(argc, argv, ARGF.current_file, opts, nonblock); + tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock); } if (NIL_P(tmp)) { if (ARGF.next_p == -1) { - return io_nonblock_eof(opts); + return io_nonblock_eof(no_exception); } argf_close(argf); ARGF.next_p = 1; if (RARRAY_LEN(ARGF.argv) == 0) { - return io_nonblock_eof(opts); + return io_nonblock_eof(no_exception); } if (NIL_P(str)) str = rb_str_new(NULL, 0); @@ -3330,18 +3330,31 @@ rb_Integer(VALUE val) return rb_convert_to_integer(val, 0, TRUE); } -static int -opts_exception_p(VALUE opts) +int +rb_bool_expected(VALUE obj, const char *flagname) { - static ID kwds[1]; - VALUE exception; - if (!kwds[0]) { - kwds[0] = idException; + switch (obj) { + case Qtrue: case Qfalse: + break; + default: + rb_raise(rb_eArgError, "true or false is expected as %s: %+"PRIsVALUE, + flagname, obj); } - rb_get_kwargs(opts, kwds, 0, 1, &exception); - return exception != Qfalse; + return obj != Qfalse; +} + +int +rb_opts_exception_p(VALUE opts, int default_value) +{ + static ID kwds[1] = {idException}; + VALUE exception; + if (rb_get_kwargs(opts, kwds, 0, 1, &exception)) + return rb_bool_expected(exception, "exception"); + return default_value; } +#define opts_exception_p(opts) rb_opts_exception_p((opts), TRUE) + /* * call-seq: * Integer(arg, base=0, exception: true) -> integer or nil diff --git a/rational.c b/rational.c index 207c4c46b3..e137ac23e7 100644 --- a/rational.c +++ b/rational.c @@ -574,13 +574,7 @@ nurat_f_rational(int argc, VALUE *argv, VALUE klass) a2 = Qundef; } if (!NIL_P(opts)) { - static ID kwds[1]; - VALUE exception; - if (!kwds[0]) { - kwds[0] = idException; - } - rb_get_kwargs(opts, kwds, 0, 1, &exception); - raise = (exception != Qfalse); + raise = rb_opts_exception_p(opts, raise); } return nurat_convert(rb_cRational, a1, a2, raise); } diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index 60a46d737d..2a72f3bcb9 100644 --- a/test/ruby/test_complex.rb +++ b/test/ruby/test_complex.rb @@ -868,6 +868,12 @@ class Complex_Test < Test::Unit::TestCase end + def test_Complex_with_invalid_exception + assert_raise(ArgumentError) { + Complex("0", exception: 1) + } + end + def test_Complex_without_exception assert_nothing_raised(ArgumentError){ assert_equal(nil, Complex('5x', exception: false)) diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index 3453440694..02bafb0303 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -802,6 +802,12 @@ class TestFloat < Test::Unit::TestCase assert_raise(ArgumentError, bug4310) {under_gc_stress {Float('a'*10000)}} end + def test_Float_with_invalid_exception + assert_raise(ArgumentError) { + Float("0", exception: 1) + } + end + def test_Float_with_exception_keyword assert_raise(ArgumentError) { Float(".", exception: true) diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index 2334cab50a..84730b2a5d 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -193,6 +193,12 @@ class TestInteger < Test::Unit::TestCase end def test_Integer_with_exception_keyword + assert_raise(ArgumentError) { + Integer("0", exception: 1) + } + end + + def test_Integer_with_exception_keyword assert_nothing_raised(ArgumentError) { assert_equal(nil, Integer("1z", exception: false)) } diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 4f66685f9b..3c5dc7671a 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1509,6 +1509,12 @@ class TestIO < Test::Unit::TestCase } end if have_nonblock? + def test_read_nonblock_invalid_exception + with_pipe {|r, w| + assert_raise(ArgumentError) {r.read_nonblock(4096, exception: 1)} + } + end if have_nonblock? + def test_read_nonblock_no_exceptions skip '[ruby-core:90895] MJIT worker may leave fd open in a forked child' if RubyVM::MJIT.enabled? # TODO: consider acquiring GVL from MJIT worker. with_pipe {|r, w| @@ -1545,6 +1551,12 @@ class TestIO < Test::Unit::TestCase } end if have_nonblock? + def test_write_nonblock_invalid_exception + with_pipe {|r, w| + assert_raise(ArgumentError) {w.write_nonblock(4096, exception: 1)} + } + end if have_nonblock? + def test_write_nonblock_no_exceptions with_pipe {|r, w| loop { diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb index a8cdf22a49..301890b620 100644 --- a/test/ruby/test_rational.rb +++ b/test/ruby/test_rational.rb @@ -808,6 +808,12 @@ class Rational_Test < Test::Unit::TestCase assert_raise(ZeroDivisionError) {Rational("1/0")} end + def test_Rational_with_invalid_exception + assert_raise(ArgumentError) { + Rational("1/1", exception: 1) + } + end + def test_Rational_without_exception assert_nothing_raised(ArgumentError) { assert_equal(nil, Rational("5/3x", exception: false)) |