Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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=''])
Expand Down
9 changes: 6 additions & 3 deletions ext/json/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
18 changes: 3 additions & 15 deletions gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion include/ruby/internal/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
14 changes: 13 additions & 1 deletion pathname_builtin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions test/json/resumable_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 18 additions & 1 deletion tool/leaked-globals
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down