From 64ac984129a7a4645efe5ac57c168ef880b479b2 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 21 May 2021 11:01:06 -0700 Subject: Make RubyVM::AbstractSyntaxTree.of raise for method/proc created in eval This changes Thread::Location::Backtrace#absolute_path to return nil for methods/procs defined in eval. If the realpath of an iseq is nil, that indicates it was defined in eval, in which case you cannot use RubyVM::AbstractSyntaxTree.of. Fixes [Bug #16983] Co-authored-by: Koichi Sasada --- vm_eval.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'vm_eval.c') diff --git a/vm_eval.c b/vm_eval.c index bc40c15b6c..19ba6dd96b 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1661,13 +1661,15 @@ rb_each(VALUE obj) } void rb_parser_warn_location(VALUE, int); + +static VALUE eval_default_path; + static const rb_iseq_t * eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind, const struct rb_block *base_block) { const VALUE parser = rb_parser_new(); const rb_iseq_t *const parent = vm_block_iseq(base_block); - VALUE realpath = Qnil; rb_iseq_t *iseq = NULL; rb_ast_t *ast; int isolated_depth = 0; @@ -1694,10 +1696,14 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind, if (fname != Qundef) { if (!NIL_P(fname)) fname = rb_fstring(fname); - realpath = fname; } else { fname = rb_fstring_lit("(eval)"); + if (!eval_default_path) { + eval_default_path = rb_fstring_lit("(eval)"); + rb_gc_register_mark_object(eval_default_path); + } + fname = eval_default_path; } rb_parser_set_context(parser, parent, FALSE); @@ -1705,7 +1711,7 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind, if (ast->body.root) { iseq = rb_iseq_new_eval(&ast->body, parent->body->location.label, - fname, realpath, INT2FIX(line), + fname, Qnil, INT2FIX(line), parent, isolated_depth); } rb_ast_dispose(ast); @@ -2590,7 +2596,18 @@ rb_current_realfilepath(void) const rb_execution_context_t *ec = GET_EC(); rb_control_frame_t *cfp = ec->cfp; cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)); - if (cfp != 0) return rb_iseq_realpath(cfp->iseq); + if (cfp != NULL) { + VALUE path = rb_iseq_realpath(cfp->iseq); + if (RTEST(path)) return path; + // eval context + path = rb_iseq_path(cfp->iseq); + if (path == eval_default_path) { + return Qnil; + } + else { + return path; + } + } return Qnil; } -- cgit v1.2.1