diff options
-rw-r--r-- | error.c | 3 | ||||
-rw-r--r-- | eval_error.c | 48 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | ruby.c | 9 | ||||
-rw-r--r-- | string.c | 37 | ||||
-rw-r--r-- | test/ruby/test_exception.rb | 37 | ||||
-rw-r--r-- | test/ruby/test_module.rb | 8 | ||||
-rw-r--r-- | test/ruby/test_rubyoptions.rb | 2 |
8 files changed, 106 insertions, 39 deletions
@@ -1675,7 +1675,6 @@ name_err_mesg_to_str(VALUE obj) d = rb_any_to_s(obj); } singleton = (RSTRING_LEN(d) > 0 && RSTRING_PTR(d)[0] == '#'); - d = QUOTE(d); break; } if (!singleton) { @@ -1685,7 +1684,7 @@ name_err_mesg_to_str(VALUE obj) else { c = s = FAKE_CSTR(&s_str, ""); } - args[0] = QUOTE(rb_obj_as_string(ptr[NAME_ERR_MESG__NAME])); + args[0] = rb_obj_as_string(ptr[NAME_ERR_MESG__NAME]); args[1] = d; args[2] = s; args[3] = c; diff --git a/eval_error.c b/eval_error.c index 8ea58a4742..8e10c57d8e 100644 --- a/eval_error.c +++ b/eval_error.c @@ -79,6 +79,44 @@ error_print(rb_execution_context_t *ec) rb_ec_error_print(ec, ec->errinfo); } +static void +write_warnq(VALUE out, VALUE str, const char *ptr, long len) +{ + if (NIL_P(out)) { + const char *beg = ptr; + const long olen = len; + for (; len > 0; --len, ++ptr) { + unsigned char c = *ptr; + if (rb_iscntrl(c)) { + char buf[5]; + const char *cc = 0; + if (ptr > beg) rb_write_error2(beg, ptr - beg); + beg = ptr + 1; + cc = ruby_escaped_char(c); + if (cc) { + rb_write_error2(cc, strlen(cc)); + } + else { + rb_write_error2(buf, snprintf(buf, sizeof(buf), "\\x%02X", c)); + } + } + else if (c == '\\') { + rb_write_error2(beg, ptr - beg + 1); + beg = ptr; + } + } + if (ptr > beg) { + if (beg == RSTRING_PTR(str) && olen == RSTRING_LEN(str)) + rb_write_error_str(str); + else + rb_write_error2(beg, ptr - beg); + } + } + else { + rb_str_cat(out, ptr, len); + } +} + #define CSI_BEGIN "\033[" #define CSI_SGR "m" @@ -134,11 +172,11 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { - write_warn2(str, einfo, tail - einfo); + write_warnq(str, emesg, einfo, tail - einfo); tail++; /* skip newline */ } else { - write_warn_str(str, emesg); + write_warnq(str, emesg, einfo, elen); } if (epath) { write_warn(str, " ("); @@ -154,7 +192,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA } if (tail && einfo+elen > tail) { if (!highlight) { - write_warn2(str, tail, einfo+elen-tail); + write_warnq(str, emesg, tail, einfo+elen-tail); if (einfo[elen-1] != '\n') write_warn2(str, "\n", 1); } else { @@ -164,7 +202,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA tail = memchr(einfo, '\n', elen); if (!tail || tail > einfo) { write_warn(str, bold); - write_warn2(str, einfo, tail ? tail-einfo : elen); + write_warnq(str, emesg, einfo, tail ? tail-einfo : elen); write_warn(str, reset); if (!tail) { write_warn2(str, "\n", 1); @@ -174,7 +212,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA elen -= tail - einfo; einfo = tail; do ++tail; while (tail < einfo+elen && *tail == '\n'); - write_warn2(str, einfo, tail-einfo); + write_warnq(str, emesg, einfo, tail-einfo); elen -= tail - einfo; einfo = tail; } diff --git a/internal.h b/internal.h index c6cf73bf10..f57c1b73cd 100644 --- a/internal.h +++ b/internal.h @@ -2021,6 +2021,7 @@ VALUE rb_sym_to_proc(VALUE sym); char *rb_str_to_cstr(VALUE str); VALUE rb_str_eql(VALUE str1, VALUE str2); VALUE rb_obj_as_string_result(VALUE str, VALUE obj); +const char *ruby_escaped_char(int c); /* symbol.c */ #ifdef RUBY_ENCODING_H @@ -1367,16 +1367,9 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) default: { - if (ISPRINT(*s)) { - rb_raise(rb_eRuntimeError, + rb_raise(rb_eRuntimeError, "invalid option -%c (-h will show valid options)", (int)(unsigned char)*s); - } - else { - rb_raise(rb_eRuntimeError, - "invalid option -\\x%02X (-h will show valid options)", - (int)(unsigned char)*s); - } } goto switch_end; @@ -5818,6 +5818,24 @@ rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p) return l; } +const char * +ruby_escaped_char(int c) +{ + switch (c) { + case '\0': return "\\0"; + case '\n': return "\\n"; + case '\r': return "\\r"; + case '\t': return "\\t"; + case '\f': return "\\f"; + case '\013': return "\\v"; + case '\010': return "\\b"; + case '\007': return "\\a"; + case '\033': return "\\e"; + case '\x7f': return "\\c?"; + } + return NULL; +} + VALUE rb_str_escape(VALUE str) { @@ -5832,7 +5850,8 @@ rb_str_escape(VALUE str) int asciicompat = rb_enc_asciicompat(enc); while (p < pend) { - unsigned int c, cc; + unsigned int c; + const char *cc; int n = rb_enc_precise_mbclen(p, pend, enc); if (!MBCLEN_CHARFOUND_P(n)) { if (p > prev) str_buf_cat(result, prev, p - prev); @@ -5849,22 +5868,10 @@ rb_str_escape(VALUE str) n = MBCLEN_CHARFOUND_LEN(n); c = rb_enc_mbc_to_codepoint(p, pend, enc); p += n; - switch (c) { - case '\n': cc = 'n'; break; - case '\r': cc = 'r'; break; - case '\t': cc = 't'; break; - case '\f': cc = 'f'; break; - case '\013': cc = 'v'; break; - case '\010': cc = 'b'; break; - case '\007': cc = 'a'; break; - case 033: cc = 'e'; break; - default: cc = 0; break; - } + cc = ruby_escaped_char(c); if (cc) { if (p - n > prev) str_buf_cat(result, prev, p - n - prev); - buf[0] = '\\'; - buf[1] = (char)cc; - str_buf_cat(result, buf, 2); + str_buf_cat(result, cc, strlen(cc)); prev = p; } else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) { diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 05c74f6dcd..cabd20c0e8 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -1071,6 +1071,43 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end; end + def assert_null_char(src, *args, **opts) + begin + eval(src) + rescue => e + end + assert_not_nil(e) + assert_include(e.message, "\0") + assert_in_out_err([], src, [], [], *args, **opts) do |_, err,| + err.each do |e| + assert_not_include(e, "\0") + end + end + e + end + + def test_control_in_message + bug7574 = '[ruby-dev:46749]' + assert_null_char("#{<<~"begin;"}\n#{<<~'end;'}", bug7574) + begin; + Object.const_defined?("String\0") + end; + assert_null_char("#{<<~"begin;"}\n#{<<~'end;'}", bug7574) + begin; + Object.const_get("String\0") + end; + end + + def test_encoding_in_message + name = "\u{e9}t\u{e9}" + e = EnvUtil.with_default_external("US-ASCII") do + assert_raise(NameError) do + Object.const_get(name) + end + end + assert_include(e.message, name) + end + def test_method_missing_reason_clear bug10969 = '[ruby-core:68515] [Bug #10969]' a = Class.new {def method_missing(*) super end}.new diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 4ca0e09277..bac16f2bda 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -745,10 +745,6 @@ class TestModule < Test::Unit::TestCase assert_raise(NameError) { c1.const_get(:foo) } bug5084 = '[ruby-dev:44200]' assert_raise(TypeError, bug5084) { c1.const_get(1) } - bug7574 = '[ruby-dev:46749]' - assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { - Object.const_get("String\0") - } end def test_const_defined_invalid_name @@ -756,10 +752,6 @@ class TestModule < Test::Unit::TestCase assert_raise(NameError) { c1.const_defined?(:foo) } bug5084 = '[ruby-dev:44200]' assert_raise(TypeError, bug5084) { c1.const_defined?(1) } - bug7574 = '[ruby-dev:46749]' - assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { - Object.const_defined?("String\0") - } end def test_const_get_no_inherited diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index 69521b1d23..d913e8b918 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -310,7 +310,7 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%W(-\r -e) + [""], "", [], []) - assert_in_out_err(%W(-\rx), "", [], /invalid option -\\x0D \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\rx), "", [], /invalid option -\\r \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/) |