diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index bec742da4be0d5..af739ba4bc7fd7 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -1116,6 +1116,23 @@ class C end.value RUBY +# Inserting into the id2ref table should be Ractor-safe +assert_equal 'ok', <<~'RUBY' + # Force all calls to Kernel#object_id to insert into the id2ref table + ObjectSpace._id2ref(Object.new.object_id) + + 10.times.map do + Ractor.new do + 10_000.times do + a = Object.new + a.object_id + end + end + end.map(&:value) + + :ok +RUBY + # Ractor.make_shareable(obj) assert_equal 'true', <<~'RUBY', frozen_string_literal: false class C diff --git a/ext/date/date_core.c b/ext/date/date_core.c index cf8ea3c0a44990..6bcf272b62d8b0 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -9496,6 +9496,7 @@ Init_date_core(void) sym_zone = ID2SYM(rb_intern_const("zone")); half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2)); + rb_gc_register_mark_object(half_days_in_day); #if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS * @@ -9507,8 +9508,6 @@ Init_date_core(void) day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS), INT2FIX(SECOND_IN_NANOSECONDS)); #endif - - rb_gc_register_mark_object(half_days_in_day); rb_gc_register_mark_object(day_in_nanoseconds); positive_inf = +INFINITY; diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index a19ff23b107c88..5fd6bff98b7bbe 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -122,7 +122,7 @@ ossl_buf2str(char *buf, int len) } void -ossl_bin2hex(unsigned char *in, char *out, size_t inlen) +ossl_bin2hex(const unsigned char *in, char *out, size_t inlen) { const char *hex = "0123456789abcdef"; size_t i; diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index 93deafb4b68363..0b479a7200a1f4 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -131,7 +131,7 @@ do{\ * Convert binary string to hex string. The caller is responsible for * ensuring out has (2 * len) bytes of capacity. */ -void ossl_bin2hex(unsigned char *in, char *out, size_t len); +void ossl_bin2hex(const unsigned char *in, char *out, size_t len); /* * Our default PEM callback diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index b21a79484ccc4a..628140a75e3ea4 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -114,7 +114,8 @@ ossl_time_split(VALUE time, time_t *sec, int *days) VALUE asn1str_to_str(const ASN1_STRING *str) { - return rb_str_new((const char *)str->data, str->length); + return rb_str_new((const char *)ASN1_STRING_get0_data(str), + ASN1_STRING_length(str)); } /* @@ -129,9 +130,8 @@ asn1integer_to_num(const ASN1_INTEGER *ai) if (!ai) { ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!"); } - if (ai->type == V_ASN1_ENUMERATED) - /* const_cast: workaround for old OpenSSL */ - bn = ASN1_ENUMERATED_to_BN((ASN1_ENUMERATED *)ai, NULL); + if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED) + bn = ASN1_ENUMERATED_to_BN(ai, NULL); else bn = ASN1_INTEGER_to_BN(ai, NULL); diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c index 1d1498824620a9..8440c2ee82b909 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -230,13 +230,12 @@ ossl_spki_get_challenge(VALUE self) NETSCAPE_SPKI *spki; GetSPKI(self, spki); - if (spki->spkac->challenge->length <= 0) { + if (ASN1_STRING_length(spki->spkac->challenge) <= 0) { OSSL_Debug("Challenge.length <= 0?"); return rb_str_new(0, 0); } - return rb_str_new((const char *)spki->spkac->challenge->data, - spki->spkac->challenge->length); + return asn1str_to_str(spki->spkac->challenge); } /* diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index 97ab24c347b556..93d8bc85671eac 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -1550,8 +1550,9 @@ ossl_ocspcid_get_issuer_name_hash(VALUE self) GetOCSPCertId(self, id); OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id); - ret = rb_str_new(NULL, name_hash->length * 2); - ossl_bin2hex(name_hash->data, RSTRING_PTR(ret), name_hash->length); + ret = rb_str_new(NULL, ASN1_STRING_length(name_hash) * 2); + ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret), + ASN1_STRING_length(name_hash)); return ret; } @@ -1573,8 +1574,9 @@ ossl_ocspcid_get_issuer_key_hash(VALUE self) GetOCSPCertId(self, id); OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id); - ret = rb_str_new(NULL, key_hash->length * 2); - ossl_bin2hex(key_hash->data, RSTRING_PTR(ret), key_hash->length); + ret = rb_str_new(NULL, ASN1_STRING_length(key_hash) * 2); + ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret), + ASN1_STRING_length(key_hash)); return ret; } diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c index 615eedc016a0f4..b31a854a63e9ac 100644 --- a/ext/openssl/ossl_ts.c +++ b/ext/openssl/ossl_ts.c @@ -259,7 +259,7 @@ ossl_ts_req_get_msg_imprint(VALUE self) mi = TS_REQ_get_msg_imprint(req); hashed_msg = TS_MSG_IMPRINT_get_msg(mi); - ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length); + ret = asn1str_to_str(hashed_msg); return ret; } @@ -470,7 +470,7 @@ ossl_ts_req_to_der(VALUE self) ossl_raise(eTimestampError, "Message imprint missing algorithm"); hashed_msg = TS_MSG_IMPRINT_get_msg(mi); - if (!hashed_msg->length) + if (!ASN1_STRING_length(hashed_msg)) ossl_raise(eTimestampError, "Message imprint missing hashed message"); return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ); @@ -981,7 +981,7 @@ ossl_ts_token_info_get_msg_imprint(VALUE self) GetTSTokenInfo(self, info); mi = TS_TST_INFO_get_msg_imprint(info); hashed_msg = TS_MSG_IMPRINT_get_msg(mi); - ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length); + ret = asn1str_to_str(hashed_msg); return ret; } diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index 85e2eff7a275c6..ef66ecc3fe8390 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -402,7 +402,7 @@ ossl_x509ext_get_value_der(VALUE obj) if ((value = X509_EXTENSION_get_data(ext)) == NULL) ossl_raise(eX509ExtError, NULL); - return rb_str_new((const char *)value->data, value->length); + return asn1str_to_str(value); } static VALUE diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index 5556426fdc387a..9240929646d5ea 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -1888,7 +1888,7 @@ strio_truncate(VALUE self, VALUE len) * external_encoding -> encoding or nil * * Returns an Encoding object that represents the encoding of the string; - * see {Encoding}[rdoc-ref:Encoding]: + * see {Encodings}[rdoc-ref:StringIO@Encodings]: * * strio = StringIO.new('foo') * strio.external_encoding # => # diff --git a/gc.c b/gc.c index 4f5f041fb348fb..c660d1491f3a6d 100644 --- a/gc.c +++ b/gc.c @@ -1905,7 +1905,9 @@ object_id0(VALUE obj) RUBY_ASSERT(rb_shape_obj_has_id(obj)); if (RB_UNLIKELY(id2ref_tbl)) { - st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj); + RB_VM_LOCKING() { + st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj); + } } return id; } diff --git a/io_buffer.c b/io_buffer.c index 0d2cbdb4b7e704..b81527ff71147a 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -1928,13 +1928,19 @@ ruby_swap128_uint(rb_uint128_t x) return result; } +union uint128_int128_conversion { + rb_uint128_t uint128; + rb_int128_t int128; +}; + static inline rb_int128_t ruby_swap128_int(rb_int128_t x) { - // Cast to unsigned, swap, then cast back - rb_uint128_t u = *(rb_uint128_t*)&x; - rb_uint128_t swapped = ruby_swap128_uint(u); - return *(rb_int128_t*)&swapped; + union uint128_int128_conversion conversion = { + .int128 = x + }; + conversion.uint128 = ruby_swap128_uint(conversion.uint128); + return conversion.int128; } #define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \ diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 1dedf5e08df546..3d78619c9e4041 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -195,15 +195,14 @@ class Pathname # :stopdoc: - # to_path is implemented so Pathname objects are usable with File.open, etc. - TO_PATH = :to_path - SAME_PATHS = if File::FNM_SYSCASE.nonzero? # Avoid #zero? here because #casecmp can return nil. proc {|a, b| a.casecmp(b) == 0} else proc {|a, b| a == b} end + SAME_PATHS.freeze + private_constant :SAME_PATHS attr_reader :path protected :path @@ -215,17 +214,7 @@ class Pathname # If +path+ contains a NUL character (\0), an ArgumentError is raised. # def initialize(path) - unless String === path - path = path.to_path if path.respond_to? :to_path - path = path.to_str if path.respond_to? :to_str - raise TypeError, "Pathname.new requires a String, #to_path or #to_str" unless String === path - end - - if path.include?("\0") - raise ArgumentError, "pathname contains \\0: #{path.inspect}" - end - - @path = path.dup + @path = File.path(path).dup end def freeze @@ -264,7 +253,7 @@ def to_s end # to_path is implemented so Pathname objects are usable with File.open, etc. - alias_method TO_PATH, :to_s + alias to_path to_s def inspect # :nodoc: "#<#{self.class}:#{@path}>" @@ -320,6 +309,9 @@ def sub_ext(repl) SEPARATOR_LIST = Regexp.quote File::SEPARATOR SEPARATOR_PAT = /#{SEPARATOR_LIST}/ end + SEPARATOR_LIST.freeze + SEPARATOR_PAT.freeze + private_constant :SEPARATOR_LIST, :SEPARATOR_LIST if File.dirname('A:') == 'A:.' # DOSish drive letter # Regexp that matches an absolute path. @@ -327,6 +319,7 @@ def sub_ext(repl) else ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/ end + ABSOLUTE_PATH.freeze private_constant :ABSOLUTE_PATH # :startdoc: diff --git a/test/-ext-/scheduler/test_interrupt_with_scheduler.rb b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb index 3f9a7f55a07d11..42a109b98b51a6 100644 --- a/test/-ext-/scheduler/test_interrupt_with_scheduler.rb +++ b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb @@ -13,6 +13,8 @@ def setup def test_without_handle_interrupt_signal_works IO.pipe do |input, output| pid = fork do + STDERR.reopen(output) + scheduler = Scheduler.new Fiber.set_scheduler scheduler @@ -33,7 +35,7 @@ def test_without_handle_interrupt_signal_works assert_equal "ready\n", input.gets sleep 0.1 # Ensure the child is in the blocking loop - $stderr.puts "Sending interrupt" + # $stderr.puts "Sending interrupt" Process.kill(:INT, pid) reaper = Thread.new do