Bug #4487

require_relative fails in an eval'ed file

Added by Roger Pack about 4 years ago. Updated about 2 years ago.

[ruby-core:<unknown>]
Status:Assigned
Priority:Normal
Assignee:Yukihiro Matsumoto
ruby -v:- Backport:

Description

=begin
Hello all.

$cat eval_me1.rb
eval(File.read('eval_me2.rb'), binding, File.expand_path('./eval_me2.rb'))
$cat eval_me2.rb
require_relative 'eval_me1.rb'
$ ruby eval_me1.rb
C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in require_relative': cannot infer basepath (LoadError)
from C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in
'
from eval_me1.rb:1:in eval'
from eval_me1.rb:1:in
'

I suppose was assuming that if eval included a filename, then require_relative would work from within it. Perhaps I am mistaken?
Thanks!
-r
=end


Related issues

Related to Ruby trunk - Bug #4352: [patch] Fix eval(s, b) backtrace; make eval(s, b) consistent with eval(s) Assigned 02/01/2011
Related to Ruby trunk - Bug #7391: Allow to use require_relative from eval and irb environment Assigned 11/19/2012

History

#1 Updated by Yui NARUSE almost 4 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yusuke Endoh

#2 Updated by Yusuke Endoh almost 4 years ago

  • ruby -v changed from ruby 1.9.3dev (2011-03-04 trunk 31024) [i386-mingw32] to -

Hello,

 $cat eval_me1.rb
 eval(File.read('eval_me2.rb'), binding, File.expand_path('./eval_me2.rb'))
 $cat eval_me2.rb
 require_relative 'eval_me1.rb'
 $ ruby eval_me1.rb
 C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in require_relative': cannot infer basepath (LoadError)
       from C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in
'
       from eval_me1.rb:1:in eval'
       from eval_me1.rb:1:in
'

I suppose was assuming that if eval included a filename, then require_relative would work from within it. Perhaps I am mistaken?

I think your expectation is reasonable, though I personally dislike
the eval's feature to fake filepath.

The following patch makes require_relative use the given file path.
I'm afraid if I should include this patch in 1.9.3 because I can't
estimate the impact of this patch. What do you think?

diff --git a/vm_eval.c b/vm_eval.c
index 7df7f5f..3710401 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1007,7 +1007,7 @@ eval_string_with_cref(VALUE self, VALUE src,
VALUE scope, NODE cref, const char
/
make eval iseq */
th->parse_in_eval++;
th->mild_compile_error++;
- iseqval

#3 Updated by Yusuke Endoh almost 4 years ago

  • Assignee changed from Yusuke Endoh to Yukihiro Matsumoto

Related to #4352.

I need matz's judgment.

Yusuke Endoh mame@tsg.ne.jp

#4 Updated by Piotr Niełacny almost 3 years ago

=begin
If in irb we can execute

(({load("file.rb")}))

why we can't

(({require_relative("file")}))

Ruby just return exception (LoadError: cannot infer basepath). Unfortunately, this is a 'lie' because ruby can recognize basepath.
=end

#5 Updated by Shyouhei Urabe almost 3 years ago

=begin

@LTe sorry, I can't get it. load loads from $LOAD_PATH, while require_relative requires from relative path. They are different.

=end

#6 Updated by Piotr Niełacny almost 3 years ago

@shyouhei yes I agree but load method tries to load file from relative path. When load method can't find file in relative path it loads from $LOAD_PATH. The same can be done by require_relative (recognize path).

https://github.com/ruby/ruby/pull/139

#7 Updated by Shyouhei Urabe almost 3 years ago

=begin
@LTe I'd rather ask you "require_relative loads something relative from WHAT?"

Obviously it is not relative from your mind :)

Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).

OTOH load loads from process PWD, which is possible in IRB.

So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".
=end

#8 Updated by Benoit Daloze almost 3 years ago

shyouhei (Shyouhei Urabe) wrote:

Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).

OTOH load loads from process PWD, which is possible in IRB.

So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".

From the process current working directory I guess, especially since you almost always launch IRB from a terminal.

Personally I'm doing require './myfile' which is not the most elegant, but if you don't have completion in IRB, that's shorter to type.

Otherwise, there's always the option to do irb -I. and use plain require.

#9 Updated by Yui NARUSE almost 3 years ago

Eregon (Benoit Daloze) wrote:

shyouhei (Shyouhei Urabe) wrote:

Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).

OTOH load loads from process PWD, which is possible in IRB.

So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".

From the process current working directory I guess, especially since you almost always launch IRB from a terminal.

Personally I'm doing require './myfile' which is not the most elegant, but if you don't have completion in IRB, that's shorter to type.

Otherwise, there's always the option to do irb -I. and use plain require.

require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.

#10 Updated by Shyouhei Urabe almost 3 years ago

naruse (Yui NARUSE) wrote:

require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.

I'm not pretty sure about this. Is there a chance for a (proposed behaviour of) require_relative to require a malicious file on the current directory?

Because you are on an IRB session and intentionally emitting require_relative (not require), I doubt the danger you say.

#11 Updated by Yui NARUSE almost 3 years ago

shyouhei (Shyouhei Urabe) wrote:

naruse (Yui NARUSE) wrote:

require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.

I'm not pretty sure about this. Is there a chance for a (proposed behaviour of) require_relative to require a malicious file on the current directory?

Because you are on an IRB session and intentionally emitting require_relative (not require), I doubt the danger you say.

  • irb is not the only user of eval.
  • A user won't always use require_relative intentionally.
  • There is a suitable another way: require './myfile'

With those reason, I don't think require_relative should be changed.

#12 Updated by Benoit Daloze almost 3 years ago

naruse (Yui NARUSE) wrote:

Eregon (Benoit Daloze) wrote:

From the process current working directory I guess, especially since you almost always launch IRB from a terminal.

require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.

I see, you're right.
Indeed, with this in mind I think it's not worth changing, and the actual require_relative behavior is clearer (relative to "this file" directory, if there is no accurate "this file", just #raise).

#13 Updated by Koichi Sasada almost 3 years ago

  • Assignee changed from Yukihiro Matsumoto to Yusuke Endoh

mame-san, please ask matz.

#14 Updated by Yusuke Endoh about 2 years ago

  • Subject changed from require_relative fails in an eval'ed file to require_relative fails in an eval&#x27;ed file
  • Assignee changed from Yusuke Endoh to Yukihiro Matsumoto
  • Target version set to next minor

#15 Updated by Conrad Irwin about 2 years ago

This bug also affects pry: https://github.com/pry/pry/issues/880. Our use-case is slightly different because we are doing TOPLEVEL_BINDING.eval("some code", "/absolute/path.rb").

I think that when an absolute path is set in eval, then require_relative should use it.

Also available in: Atom PDF