diff options
67 files changed, 915 insertions, 765 deletions
@@ -185,19 +185,14 @@ define rp print (struct RBasic *)($arg0) else if ($flags & RUBY_T_MASK) == RUBY_T_DATA - if ($flags & RUBY_TYPED_FL_IS_TYPED_DATA) - set $data = (struct RTypedData *)($arg0) - set $type = (const rb_data_type_t *)($data->type & ~1) - printf "%sT_DATA%s(%s): ", $color_type, $color_end, $type->wrap_struct_name - print *$type - if ($data->type & 1) - print (void *)&$data->data - else - print $data - end + set $data = (struct RTypedData *)($arg0) + set $type = (const rb_data_type_t *)($data->type & ~1) + printf "%sT_DATA%s(%s): ", $color_type, $color_end, $type->wrap_struct_name + print *$type + if ($data->type & 1) + print (void *)&$data->data else - printf "%sT_DATA%s: ", $color_type, $color_end - print *(struct RData *)($arg0) + print $data end else if ($flags & RUBY_T_MASK) == RUBY_T_MATCH diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml index 091f98ef34..6fd1be6542 100644 --- a/.github/workflows/check_sast.yml +++ b/.github/workflows/check_sast.yml @@ -92,7 +92,7 @@ jobs: output: sarif-results - name: filter-sarif - uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1.0.1.1 + uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1 with: patterns: | +**/*.rb @@ -100,6 +100,7 @@ jobs: -lib/uri/rfc3986_parser.rb:rb/overly-large-range -lib/bundler/vendor/uri/lib/uri/mailto.rb:rb/overly-large-range -lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb:rb/overly-large-range + -spec/ruby/core/regexp/timeout_spec.rb:rb/redos -test/ruby/test_io.rb:rb/non-constant-kernel-open -test/open-uri/test_open-uri.rb:rb/non-constant-kernel-open -test/open-uri/test_ssl.rb:rb/non-constant-kernel-open @@ -115,7 +116,7 @@ jobs: continue-on-error: true - name: filter-sarif - uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1.0.1.1 + uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1 with: patterns: | +**/*.c diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index d355e4f4ab..501d35698b 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -26,25 +26,29 @@ jobs: matrix: include: - test_task: check - os: macos-14 + os: macos-26 - test_task: check - os: macos-14 + os: macos-15 configure_args: '--with-gcc=gcc-14' - test_task: check - os: macos-14 + os: macos-26 configure_args: '--with-jemalloc --with-opt-dir=$(brew --prefix jemalloc)' - test_task: check - os: macos-14 + os: macos-26 configure_args: '--with-gmp' - test_task: test-all test_opts: --repeat-count=2 - os: macos-14 + os: macos-26 - test_task: test-bundler-parallel - os: macos-14 + os: macos-26 - test_task: test-bundled-gems - os: macos-14 + os: macos-26 - test_task: check os: macos-15 + - test_task: check + os: macos-15-intel + - test_task: check + os: macos-14 fail-fast: false env: diff --git a/.github/workflows/modgc.yml b/.github/workflows/modgc.yml index f6aa445ad0..bd3c6ab575 100644 --- a/.github/workflows/modgc.yml +++ b/.github/workflows/modgc.yml @@ -28,7 +28,7 @@ jobs: - name: default - name: mmtk mmtk_build: release - os: [macos-latest, ubuntu-latest] + os: [macos-26, ubuntu-latest] include: - test_task: check fail-fast: false diff --git a/.github/workflows/tarball-macos.yml b/.github/workflows/tarball-macos.yml index 72c5a78c14..9bec94d528 100644 --- a/.github/workflows/tarball-macos.yml +++ b/.github/workflows/tarball-macos.yml @@ -12,13 +12,21 @@ on: required: false type: boolean default: false + secrets: + SIMPLER_ALERTS_URL: + required: false + SNAPSHOT_SLACK_WEBHOOK_URL: + required: false + +permissions: + contents: read jobs: macos: strategy: matrix: test_task: [check, test-bundled-gems, test-bundler-parallel] - os: [macos-14, macos-15] + os: [macos-26, macos-15, macos-14] include: - os: macos-15-intel test_task: check diff --git a/.github/workflows/tarball-non-development.yml b/.github/workflows/tarball-non-development.yml index 154d204a2c..db6230b301 100644 --- a/.github/workflows/tarball-non-development.yml +++ b/.github/workflows/tarball-non-development.yml @@ -3,6 +3,9 @@ name: tarball-non-development (reusable) on: workflow_call: {} +permissions: + contents: read + jobs: non_development: strategy: diff --git a/.github/workflows/tarball-test.yml b/.github/workflows/tarball-test.yml index e99c4515c8..52c4d31fc8 100644 --- a/.github/workflows/tarball-test.yml +++ b/.github/workflows/tarball-test.yml @@ -50,6 +50,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 # actions/checkout fetches all heads/tags unless > 0 + persist-credentials: false # tool/make-snapshot derives the branch name from HEAD and looks up # the upstream during ChangeLog generation. Detached checkouts # (pull_request, merge_group) lack a local branch with tracking, so @@ -73,7 +74,9 @@ jobs: with: archname: snapshot-${{ needs.tarball.outputs.branch }} notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }} - secrets: inherit + secrets: + SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }} + SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }} macos: needs: tarball @@ -82,7 +85,9 @@ jobs: with: archname: snapshot-${{ needs.tarball.outputs.branch }} notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }} - secrets: inherit + secrets: + SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }} + SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }} windows: needs: tarball @@ -91,9 +96,10 @@ jobs: with: archname: snapshot-${{ needs.tarball.outputs.branch }} notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }} - secrets: inherit + secrets: + SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }} + SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }} non_development: needs: tarball uses: ./.github/workflows/tarball-non-development.yml - secrets: inherit diff --git a/.github/workflows/tarball-ubuntu.yml b/.github/workflows/tarball-ubuntu.yml index f0e773b526..03f2f946b5 100644 --- a/.github/workflows/tarball-ubuntu.yml +++ b/.github/workflows/tarball-ubuntu.yml @@ -12,6 +12,14 @@ on: required: false type: boolean default: false + secrets: + SIMPLER_ALERTS_URL: + required: false + SNAPSHOT_SLACK_WEBHOOK_URL: + required: false + +permissions: + contents: read jobs: ubuntu: diff --git a/.github/workflows/tarball-windows.yml b/.github/workflows/tarball-windows.yml index 1cd4ef454d..1ce95de6fc 100644 --- a/.github/workflows/tarball-windows.yml +++ b/.github/workflows/tarball-windows.yml @@ -12,6 +12,14 @@ on: required: false type: boolean default: false + secrets: + SIMPLER_ALERTS_URL: + required: false + SNAPSHOT_SLACK_WEBHOOK_URL: + required: false + +permissions: + contents: read jobs: windows: diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml index 6e0827c8fe..b52c6355ad 100644 --- a/.github/workflows/yjit-macos.yml +++ b/.github/workflows/yjit-macos.yml @@ -30,7 +30,7 @@ jobs: cargo: name: cargo test - runs-on: macos-14 + runs-on: macos-26 if: >- ${{!(false @@ -74,7 +74,7 @@ jobs: RUN_OPTS: ${{ matrix.yjit_opts }} SPECOPTS: ${{ matrix.specopts }} - runs-on: macos-14 + runs-on: macos-26 if: >- ${{!(false @@ -134,7 +134,7 @@ jobs: id: launchable uses: ./.github/actions/launchable/setup with: - os: macos-14 + os: macos-26 test-opts: ${{ matrix.configure }} launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }} builddir: build diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 3011a04cac..f9282d64e8 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -58,7 +58,7 @@ jobs: RUST_BACKTRACE: 1 ZJIT_RB_BUG: 1 - runs-on: macos-14 + runs-on: macos-26 if: >- ${{!(false @@ -93,7 +93,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@8f531eaecd1898bc3da7d104ad91bee98d1b97bd # v2.79.9 + - uses: taiki-e/install-action@13608cbb45b01feb47ef444ab1a42dc41ad56f1a # v2.79.11 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} @@ -118,7 +118,7 @@ jobs: id: launchable uses: ./.github/actions/launchable/setup with: - os: macos-14 + os: macos-26 test-opts: ${{ matrix.configure }} launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }} builddir: build @@ -181,7 +181,7 @@ jobs: bench_opts: '--warmup=1 --bench=1 --excludes=shipit' configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow - runs-on: macos-14 + runs-on: macos-26 if: >- ${{!(false diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index d91dfcbeeb..1e7bec3859 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -119,7 +119,7 @@ jobs: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@8f531eaecd1898bc3da7d104ad91bee98d1b97bd # v2.79.9 + - uses: taiki-e/install-action@13608cbb45b01feb47ef444ab1a42dc41ad56f1a # v2.79.11 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 53112a2815..65b67fb6c8 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -13,6 +13,7 @@ rules: misfeature: ignore: - mingw.yml + - tarball-windows.yml - windows.yml unpinned-images: ignore: @@ -82,8 +82,8 @@ releases. * 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4] * ipaddr 1.2.9 * 1.2.8 to [v1.2.9][ipaddr-v1.2.9] -* json 2.19.5 - * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5] +* json 2.19.7 + * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5], [v2.19.6][json-v2.19.6], [v2.19.7][json-v2.19.7] * openssl 4.0.2 * 4.0.0 to [v4.0.1][openssl-v4.0.1], [v4.0.2][openssl-v4.0.2] * prism 1.9.0 @@ -161,6 +161,19 @@ Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for det [[Feature #21861]] +### Removed APIs + +The following APIs, which have been deprecated for many years, are removed. +[[Feature #21768]] + +* old postponed job functions, +* untyped data object type/functions, +* old APIs to allocate a data object, +* taintedness/trustedness enums/macros, +* `rb_gc_force_recycle` function, +* `rb_iterate` function, +* and some functions and constants for internal use. + ## Implementation improvements ### Ractor @@ -172,6 +185,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [Feature #8948]: https://bugs.ruby-lang.org/issues/8948 [Feature #15330]: https://bugs.ruby-lang.org/issues/15330 [Feature #21390]: https://bugs.ruby-lang.org/issues/21390 +[Feature #21768]: https://bugs.ruby-lang.org/issues/21768 [Feature #21785]: https://bugs.ruby-lang.org/issues/21785 [Feature #21796]: https://bugs.ruby-lang.org/issues/21796 [Feature #21853]: https://bugs.ruby-lang.org/issues/21853 @@ -208,6 +222,8 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [json-v2.19.3]: https://github.com/ruby/json/releases/tag/v2.19.3 [json-v2.19.4]: https://github.com/ruby/json/releases/tag/v2.19.4 [json-v2.19.5]: https://github.com/ruby/json/releases/tag/v2.19.5 +[json-v2.19.6]: https://github.com/ruby/json/releases/tag/v2.19.6 +[json-v2.19.7]: https://github.com/ruby/json/releases/tag/v2.19.7 [openssl-v4.0.1]: https://github.com/ruby/openssl/releases/tag/v4.0.1 [openssl-v4.0.2]: https://github.com/ruby/openssl/releases/tag/v4.0.2 [prism-v1.8.0]: https://github.com/ruby/prism/releases/tag/v1.8.0 diff --git a/encoding.c b/encoding.c index 8bb393b471..73fad8f1a6 100644 --- a/encoding.c +++ b/encoding.c @@ -126,7 +126,7 @@ static const rb_data_type_t encoding_data_type = { }; #define is_encoding_type(obj) (RTYPEDDATA_TYPE(obj) == &encoding_data_type) -#define is_data_encoding(obj) (rbimpl_rtypeddata_p(obj) && is_encoding_type(obj)) +#define is_data_encoding(obj) is_encoding_type(obj) #define is_obj_encoding(obj) (rbimpl_obj_typeddata_p(obj) && is_encoding_type(obj)) int @@ -1364,8 +1364,7 @@ rb_check_type(VALUE x, int t) rb_bug(UNDEF_LEAKED); } - xt = TYPE(x); - if (xt != t || (xt == T_DATA && rbimpl_rtypeddata_p(x))) { + if (t == T_DATA) { /* * Typed data is not simple `T_DATA`, but in a sense an * extension of `struct RVALUE`, which are incompatible with @@ -1374,6 +1373,10 @@ rb_check_type(VALUE x, int t) * So it is not enough to just check `T_DATA`, it must be * identified by its `type` using `Check_TypedStruct` instead. */ + rb_unexpected_object_type(x, builtin_types[t]); + } + xt = TYPE(x); + if (xt != t) { unexpected_type(x, xt, t); } } diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 6295264a3d..72d697c8ea 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -27,7 +27,7 @@ static VALUE eDateError; static VALUE half_days_in_day, day_in_nanoseconds; static double positive_inf, negative_inf; -// used by deconstruct_keys +/* used by deconstruct_keys */ static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday; static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone; @@ -4528,6 +4528,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, rb_scan_args(argc, argv, "11", &vstr, &vfmt); StringValue(vstr); + if (argc > 1) StringValue(vfmt); if (!rb_enc_str_asciicompat_p(vstr)) rb_raise(rb_eArgError, "string should have ASCII compatible encoding"); @@ -4538,7 +4539,6 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, flen = strlen(default_fmt); } else { - StringValue(vfmt); if (!rb_enc_str_asciicompat_p(vfmt)) rb_raise(rb_eArgError, "format should have ASCII compatible encoding"); diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c index f1c8201de8..1dde5fa3ec 100644 --- a/ext/date/date_strptime.c +++ b/ext/date/date_strptime.c @@ -661,6 +661,9 @@ date__strptime(const char *str, size_t slen, si = date__strptime_internal(str, slen, fmt, flen, hash); + if (fail_p()) + return Qnil; + if (slen > si) { VALUE s; @@ -668,9 +671,6 @@ date__strptime(const char *str, size_t slen, set_hash("leftover", s); } - if (fail_p()) - return Qnil; - cent = del_hash("_cent"); if (!NIL_P(cent)) { VALUE year; diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index 882d47a611..110b5f6b32 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -1367,12 +1367,14 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig) if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State"); MEMCPY(objState, origState, JSON_Generator_State, 1); - objState->indent = origState->indent; - objState->space = origState->space; - objState->space_before = origState->space_before; - objState->object_nl = origState->object_nl; - objState->array_nl = origState->array_nl; - objState->as_json = origState->as_json; + + RB_OBJ_WRITTEN(obj, Qundef, objState->indent); + RB_OBJ_WRITTEN(obj, Qundef, objState->space); + RB_OBJ_WRITTEN(obj, Qundef, objState->space_before); + RB_OBJ_WRITTEN(obj, Qundef, objState->object_nl); + RB_OBJ_WRITTEN(obj, Qundef, objState->array_nl); + RB_OBJ_WRITTEN(obj, Qundef, objState->as_json); + return obj; } @@ -1579,7 +1581,7 @@ static VALUE cState_max_nesting(VALUE self) static long long_config(VALUE num) { - return RTEST(num) ? FIX2LONG(num) : 0; + return RTEST(num) ? NUM2LONG(num) : 0; } // depth must never be negative; reject early with a clear error. @@ -1590,6 +1592,9 @@ static long depth_config(VALUE num) if (RB_UNLIKELY(d < 0)) { rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d); } + if (RB_UNLIKELY(d > INT_MAX)) { + rb_raise(rb_eArgError, "depth is too large (got %ld)", d); + } return d; } diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index ebb55656d7..a69590ff9c 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JSON - VERSION = '2.19.5' + VERSION = '2.19.7' end diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index a740bd42ed..503bed1fd4 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -385,6 +385,13 @@ static inline char peek(JSON_ParserState *state) static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out) { + JSON_ASSERT(state->cursor <= state->end); + + // Redundant but helpful for hardening + if (RB_UNLIKELY(state->cursor > state->end)) { + state->cursor = state->end; + } + const char *cursor = state->cursor; long column = 0; long line = 1; @@ -1022,6 +1029,13 @@ ALWAYS_INLINE(static) bool string_scan(JSON_ParserState *state) } state->cursor++; } + + // If the string ended with an unterminated escape sequence, we might + // have gone past the end. + if (RB_UNLIKELY(state->cursor > state->end)) { + state->cursor = state->end; + } + return false; } @@ -1202,7 +1216,11 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig raise_parse_error_at("invalid number: %s", state, start); } - exponent = negative_exponent ? -abs_exponent : abs_exponent; + if (RB_UNLIKELY(exponent_digits >= 20 || abs_exponent > (uint64_t)INT64_MAX)) { + exponent = negative_exponent ? INT64_MIN : INT64_MAX; + } else { + exponent = negative_exponent ? -(int64_t)abs_exponent : (int64_t)abs_exponent; + } } if (integer) { @@ -1457,18 +1475,21 @@ static void json_ensure_eof(JSON_ParserState *state) static VALUE convert_encoding(VALUE source) { - int encindex = RB_ENCODING_GET(source); + StringValue(source); + int encindex = RB_ENCODING_GET(source); - if (RB_LIKELY(encindex == utf8_encindex)) { - return source; - } + if (RB_LIKELY(encindex == utf8_encindex)) { + return source; + } - if (encindex == binary_encindex) { - // For historical reason, we silently reinterpret binary strings as UTF-8 - return rb_enc_associate_index(rb_str_dup(source), utf8_encindex); - } + if (encindex == binary_encindex) { + // For historical reason, we silently reinterpret binary strings as UTF-8 + return rb_enc_associate_index(rb_str_dup(source), utf8_encindex); + } - return rb_funcall(source, i_encode, 1, Encoding_UTF_8); + source = rb_funcall(source, i_encode, 1, Encoding_UTF_8); + StringValue(source); + return source; } struct parser_config_init_args { @@ -1583,10 +1604,16 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts) return self; } -static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) +static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src) { - Vsource = convert_encoding(StringValue(Vsource)); - StringValue(Vsource); + VALUE Vsource = convert_encoding(src); + + // Ensure the string isn't mutated under us. + // The classic API to use is `rb_str_locktmp`, but then we'd + // need to use `rb_protect` to make sure we always unlock. + if (Vsource == src) { + Vsource = rb_str_new_frozen(Vsource); + } VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; rvalue_stack stack = { @@ -1597,6 +1624,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) long len; const char *start; + RSTRING_GETMEM(Vsource, start, len); VALUE stack_handle = 0; @@ -1615,6 +1643,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) // it won't cause a leak. rvalue_stack_eagerly_release(stack_handle); RB_GC_GUARD(stack_handle); + RB_GC_GUARD(Vsource); json_ensure_eof(state); return result; @@ -1635,9 +1664,6 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource) static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts) { - Vsource = convert_encoding(StringValue(Vsource)); - StringValue(Vsource); - JSON_ParserConfig _config = {0}; JSON_ParserConfig *config = &_config; parser_config_init(config, opts, false); diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index b644c489b8..68ada01af3 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -573,7 +573,7 @@ dump_object(VALUE obj, struct dump_config *dc) break; case T_DATA: - if (RTYPEDDATA_P(obj)) { + { const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); dump_append(dc, ", \"struct\":\""); dump_append(dc, type->wrap_struct_name); diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb index 46ddfd6021..4e6dea8d03 100644 --- a/ext/openssl/lib/openssl/digest.rb +++ b/ext/openssl/lib/openssl/digest.rb @@ -27,17 +27,21 @@ module OpenSSL end %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name| - klass = Class.new(self) { - define_method(:initialize, ->(data = nil) {super(name, data)}) - } - - singleton = (class << klass; self; end) - - singleton.class_eval{ - define_method(:digest) {|data| new.digest(data)} - define_method(:hexdigest) {|data| new.hexdigest(data)} - } + klass = Class.new(self) + klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def initialize(data = nil) + super("#{name}", data) + end + RUBY + klass.singleton_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def digest(data) + new.digest(data) + end + def hexdigest(data) + new.hexdigest(data) + end + RUBY const_set(name.tr('-', '_'), klass) end diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c index f70b7f6cf9..99a3589b39 100644 --- a/ext/openssl/ossl_kdf.c +++ b/ext/openssl/ossl_kdf.c @@ -39,6 +39,10 @@ pbkdf2_hmac_nogvl(void *args_) * For more information about PBKDF2, see RFC 2898 Section 5.2 * (https://www.rfc-editor.org/rfc/rfc2898#section-5.2). * + * *NOTE*: This method cannot be interrupted by Timeout.timeout from the + * "timeout" library. Do not take parameters from untrusted sources without + * enforcing reasonable limits. + * * === Parameters * pass :: The password. * salt :: The salt. Salts prevent attacks based on dictionaries of common @@ -143,6 +147,10 @@ scrypt_nogvl(void *args_) * * See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information. * + * *NOTE*: This method cannot be interrupted by Timeout.timeout from the + * "timeout" library. Do not take parameters from untrusted sources without + * enforcing reasonable limits. + * * === Parameters * pass :: Passphrase. * salt :: Salt. diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index 32b82a881c..a47c81354c 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -191,6 +191,7 @@ ossl_x509_sk2ary_i(VALUE arg) static VALUE ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) { + PKCS12 *p12, *p12_orig = DATA_PTR(self); BIO *in; VALUE arg, pass, pkey, cert, ca; char *passphrase; @@ -198,17 +199,19 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) X509 *x509; STACK_OF(X509) *x509s = NULL; int st = 0; - PKCS12 *pkcs = DATA_PTR(self); if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self; passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass); in = ossl_obj2bio(&arg); - d2i_PKCS12_bio(in, &pkcs); - DATA_PTR(self) = pkcs; + p12 = d2i_PKCS12_bio(in, NULL); BIO_free(in); + if (!p12) + ossl_raise(ePKCS12Error, "d2i_PKCS12_bio"); + PKCS12_free(p12_orig); + RTYPEDDATA_DATA(self) = p12; pkey = cert = ca = Qnil; - if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s)) + if (!PKCS12_parse(p12, passphrase, &key, &x509, &x509s)) ossl_raise(ePKCS12Error, "PKCS12_parse"); if (key) { pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st); diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 3cf5820c36..44e8cb305b 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -453,7 +453,7 @@ ossl_pkcs7_sym2typeid(VALUE sym) if(i == numberof(p7_type_tab)) ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym); if(strlen(p7_type_tab[i].name) != l) continue; - if(strcmp(p7_type_tab[i].name, s) == 0){ + if(memcmp(p7_type_tab[i].name, s, l) == 0){ ret = p7_type_tab[i].nid; break; } diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c index 393e08acff..317f7786aa 100644 --- a/ext/openssl/ossl_ts.c +++ b/ext/openssl/ossl_ts.c @@ -168,7 +168,7 @@ ossl_ts_req_alloc(VALUE klass) static VALUE ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self) { - TS_REQ *ts_req = DATA_PTR(self); + TS_REQ *req, *req_orig = DATA_PTR(self); BIO *in; VALUE arg; @@ -178,13 +178,14 @@ ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self) arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(&arg); - ts_req = d2i_TS_REQ_bio(in, &ts_req); + req = d2i_TS_REQ_bio(in, NULL); BIO_free(in); - if (!ts_req) { - DATA_PTR(self) = NULL; - ossl_raise(eTimestampError, "Error when decoding the timestamp request"); + if (!req) { + ossl_raise(eTimestampError, + "Error when decoding the timestamp request"); } - DATA_PTR(self) = ts_req; + TS_REQ_free(req_orig); + RTYPEDDATA_DATA(self) = req; return self; } @@ -522,18 +523,19 @@ ossl_ts_resp_alloc(VALUE klass) static VALUE ossl_ts_resp_initialize(VALUE self, VALUE der) { - TS_RESP *ts_resp = DATA_PTR(self); + TS_RESP *resp, *resp_orig = DATA_PTR(self); BIO *in; der = ossl_to_der_if_possible(der); - in = ossl_obj2bio(&der); - ts_resp = d2i_TS_RESP_bio(in, &ts_resp); + in = ossl_obj2bio(&der); + resp = d2i_TS_RESP_bio(in, NULL); BIO_free(in); - if (!ts_resp) { - DATA_PTR(self) = NULL; - ossl_raise(eTimestampError, "Error when decoding the timestamp response"); + if (!resp) { + ossl_raise(eTimestampError, + "Error when decoding the timestamp response"); } - DATA_PTR(self) = ts_resp; + TS_RESP_free(resp_orig); + RTYPEDDATA_DATA(self) = resp; return self; } @@ -876,18 +878,19 @@ ossl_ts_token_info_alloc(VALUE klass) static VALUE ossl_ts_token_info_initialize(VALUE self, VALUE der) { - TS_TST_INFO *info = DATA_PTR(self); + TS_TST_INFO *info, *info_orig = DATA_PTR(self); BIO *in; der = ossl_to_der_if_possible(der); - in = ossl_obj2bio(&der); - info = d2i_TS_TST_INFO_bio(in, &info); + in = ossl_obj2bio(&der); + info = d2i_TS_TST_INFO_bio(in, NULL); BIO_free(in); if (!info) { - DATA_PTR(self) = NULL; - ossl_raise(eTimestampError, "Error when decoding the timestamp token info"); + ossl_raise(eTimestampError, + "Error when decoding the timestamp token info"); } - DATA_PTR(self) = info; + TS_TST_INFO_free(info_orig); + RTYPEDDATA_DATA(self) = info; return self; } @@ -4479,31 +4479,43 @@ rb_file_s_expand_path(int argc, const VALUE *argv) } /* + * :markup: markdown + * * call-seq: - * File.expand_path(file_name [, dir_string] ) -> abs_file_name + * File.expand_path(path, dirpath = '.') -> absolute_path * - * Converts a pathname to an absolute pathname. Relative paths are - * referenced from the current working directory of the process unless - * +dir_string+ is given, in which case it will be used as the - * starting point. The given pathname may start with a - * ``<code>~</code>'', which expands to the process owner's home - * directory (the environment variable +HOME+ must be set - * correctly). ``<code>~</code><i>user</i>'' expands to the named - * user's home directory. + * Returns the string absolute path for the given `path`. * - * File.expand_path("~oracle/bin") #=> "/home/oracle/bin" + * Evaluates a relative path with respect to the directory given by `dirpath`: * - * A simple example of using +dir_string+ is as follows. - * File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby" + * ```ruby + * Dir.chdir('/snap') + * # Default dirpath. + * File.expand_path('README') # => "/snap/README" + * File.expand_path('bin') # => "/snap/bin" + * File.expand_path('bin/../var') # => "/snap/var" # Cleaned. + * # Other dirpath. + * File.expand_path('../zip', '/usr/bin/ruby') # => "/usr/bin/zip" + * Dir.chdir('/usr/bin') + * File.expand_path('../../snap', __FILE__) # => "/usr/snap" + * ``` * - * A more complex example which also resolves parent directory is as follows. - * Suppose we are in bin/mygem and want the absolute path of lib/mygem.rb. + * Evaluates an absolute path without respect to `dirpath`: * - * File.expand_path("../../lib/mygem.rb", __FILE__) - * #=> ".../path/to/project/lib/mygem.rb" + * ```ruby + * File.expand_path('/snap') # => "/snap" + * File.expand_path('/snap', 'nosuch') # => "/snap" + * File.expand_path('/snap/../snap') # => "/snap" # Cleaned. + * ``` + * + * More examples: + * + * ``` + * Dir.chdir('/usr/bin') + * File.expand_path('../../snap', __FILE__) # => "/usr/snap" + * File.expand_path('../../snap') # => "/snap" + * ``` * - * So first it resolves the parent of __FILE__, that is bin/, then go to the - * parent, the root of the project and appends +lib/mygem.rb+. */ static VALUE @@ -5318,28 +5330,42 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc) } /* + * :markup: markdown + * * call-seq: - * File.extname(path) -> string + * File.extname(path) -> extension + * + * Returns the filename extension -- + * usually the portion of the string `path` + * beginning from the last period: + * + * ```ruby + * File.extname('t.rb') # => ".rb" + * File.extname('foo.bar.t.rb') # => ".rb" + * File.extname('foo/bar/t.rb') # => ".rb" + * File.extname('nosuch.txt') # => ".txt" # Path need not exist. + * ``` + * + * Returns the entire string when there is no period: * - * Returns the extension (the portion of file name in +path+ - * starting from the last period). + * ```ruby + * Pathname('foo').extname # => "" + * ``` * - * If +path+ is a dotfile, or starts with a period, then the starting - * dot is not dealt with the start of the extension. + * Returns an empty string when the only period is the first character: * - * An empty string will also be returned when the period is the last character - * in +path+. + * ```ruby + * File.extname('.irbrc') # => "" + * ``` * - * On Windows, trailing dots are truncated. + * Returns an empty string or `'.'` when `path` ends with a period: * - * File.extname("test.rb") #=> ".rb" - * File.extname("a/b/d/test.rb") #=> ".rb" - * File.extname(".a/b/d/test.rb") #=> ".rb" - * File.extname("foo.") #=> "" on Windows - * File.extname("foo.") #=> "." on non-Windows - * File.extname("test") #=> "" - * File.extname(".profile") #=> "" - * File.extname(".profile.sh") #=> ".sh" + * ``` + * File.extname('foo.') # => "" # On Windows. + * File.extname('foo.') # => "." # Elsewhere. + * File.extname('foo....') # => "" # On Windows. + * File.extname('foo....') # => "." # Elsewhere. + * ``` * */ @@ -337,8 +337,10 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj) { switch (BUILTIN_TYPE(obj)) { case T_DATA: - if (!ruby_free_at_exit_p() && !DATA_PTR(obj)) return false; - if (!ruby_free_at_exit_p() && !RTYPEDDATA_P(obj) && !RDATA(obj)->dfree) return false; + if (!ruby_free_at_exit_p()) { + if (!RDATA(obj)->type) return false; + if (!rbimpl_typeddata_embedded_p(obj) && !RTYPEDDATA(obj)->data) return false; + } if (rb_obj_is_thread(obj)) return false; if (rb_obj_is_mutex(obj)) return false; if (rb_obj_is_fiber(obj)) return false; @@ -374,7 +376,6 @@ void rb_vm_update_references(void *ptr); #define rb_setjmp(env) RUBY_SETJMP(env) #define rb_jmp_buf rb_jmpbuf_t -#undef rb_data_object_wrap #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) #define MAP_ANONYMOUS MAP_ANON @@ -1138,33 +1139,6 @@ rb_data_object_check(VALUE klass) } } -VALUE -rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree) -{ - RUBY_ASSERT_ALWAYS(dfree != (RUBY_DATA_FUNC)1); - if (klass) rb_data_object_check(klass); - VALUE obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID, !dmark, sizeof(struct RData)); - - rb_gc_register_pinning_obj(obj); - - struct RData *data = (struct RData *)obj; - data->fields_obj = 0; - data->_reserved = 0; - data->data = datap; - data->dmark = dmark; - data->dfree = dfree; - - return obj; -} - -VALUE -rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree) -{ - VALUE obj = rb_data_object_wrap(klass, 0, dmark, dfree); - DATA_PTR(obj) = xcalloc(1, size); - return obj; -} - #define RTYPEDDATA_EMBEDDED_P rbimpl_typeddata_embedded_p #define RB_DATA_TYPE_EMBEDDABLE_P(type) ((type)->flags & RUBY_TYPED_EMBEDDABLE) #define RTYPEDDATA_EMBEDDABLE_P(obj) RB_DATA_TYPE_EMBEDDABLE_P(RTYPEDDATA_TYPE(obj)) @@ -1175,7 +1149,7 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_ RBIMPL_NONNULL_ARG(type); if (klass) rb_data_object_check(klass); bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark; - VALUE obj = rb_newobj(GET_EC(), klass, T_DATA | RUBY_TYPED_FL_IS_TYPED_DATA, ROOT_SHAPE_ID, wb_protected, size); + VALUE obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID, wb_protected, size); rb_gc_register_pinning_obj(obj); @@ -1237,18 +1211,16 @@ static size_t rb_objspace_data_type_memsize(VALUE obj) { size_t size = 0; - if (RTYPEDDATA_P(obj)) { - const void *ptr = RTYPEDDATA_GET_DATA(obj); + const void *ptr = RTYPEDDATA_GET_DATA(obj); - if (ptr) { - if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) { - size += ruby_xmalloc_usable_size((void *)ptr); - } + if (ptr) { + if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) { + size += ruby_xmalloc_usable_size((void *)ptr); + } - const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); - if (type->function.dsize) { - size += type->function.dsize(ptr); - } + const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); + if (type->function.dsize) { + size += type->function.dsize(ptr); } } @@ -1258,12 +1230,7 @@ rb_objspace_data_type_memsize(VALUE obj) const char * rb_objspace_data_type_name(VALUE obj) { - if (RTYPEDDATA_P(obj)) { - return RTYPEDDATA_TYPE(obj)->wrap_struct_name; - } - else { - return 0; - } + return RTYPEDDATA_TYPE(obj)->wrap_struct_name; } void @@ -1285,7 +1252,7 @@ rb_gc_handle_weak_references(VALUE obj) { switch (BUILTIN_TYPE(obj)) { case T_DATA: - if (RTYPEDDATA_P(obj)) { + { const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); if (type->function.handle_weak_references) { @@ -1298,9 +1265,6 @@ rb_gc_handle_weak_references(VALUE obj) ); } } - else { - rb_bug("rb_gc_handle_weak_references: unknown T_DATA"); - } break; case T_IMEMO: { @@ -1423,7 +1387,7 @@ rb_gc_obj_needs_cleanup_p(VALUE obj) return false; case T_DATA: - if (flags & RUBY_TYPED_FL_IS_TYPED_DATA) { + { uintptr_t type = (uintptr_t)RTYPEDDATA(obj)->type; if (type & TYPED_DATA_EMBEDDED) { RUBY_DATA_FUNC dfree = ((const rb_data_type_t *)(type & TYPED_DATA_PTR_MASK))->function.dfree; @@ -1485,22 +1449,17 @@ make_io_zombie(void *objspace, VALUE obj) static bool rb_data_free(void *objspace, VALUE obj) { - void *data = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj); + void *data = RTYPEDDATA_GET_DATA(obj); if (data) { int free_immediately = false; void (*dfree)(void *); - if (RTYPEDDATA_P(obj)) { - free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0; - dfree = RTYPEDDATA_TYPE(obj)->function.dfree; - } - else { - dfree = RDATA(obj)->dfree; - } + free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0; + dfree = RTYPEDDATA_TYPE(obj)->function.dfree; if (dfree) { if (dfree == RUBY_DEFAULT_FREE) { - if (!RTYPEDDATA_P(obj) || !RTYPEDDATA_EMBEDDED_P(obj)) { + if (!RTYPEDDATA_EMBEDDED_P(obj)) { xfree(data); RB_DEBUG_COUNTER_INC(obj_data_xfree); } @@ -3512,13 +3471,12 @@ rb_gc_mark_children(void *objspace, VALUE obj) break; case T_DATA: { - bool typed_data = RTYPEDDATA_P(obj); - void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj); + void *const ptr = RTYPEDDATA_GET_DATA(obj); gc_mark_internal(RTYPEDDATA(obj)->fields_obj); if (ptr) { - if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { + if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj); for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) { @@ -3526,9 +3484,7 @@ rb_gc_mark_children(void *objspace, VALUE obj) } } else { - RUBY_DATA_FUNC mark_func = typed_data ? - RTYPEDDATA_TYPE(obj)->function.dmark : - RDATA(obj)->dmark; + RUBY_DATA_FUNC mark_func = RTYPEDDATA_TYPE(obj)->function.dmark; if (mark_func) (*mark_func)(ptr); } } @@ -4460,13 +4416,12 @@ rb_gc_update_object_references(void *objspace, VALUE obj) case T_DATA: /* Call the compaction callback, if it exists */ { - bool typed_data = RTYPEDDATA_P(obj); - void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj); + void *const ptr = RTYPEDDATA_GET_DATA(obj); UPDATE_IF_MOVED(objspace, RTYPEDDATA(obj)->fields_obj); if (ptr) { - if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { + if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj); for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) { @@ -4474,7 +4429,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj) *ref = gc_location_internal(objspace, *ref); } } - else if (typed_data) { + else { RUBY_DATA_FUNC compact_func = RTYPEDDATA_TYPE(obj)->function.dcompact; if (compact_func) (*compact_func)(ptr); } @@ -528,7 +528,7 @@ hash_st_table_init(VALUE hash, const struct st_hash_type *type, st_index_t size) RHASH_SET_ST_FLAG(hash); } -void +static void rb_hash_st_table_set(VALUE hash, st_table *st) { HASH_ASSERT(st != NULL); @@ -730,7 +730,7 @@ ar_force_convert_table(VALUE hash, const char *file, int line) st_init_existing_table_with_size(new_tab, &objhash, size); ar_each_key(ar, bound, ar_each_key_insert, NULL, new_tab, hashes); hash_ar_free_and_clear_table(hash); - RHASH_ST_TABLE_SET(hash, new_tab); + rb_hash_st_table_set(hash, new_tab); return RHASH_ST_TABLE(hash); } } @@ -1986,7 +1986,7 @@ rb_hash_rehash(VALUE hash) rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); hash_st_free(hash); - RHASH_ST_TABLE_SET(hash, tbl); + rb_hash_st_table_set(hash, tbl); RHASH_ST_CLEAR(tmp); } hash_verify(hash); @@ -4669,7 +4669,7 @@ rb_hash_compare_by_id(VALUE hash) // We know for sure `identtable` is an st table, // so we can skip `ar_force_convert_table` here. - RHASH_ST_TABLE_SET(hash, identtable); + rb_hash_st_table_set(hash, identtable); RHASH_ST_CLEAR(tmp); } diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h index 0c99d93bf9..7ceb8c40b7 100644 --- a/include/ruby/internal/abi.h +++ b/include/ruby/internal/abi.h @@ -24,7 +24,7 @@ * In released versions of Ruby, this number is not defined since teeny * versions of Ruby should guarantee ABI compatibility. */ -#define RUBY_ABI_VERSION 2 +#define RUBY_ABI_VERSION 3 /* Windows does not support weak symbols so ruby_abi_version will not exist * in the shared library. */ diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h index 5ebeb2473e..d0a4dc7c83 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -42,31 +42,9 @@ #endif #define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f)) -#define RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() \ - RBIMPL_ATTR_WARNING(("untyped Data is unsafe; use TypedData instead")) \ - RBIMPL_ATTR_DEPRECATED(("by TypedData")) - -#define RBIMPL_MACRO_SELECT(x, y) x ## y -#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y) /** @endcond */ /** - * Convenient casting macro. - * - * @param obj An object, which is in fact an ::RData. - * @return The passed object casted to ::RData. - */ -#define RDATA(obj) RBIMPL_CAST((struct RData *)(obj)) - -/** - * Convenient getter macro. - * - * @param obj An object, which is in fact an ::RData. - * @return The passed object's ::RData::data field. - */ -#define DATA_PTR(obj) RDATA(obj)->data - -/** * This is a value you can set to ::RData::dfree. Setting this means the data * was allocated using ::ruby_xmalloc() (or variants), and shall be freed using * ::ruby_xfree(). @@ -85,19 +63,6 @@ #define RUBY_NEVER_FREE RBIMPL_DATA_FUNC(0) /** - * @private - * - * @deprecated This macro once was a thing in the old days, but makes no sense - * any longer today. Exists here for backwards compatibility - * only. You can safely forget about it. - */ -#define RUBY_UNTYPED_DATA_FUNC(f) f RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() - -/* -#define RUBY_DATA_FUNC(func) ((void (*)(void*))(func)) -*/ - -/** * This is the type of callbacks registered to ::RData. The argument is the * `data` field. */ @@ -106,264 +71,16 @@ typedef void (*RUBY_DATA_FUNC)(void*); /** * @deprecated * - * Old "untyped" user data. It has roughly the same usage as struct - * ::RTypedData, but lacked several features such as support for compaction GC. - * Use of this struct is not recommended any longer. If it is dead necessary, - * please inform the core devs about your usage. - * - * @internal - * - * @shyouhei tried to add RBIMPL_ATTR_DEPRECATED for this type but that yielded - * too many warnings in the core. Maybe we want to retry later... Just add - * deprecated document for now. - * - * RData shares its initial fields with struct ::RTypedData so the VM can handle - * per-object fields without checking whether a T_DATA object is typed or legacy. + * DO NOT USE: Obsolete "untyped" user data, that is remained only for + * the backward compatibility for some wrapper generator gems. */ struct RData { - - /** Basic part, including flags and class. */ struct RBasic basic; - - /** @internal Direct reference to the slots that hold instance variables, if any. */ VALUE fields_obj; - - /** @internal Padding where ::RTypedData stores its type, so both structs place data at the same offset. */ VALUE _reserved; - - /** Pointer to the actual C level struct that you want to wrap. */ void *data; - - /** - * This function is called when the object is experiencing GC marks. If it - * contains references to other Ruby objects, you need to mark them also. - * Otherwise GC will smash your data. - * - * @see rb_gc_mark() - * @warning This is called during GC runs. Object allocations are - * impossible at that moment (that is why GC runs). - */ RUBY_DATA_FUNC dmark; - - /** - * This function is called when the object is no longer used. You need to - * do whatever necessary to avoid memory leaks. - * - * @warning This is called during GC runs. Object allocations are - * impossible at that moment (that is why GC runs). - */ RUBY_DATA_FUNC dfree; }; -RBIMPL_SYMBOL_EXPORT_BEGIN() - -/** - * This is the primitive way to wrap an existing C struct into ::RData. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] datap Pointer to the target C struct. - * @param[in] dmark Mark function. - * @param[in] dfree Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps `datap`. - */ -VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); - -/** - * Identical to rb_data_object_wrap(), except it allocates a new data region - * internally instead of taking an existing one. The allocation is done using - * ruby_calloc(). Hence it makes no sense to pass anything other than - * ::RUBY_DEFAULT_FREE to the last argument. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] size Requested size of memory to allocate. - * @param[in] dmark Mark function. - * @param[in] dfree Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps a new `size` byte region. - */ -VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); - -RBIMPL_SYMBOL_EXPORT_END() - -/** - * Converts sval, a pointer to your struct, into a Ruby object. - * - * @param klass A ruby level class. - * @param mark Mark function. - * @param free Free function. - * @param sval A pointer to your struct. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - */ -#define Data_Wrap_Struct(klass, mark, free, sval) \ - rb_data_object_wrap( \ - (klass), \ - (sval), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free)) - -/** - * @private - * - * This is an implementation detail of #Data_Make_Struct. People don't use it - * directly. - * - * @param result Variable name of created Ruby object. - * @param klass Ruby level class of the object. - * @param type Type name of the C struct. - * @param size Size of the C struct. - * @param mark Mark function. - * @param free Free function. - * @param sval Variable name of created C struct. - */ -#define Data_Make_Struct0(result, klass, type, size, mark, free, sval) \ - VALUE result = rb_data_object_zalloc( \ - (klass), \ - (size), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free)); \ - (sval) = RBIMPL_CAST((type *)DATA_PTR(result)); \ - RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval)) - -/** - * Identical to #Data_Wrap_Struct, except it allocates a new data region - * internally instead of taking an existing one. The allocation is done using - * ruby_calloc(). Hence it makes no sense to pass anything other than - * ::RUBY_DEFAULT_FREE to the `free` argument. - * - * @param klass Ruby level class of the returning object. - * @param type Type name of the C struct. - * @param mark Mark function. - * @param free Free function. - * @param sval Variable name of created C struct. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - */ -#ifdef HAVE_STMT_AND_DECL_IN_EXPR -#define Data_Make_Struct(klass, type, mark, free, sval) \ - RB_GNUC_EXTENSION({ \ - Data_Make_Struct0( \ - data_struct_obj, \ - klass, \ - type, \ - sizeof(type), \ - mark, \ - free, \ - sval); \ - data_struct_obj; \ - }) -#else -#define Data_Make_Struct(klass, type, mark, free, sval) \ - rb_data_object_make( \ - (klass), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free), \ - RBIMPL_CAST((void **)&(sval)), \ - sizeof(type)) -#endif - -/** - * Obtains a C struct from inside of a wrapper Ruby object. - * - * @param obj An instance of ::RData. - * @param type Type name of the C struct. - * @param sval Variable name of obtained C struct. - * @return Unwrapped C struct that `obj` holds. - */ -#define Data_Get_Struct(obj, type, sval) \ - ((sval) = RBIMPL_CAST((type*)rb_data_object_get(obj))) - -RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() -/** - * @private - * - * This is an implementation detail of rb_data_object_wrap(). People don't use - * it directly. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] ptr Pointer to the target C struct. - * @param[in] mark Mark function. - * @param[in] free Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps `datap`. - */ -static inline VALUE -rb_data_object_wrap_warning(VALUE klass, void *ptr, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free) -{ - return rb_data_object_wrap(klass, ptr, mark, free); -} - -/** - * @private - * - * This is an implementation detail of #Data_Get_Struct. People don't use it - * directly. - * - * @param[in] obj An instance of ::RData. - * @return Unwrapped C struct that `obj` holds. - */ -static inline void * -rb_data_object_get(VALUE obj) -{ - Check_Type(obj, RUBY_T_DATA); - return DATA_PTR(obj); -} - -RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() -/** - * @private - * - * This is an implementation detail of #Data_Get_Struct. People don't use it - * directly. - * - * @param[in] obj An instance of ::RData. - * @return Unwrapped C struct that `obj` holds. - */ -static inline void * -rb_data_object_get_warning(VALUE obj) -{ - return rb_data_object_get(obj); -} - -/** - * This is an implementation detail of #Data_Make_Struct. People don't use it - * directly. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] mark_func Mark function. - * @param[in] free_func Free function. - * @param[in] datap Variable of created C struct. - * @param[in] size Requested size of allocation. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - * @post `*datap` holds the created C struct. - */ -static inline VALUE -rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_func, void **datap, size_t size) -{ - Data_Make_Struct0(result, klass, void, size, mark_func, free_func, *datap); - return result; -} - -/** @cond INTERNAL_MACRO */ -#define rb_data_object_wrap_0 rb_data_object_wrap -#define rb_data_object_wrap_1 rb_data_object_wrap_warning -#define rb_data_object_wrap_2 rb_data_object_wrap_ /* Used here vvvv */ -#define rb_data_object_wrap RUBY_MACRO_SELECT(rb_data_object_wrap_2, RUBY_UNTYPED_DATA_WARNING) -#define rb_data_object_get_0 rb_data_object_get -#define rb_data_object_get_1 rb_data_object_get_warning -#define rb_data_object_get_2 rb_data_object_get_ /* Used here vvvv */ -#define rb_data_object_get RUBY_MACRO_SELECT(rb_data_object_get_2, RUBY_UNTYPED_DATA_WARNING) -#define rb_data_object_make_0 rb_data_object_make -#define rb_data_object_make_1 rb_data_object_make_warning -#define rb_data_object_make_2 rb_data_object_make_ /* Used here vvvv */ -#define rb_data_object_make RUBY_MACRO_SELECT(rb_data_object_make_2, RUBY_UNTYPED_DATA_WARNING) -/** @endcond */ #endif /* RBIMPL_RDATA_H */ diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index 0b189c7ef8..eb8313f180 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -206,11 +206,6 @@ rbimpl_typeddata_flags { RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */ /** - * This flag is used to distinguish RTypedData from deprecated RData objects. - */ - RUBY_TYPED_FL_IS_TYPED_DATA = RUBY_FL_USERPRIV0, - - /** * This flag determines whether marking and compaction should be carried out * using the dmark/dcompact callback functions or whether we should mark * declaratively using a list of references defined inside the data struct we're wrapping @@ -409,6 +404,22 @@ RBIMPL_STATIC_ASSERT(fields_obj_in_rdata, offsetof(struct RData, fields_obj) == RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data)); #endif +/** + * Convenient casting macro for backward compatibility. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object casted to ::RData. + */ +#define RDATA(obj) RTYPEDDATA(obj) + +/** + * Convenient casting macro for backward compatibility. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object's ::RTypedData::data field. + */ +#define DATA_PTR(obj) RTYPEDDATA_DATA(obj) + RBIMPL_SYMBOL_EXPORT_BEGIN() RBIMPL_ATTR_NONNULL((3)) /** @@ -621,27 +632,7 @@ RBIMPL_ATTR_ARTIFICIAL() /** * @private * - * This is an implementation detail of Check_Type(). People don't use it - * directly. - * - * @param[in] obj Object in question - * @retval true `obj` is an instance of ::RTypedData. - * @retval false `obj` is an instance of ::RData. - * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. - */ -static inline bool -rbimpl_rtypeddata_p(VALUE obj) -{ - return FL_TEST_RAW(obj, RUBY_TYPED_FL_IS_TYPED_DATA); -} - -RBIMPL_ATTR_PURE() -RBIMPL_ATTR_ARTIFICIAL() -/** - * @private - * - * Identical to rbimpl_rtypeddata_p(), except it is allowed to call on non-data - * objects. + * Checks whether the passed object is ::RTypedData. * * This is an implementation detail of inline functions defined in this file. * People don't use it directly. @@ -653,17 +644,16 @@ RBIMPL_ATTR_ARTIFICIAL() static inline bool rbimpl_obj_typeddata_p(VALUE obj) { - return RB_TYPE_P(obj, RUBY_T_DATA) && rbimpl_rtypeddata_p(obj); + return RB_TYPE_P(obj, RUBY_T_DATA); } RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() /** - * Checks whether the passed object is ::RTypedData or ::RData. + * Checks whether the passed object is ::RTypedData. * * @param[in] obj Object in question - * @retval true `obj` is an instance of ::RTypedData. - * @retval false `obj` is an instance of ::RData. + * @retval true * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. */ static inline bool @@ -671,7 +661,7 @@ RTYPEDDATA_P(VALUE obj) { RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); - return rbimpl_rtypeddata_p(obj); + return true; } RBIMPL_ATTR_PURE_UNLESS_DEBUG() @@ -752,7 +742,6 @@ static inline VALUE rbimpl_check_external_typeddata(VALUE obj) { RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); - RUBY_ASSERT(rbimpl_obj_typeddata_p(obj)); RUBY_ASSERT(!rbimpl_typeddata_embedded_p(obj)); return obj; } diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index e3878d9ed7..f7ec742422 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -205,11 +205,11 @@ ruby_fl_type { RUBY_FL_PROMOTED = (1<<5), /** - * This flag meaning is type dependent, currently only used by T_DATA. + * This flag is no longer in use * * @internal */ - RUBY_FL_USERPRIV0 = (1<<6), + RUBY_FL_UNUSED6 = (1<<6), /** * This flag has something to do with finalisers. A ruby object can have diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h index b47d8afb97..77cb38bc7d 100644 --- a/include/ruby/internal/value_type.h +++ b/include/ruby/internal/value_type.h @@ -410,14 +410,6 @@ RB_TYPE_P(VALUE obj, enum ruby_value_type t) #endif /** @endcond */ -RBIMPL_ATTR_PURE() -RBIMPL_ATTR_ARTIFICIAL() -/** - * @private - * Defined in ruby/internal/core/rtypeddata.h - */ -static inline bool rbimpl_rtypeddata_p(VALUE obj); - RBIMPL_ATTR_ARTIFICIAL() /** * Identical to RB_TYPE_P(), except it raises exceptions on predication @@ -432,19 +424,11 @@ RBIMPL_ATTR_ARTIFICIAL() static inline void Check_Type(VALUE v, enum ruby_value_type t) { + /* Typed data is not simple `T_DATA`, see `rb_check_type` */ + RUBY_ASSERT_ALWAYS(t != RUBY_T_DATA); if (RB_UNLIKELY(! RB_TYPE_P(v, t))) { - goto unexpected_type; + rb_unexpected_type(v, RBIMPL_CAST((int)t)); } - else if (t == RUBY_T_DATA && rbimpl_rtypeddata_p(v)) { - /* Typed data is not simple `T_DATA`, see `rb_check_type` */ - goto unexpected_type; - } - else { - return; - } - - unexpected_type: - rb_unexpected_type(v, RBIMPL_CAST((int)t)); } #endif /* RBIMPL_VALUE_TYPE_H */ diff --git a/include/ruby/random.h b/include/ruby/random.h index 740be6bdad..3b63a23334 100644 --- a/include/ruby/random.h +++ b/include/ruby/random.h @@ -333,7 +333,6 @@ static inline const rb_random_interface_t * rb_rand_if(VALUE obj) { RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(obj, T_DATA)); - RBIMPL_ASSERT_OR_ASSUME(RTYPEDDATA_P(obj)); RUBY_ASSERT(rb_typeddata_is_kind_of(obj, &rb_random_data_type)); const struct rb_data_type_struct *t = RTYPEDDATA_TYPE(obj); const void *ret = t->data; @@ -1099,10 +1099,25 @@ invokesuper // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); // attr bool zjit_profile = true; { - VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true); - val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super); + struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci), + vm_ci_flag(cd->ci), + vm_ci_argc(cd->ci), + vm_ci_kwarg(cd->ci)); + const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE); + struct rb_call_data adjusted_cd = { + .ci = &adjusted_ci, + .cc = original_cc, + }; + + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true); + val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super); JIT_EXEC(ec, val); + if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) { + rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE); + RB_OBJ_WRITTEN(GET_ISEQ(), Qundef, adjusted_cd.cc); + } + if (UNDEF_P(val)) { RESTORE_REGS(); NEXT_INSN(); diff --git a/internal/hash.h b/internal/hash.h index baf5af9abd..0386a5009c 100644 --- a/internal/hash.h +++ b/internal/hash.h @@ -70,7 +70,6 @@ struct RHash { #endif /* hash.c */ -void rb_hash_st_table_set(VALUE hash, st_table *st); VALUE rb_hash_default_value(VALUE hash, VALUE key); VALUE rb_hash_set_default(VALUE hash, VALUE ifnone); VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); @@ -197,7 +196,6 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h) ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \ (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT))) -#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s) #define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type) static inline unsigned int diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb index a1d5c94fc5..b2547b136b 100644 --- a/lib/rubygems/yaml_serializer.rb +++ b/lib/rubygems/yaml_serializer.rb @@ -72,9 +72,7 @@ module Gem def parse_node(base_indent) @depth += 1 - if @depth > MAX_NESTING_DEPTH - raise Psych::SyntaxError, "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})" - end + raise_max_nesting! if @depth > MAX_NESTING_DEPTH skip_blank_and_comments return nil if @lines.empty? @@ -285,7 +283,9 @@ module Gem Scalar.new(value: result) end - def coerce(val) + def coerce(val, depth = 0) + raise_max_nesting! if depth > MAX_NESTING_DEPTH + val = val.sub(/^! /, "") if val.start_with?("! ") if val =~ /^"(.*)"$/ @@ -311,7 +311,7 @@ module Gem elsif val =~ /^\[(.*)\]$/ inner = $1.strip return Sequence.new if inner.empty? - items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e)) } + items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e, depth + 1)) } Sequence.new(items: items) elsif /\A\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}:\d{2})?/.match?(val) begin @@ -392,6 +392,15 @@ module Gem node end + def raise_max_nesting! + message = "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})" + if defined?(Psych::VERSION) + raise Psych::SyntaxError.new(nil, 0, 0, 0, message, nil) + else + raise Psych::SyntaxError, message + end + end + def skip_blank_and_comments while @lines.any? line = @lines[0] @@ -454,9 +463,7 @@ module Gem result = build_node(node) - if result.is_a?(Hash) && - (result[:tag] == "!ruby/object:Gem::Specification" || - result["tag"] == "!ruby/object:Gem::Specification") + if result.is_a?(Hash) && result[:tag] == "!ruby/object:Gem::Specification" build_specification(result) else result @@ -482,7 +489,11 @@ module Gem if @alias_count > MAX_ALIAS_RESOLUTIONS raise Psych::BadAlias, "exceeded maximum alias resolutions (#{MAX_ALIAS_RESOLUTIONS})" end - @anchor_values.fetch(node.name, nil) + unless @anchor_values.key?(node.name) + klass = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias + raise klass, "An alias referenced an unknown anchor: #{node.name}" + end + @anchor_values.fetch(node.name) end def store_anchor(name, value) @@ -491,7 +502,6 @@ module Gem end def build_mapping(node) - check_anchor!(node) validate_tag!(node.tag) if node.tag result = case node.tag @@ -592,9 +602,14 @@ module Gem d.instance_variable_set(:@requirement, hash["requirement"] || hash["version_requirements"]) - type = hash["type"] - type = type ? type.to_s.sub(/^:/, "").to_sym : :runtime - validate_symbol!(type) + raw_type = hash["type"] + if raw_type + name = raw_type.to_s.sub(/^:/, "") + validate_symbol!(name) + type = name.to_sym + else + type = :runtime + end d.instance_variable_set(:@type, type) d.instance_variable_set(:@prerelease, ["true", true].include?(hash["prerelease"])) @@ -634,19 +649,14 @@ module Gem end end - def validate_symbol!(sym) - if @permitted_symbols.any? && !@permitted_symbols.include?(sym.to_s) - if defined?(Psych::VERSION) - raise Psych::DisallowedClass.new("load", sym.inspect) - else - raise Psych::DisallowedClass, "Tried to load unspecified class: #{sym.inspect}" - end - end - end + def validate_symbol!(name) + return if @permitted_symbols.empty? || @permitted_symbols.include?(name) - def check_anchor!(node) - if node.anchor - raise Psych::AliasesNotEnabled unless @aliases + label = ":#{name}" + if defined?(Psych::VERSION) + raise Psych::DisallowedClass.new("load", label) + else + raise Psych::DisallowedClass, "Tried to load unspecified class: #{label}" end end @@ -1242,6 +1242,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit) struct load_arg { VALUE src; char *buf; + long bufsize; long buflen; long readable; long offset; @@ -1327,15 +1328,23 @@ static unsigned char r_byte1_buffered(struct load_arg *arg) { if (arg->buflen == 0) { - long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ; + long readable = arg->readable < arg->bufsize ? arg->readable : arg->bufsize; + long read_len; VALUE str, n = LONG2NUM(readable); str = load_funcall(arg, arg->src, s_read, 1, &n); if (NIL_P(str)) too_short(); StringValue(str); - memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str)); + read_len = RSTRING_LEN(str); + if (UNLIKELY(read_len < readable)) too_short(); + if (UNLIKELY(read_len > arg->bufsize)) { + arg->buf = ruby_sized_realloc_n(arg->buf, read_len, 1, arg->bufsize); + arg->bufsize = read_len; + } + memcpy(arg->buf, RSTRING_PTR(str), read_len); arg->offset = 0; - arg->buflen = RSTRING_LEN(str); + arg->buflen = read_len; + RB_GC_GUARD(str); } arg->buflen--; return arg->buf[arg->offset++]; @@ -1422,6 +1431,18 @@ ruby_marshal_read_long(const char **buf, long len) return x; } +static long +r_keep_readable(struct load_arg *arg, long len, size_t size) +{ + if (UNLIKELY(len < 0)) { + rb_raise(rb_eArgError, "negative length"); + } + if (UNLIKELY((unsigned long)len > SIZE_MAX / size || arg->readable >= LONG_MAX - len)) { + rb_raise(rb_eArgError, "marshaled data too big"); + } + return len; +} + static VALUE r_bytes1(long len, struct load_arg *arg) { @@ -1451,7 +1472,7 @@ r_bytes1_buffered(long len, struct load_arg *arg) long tmp_len, read_len, need_len = len - buflen; VALUE tmp, n; - readable = readable < BUFSIZ ? readable : BUFSIZ; + readable = readable < arg->bufsize ? readable : arg->bufsize; read_len = need_len > readable ? need_len : readable; n = LONG2NUM(read_len); tmp = load_funcall(arg, arg->src, s_read, 1, &n); @@ -2005,7 +2026,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex int sign; sign = r_byte(arg); - len = r_long(arg); + if (sign != '+' && sign != '-') { + rb_raise(rb_eArgError, "invalid Bignum sign"); + } + len = r_keep_readable(arg, r_long(arg), 2); if (SIZEOF_VALUE >= 8 && len <= 4) { // Representable within uintptr, likely FIXNUM @@ -2083,7 +2107,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex case TYPE_ARRAY: { - long len = r_long(arg); + long len = r_keep_readable(arg, r_long(arg), 1); v = rb_ary_new2(len); v = r_entry(v, arg); @@ -2101,7 +2125,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex case TYPE_HASH_DEF: type_hash: { - long len = r_long(arg); + long len = r_keep_readable(arg, r_long(arg), 2); v = hash_new_with_size(len); v = r_entry(v, arg); @@ -2127,7 +2151,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex VALUE slot; st_index_t idx = r_prepare(arg); VALUE klass = path2class(r_unique(arg)); - long len = r_long(arg); + long len = r_keep_readable(arg, r_long(arg), 2); v = rb_obj_alloc(klass); if (!RB_TYPE_P(v, T_STRUCT)) { @@ -2344,8 +2368,9 @@ r_object(struct load_arg *arg) static void clear_load_arg(struct load_arg *arg) { - ruby_xfree_sized(arg->buf, BUFSIZ); + ruby_xfree_sized(arg->buf, arg->bufsize); arg->buf = NULL; + arg->bufsize = 0; arg->buflen = 0; arg->offset = 0; arg->readable = 0; @@ -2391,10 +2416,14 @@ rb_marshal_load_with_proc(VALUE port, VALUE proc, bool freeze) arg->readable = 0; arg->freeze = freeze; - if (NIL_P(v)) + if (NIL_P(v)) { + arg->bufsize = BUFSIZ; arg->buf = xmalloc(BUFSIZ); - else + } + else { + arg->bufsize = 0; arg->buf = 0; + } major = r_byte(arg); minor = r_byte(arg); diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py index e0cb609b1a..a2bcedc328 100644 --- a/misc/lldb_rb/utils.py +++ b/misc/lldb_rb/utils.py @@ -236,29 +236,20 @@ class RbInspector(LLDBInterface): elif rval.is_type("RUBY_T_DATA"): tRTypedData = self.target.FindFirstType("struct RTypedData").GetPointerType() val = val.Cast(tRTypedData) - is_typed_data = self.ruby_globals.get("RUBY_TYPED_FL_IS_TYPED_DATA", None) - if is_typed_data: - typed = rval.flags & is_typed_data - else: - typed = val.GetValueForExpressionPath("->typed_flag").GetValueAsUnsigned() == 1 - - if typed: - type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned() - embed = (type & 1) - if embed: - flaginfo += "[EMBED] " - type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1)) - print("T_DATA: %s%s" % - (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")), - file=self.result) - print("%s", type.Dereference(), file=self.result) - ptr = val.GetValueForExpressionPath("->data") - if embed: - ptr = ptr.AddressOf() - self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned()) - else: - print("T_DATA:", file=self.result) - self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned()) + + type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned() + embed = (type & 1) + if embed: + flaginfo += "[EMBED] " + type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1)) + print("T_DATA: %s%s" % + (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")), + file=self.result) + print("%s", type.Dereference(), file=self.result) + ptr = val.GetValueForExpressionPath("->data") + if embed: + ptr = ptr.AddressOf() + self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned()) elif rval.is_type("RUBY_T_IMEMO"): imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"]) diff --git a/pathname_builtin.rb b/pathname_builtin.rb index ac436d4946..11ade220f0 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -557,19 +557,28 @@ class Pathname !absolute? end + # :markup: markdown + # + # call-seq: + # each_filename {|component| ... } -> nil + # each_filename -> new_enumerator # - # Iterates over each component of the path. + # With a block given, yields each component of the string path: # - # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... } - # # yields "usr", "bin", and "ruby". + # ```ruby + # Pathname('/foo/bar/baz').each_filename {|filename| p filename } + # => nil + # ``` # - # Returns an Enumerator if no block was given. + # Output: # - # enum = Pathname.new("/usr/bin/ruby").each_filename - # # ... do stuff ... - # enum.each { |e| ... } - # # yields "usr", "bin", and "ruby". + # ```text + # "foo" + # "bar" + # "baz" + # ``` # + # With no block given, returns a new Enumerator. def each_filename # :yield: filename return to_enum(__method__) unless block_given? _, names = split_names(@path) @@ -901,12 +910,34 @@ class Pathname end class Pathname # * File * + + # :markup: markdown + # + # call-seq: + # each_line(sep = $/, **opts) {|line| ... } → nil + # each_line(limit, **opts) {|line| ... } → nil + # each_line(sep, limit, **opts) {|line| ... } → nil + # each_line(...) → new_enumerator + # + # With a block given, calls the block with each line + # from the file represented by `self`; + # returns `nil`: # - # #each_line iterates over the line in the file. It yields a String object - # for each line. + # ```ruby + # lines = [] + # Pathname('COPYING').each_line {|line| lines << line } + # lines.take(3) + # # => + # # ["{日本語}[rdoc-ref:COPYING.ja]\n", + # # "\n", + # # "Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.\n"] + # ``` # - # This method has existed since 1.8.1. + # The lines are read using IO.foreach, + # all arguments and options are passed to that method; + # see details at IO.foreach. # + # With no block given, returns a new Enumerator. def each_line(...) # :yield: line File.foreach(@path, ...) end @@ -1391,10 +1422,81 @@ class Pathname # * File * # See <tt>File.dirname</tt>. Returns all but the last component of the path. def dirname() self.class.new(File.dirname(@path)) end - # See <tt>File.extname</tt>. Returns the file's extension. + # :markup: markdown + # + # call-seq: + # extname -> extension + # + # Returns the filename extension of `self` -- + # usually the portion of the string path beginning from the last period: + # + # ```ruby + # Pathname('t.rb').extname # => ".rb" + # Pathname('foo.bar.t.rb').extname # => ".rb" + # Pathname('foo/bar/t.rb').extname # => ".rb" + # Pathname('nosuch.txt').extname # => ".txt" # Path need not exist. + # ``` + # + # Returns the entire string when there is no period: + # + # ```ruby + # Pathname('foo').extname # => "" + # ``` + # + # Returns an empty string when the only period is the first character: + # + # ```ruby + # Pathname('.irbrc').extname # => "" + # ``` + # + # Returns an empty string or `'.'` when `path` ends with a period: + # + # ```ruby + # Pathname('foo.').extname # => "" # On Windows. + # Pathname('foo.').extname # => "." # Elsewhere. + # Pathname('foo....').extname # => "" # On Windows. + # Pathname('foo....').extname # => "." # Elsewhere. + # ``` + # def extname() File.extname(@path) end - # See <tt>File.expand_path</tt>. + # :markup: markdown + # + # call-seq: + # expand_path(dirpath = '.') -> new_pathname + # + # Returns a new pathname containing the absolute path for `self`. + # + # Evaluates a relative path with respect to the directory given by `dirpath`: + # + # ```ruby + # Dir.chdir('/snap') + # # Default dirpath. + # Pathname('README').expand_path # => #<Pathname:/snap/README> + # Pathname('bin').expand_path # => #<Pathname:/snap/bin> + # Pathname('bin/../var').expand_path # => #<Pathname:/snap/var> # Cleaned. + # # Other dirpath. + # Pathname('../zip').expand_path('/usr/bin/ruby') # => #<Pathname:/usr/bin/zip> + # Dir.chdir('/usr/bin') + # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap> + # ``` + # + # Evaluates an absolute path without respect to `dirpath`: + # + # ```ruby + # Pathname('/snap').expand_path # => #<Pathname:/snap> + # Pathname('/snap').expand_path.expand_path('nosuch') # => #<Pathname:/snap> + # Pathname('/snap/../snap').expand_path # => #<Pathname:/snap> # Cleaned. + # ``` + # + # More examples: + # + # ``` + # Dir.chdir('/usr/bin') + # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap> + # Pathname('../../snap').expand_path # => #<Pathname:/snap> + # ``` + # def expand_path(...) self.class.new(File.expand_path(@path, ...)) end # See <tt>File.split</tt>. Returns the #dirname and the #basename in an @@ -1694,8 +1796,24 @@ class Pathname # * Dir * alias pwd getwd end - # Return the entries (files and subdirectories) in the directory, each as a - # Pathname object. + # :markup: markdown + # + # call-seq: + # entries -> array_of_pathnames + # + # Returns an array of pathnames, + # one for each entry in the directory represented by `self`: + # + # ```ruby + # Pathname('.').entries.take(5) + # # => + # # [#<Pathname:.>, + # # #<Pathname:..>, + # # #<Pathname:gc.rb>, + # # #<Pathname:yjit.rb>, + # # #<Pathname:iseq.h>] + # ``` + # def entries() Dir.entries(@path).map {|f| self.class.new(f) } end # :markup: markdown @@ -1451,7 +1451,7 @@ allow_frozen_shareable_p(VALUE obj) if (!RB_TYPE_P(obj, T_DATA)) { return true; } - else if (RTYPEDDATA_P(obj)) { + else { const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE) { return true; diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 877deca663..27ddc6a771 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -38,7 +38,7 @@ require_relative "support/indexes" require_relative "support/matchers" require_relative "support/permissions" require_relative "support/platforms" -require_relative "support/windows_tag_group" +require_relative "support/shards" begin raise LoadError if File.exist?(File.expand_path("../../lib/bundler/bundler.gemspec", __dir__)) @@ -88,7 +88,7 @@ RSpec.configure do |config| config.include Spec::Path config.include Spec::Platforms config.include Spec::Permissions - config.include Spec::WindowsTagGroup + config.include Spec::Shards # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" @@ -175,7 +175,7 @@ RSpec.configure do |config| reset! end - Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.each do |tag, file_paths| + Spec::Shards::EXAMPLE_MAPPINGS.each do |tag, file_paths| file_pattern = Regexp.union(file_paths.map {|path| Regexp.new(Regexp.escape(path) + "$") }) config.define_derived_metadata(file_path: file_pattern) do |metadata| @@ -185,8 +185,8 @@ RSpec.configure do |config| config.before(:context) do |example| metadata = example.class.metadata - if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.keys.include?(k) } - warn "#{metadata[:file_path]} is not assigned to any Windows runner group. see spec/support/windows_tag_group.rb for details." + if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::Shards::EXAMPLE_MAPPINGS.keys.include?(k) } + warn "#{metadata[:file_path]} is not assigned to any shard. see spec/support/shards.rb for details." end end unless Spec::Path.ruby_core? end diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb index e61fe921ec..e684aa8628 100644 --- a/spec/bundler/support/artifice/helpers/compact_index.rb +++ b/spec/bundler/support/artifice/helpers/compact_index.rb @@ -2,7 +2,7 @@ require_relative "endpoint" -$LOAD_PATH.unshift Dir[Spec::Path.scoped_base_system_gem_path.join("gems/compact_index*/lib")].first.to_s +$LOAD_PATH.unshift Spec::Path.tmp_root.join("compact_index/lib").to_s require "compact_index" require "digest" @@ -90,13 +90,17 @@ class CompactIndexAPI < Endpoint rescue StandardError checksum = nil end - CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil, - deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s) + build_gem_version(spec, deps, checksum) end CompactIndex::Gem.new(name, gem_versions) end end end + + def build_gem_version(spec, deps, checksum) + CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil, + deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s) + end end get "/names" do diff --git a/spec/bundler/support/windows_tag_group.rb b/spec/bundler/support/shards.rb index fb9c081149..580997eb72 100644 --- a/spec/bundler/support/windows_tag_group.rb +++ b/spec/bundler/support/shards.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -# This group classifies test files into 4 groups by running `bin/rspec --profile 10000` +# This classifies test files into 4 shards by running `bin/rspec --profile 10000` # to ensure balanced execution times. When adding new test files, it is recommended to -# re-aggregate and adjust the groups to keep them balanced. -# For now, please add new files to group 'windows_d'. +# re-aggregate and adjust the shards to keep them balanced. +# For now, please add new files to shard 'shard_d'. module Spec - module WindowsTagGroup + module Shards EXAMPLE_MAPPINGS = { - windows_a: [ + shard_a: [ "spec/runtime/setup_spec.rb", "spec/commands/install_spec.rb", "spec/commands/add_spec.rb", @@ -53,7 +53,7 @@ module Spec "spec/bundler/plugin/source_list_spec.rb", "spec/bundler/source/path_spec.rb", ], - windows_b: [ + shard_b: [ "spec/install/gemfile/git_spec.rb", "spec/install/gems/standalone_spec.rb", "spec/commands/lock_spec.rb", @@ -97,7 +97,7 @@ module Spec "spec/bundler/index_spec.rb", "spec/other/cli_man_pages_spec.rb", ], - windows_c: [ + shard_c: [ "spec/commands/newgem_spec.rb", "spec/commands/exec_spec.rb", "spec/commands/clean_spec.rb", @@ -142,7 +142,7 @@ module Spec "spec/bundler/cli_common_spec.rb", "spec/bundler/ci_detector_spec.rb", ], - windows_d: [ + shard_d: [ "spec/commands/outdated_spec.rb", "spec/commands/update_spec.rb", "spec/lock/lockfile_spec.rb", diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h index 7107bead90..5a92645785 100644 --- a/spec/ruby/optional/capi/ext/rubyspec.h +++ b/spec/ruby/optional/capi/ext/rubyspec.h @@ -35,6 +35,10 @@ (RUBY_API_VERSION_MAJOR == (major) && RUBY_API_VERSION_MINOR < (minor))) #define RUBY_VERSION_SINCE(major,minor) (!RUBY_VERSION_BEFORE(major, minor)) +#if RUBY_VERSION_SINCE(4, 1) +#define RUBY_VERSION_IS_4_1 +#endif + #if RUBY_VERSION_SINCE(4, 0) #define RUBY_VERSION_IS_4_0 #endif diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c index 221f1c8ac4..c6fcfa3bc8 100644 --- a/spec/ruby/optional/capi/ext/typed_data_spec.c +++ b/spec/ruby/optional/capi/ext/typed_data_spec.c @@ -106,6 +106,7 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) { return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar); } +#ifndef RUBY_VERSION_IS_4_1 #undef RUBY_UNTYPED_DATA_WARNING #define RUBY_UNTYPED_DATA_WARNING 0 VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) { @@ -113,6 +114,7 @@ VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) { *data = FIX2INT(val); return Data_Wrap_Struct(rb_cObject, NULL, free, data); } +#endif VALUE sws_typed_get_struct(VALUE self, VALUE obj) { struct sample_typed_wrapped_struct* bar; @@ -173,9 +175,11 @@ VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) { return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; } +#ifndef RUBY_VERSION_IS_4_1 VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) { return RTYPEDDATA_P(obj) ? Qtrue : Qfalse; } +#endif void Init_typed_data_spec(void) { VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject); @@ -183,7 +187,9 @@ void Init_typed_data_spec(void) { rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0); cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject); rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1); +#ifndef RUBY_VERSION_IS_4_1 rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1); +#endif rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1); rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1); rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1); @@ -194,10 +200,11 @@ void Init_typed_data_spec(void) { rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1); rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1); rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1); +#ifndef RUBY_VERSION_IS_4_1 rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1); +#endif } #ifdef __cplusplus } #endif - diff --git a/spec/ruby/optional/capi/typed_data_spec.rb b/spec/ruby/optional/capi/typed_data_spec.rb index 8eaf7751ba..376cfe417f 100644 --- a/spec/ruby/optional/capi/typed_data_spec.rb +++ b/spec/ruby/optional/capi/typed_data_spec.rb @@ -86,15 +86,17 @@ describe "CApiWrappedTypedStruct" do end end - describe "RTYPEDDATA_P" do - it "returns true for a typed data" do - a = @s.typed_wrap_struct(1024) - @s.RTYPEDDATA_P(a).should == true - end + ruby_version_is ""..."4.1" do + describe "RTYPEDDATA_P" do + it "returns true for a typed data" do + a = @s.typed_wrap_struct(1024) + @s.RTYPEDDATA_P(a).should == true + end - it "returns false for an untyped data object" do - a = @s.untyped_wrap_struct(1024) - @s.RTYPEDDATA_P(a).should == false + it "returns false for an untyped data object" do + a = @s.untyped_wrap_struct(1024) + @s.RTYPEDDATA_P(a).should == false + end end end end diff --git a/test/date/test_date_strptime.rb b/test/date/test_date_strptime.rb index 4efe1a47d0..6aa7db292d 100644 --- a/test/date/test_date_strptime.rb +++ b/test/date/test_date_strptime.rb @@ -517,7 +517,20 @@ class TestDateStrptime < Test::Unit::TestCase d = DateTime.strptime('9000 +0200', '%Q %z') assert_equal([1970, 1, 1, 2, 0, 9], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) assert_equal(Rational(2, 24), d.offset) - end + def test_format_modified + str = " " * 100 + fmt = Struct.new(:str) { + def to_str + str << "2026-06-01" << " "*100 + " %F " + end + }.new(str) + d = Date._strptime(str, fmt) + assert_not_nil(d) + assert_equal(2026, d[:year]) + assert_equal(6, d[:mon]) + assert_equal(1, d[:mday]) + end end diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb index 87d9cd7f7d..753ee0fbdf 100755 --- a/test/json/json_generator_test.rb +++ b/test/json/json_generator_test.rb @@ -601,6 +601,8 @@ class JSONGeneratorTest < Test::Unit::TestCase assert_equal too_deep, ok ok = generate too_deep_ary, :max_nesting => 0 assert_equal too_deep, ok + + assert_raise(TypeError) { generate too_deep_ary, max_nesting: "garbage" } end def test_backslash diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index 67d86a0b35..292ca1a670 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -545,22 +545,26 @@ class JSONParserTest < Test::Unit::TestCase end def test_backslash + assert_raise(JSON::ParserError) do + JSON.parse('"\\') + end + data = [ '\\.(?i:gif|jpe?g|png)$' ] json = '["\\\\.(?i:gif|jpe?g|png)$"]' assert_equal data, parse(json) - # + data = [ '\\"' ] json = '["\\\\\""]' assert_equal data, parse(json) - # + json = '["/"]' data = [ '/' ] assert_equal data, parse(json) - # + json = '["\""]' data = ['"'] assert_equal data, parse(json) - # + json = '["\\/"]' data = ["/"] assert_equal data, parse(json) @@ -878,6 +882,22 @@ class JSONParserTest < Test::Unit::TestCase end end + def test_mutating_source_string_during_parsing + expected = ([1] * 100) + [2.3] + ([1] * 100) + source = JSON.generate(expected) + expected.delete_at(100) + + fake_decimal_class = Class.new + fake_decimal_class.define_method(:initialize) do |number| + source.tr!('1', '0') + number.to_f + end + + actual = JSON.parse(source, decimal_class: fake_decimal_class) + actual.delete_at(100) + assert_equal expected, actual + end + private def assert_equal_float(expected, actual, delta = 1e-2) diff --git a/test/json/json_ryu_fallback_test.rb b/test/json/json_ryu_fallback_test.rb index 152de7e360..a61b3e668d 100644 --- a/test/json/json_ryu_fallback_test.rb +++ b/test/json/json_ryu_fallback_test.rb @@ -179,5 +179,13 @@ class JSONRyuFallbackTest < Test::Unit::TestCase assert_equal(-0.0, JSON.parse("-99999999999999999e-4294967296")) assert_equal(-Float::INFINITY, JSON.parse("-1e4294967295")) assert_equal(-Float::INFINITY, JSON.parse("-1e4294967297")) + + assert_equal(Float::INFINITY, JSON.parse("1e9223372036854775808")) + assert_equal(Float::INFINITY, JSON.parse("1e9999999999999999999")) + assert_equal(Float::INFINITY, JSON.parse("1e18446744073709551616")) + assert_equal(Float::INFINITY, JSON.parse("1e10000000000000000000")) + assert_equal(Float::INFINITY, JSON.parse("1e184467440737095516160")) + assert_equal 0.0, JSON.parse("1e-18446744073709551615") + assert_equal 0.0, JSON.parse("1e-9223372036854775809") end end diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb index 91ed247414..bc1f680df5 100644 --- a/test/openssl/test_digest.rb +++ b/test/openssl/test_digest.rb @@ -155,6 +155,22 @@ class OpenSSL::TestDigest < OpenSSL::TestCase assert_include digests, "sha256" assert_include digests, "sha512" end + + if respond_to?(:ractor) && defined?(Ractor.shareable_proc) + ractor + + def test_ractor + assert_nothing_raised do + Ractor.new { + [ + OpenSSL::Digest::SHA256.new(""), + OpenSSL::Digest::SHA256.hexdigest(""), + OpenSSL::Digest::SHA256.digest(""), + ] + }.value + end + end + end end end diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb index 6a12a25aa8..708d1883af 100644 --- a/test/openssl/test_kdf.rb +++ b/test/openssl/test_kdf.rb @@ -5,64 +5,31 @@ if defined?(OpenSSL) class OpenSSL::TestKDF < OpenSSL::TestCase def test_pkcs5_pbkdf2_hmac_compatibility - expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) + # PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in + # FIPS. + # SP 800-132. + # https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf + # * 5.1 The Salt (S) + # * 5.2 The Iteration Count (C) + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L235-L240 + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L247-L252 + # Use the same parameters with test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25. + expected = OpenSSL::KDF.pbkdf2_hmac("passwordPASSWORDpassword", + salt: "saltSALTsaltSALTsaltSALTsaltSALTsalt", + iterations: 4096, + length: 25, + hash: "sha1") + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("passwordPASSWORDpassword", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + 4096, + 25, + "sha1")) + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("passwordPASSWORDpassword", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + 4096, + 25)) end - def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 - p ="password" - s = "salt" - c = 1 - dk_len = 20 - raw = %w{ 0c 60 c8 0f 96 1f 0e 71 - f3 a9 b5 24 af 60 12 06 - 2f e0 37 a6 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 - p ="password" - s = "salt" - c = 2 - dk_len = 20 - raw = %w{ ea 6c 01 4d c7 2d 6f 8c - cd 1e d9 2a ce 1d 41 f0 - d8 de 89 57 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 - p ="password" - s = "salt" - c = 4096 - dk_len = 20 - raw = %w{ 4b 00 79 01 b7 65 48 9a - be ad 49 d9 26 f7 21 d0 - 65 a4 29 c1 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - -# takes too long! -# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 -# p ="password" -# s = "salt" -# c = 16777216 -# dk_len = 20 -# raw = %w{ ee fe 3d 61 cd 4d a4 e4 -# e9 94 5b 3d 6b a2 15 8c -# 26 34 e9 84 } -# expected = [raw.join('')].pack('H*') -# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") -# assert_equal(expected, value) -# end - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 p ="passwordPASSWORDpassword" s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" @@ -78,18 +45,6 @@ class OpenSSL::TestKDF < OpenSSL::TestCase assert_equal(expected, value) end - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 - p ="pass\0word" - s = "sa\0lt" - c = 4096 - dk_len = 16 - raw = %w{ 56 fa 6a a7 55 48 09 9d - cc 37 d7 f0 34 25 e0 c3 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") - assert_equal(expected, value) - end - def test_pbkdf2_hmac_sha256_c_20000_len_32 #unfortunately no official test vectors available yet for SHA-2 p ="password" @@ -103,6 +58,11 @@ class OpenSSL::TestKDF < OpenSSL::TestCase def test_scrypt_rfc7914_first pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + # scrypt is not available in FIPS. + # EVP_KDF_fetch(ctx, OSSL_KDF_NAME_SCRYPT, propq) returns NULL in FIPS. + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/crypto/evp/pbe_scrypt.c#L67-L71 + omit_on_fips + pass = "" salt = "" n = 16 @@ -118,6 +78,9 @@ class OpenSSL::TestKDF < OpenSSL::TestCase def test_scrypt_rfc7914_second pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + # scrypt is not available in FIPS. + omit_on_fips + pass = "password" salt = "NaCl" n = 1024 @@ -131,6 +94,7 @@ class OpenSSL::TestKDF < OpenSSL::TestCase assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1 def test_hkdf_rfc5869_test_case_1 hash = "sha256" ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") @@ -144,6 +108,7 @@ class OpenSSL::TestKDF < OpenSSL::TestCase assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.3 def test_hkdf_rfc5869_test_case_3 hash = "sha256" ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") @@ -157,16 +122,32 @@ class OpenSSL::TestKDF < OpenSSL::TestCase assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end - def test_hkdf_rfc5869_test_case_4 + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.5 + def test_hkdf_rfc5869_test_case_5 hash = "sha1" - ikm = B("0b0b0b0b0b0b0b0b0b0b0b") - salt = B("000102030405060708090a0b0c") - info = B("f0f1f2f3f4f5f6f7f8f9") - l = 42 - - okm = B("085a01ea1b10f36933068b56efa5ad81" \ - "a4f14b822f5b091568a9cdd4f155fda2" \ - "c22e422478d305f3f896") + ikm = B("000102030405060708090a0b0c0d0e0f" \ + "101112131415161718191a1b1c1d1e1f" \ + "202122232425262728292a2b2c2d2e2f" \ + "303132333435363738393a3b3c3d3e3f" \ + "404142434445464748494a4b4c4d4e4f") + salt = B("606162636465666768696a6b6c6d6e6f" \ + "707172737475767778797a7b7c7d7e7f" \ + "808182838485868788898a8b8c8d8e8f" \ + "909192939495969798999a9b9c9d9e9f" \ + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf") + info = B("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \ + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \ + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \ + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \ + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") + l = 82 + + okm = B("0bd770a74d1160f7c9f12cd5912a06eb" \ + "ff6adcae899d92191fe4305673ba2ffe" \ + "8fa3f1a4e5ad79f3f334b3b202b2173c" \ + "486ea37ce3d397ed034c7f9dfeb15c5e" \ + "927336d0441f4c4300e2cff0d0900b52" \ + "d3b4") assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 1adf47ac51..a78527d40e 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1393,10 +1393,6 @@ class TestIO < Test::Unit::TestCase args = ['-e', '$>.write($<.read)'] if args.empty? ruby = EnvUtil.rubybin opts = {} - if defined?(Process::RLIMIT_NPROC) - lim = Process.getrlimit(Process::RLIMIT_NPROC)[1] - opts[:rlimit_nproc] = [lim, 2048].min - end f = IO.popen([ruby] + args, 'r+', opts) pid = f.pid yield(f) diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 1e4de74503..48a67e1dc5 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -933,6 +933,41 @@ class TestMarshal < Test::Unit::TestCase end end + def test_load_overread + input = Struct.new(:bytes, :used) do + def initialize + super("\x04\x08[\x07".bytes, false) + end + + def getbyte + bytes.shift + end + + def read(_len, _outbuf = nil) + return nil if used + self.used = true + "0" * (1024 * 128) + end + end.new + + assert_equal([nil, nil], Marshal.load(input)) + end + + def test_bignum_len_overflow + assert_raise(ArgumentError) do + Marshal.load("\x04\x08l+\x04\x00\x00\x00\x40") + end + assert_raise(ArgumentError) do + Marshal.load("\x04\x08l+\xfc\x00\x00\x00\x80") + end + end + + def test_bignum_invalid_sign + assert_raise(ArgumentError) do + Marshal.load("\x04\bl?") + end + end + class TestMarshalFreezeProc < Test::Unit::TestCase include MarshalTestLib diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb index fabb414e14..611b3b7715 100644 --- a/test/ruby/test_ractor.rb +++ b/test/ruby/test_ractor.rb @@ -42,6 +42,59 @@ class TestRactor < Test::Unit::TestCase =end end + def test_shareable_proc_define_method_super_method_missing + assert_ractor(<<~'RUBY', timeout: 30) + iterations = 1_000_000 + + class SuperFromShareableProcMethodMissingBase + def method_missing(mid, *) = mid + end + + class SuperFromShareableProcMethodMissingChild < SuperFromShareableProcMethodMissingBase + BODY = Ractor.shareable_proc { super() } + define_method(:foo, &BODY) + define_method(:bar, &BODY) + end + + [:foo, :bar].map do |mid| + Ractor.new(mid, iterations) do |mid, iterations| + obj = SuperFromShareableProcMethodMissingChild.new + iterations.times do + got = obj.__send__(mid) + raise "#{mid} returned #{got.inspect}" unless got == mid + end + end + end.each(&:value) + RUBY + end + + def test_shareable_proc_define_method_super_method_entry + assert_ractor(<<~'RUBY', timeout: 30) + iterations = 1_000_000 + + class SuperFromShareableProcBase + def foo = :foo + def bar = :bar + end + + class SuperFromShareableProcChild < SuperFromShareableProcBase + BODY = Ractor.shareable_proc { super() } + define_method(:foo, &BODY) + define_method(:bar, &BODY) + end + + [:foo, :bar].map do |mid| + Ractor.new(mid, iterations) do |mid, iterations| + obj = SuperFromShareableProcChild.new + iterations.times do + got = obj.__send__(mid) + raise "#{mid} returned #{got.inspect}" unless got == mid + end + end + end.each(&:value) + RUBY + end + def test_shareability_error_uses_inspect x = (+"").instance_exec { method(:to_s) } def x.to_s diff --git a/test/rubygems/test_gem_commands_cert_command.rb b/test/rubygems/test_gem_commands_cert_command.rb index 39fda73eba..ed1a1c8627 100644 --- a/test/rubygems/test_gem_commands_cert_command.rb +++ b/test/rubygems/test_gem_commands_cert_command.rb @@ -31,14 +31,6 @@ class TestGemCommandsCertCommand < Gem::TestCase @cmd = Gem::Commands::CertCommand.new @trust_dir = Gem::Security.trust_dir - - @cleanup = [] - end - - def teardown - FileUtils.rm_f(@cleanup) - - super end def test_certificates_matching @@ -661,8 +653,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis assert_equal "/CN=nobody/DC=example", EXPIRED_PUBLIC_CERT.issuer.to_s - tmp_expired_cert_file = File.join(Dir.tmpdir, File.basename(EXPIRED_PUBLIC_CERT_FILE)) - @cleanup << tmp_expired_cert_file + tmp_expired_cert_file = File.join(@tempdir, File.basename(EXPIRED_PUBLIC_CERT_FILE)) File.write(tmp_expired_cert_file, File.read(EXPIRED_PUBLIC_CERT_FILE)) @cmd.handle_options %W[ @@ -694,8 +685,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis assert_equal "/CN=nobody/DC=example", EXPIRED_PUBLIC_CERT.issuer.to_s - tmp_expired_cert_file = File.join(Dir.tmpdir, File.basename(EXPIRED_PUBLIC_CERT_FILE)) - @cleanup << tmp_expired_cert_file + tmp_expired_cert_file = File.join(@tempdir, File.basename(EXPIRED_PUBLIC_CERT_FILE)) File.write(tmp_expired_cert_file, File.read(EXPIRED_PUBLIC_CERT_FILE)) @cmd.handle_options %W[ diff --git a/test/rubygems/test_gem_safe_yaml.rb b/test/rubygems/test_gem_safe_yaml.rb index d6fef1d7de..8d0ac63c41 100644 --- a/test/rubygems/test_gem_safe_yaml.rb +++ b/test/rubygems/test_gem_safe_yaml.rb @@ -70,6 +70,19 @@ class TestGemSafeYAML < Gem::TestCase assert_match(/unspecified class/, exception.message) end + def test_plain_tag_key_does_not_construct_specification + yaml = <<~YAML + tag: "!ruby/object:Gem::Specification" + name: pwned + arbitrary_ivar: hello + YAML + + result = Gem::SafeYAML.safe_load(yaml) + assert_kind_of Hash, result + assert_equal "!ruby/object:Gem::Specification", result["tag"] + assert_equal "pwned", result["name"] + end + def test_disallowed_symbol_rejected yaml = <<~YAML --- !ruby/object:Gem::Dependency @@ -94,6 +107,66 @@ class TestGemSafeYAML < Gem::TestCase assert_match(/unspecified class/, exception.message) end + def test_disallowed_symbol_not_interned + unique = "rejected_symbol_#{rand(1 << 30)}" + yaml = <<~YAML + --- !ruby/object:Gem::Dependency + name: test + requirement: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 0 + type: :#{unique} + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 0 + YAML + + assert_raise(Psych::DisallowedClass) do + Gem::YAMLSerializer.load(yaml, + permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES, + permitted_symbols: Gem::SafeYAML::PERMITTED_SYMBOLS) + end + refute_includes Symbol.all_symbols.map(&:to_s), unique + end + + def test_inline_array_nesting_capped + depth = Gem::YAMLSerializer::Parser::MAX_NESTING_DEPTH + 1 + yaml = "x: " + ("[" * depth) + "a" + ("]" * depth) + "\n" + + expected = [Psych::SyntaxError] + # JRuby's JVM stack overflows before the Ruby-level nesting cap fires. + expected << ::Java::JavaLang::StackOverflowError if RUBY_ENGINE == "jruby" + + assert_raise(*expected) do + Gem::YAMLSerializer.load(yaml, permitted_classes: []) + end + end + + def test_unknown_alias_raises + yaml = <<~YAML + foo: 1 + bar: *missing + YAML + + expected_error = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias + assert_raise(expected_error) { Gem::SafeYAML.safe_load(yaml) } + end + + def test_unused_anchor_with_aliases_disabled_is_allowed + aliases_enabled = Gem::SafeYAML.aliases_enabled? + Gem::SafeYAML.aliases_enabled = false + + result = Gem::SafeYAML.safe_load("foo: &unused 1\nbar: 2\n") + assert_equal({ "foo" => 1, "bar" => 2 }, result) + ensure + Gem::SafeYAML.aliases_enabled = aliases_enabled + end + def test_yaml_serializer_aliases_disabled aliases_enabled = Gem::SafeYAML.aliases_enabled? Gem::SafeYAML.aliases_enabled = false diff --git a/tool/bundler/test_gems.rb b/tool/bundler/test_gems.rb index 384ff85d1f..71230c32b7 100644 --- a/tool/bundler/test_gems.rb +++ b/tool/bundler/test_gems.rb @@ -4,7 +4,6 @@ source "https://rubygems.org" gem "rack", "~> 3.1" gem "rack-test", "~> 2.1" -gem "compact_index", "~> 0.15.0" gem "sinatra", "~> 4.1" gem "rake", "~> 13.1" gem "builder", "~> 3.2" diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock index a8352f3070..0b9ac34162 100644 --- a/tool/bundler/test_gems.rb.lock +++ b/tool/bundler/test_gems.rb.lock @@ -57,7 +57,6 @@ PLATFORMS DEPENDENCIES builder (~> 3.2) - compact_index (~> 0.15.0) concurrent-ruby etc fiddle diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 75d5023566..ac0d81092d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6080,8 +6080,23 @@ rb_vm_invokesuper(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_ { stack_check(ec); - VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true); - VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super); + struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci), + vm_ci_flag(cd->ci), + vm_ci_argc(cd->ci), + vm_ci_kwarg(cd->ci)); + const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE); + struct rb_call_data adjusted_cd = { + .ci = &adjusted_ci, + .cc = original_cc, + }; + + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true); + VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super); + + if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) { + rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE); + RB_OBJ_WRITTEN(CFP_ISEQ(GET_CFP()), Qundef, adjusted_cd.cc); + } VM_EXEC(ec, val); return val; diff --git a/win32/win32.c b/win32/win32.c index f25139ca8b..e3a3df71f6 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -6603,7 +6603,7 @@ rb_w32_pipe(int fds[2]) memcpy(name, prefix, width_of_prefix); snprintf(name + width_of_prefix, width_of_ids, "%.*"PRI_PIDT_PREFIX"x-%.*lx", - width_of_pid, rb_w32_getpid(), width_of_serial, InterlockedIncrement(&serial)-1); + width_of_pid, rb_w32_getpid(), width_of_serial, (unsigned long)(InterlockedIncrement(&serial)-1)); sec.nLength = sizeof(sec); sec.lpSecurityDescriptor = NULL; diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index ae372711d7..272c10fde9 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -223,7 +223,7 @@ pub const RUBY_FL_USHIFT: ruby_fl_ushift = 12; pub type ruby_fl_ushift = u32; pub const RUBY_FL_WB_PROTECTED: ruby_fl_type = 32; pub const RUBY_FL_PROMOTED: ruby_fl_type = 32; -pub const RUBY_FL_USERPRIV0: ruby_fl_type = 64; +pub const RUBY_FL_UNUSED6: ruby_fl_type = 64; pub const RUBY_FL_FINALIZE: ruby_fl_type = 128; pub const RUBY_FL_EXIVAR: ruby_fl_type = 0; pub const RUBY_FL_SHAREABLE: ruby_fl_type = 256; diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index dad29087be..bd832acc96 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -286,7 +286,7 @@ pub const RUBY_FL_USHIFT: ruby_fl_ushift = 12; pub type ruby_fl_ushift = u32; pub const RUBY_FL_WB_PROTECTED: ruby_fl_type = 32; pub const RUBY_FL_PROMOTED: ruby_fl_type = 32; -pub const RUBY_FL_USERPRIV0: ruby_fl_type = 64; +pub const RUBY_FL_UNUSED6: ruby_fl_type = 64; pub const RUBY_FL_FINALIZE: ruby_fl_type = 128; pub const RUBY_FL_EXIVAR: ruby_fl_type = 0; pub const RUBY_FL_SHAREABLE: ruby_fl_type = 256; @@ -347,7 +347,6 @@ pub const RUBY_TYPED_FREE_IMMEDIATELY: rbimpl_typeddata_flags = 1; pub const RUBY_TYPED_EMBEDDABLE: rbimpl_typeddata_flags = 2; pub const RUBY_TYPED_FROZEN_SHAREABLE: rbimpl_typeddata_flags = 256; pub const RUBY_TYPED_WB_PROTECTED: rbimpl_typeddata_flags = 32; -pub const RUBY_TYPED_FL_IS_TYPED_DATA: rbimpl_typeddata_flags = 64; pub const RUBY_TYPED_DECL_MARKING: rbimpl_typeddata_flags = 16384; pub type rbimpl_typeddata_flags = u32; pub type rb_event_flag_t = u32; diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 86078f4ac8..6911129ad3 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -1984,9 +1984,10 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::FixnumAref { recv, index } => write!(f, "FixnumAref {recv}, {index}"), Insn::Jump(target) => { write!(f, "Jump {target}") } Insn::CondBranch { val, if_true, if_false } => { write!(f, "CondBranch {val}, {if_true}, {if_false}") }, - Insn::SendDirect { recv, cd, iseq, args, block, .. } => { + Insn::SendDirect { recv, cme, iseq, args, block, .. } => { let blockiseq = block.map(|bh| match bh { BlockHandler::BlockIseq(iseq) => iseq, BlockHandler::BlockArg => unreachable!() }); - write!(f, "SendDirect {recv}, {:p}, :{} ({:?})", self.ptr_map.map_ptr(&blockiseq), ruby_call_method_name(*cd), self.ptr_map.map_ptr(iseq))?; + let method_name = unsafe { (**cme).called_id }; + write!(f, "SendDirect {recv}, {:p}, :{} ({:?})", self.ptr_map.map_ptr(&blockiseq), method_name, self.ptr_map.map_ptr(iseq))?; for arg in args { write!(f, ", {arg}")?; } |
