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
161 changes: 161 additions & 0 deletions ext/-test-/fatal/depend
Original file line number Diff line number Diff line change
Expand Up @@ -483,4 +483,165 @@ rb_fatal.o: $(hdrdir)/ruby/ruby.h
rb_fatal.o: $(hdrdir)/ruby/st.h
rb_fatal.o: $(hdrdir)/ruby/subst.h
rb_fatal.o: rb_fatal.c
segv.o: $(RUBY_EXTCONF_H)
segv.o: $(arch_hdrdir)/ruby/config.h
segv.o: $(hdrdir)/ruby.h
segv.o: $(hdrdir)/ruby/assert.h
segv.o: $(hdrdir)/ruby/backward.h
segv.o: $(hdrdir)/ruby/backward/2/assume.h
segv.o: $(hdrdir)/ruby/backward/2/attributes.h
segv.o: $(hdrdir)/ruby/backward/2/bool.h
segv.o: $(hdrdir)/ruby/backward/2/inttypes.h
segv.o: $(hdrdir)/ruby/backward/2/limits.h
segv.o: $(hdrdir)/ruby/backward/2/long_long.h
segv.o: $(hdrdir)/ruby/backward/2/stdalign.h
segv.o: $(hdrdir)/ruby/backward/2/stdarg.h
segv.o: $(hdrdir)/ruby/defines.h
segv.o: $(hdrdir)/ruby/intern.h
segv.o: $(hdrdir)/ruby/internal/abi.h
segv.o: $(hdrdir)/ruby/internal/anyargs.h
segv.o: $(hdrdir)/ruby/internal/arithmetic.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/char.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/double.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/int.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/long.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/short.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
segv.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
segv.o: $(hdrdir)/ruby/internal/assume.h
segv.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
segv.o: $(hdrdir)/ruby/internal/attr/artificial.h
segv.o: $(hdrdir)/ruby/internal/attr/cold.h
segv.o: $(hdrdir)/ruby/internal/attr/const.h
segv.o: $(hdrdir)/ruby/internal/attr/constexpr.h
segv.o: $(hdrdir)/ruby/internal/attr/deprecated.h
segv.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
segv.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
segv.o: $(hdrdir)/ruby/internal/attr/error.h
segv.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
segv.o: $(hdrdir)/ruby/internal/attr/forceinline.h
segv.o: $(hdrdir)/ruby/internal/attr/format.h
segv.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
segv.o: $(hdrdir)/ruby/internal/attr/noalias.h
segv.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
segv.o: $(hdrdir)/ruby/internal/attr/noexcept.h
segv.o: $(hdrdir)/ruby/internal/attr/noinline.h
segv.o: $(hdrdir)/ruby/internal/attr/nonnull.h
segv.o: $(hdrdir)/ruby/internal/attr/noreturn.h
segv.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
segv.o: $(hdrdir)/ruby/internal/attr/pure.h
segv.o: $(hdrdir)/ruby/internal/attr/restrict.h
segv.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
segv.o: $(hdrdir)/ruby/internal/attr/warning.h
segv.o: $(hdrdir)/ruby/internal/attr/weakref.h
segv.o: $(hdrdir)/ruby/internal/cast.h
segv.o: $(hdrdir)/ruby/internal/compiler_is.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
segv.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
segv.o: $(hdrdir)/ruby/internal/compiler_since.h
segv.o: $(hdrdir)/ruby/internal/config.h
segv.o: $(hdrdir)/ruby/internal/constant_p.h
segv.o: $(hdrdir)/ruby/internal/core.h
segv.o: $(hdrdir)/ruby/internal/core/rarray.h
segv.o: $(hdrdir)/ruby/internal/core/rbasic.h
segv.o: $(hdrdir)/ruby/internal/core/rbignum.h
segv.o: $(hdrdir)/ruby/internal/core/rclass.h
segv.o: $(hdrdir)/ruby/internal/core/rdata.h
segv.o: $(hdrdir)/ruby/internal/core/rfile.h
segv.o: $(hdrdir)/ruby/internal/core/rhash.h
segv.o: $(hdrdir)/ruby/internal/core/robject.h
segv.o: $(hdrdir)/ruby/internal/core/rregexp.h
segv.o: $(hdrdir)/ruby/internal/core/rstring.h
segv.o: $(hdrdir)/ruby/internal/core/rstruct.h
segv.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
segv.o: $(hdrdir)/ruby/internal/ctype.h
segv.o: $(hdrdir)/ruby/internal/dllexport.h
segv.o: $(hdrdir)/ruby/internal/dosish.h
segv.o: $(hdrdir)/ruby/internal/error.h
segv.o: $(hdrdir)/ruby/internal/eval.h
segv.o: $(hdrdir)/ruby/internal/event.h
segv.o: $(hdrdir)/ruby/internal/fl_type.h
segv.o: $(hdrdir)/ruby/internal/gc.h
segv.o: $(hdrdir)/ruby/internal/glob.h
segv.o: $(hdrdir)/ruby/internal/globals.h
segv.o: $(hdrdir)/ruby/internal/has/attribute.h
segv.o: $(hdrdir)/ruby/internal/has/builtin.h
segv.o: $(hdrdir)/ruby/internal/has/c_attribute.h
segv.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
segv.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
segv.o: $(hdrdir)/ruby/internal/has/extension.h
segv.o: $(hdrdir)/ruby/internal/has/feature.h
segv.o: $(hdrdir)/ruby/internal/has/warning.h
segv.o: $(hdrdir)/ruby/internal/intern/array.h
segv.o: $(hdrdir)/ruby/internal/intern/bignum.h
segv.o: $(hdrdir)/ruby/internal/intern/class.h
segv.o: $(hdrdir)/ruby/internal/intern/compar.h
segv.o: $(hdrdir)/ruby/internal/intern/complex.h
segv.o: $(hdrdir)/ruby/internal/intern/cont.h
segv.o: $(hdrdir)/ruby/internal/intern/dir.h
segv.o: $(hdrdir)/ruby/internal/intern/enum.h
segv.o: $(hdrdir)/ruby/internal/intern/enumerator.h
segv.o: $(hdrdir)/ruby/internal/intern/error.h
segv.o: $(hdrdir)/ruby/internal/intern/eval.h
segv.o: $(hdrdir)/ruby/internal/intern/file.h
segv.o: $(hdrdir)/ruby/internal/intern/hash.h
segv.o: $(hdrdir)/ruby/internal/intern/io.h
segv.o: $(hdrdir)/ruby/internal/intern/load.h
segv.o: $(hdrdir)/ruby/internal/intern/marshal.h
segv.o: $(hdrdir)/ruby/internal/intern/numeric.h
segv.o: $(hdrdir)/ruby/internal/intern/object.h
segv.o: $(hdrdir)/ruby/internal/intern/parse.h
segv.o: $(hdrdir)/ruby/internal/intern/proc.h
segv.o: $(hdrdir)/ruby/internal/intern/process.h
segv.o: $(hdrdir)/ruby/internal/intern/random.h
segv.o: $(hdrdir)/ruby/internal/intern/range.h
segv.o: $(hdrdir)/ruby/internal/intern/rational.h
segv.o: $(hdrdir)/ruby/internal/intern/re.h
segv.o: $(hdrdir)/ruby/internal/intern/ruby.h
segv.o: $(hdrdir)/ruby/internal/intern/select.h
segv.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
segv.o: $(hdrdir)/ruby/internal/intern/set.h
segv.o: $(hdrdir)/ruby/internal/intern/signal.h
segv.o: $(hdrdir)/ruby/internal/intern/sprintf.h
segv.o: $(hdrdir)/ruby/internal/intern/string.h
segv.o: $(hdrdir)/ruby/internal/intern/struct.h
segv.o: $(hdrdir)/ruby/internal/intern/thread.h
segv.o: $(hdrdir)/ruby/internal/intern/time.h
segv.o: $(hdrdir)/ruby/internal/intern/variable.h
segv.o: $(hdrdir)/ruby/internal/intern/vm.h
segv.o: $(hdrdir)/ruby/internal/interpreter.h
segv.o: $(hdrdir)/ruby/internal/iterator.h
segv.o: $(hdrdir)/ruby/internal/memory.h
segv.o: $(hdrdir)/ruby/internal/method.h
segv.o: $(hdrdir)/ruby/internal/module.h
segv.o: $(hdrdir)/ruby/internal/newobj.h
segv.o: $(hdrdir)/ruby/internal/scan_args.h
segv.o: $(hdrdir)/ruby/internal/special_consts.h
segv.o: $(hdrdir)/ruby/internal/static_assert.h
segv.o: $(hdrdir)/ruby/internal/stdalign.h
segv.o: $(hdrdir)/ruby/internal/stdbool.h
segv.o: $(hdrdir)/ruby/internal/stdckdint.h
segv.o: $(hdrdir)/ruby/internal/symbol.h
segv.o: $(hdrdir)/ruby/internal/value.h
segv.o: $(hdrdir)/ruby/internal/value_type.h
segv.o: $(hdrdir)/ruby/internal/variable.h
segv.o: $(hdrdir)/ruby/internal/warning_push.h
segv.o: $(hdrdir)/ruby/internal/xmalloc.h
segv.o: $(hdrdir)/ruby/missing.h
segv.o: $(hdrdir)/ruby/ruby.h
segv.o: $(hdrdir)/ruby/st.h
segv.o: $(hdrdir)/ruby/subst.h
segv.o: segv.c
# AUTOGENERATED DEPENDENCIES END
15 changes: 15 additions & 0 deletions ext/-test-/fatal/segv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <ruby.h>
#include <signal.h>

static VALUE
bug_segv(VALUE self)
{
raise(SIGSEGV);
return Qnil; /* never reached */
}

void
Init_segv(VALUE mBug)
{
rb_define_singleton_method(mBug, "segv", bug_segv, 0);
}
69 changes: 43 additions & 26 deletions prism_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -11630,51 +11630,73 @@ pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *
return error;
}

struct rb_stdin_wrapper {
VALUE rb_stdin;
int eof_seen;
};
VALUE rb_io_gets_limit_internal(VALUE io, long limit);

/**
* Report whether the stream has reached EOF. The stream reader uses this to
* tell a line that is longer than the read buffer (keep reading) apart from the
* final line of input with no trailing newline (stop). We ask the IO directly
* rather than inferring EOF from a short read, which is unreliable once we
* request fewer bytes than the buffer can hold (see pm_parse_stdin_fgets).
*/
static int
pm_parse_stdin_eof(void *stream)
{
struct rb_stdin_wrapper * wrapped_stdin = (struct rb_stdin_wrapper *)stream;
return wrapped_stdin->eof_seen;
return RTEST(rb_io_eof((VALUE) stream));
}

VALUE rb_io_gets_limit_internal(VALUE io, long limit);
/**
* The largest number of bytes a single character can occupy in any encoding
* that Ruby supports (CESU-8). Ruby's line reader treats a `gets` limit as a
* soft limit: to avoid splitting a multi-byte character it may return up to
* `MAX_ENC_LEN - 1` more bytes than requested. Reserving `MAX_ENC_LEN` bytes of
* headroom therefore leaves room for both that overshoot and the terminating
* NUL byte.
*/
#define MAX_ENC_LEN 6

/**
* An implementation of fgets that is suitable for use with Ruby IO objects.
* An implementation of fgets that is suitable for use with Ruby IO objects. As
* required by pm_source_stream_fgets_t, this never writes more than `size`
* bytes into `string` (including the terminating NUL byte).
*/
static char *
pm_parse_stdin_fgets(char *string, int size, void *stream)
{
RUBY_ASSERT(size > 0);

struct rb_stdin_wrapper * wrapped_stdin = (struct rb_stdin_wrapper *)stream;
RUBY_ASSERT(size > MAX_ENC_LEN);

VALUE line = rb_io_gets_limit_internal(wrapped_stdin->rb_stdin, size - 1);
/*
* Request fewer bytes than the buffer can hold. Ruby's line reader may
* return more bytes than requested when the limit falls in the middle of a
* multi-byte character, and the reserved headroom guarantees the result
* still fits.
*/
VALUE line = rb_io_gets_limit_internal((VALUE) stream, size - MAX_ENC_LEN);
if (NIL_P(line)) {
return NULL;
}

const char *cstr = RSTRING_PTR(line);
long length = RSTRING_LEN(line);

memcpy(string, cstr, length);
string[length] = '\0';

// We're reading strings from stdin via gets. We'll assume that if the
// string is smaller than the requested length, and doesn't end with a
// newline, that we hit EOF.
if (length < (size - 1) && string[length - 1] != '\n') {
wrapped_stdin->eof_seen = 1;
/*
* Defensively clamp the copy. The line reader relaxes the limit to avoid
* splitting a multi-byte character, so the returned string can be longer
* than requested; we must never write past the caller's buffer. One byte
* is reserved for the NUL terminator.
*/
if (length > (long) (size - 1)) {
length = (long) (size - 1);
}

memcpy(string, cstr, (size_t) length);
string[length] = '\0';

return string;
}

#undef MAX_ENC_LEN

// We need access to this function when we're done parsing stdin.
void rb_reset_argf_lineno(long n);

Expand All @@ -11688,12 +11710,7 @@ pm_parse_stdin(pm_parse_result_t *result)
{
pm_options_frozen_string_literal_init(result->options);

struct rb_stdin_wrapper wrapped_stdin = {
rb_stdin,
0
};

result->source = pm_source_stream_new((void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof);
result->source = pm_source_stream_new((void *) rb_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof);
pm_node_t *node = pm_parse_stream(&result->parser, result->arena, result->source, result->options);

// When we're done parsing, we reset $. because we don't want the fact that
Expand Down
8 changes: 6 additions & 2 deletions test/ruby/test_rubyoptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ module SEGVTest
(?:
--\sRuby\slevel\sbacktrace\sinformation\s----------------------------------------\n
(?:-e:1:in\s\'(?:block\sin\s)?<main>\'\n)*
-e:1:in\s\'kill\'\n
-e:1:in\s\'segv\'\n
\n
)?
)x,
Expand All @@ -838,7 +838,10 @@ module SEGVTest
)x,
]

KILL_SELF = "Process.kill :SEGV, $$"
# Crash the current thread with a thread-directed raise(SIGSEGV) so the
# signal is delivered synchronously on the calling thread. Requires
# -test-/fatal to be loaded.
KILL_SELF = "Bug.segv"
end

def assert_segv(args, message=nil, list: SEGVTest::ExpectedStderrList, **opt, &block)
Expand All @@ -847,6 +850,7 @@ def assert_segv(args, message=nil, list: SEGVTest::ExpectedStderrList, **opt, &b
env = Hash === args.first ? args.shift : {}
args.unshift("--yjit") if JITSupport.yjit_enabled?
args.unshift("--zjit") if JITSupport.zjit_enabled?
args.unshift("-r-test-/fatal")
env.update({'RUBY_ON_BUG' => nil})
env['RUBY_CRASH_REPORT'] ||= nil # default to not passing down parent setting
# ASAN registers a segv handler which prints out "AddressSanitizer: DEADLYSIGNAL" when
Expand Down
1 change: 1 addition & 0 deletions zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def stats_string
:side_exit_size_ratio,
:zjit_alloc_bytes,
:total_mem_bytes,
:total_native_stack_bytes,

:side_exit_count,
:total_insn_count,
Expand Down
1 change: 1 addition & 0 deletions zjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ fn main() {
.allowlist_function("rb_funcallv")
.allowlist_function("rb_protect")
.allowlist_function("rb_zjit_profile_disable")
.allowlist_function("rb_zjit_profile_enable")
.allowlist_function("rb_zjit_insn_to_bare_insn")
.allowlist_function("rb_zjit_hash_new_size")
.allowlist_function("rb_zjit_class_allocate_instance_fastpath")
Expand Down
8 changes: 6 additions & 2 deletions zjit/src/asm/arm64/arg/shifted_imm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ pub struct ShiftedImmediate {
value: u16
}

impl ShiftedImmediate {
pub const MAX: u64 = 2_u64.pow(12) - 1;
}

impl TryFrom<u64> for ShiftedImmediate {
type Error = ();

fn try_from(value: u64) -> Result<Self, Self::Error> {
let current = value;
if current < 2_u64.pow(12) {
if current <= Self::MAX {
return Ok(ShiftedImmediate { shift: Shift::LSL0, value: current as u16 });
}

if (current & (2_u64.pow(12) - 1) == 0) && ((current >> 12) < 2_u64.pow(12)) {
if (current & Self::MAX == 0) && ((current >> 12) <= Self::MAX) {
return Ok(ShiftedImmediate { shift: Shift::LSL12, value: (current >> 12) as u16 });
}

Expand Down
Loading