summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNARUSE, Yui <naruse@airemix.jp>2023-03-15 16:36:32 +0900
committerNARUSE, Yui <naruse@airemix.jp>2023-03-15 16:36:32 +0900
commitb73a07359758a9034996752e981e09ddaffe8d87 (patch)
tree242744cff549124d9e351c3d912591866a853db6
parentdb28f7003f7d49cfa13871c38d10c1967282ca6b (diff)
downloadruby-b73a07359758a9034996752e981e09ddaffe8d87.tar.gz
merge revision(s) 0eb634ae73cb327ede833b72492f912792a4a9d5: [Backport #19464]
YJIT: Detect and reject `send(:alias_for_send, :foo)` Previously, YJIT failed to put the stack into the correct shape when `BasicObject#send` calls an alias method for the send method itself. This can manifest as strange `NoMethodError`s in the final non-send receiver, as [seen][1] with the kt-paperclip gem. I also found a case where it makes YJIT fail the stack size assertion while compiling `leave`. YJIT's `BasicObject#__send__` implementation already rejects sends to `send`, but didn't detect sends to aliases of `send`. Adjust the detection and reject these cases. Fixes [Bug #19464] [1]: https://github.com/Shopify/yjit/issues/306 --- test/ruby/test_yjit.rb | 20 ++++++++++++++++++++ yjit/src/codegen.rs | 25 ++++++++++--------------- 2 files changed, 30 insertions(+), 15 deletions(-)
-rw-r--r--test/ruby/test_yjit.rb20
-rw-r--r--version.h2
-rw-r--r--yjit/src/codegen.rs25
3 files changed, 31 insertions, 16 deletions
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 2ea915bc0d..e4080595b0 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -1121,6 +1121,26 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_nested_send
+ #[Bug #19464]
+ assert_compiles(<<~RUBY, result: [:ok, :ok])
+ klass = Class.new do
+ class << self
+ alias_method :my_send, :send
+
+ def bar = :ok
+
+ def foo = bar
+ end
+ end
+
+ with_break = -> { break klass.send(:my_send, :foo) }
+ wo_break = -> { klass.send(:my_send, :foo) }
+
+ [with_break[], wo_break[]]
+ RUBY
+ end
+
private
def code_gc_helpers
diff --git a/version.h b/version.h
index 75e081cf3c..5eb9d00160 100644
--- a/version.h
+++ b/version.h
@@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 39
+#define RUBY_PATCHLEVEL 40
#include "ruby/version.h"
#include "ruby/internal/abi.h"
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 8c5b413286..687205e10f 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -5822,7 +5822,6 @@ fn gen_send_general(
let opt_type = unsafe { get_cme_def_body_optimized_type(cme) };
match opt_type {
OPTIMIZED_METHOD_TYPE_SEND => {
-
// This is for method calls like `foo.send(:bar)`
// The `send` method does not get its own stack frame.
// instead we look up the method and call it,
@@ -5830,6 +5829,16 @@ fn gen_send_general(
let starting_context = ctx.clone();
+ // Reject nested cases such as `send(:send, :alias_for_send, :foo))`.
+ // We would need to do some stack manipulation here or keep track of how
+ // many levels deep we need to stack manipulate. Because of how exits
+ // currently work, we can't do stack manipulation until we will no longer
+ // side exit.
+ if flags & VM_CALL_OPT_SEND != 0 {
+ gen_counter_incr!(asm, send_send_nested);
+ return CantCompile;
+ }
+
if argc == 0 {
gen_counter_incr!(asm, send_send_wrong_args);
return CantCompile;
@@ -5856,20 +5865,6 @@ fn gen_send_general(
return CantCompile;
}
- // We aren't going to handle `send(send(:foo))`. We would need to
- // do some stack manipulation here or keep track of how many levels
- // deep we need to stack manipulate
- // Because of how exits currently work, we can't do stack manipulation
- // until we will no longer side exit.
- let def_type = unsafe { get_cme_def_type(cme) };
- if let VM_METHOD_TYPE_OPTIMIZED = def_type {
- let opt_type = unsafe { get_cme_def_body_optimized_type(cme) };
- if let OPTIMIZED_METHOD_TYPE_SEND = opt_type {
- gen_counter_incr!(asm, send_send_nested);
- return CantCompile;
- }
- }
-
flags |= VM_CALL_FCALL | VM_CALL_OPT_SEND;
assume_method_lookup_stable(jit, ocb, cme);