1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/bootstraptest/test_eval.rb
ko1 c4bc9b5758 * iseq.c, vm_eval.c: set th->base_block properly.
th->base_block is information for (a) parsing, (b) compiling
  and (c) setting up the frame to execute the program passed by
  `eval' method.  For example, (1) parser need to know up-level
  variables to detect it is variable or method without paren.
  Befor (a), (b) and (c), VM set th->base_block by passed bindng
  (or previous frame information).  After execute (a), (b) and (c),
  VM should clear th->base_block.  However, if (a), (b) or (c)
  raises an exception, then th->base_block is not cleared.
  Problem is that the uncleared value th->balo_block is used for
  irrelevant iseq compilation.  It causes SEGV or critical error.
  I tried to solve this problem: to clear them before exception,
  but finally I found out that it is difficult to do it (Ruby
  program can be run in many places).
  Because of this background, I set th->base_block before
  compiling iseq and restore it after compiling.
  Basically, th->base_block is dirty hack (similar to global
  variable) and this patch is also dirty.
* bootstraptest/test_eval.rb: add a test for above.
* internal.h: remove unused decl.
* iseq.c (rb_iseq_compile_with_option): add base_block parameter.
  set th->base_block before compation and restore it after
  compilation.
* ruby.c (require_libraries): pass 0 as base_block instead of
  setting th->base_block
* tool/compile_prelude.rb (prelude_eval): apply above changes.
* vm.c, vm_eval.c: ditto.
* vm_core.h: add comments.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-22 09:32:56 +00:00

330 lines
4.7 KiB
Ruby

assert_equal %q{ok}, %q{
def m
a = :ok
$b = binding
end
m
eval('a', $b)
}
assert_equal %q{[:ok, :ok2]}, %q{
def m
a = :ok
$b = binding
end
m
eval('b = :ok2', $b)
eval('[a, b]', $b)
}
assert_equal %q{[nil, 1]}, %q{
$ans = []
def m
$b = binding
end
m
$ans << eval(%q{
$ans << eval(%q{
a
}, $b)
a = 1
}, $b)
$ans
}
assert_equal %q{C}, %q{
Const = :top
class C
Const = :C
def m
binding
end
end
eval('Const', C.new.m)
}
assert_equal %q{top}, %q{
Const = :top
a = 1
class C
Const = :C
def m
eval('Const', TOPLEVEL_BINDING)
end
end
C.new.m
}
assert_equal %q{:ok
ok}, %q{
class C
$b = binding
end
eval %q{
def m
:ok
end
}, $b
p C.new.m
}
assert_equal %q{ok}, %q{
b = proc{
a = :ok
binding
}.call
a = :ng
eval("a", b)
}
assert_equal %q{C}, %q{
class C
def foo
binding
end
end
C.new.foo.eval("self.class.to_s")
}
assert_equal %q{1}, %q{
eval('1')
}
assert_equal %q{1}, %q{
eval('a=1; a')
}
assert_equal %q{1}, %q{
a = 1
eval('a')
}
assert_equal %q{ok}, %q{
__send__ :eval, %{
:ok
}
}
assert_equal %q{ok}, %q{
1.__send__ :instance_eval, %{
:ok
}
}
assert_equal %q{1}, %q{
1.instance_eval{
self
}
}
assert_equal %q{foo}, %q{
'foo'.instance_eval{
self
}
}
assert_equal %q{1}, %q{
class Fixnum
Const = 1
end
1.instance_eval %{
Const
}
}
assert_equal %q{top}, %q{
Const = :top
class C
Const = :C
end
C.module_eval{
Const
}
}
assert_equal %q{C}, %q{
Const = :top
class C
Const = :C
end
C.class_eval %{
def m
Const
end
}
C.new.m
}
assert_equal %q{top}, %q{
Const = :top
class C
Const = :C
end
C.class_eval{
def m
Const
end
}
C.new.m
}
assert_equal %q{[:top, :C, :top, :C]}, %q{
Const = :top
class C
Const = :C
end
$nest = false
$ans = []
def m
$ans << Const
C.module_eval %{
$ans << Const
Boo = false unless defined? Boo
unless $nest
$nest = true
m
end
}
end
m
$ans
}
assert_equal %q{[10, main]}, %q{
$nested = false
$ans = []
$pr = proc{
$ans << self
unless $nested
$nested = true
$pr.call
end
}
class C
def initialize &b
10.instance_eval(&b)
end
end
C.new(&$pr)
$ans
}
%w[break next redo].each do |keyword|
assert_match %r"Can't escape from eval with #{keyword}\z", %{
begin
eval "0 rescue #{keyword}"
rescue SyntaxError => e
e.message
end
}, '[ruby-dev:31372]'
end
assert_normal_exit %q{
STDERR.reopen(STDOUT)
class Foo
def self.add_method
class_eval("def some-bad-name; puts 'hello' unless @some_variable.some_function(''); end")
end
end
Foo.add_method
}, '[ruby-core:14556] reported by Frederick Cheung'
assert_equal 'ok', %q{
class Module
def my_module_eval(&block)
module_eval(&block)
end
end
class String
Integer.my_module_eval do
def hoge; end
end
end
if Integer.instance_methods(false).map{|m|m.to_sym}.include?(:hoge) &&
!String.instance_methods(false).map{|m|m.to_sym}.include?(:hoge)
:ok
else
:ng
end
}, "[ruby-dev:34236]"
assert_equal 'ok', %q{
begin
eval("class nil::Foo; end")
:ng
rescue Exception
:ok
end
}
assert_equal 'ok', %q{
begin
0.instance_eval { def m() :m end }
1.m
:ng
rescue Exception
:ok
end
}, '[ruby-dev:34579]'
assert_equal 'ok', %q{
begin
12.instance_eval { @@a }
rescue NameError
:ok
end
}, '[ruby-core:16794]'
assert_equal 'ok', %q{
begin
12.instance_exec { @@a }
rescue NameError
:ok
end
}, '[ruby-core:16794]'
assert_equal 'ok', %q{
begin
nil.instance_eval {
def a() :a end
}
rescue TypeError
:ok
end
}, '[ruby-core:16796]'
assert_equal 'ok', %q{
begin
nil.instance_exec {
def a() :a end
}
rescue TypeError
:ok
end
}, '[ruby-core:16796]'
assert_normal_exit %q{
eval("", method(:proc).call {}.binding)
}
assert_equal "", %q{
b = binding
10.times{
eval('', b)
}
begin
eval('1.times{raise}', b)
rescue => e
e.message
end
}, '[ruby-dev:35392]'
assert_equal "[:x]", %q{
def kaboom!
yield.eval("local_variables")
end
for x in enum_for(:kaboom!)
binding
end
}, '[ruby-core:25125]'
assert_normal_exit %q{
hash = {}
("aaaa".."matz").each_with_index do |s, i|
hash[s] = i
end
begin
eval "class C; @@h = #{hash.inspect}; end"
end
}, '[ruby-core:25714]'
assert_normal_exit %q{
begin
eval("# encoding:utf-16le\nfoo")
rescue Exception => e
p e
RubyVM::InstructionSequence.compile("p:hello")
end
}, 'check escaping the internal value th->base_block'