diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 6a05028db34e55..4106f9e60d8afe 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -137,6 +137,13 @@ jobs: run: echo "DFLTCC=0" >> $GITHUB_ENV if: ${{ endsWith(matrix.os, 's390x') }} + # Emulated ppc64le/s390x runners are slow enough that subprocess + # assertion timeouts (e.g. assert_separately) flake. Scale them up, as + # macos.yml does for slower/contended runners. + - name: Set timeout scale for emulated runners + run: echo "RUBY_TEST_TIMEOUT_SCALE=10" >> $GITHUB_ENV + if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} + - name: make ${{ matrix.test_task }} run: | test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") diff --git a/configure.ac b/configure.ac index 2de91209d61919..8d020771c6d505 100644 --- a/configure.ac +++ b/configure.ac @@ -4163,7 +4163,7 @@ AC_SUBST(JIT_CARGO_SUPPORT)dnl "no" or the cargo profile of the rust code [begin]_group "build section" && { AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[extern void conftest_external(void) {}]], [[]])],[ - rb_cv_symbol_prefix=`$NM conftest.$ac_objext | + rb_cv_symbol_prefix=`$NM conftest.$ac_objext 2>/dev/null | sed -n ['/.*T[ ]\([^ ]*\)conftest_external.*/!d;s//\1/p;q']` ], [rb_cv_symbol_prefix='']) diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index c216faf4b5a56e..136aab6ae764f5 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -2300,16 +2300,19 @@ static VALUE cResumableParser_feed(VALUE self, VALUE str) const size_t size = parser->state.end - parser->state.start; const size_t consumed = size - remaining; - char *old_ptr = RSTRING_PTR(parser->buffer); if (RB_OBJ_FROZEN_RAW(parser->buffer)) { VALUE new_buffer = rb_obj_hide(rb_str_buf_new(remaining + RSTRING_LEN(str))); - MEMCPY(RSTRING_PTR(new_buffer), old_ptr + consumed, char, remaining); + + char *old_ptr = RSTRING_PTR(parser->buffer); + memcpy(RSTRING_PTR(new_buffer), old_ptr + consumed, remaining); rb_str_set_len(new_buffer, remaining); offset = 0; parser->buffer = new_buffer; } else if (consumed > (size / 2) && size >= 512) { - MEMMOVE(old_ptr, old_ptr + consumed, char, remaining); + rb_str_modify(parser->buffer); + char *old_ptr = RSTRING_PTR(parser->buffer); + memmove(old_ptr, old_ptr + consumed, remaining); rb_str_set_len(parser->buffer, remaining); offset = 0; } diff --git a/gc/default/default.c b/gc/default/default.c index 18d7a05b336430..66df18d879a101 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -1047,27 +1047,15 @@ gc_malloc_counters_increase_unsigned(rb_objspace_t *objspace, const struct gc_ma return (size_t)inc; } -static inline int64_t +static inline void gc_malloc_counters_snapshot(rb_objspace_t *objspace, struct gc_malloc_bytes *c) { MALLOC_COUNTERS_LOCK(objspace); gc_counter_t malloc_now = gc_counter_load_relaxed(&c->malloc); gc_counter_t free_now = gc_counter_load_relaxed(&c->free); - gc_counter_t malloc_at = gc_counter_load_relaxed(&c->malloc_at_last_gc); - gc_counter_t free_at = gc_counter_load_relaxed(&c->free_at_last_gc); gc_counter_store_release(&c->malloc_at_last_gc, malloc_now); gc_counter_store_release(&c->free_at_last_gc, free_now); MALLOC_COUNTERS_UNLOCK(objspace); - - gc_counter_t malloc_delta = malloc_now - malloc_at; - gc_counter_t free_delta = free_now - free_at; - - if (malloc_delta >= free_delta) { - return (int64_t)(malloc_delta - free_delta); - } - else { - return -(int64_t)(free_delta - malloc_delta); - } } #define heap_pages_lomem objspace->heap_pages.range[0] @@ -4224,10 +4212,10 @@ gc_sweep_finish(rb_objspace_t *objspace) } } - (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters); + gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters); #if RGENGC_ESTIMATE_OLDMALLOC if (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) { - (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters); + gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters); } #endif diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h index 7ceb8c40b70eef..322761fc683341 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 3 +#define RUBY_ABI_VERSION 4 /* Windows does not support weak symbols so ruby_abi_version will not exist * in the shared library. */ diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 60ae6d34129b92..8fdf871201cc61 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -533,7 +533,19 @@ def parent self + '..' end - # Returns +true+ if +self+ points to a mountpoint. + # :markup: markdown + # + # call-seq: + # mountpoint? -> true or false + # + # Returns whether the path in `self` points to a mountpoint: + # + # ```ruby + # Pathname('/').mountpoint? # => true + # Pathname('/etc').mountpoint? # => false + # Pathname('nosuch').mountpoint? # => false + # ``` + # def mountpoint? begin stat1 = self.lstat diff --git a/test/json/resumable_parser_test.rb b/test/json/resumable_parser_test.rb index 600cd33e5ecf28..52f1356a704f9a 100644 --- a/test/json/resumable_parser_test.rb +++ b/test/json/resumable_parser_test.rb @@ -244,6 +244,21 @@ def test_spill_frames_stack assert_equal expected, @parser.value end + def test_buffer_shrink + doc1 = '{"a":"' + ("x" * 800) + '"} {' # >= 512 bytes + doc2 = '"b":1} ' + + parser = JSON::ResumableParser.new({}) + + parser << doc1 # internal buffer becomes a *shared* string here + parser.parse # consume doc1 -> >50% of a >=512B buffer is now consumed + parser.value + + parser << doc2 # buffer is shrinked + parser.parse + parser.value + end + private def assert_partial_value(expected, json) diff --git a/tool/leaked-globals b/tool/leaked-globals index 73da769318ad37..c1a3fb42b8869c 100755 --- a/tool/leaked-globals +++ b/tool/leaked-globals @@ -60,6 +60,23 @@ end # extern, so we allow the Rust one. REPLACE.push("rust_eh_personality") if RUBY_PLATFORM.include?("darwin") +# Under LTO the compiler emits raw LLVM bitcode objects (magic "BC\xC0\xDE", or +# the bitcode wrapper magic). nm carries --no-llvm-bc (added in configure so it +# ignores Rust's newer-version bitcode) and so cannot read them, only emitting +# "not recognized" noise. Drop them; leaked symbols are still checked on the +# linked library and any non-bitcode objects. +if defined?(NM) and NM.include?("--no-llvm-bc") + bitcode = 0 + ARGV.reject! do |n| + next false unless File.file?(n) + case File.binread(n, 4)&.bytes + when [0x42, 0x43, 0xC0, 0xDE], [0xDE, 0xC0, 0x17, 0x0B] + bitcode += 1 + end + end + puts "Skip #{col.skip("#{bitcode} LLVM bitcode object(s)")}" if bitcode > 0 +end + print "Checking leaked global symbols..." STDOUT.flush if soext @@ -105,7 +122,7 @@ Pipe.new(NM + ARGV).each do |line| puts col.fail("leaked") if count.zero? count += 1 puts " #{n}" -end +end unless ARGV.empty? case count when 0 puts col.pass("none")