diff --git a/.github/workflows/shstk-amd64.yml b/.github/workflows/shstk-amd64.yml index a976c9bf8c4bc4..20f4edc0161e54 100644 --- a/.github/workflows/shstk-amd64.yml +++ b/.github/workflows/shstk-amd64.yml @@ -92,7 +92,14 @@ jobs: runuser -u ruby -- ./miniruby -e ' line = File.foreach("/proc/self/status").find { |entry| entry.start_with?("x86_Thread_features:") } features = line&.split(":", 2)&.last&.split || [] - abort "SHSTK is not active (x86_Thread_features: #{features.join(" ")})" unless features.include?("shstk") + unless features.include?("shstk") + warn "::notice::SHSTK is not active (x86_Thread_features: #{features.join(" ")})" + cpuinfo = File.read("/proc/cpuinfo") + model = cpuinfo[/^model name.*/] + flags = cpuinfo[/^flags.*/] + puts model, flags, ENV["GLIBC_TUNABLES"] + exit !/\buser_shstk\b/.match?(flags) + end ' - name: make check diff --git a/class.c b/class.c index 7c6d9e3be49ea8..2f7f51b245357d 100644 --- a/class.c +++ b/class.c @@ -23,6 +23,7 @@ #include "internal.h" #include "internal/box.h" #include "internal/class.h" +#include "internal/error.h" #include "internal/eval.h" #include "internal/gc.h" #include "internal/hash.h" @@ -3000,6 +3001,9 @@ singleton_class_of(VALUE obj, bool ensure_eigenclass) return klass; } +#if RUBY_VERSION_SINCE(4, 2) +RBIMPL_TODO("make rb_freeze_singleton_class internal; remove from fl_type.h") +#endif void rb_freeze_singleton_class(VALUE attached_object) { diff --git a/doc/NEWS/NEWS-4.0.0.md b/doc/NEWS/NEWS-4.0.0.md index 077cd97ab07384..0796fa241ce0c7 100644 --- a/doc/NEWS/NEWS-4.0.0.md +++ b/doc/NEWS/NEWS-4.0.0.md @@ -240,7 +240,7 @@ Note: We're only listing outstanding class updates. * Ruby::Box * A new (experimental) feature to provide separation about definitions. - For the detail of "Ruby Box", see [doc/language/box.md](doc/language/box.md). + For the detail of "Ruby Box", see [box.md](rdoc-ref:language/box.md). [[Feature #21311]] [[Misc #21385]] * Set diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index f7ec7424220fdd..2b780d018ec29a 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -88,7 +88,6 @@ #define FL_USER19 RBIMPL_CAST((VALUE)(unsigned int)RUBY_FL_USER19) /**< @old{RUBY_FL_USER19} */ #define ELTS_SHARED RUBY_ELTS_SHARED /**< @old{RUBY_ELTS_SHARED} */ -#define RB_OBJ_FREEZE rb_obj_freeze_inline /**< @alias{rb_obj_freeze_inline} */ /** @cond INTERNAL_MACRO */ #define RUBY_ELTS_SHARED RUBY_ELTS_SHARED @@ -105,6 +104,7 @@ #define RB_FL_TEST_RAW RB_FL_TEST_RAW #define RB_FL_UNSET RB_FL_UNSET #define RB_FL_UNSET_RAW RB_FL_UNSET_RAW +#define RB_OBJ_FREEZE RB_OBJ_FREEZE #define RB_OBJ_FREEZE_RAW RB_OBJ_FREEZE_RAW #define RB_OBJ_FROZEN RB_OBJ_FROZEN #define RB_OBJ_FROZEN_RAW RB_OBJ_FROZEN_RAW @@ -355,6 +355,8 @@ ruby_fl_type { #undef RBIMPL_HAVE_ENUM_ATTRIBUTE RBIMPL_SYMBOL_EXPORT_BEGIN() + +RBIMPL_ATTR_DEPRECATED_EXT(("only for internal use")) /** * This is an implementation detail of #RB_OBJ_FREEZE(). People don't use it * directly. @@ -363,6 +365,7 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() * @post `klass` gets frozen. */ void rb_freeze_singleton_class(VALUE klass); + RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() @@ -743,4 +746,16 @@ RB_OBJ_FREEZE_RAW(VALUE obj) rb_obj_freeze_inline(obj); } +RBIMPL_ATTR_ARTIFICIAL() +/** + * Freeze the given object if it is not frozen yet. + * + * @param[out] obj Object in question. + */ +static inline void +RB_OBJ_FREEZE(VALUE obj) +{ + if (!RB_OBJ_FROZEN(obj)) RB_OBJ_FREEZE_RAW(obj); +} + #endif /* RBIMPL_FL_TYPE_H */ diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h index c008b058b63150..031230f809c93c 100644 --- a/include/ruby/internal/intern/object.h +++ b/include/ruby/internal/intern/object.h @@ -203,8 +203,7 @@ VALUE rb_obj_dup(VALUE obj); VALUE rb_obj_init_copy(VALUE src, VALUE dst); /** - * Just calls rb_obj_freeze_inline() inside. Does this make any sens to - * extension libraries? + * Same as RB_OBJ_FREEZE(), but returns the given object. * * @param[out] obj Object to freeze. * @return Verbatim `obj`. @@ -213,8 +212,7 @@ VALUE rb_obj_freeze(VALUE obj); RBIMPL_ATTR_PURE() /** - * Just calls RB_OBJ_FROZEN() inside. Does this make any sens to extension - * libraries? + * Same as RB_OBJ_FROZEN(), but returns #Qtrue/#Qfalse instead of #bool. * * @param[in] obj Object in question. * @retval RUBY_Qtrue Yes it is. diff --git a/internal/class.h b/internal/class.h index 1d608e38db2966..49a5d96521d10c 100644 --- a/internal/class.h +++ b/internal/class.h @@ -493,6 +493,7 @@ VALUE rb_keyword_error_new(const char *, VALUE); rb_classext_t *rb_class_unlink_classext(VALUE klass, const rb_box_t *box); void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); +void rb_freeze_singleton_class(VALUE attached_object); RUBY_SYMBOL_EXPORT_BEGIN diff --git a/internal/error.h b/internal/error.h index 8cda52827360d6..cc065f1b5fa6db 100644 --- a/internal/error.h +++ b/internal/error.h @@ -75,6 +75,8 @@ PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *f PRINTF_ARGS(void rb_warn_reserved_name(const char *removal, const char *fmt, ...), 2, 3); #if RUBY_DEBUG # include "ruby/version.h" +#endif +#ifdef RUBY_API_VERSION_CODE # define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major) * 10000 + (minor) * 100) # define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major) * 10000 + (minor) * 100) # if defined(RBIMPL_WARNING_PRAGMA0) diff --git a/object.c b/object.c index 11b10b169566c3..69127b759d7417 100644 --- a/object.c +++ b/object.c @@ -1370,12 +1370,7 @@ rb_obj_dummy1(VALUE _x, VALUE _y) VALUE rb_obj_freeze(VALUE obj) { - if (!OBJ_FROZEN(obj)) { - OBJ_FREEZE(obj); - if (SPECIAL_CONST_P(obj)) { - rb_bug("special consts should be frozen."); - } - } + OBJ_FREEZE(obj); return obj; } diff --git a/string.c b/string.c index d372f923b65add..2129f97595f697 100644 --- a/string.c +++ b/string.c @@ -11736,6 +11736,12 @@ rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + str_modify_keep_cr(str); + enc = STR_ENC_GET(str); + RSTRING_GETMEM(str, start, olen); + loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel); } else { @@ -11792,6 +11798,10 @@ rb_str_lstrip(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + RSTRING_GETMEM(str, start, len); + loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel); } else { @@ -11880,6 +11890,12 @@ rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + str_modify_keep_cr(str); + enc = STR_ENC_GET(str); + RSTRING_GETMEM(str, start, olen); + roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel); } else { @@ -11936,6 +11952,11 @@ rb_str_rstrip(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + enc = STR_ENC_GET(str); + + RSTRING_GETMEM(str, start, olen); roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel); } else { @@ -11974,6 +11995,12 @@ rb_str_strip_bang(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + str_modify_keep_cr(str); + enc = STR_ENC_GET(str); + RSTRING_GETMEM(str, start, olen); + loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel); roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel); } @@ -12037,6 +12064,11 @@ rb_str_strip(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; tr_setup_table_multi(table, &del, &nodel, str, argc, argv); + + /* the selector conversion may have modified str */ + enc = STR_ENC_GET(str); + RSTRING_GETMEM(str, start, olen); + loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel); roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel); } diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 5fb76986cf5791..db92a2cac1da83 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -2635,6 +2635,23 @@ def test_rstrip_bang_with_chars assert_equal(S("abc"), a) end + def test_strip_selector_modifying_receiver + [:strip, :strip!, :lstrip, :lstrip!, :rstrip, :rstrip!].each do |m| + s = S("-" * 100 + "abc" + "-" * 100) + obj = Object.new + obj.define_singleton_method(:to_str) do + s.clear + "-" + end + + if m.end_with?("!") + assert_nil(s.public_send(m, obj), "String##{m}") + else + assert_equal("", s.public_send(m, obj), "String##{m}") + end + end + end + def test_sub assert_equal(S("h*llo"), S("hello").sub(/[aeiou]/, S('*'))) assert_equal(S("hllo"), S("hello").sub(/([aeiou])/, S('<\1>')))