Bug #4487

require_relative fails in an eval'ed file

Added by Roger Pack about 3 years ago. Updated about 1 year ago.

[ruby-core:<unknown>]
Status:Assigned
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:-
Target version:next minor
ruby -v:- Backport:

Description

=begin
Hello all.

$cat evalme1.rb
eval(File.read('eval
me2.rb'), binding, File.expandpath('./evalme2.rb'))
$cat evalme2.rb
require
relative 'evalme1.rb'
$ ruby eval
me1.rb
C:/dev/ruby/fasterrequire/spec/evalme2.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) consist... 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 3 years ago

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

#2 Updated by Yusuke Endoh almost 3 years ago

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

Hello,

 $cat evalme1.rb
 eval(File.read('eval
me2.rb'), binding, File.expandpath('./evalme2.rb'))
 $cat evalme2.rb
 require
relative 'evalme1.rb'
 $ ruby eval
me1.rb
 C:/dev/ruby/fasterrequire/spec/evalme2.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/vmeval.c b/vmeval.c
index 7df7f5f..3710401 100644
--- a/vmeval.c
+++ b/vm
eval.c
@@ -1007,7 +1007,7 @@ evalstringwithcref(VALUE self, VALUE src,
VALUE scope, NODE cref, const char
/
make eval iseq */
th->parse
ineval++;
th->mild
compile_error++;
- iseqval

#3 Updated by Yusuke Endoh almost 3 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 2 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 2 years ago

=begin

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

=end

#6 Updated by Piotr Niełacny almost 2 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 $LOADPATH. The same can be done by requirerelative (recognize path).

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

#7 Updated by Shyouhei Urabe almost 2 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 requirerelative loads relative from where the requirerelative 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 requirerelative to work on an IRB session, you have to define "from where requirerelative should search relativeness".
=end

#8 Updated by Benoit Daloze almost 2 years ago

shyouhei (Shyouhei Urabe) wrote:

Current requirerelative loads relative from where the requirerelative 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 requirerelative to work on an IRB session, you have to define "from where requirerelative 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 2 years ago

Eregon (Benoit Daloze) wrote:

shyouhei (Shyouhei Urabe) wrote:

Current requirerelative loads relative from where the requirerelative 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 requirerelative to work on an IRB session, you have to define "from where requirerelative 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 2 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 2 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 2 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 2 years ago

  • Assignee changed from Yukihiro Matsumoto to Yusuke Endoh

mame-san, please ask matz.

#14 Updated by Yusuke Endoh about 1 year 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 1 year 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