merge revision(s) e0d600ec19: [Backport #21012]

Avoid opt_aset_with optimization inside multiple assignment

	Previously, since the opt_aset_with optimization was introduced,
	use of the opt_aset_with optimization inside multiple assignment
	would result in a segfault or incorrect instructions.

	Fixes [Bug #21012]

	Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
This commit is contained in:
Takashi Kokubun 2025-02-13 21:08:44 -08:00
parent 3db440f5a1
commit 3fdf7279a0
4 changed files with 17 additions and 2 deletions

View file

@ -10176,7 +10176,8 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
/* optimization shortcut /* optimization shortcut
* obj["literal"] = value -> opt_aset_with(obj, "literal", value) * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
*/ */
if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args && if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 && nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
(nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) && (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL && ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
@ -10729,7 +10730,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
} }
case NODE_MASGN:{ case NODE_MASGN:{
bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
compile_massign(iseq, ret, node, popped); compile_massign(iseq, ret, node, popped);
ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
break; break;
} }

1
iseq.h
View file

@ -119,6 +119,7 @@ struct iseq_compile_data {
struct iseq_compile_data_storage *storage_current; struct iseq_compile_data_storage *storage_current;
} insn; } insn;
bool in_rescue; bool in_rescue;
bool in_masgn;
int loopval_popped; /* used by NODE_BREAK */ int loopval_popped; /* used by NODE_BREAK */
int last_line; int last_line;
int label_no; int label_no;

View file

@ -248,6 +248,16 @@ class TestAssignment < Test::Unit::TestCase
a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c]) a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c])
end end
def test_massign_optimized_literal_bug_21012
a = []
def a.[]=(*args)
push args
end
a["a", "b"], = 1
a["a", 10], = 2
assert_equal [["a", "b", 1], ["a", 10, 2]], a
end
def test_assign_rescue def test_assign_rescue
a = raise rescue 2; assert_equal(2, a) a = raise rescue 2; assert_equal(2, a)
a, b = raise rescue [3,4]; assert_equal([3, 4], [a, b]) a, b = raise rescue [3,4]; assert_equal([3, 4], [a, b])

View file

@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1 #define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 17 #define RUBY_PATCHLEVEL 18
#include "ruby/version.h" #include "ruby/version.h"
#include "ruby/internal/abi.h" #include "ruby/internal/abi.h"