diff options
author | Luke Gruber <[email protected]> | 2024-09-29 12:39:23 -0400 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2024-10-01 02:12:56 +0900 |
commit | d592ddd5e619ffe1691b8050de2ccc3e1bd6e080 () | |
tree | 01102e6ea49ef52cf3c8ad4c5d1124d8ec088efc | |
parent | 2a58092360c70caf7544544c95549b4c83e81237 (diff) |
Fix compile issue with a short-circuited if/unless condition and `defined?`
This caused an issue when `defined?` was in the `if` condition. Its instructions weren't appended to the instruction sequence even though it was compiled if a compile-time known logical short-circuit happened before the `defined?`. The catch table entry (`defined?` compilation produces a catch table entry) was still on the iseq even though the instructions weren't there. This caused faulty exception handling in the method. The solution is to no add the catch table entry for `defined?` after a compile-time known logical short circuit. This shouldn't touch much code, it's only for cases like the following, which can occur during debugging: if false && defined?(Some::CONSTANT) "more code..." end Fixes [Bug #20501]
Notes: Merged: https://.com/ruby/ruby/pull/11554
-rw-r--r-- | compile.c | 39 | ||||
-rw-r--r-- | prism_compile.c | 5 | ||||
-rw-r--r-- | test/ruby/test_syntax.rb | 37 | ||||
-rw-r--r-- | tool/lib/envutil.rb | 5 |
4 files changed, 71 insertions, 15 deletions
@@ -495,7 +495,7 @@ static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor); static int iseq_set_exception_table(rb_iseq_t *iseq); static int iseq_set_optargs_table(rb_iseq_t *iseq); -static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr); static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped); /* @@ -1353,6 +1353,7 @@ new_label_body(rb_iseq_t *iseq, long line) labelobj->set = 0; labelobj->rescued = LABEL_RESCUE_NONE; labelobj->unremovable = 0; return labelobj; } @@ -2878,11 +2879,16 @@ iseq_set_exception_table(rb_iseq_t *iseq) table->size = tlen; for (i = 0; i < table->size; i++) { ptr = RARRAY_CONST_PTR(tptr[i]); entry = UNALIGNED_MEMBER_PTR(table, entries[i]); entry->type = (enum rb_catch_type)(ptr[0] & 0xffff); - entry->start = label_get_position((LABEL *)(ptr[1] & ~1)); - entry->end = label_get_position((LABEL *)(ptr[2] & ~1)); entry->iseq = (rb_iseq_t *)ptr[3]; RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq); @@ -4640,7 +4646,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond, CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label)); return COMPILE_OK; case NODE_DEFINED: - CHECK(compile_defined_expr(iseq, ret, cond, Qfalse)); break; default: { @@ -5857,7 +5863,7 @@ private_recv_p(const NODE *node) static void defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, - const NODE *const node, LABEL **lfinish, VALUE needstr); static int compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver); @@ -6098,7 +6104,7 @@ build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *u static void defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, - const NODE *const node, LABEL **lfinish, VALUE needstr) { LINK_ELEMENT *lcur = ret->last; defined_expr0(iseq, ret, node, lfinish, needstr, false); @@ -6117,12 +6123,14 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, lend->rescued = LABEL_RESCUE_END; APPEND_LABEL(ret, lcur, lstart); ADD_LABEL(ret, lend); - ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]); } } static int -compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr) { const int line = nd_line(node); const NODE *line_node = node; @@ -6136,7 +6144,7 @@ compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const lfinish[0] = NEW_LABEL(line); lfinish[1] = 0; lfinish[2] = 0; - defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr); if (lfinish[1]) { ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link); ADD_INSN(ret, line_node, swap); @@ -6695,7 +6703,12 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int else_label = NEW_LABEL(line); end_label = 0; - CHECK(compile_branch_condition(iseq, cond_seq, RNODE_IF(node)->nd_cond, then_label, else_label)); ADD_SEQ(ret, cond_seq); if (then_label->refcnt && else_label->refcnt) { @@ -8179,7 +8192,7 @@ compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in // Normally, "send" instruction is at the last. // However, qcall under branch coverage measurement adds some instructions after the "send". // - // Note that "invokesuper" appears instead of "send". INSN *iobj; LINK_ELEMENT *last_elem = LAST_ELEMENT(ret); iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem); @@ -9638,7 +9651,7 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *lfinish[2]; lfinish[0] = lfin; lfinish[1] = 0; - defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse); lassign = lfinish[1]; if (!lassign) { lassign = NEW_LABEL(line); @@ -11233,7 +11246,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no break; case NODE_DEFINED: if (!popped) { - CHECK(compile_defined_expr(iseq, ret, node, Qtrue)); } break; case NODE_POSTEXE:{ @@ -3310,7 +3310,7 @@ pm_scope_node_destroy(pm_scope_node_t *scope_node) * Normally, "send" instruction is at the last. However, qcall under branch * coverage measurement adds some instructions after the "send". * - * Note that "invokesuper" appears instead of "send". */ static void pm_compile_retry_end_label(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *retry_end_l) @@ -8154,9 +8154,10 @@ pm_compile_super_node(rb_iseq_t *iseq, const pm_super_node_t *node, const pm_nod PUSH_INSN2(ret, *location, invokesuper, callinfo, current_block); } - pm_compile_retry_end_label(iseq, ret, retry_end_l); } if (popped) PUSH_INSN(ret, *location, pop); ISEQ_COMPILE_DATA(iseq)->current_block = previous_block; PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, current_block, retry_end_l); @@ -2229,6 +2229,43 @@ eom RUBY end private def not_label(x) @result = x; @not_label ||= nil end @@ -165,6 +165,11 @@ module EnvUtil } args = [args] if args.kind_of?(String) pid = spawn(child_env, *precommand, rubybin, *args, opt) in_c.close out_c&.close |