gpt4 book ai didi

ruby - 如何获取传递给 eval 方法的 block 的返回值?

转载 作者:数据小太阳 更新时间:2023-10-29 08:37:52 26 4
gpt4 key购买 nike

我想实现类似沙箱的东西

  • 评估给定的字符串
  • 在与 eval 相同的上下文中执行给定的 block
  • 返回 block 的结果

沙盒的目的是检查内容——函数、变量等。 - 易受攻击的代码。

这是我的规范

it 'returns return value of given block' do
value = Sandbox.secure_eval('hoge = ["hoge", "fuga"]') do
hoge[0]
end
expect(value).to eq('hoge')
end

而且,这是我的沙箱实现

require 'timeout'
module Sandbox
def self.secure_eval(code, timeout: 5, safe_level: 2)
raise ArgumentError, 'please set call back by block' unless block_given?

proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
eval code do
yield
end
end
end

proc.call
end
end

但是#secure_eval返回的是eval的结果,在本例中是["hoge", "fuga"],无法捕获block的返回值。

我怎样才能做到?

最佳答案

您可以使用 yield 将 eval 的结果返回给 block 。您只需要 yield 这个值;因此我将您的 yield 更改为 yield eval code。在您提供给 Sandbox.secure_eval 的 block 中,您必须将此结果绑定(bind)到 block 变量。 secure_eval 的结果将是 block 的结果,如您所愿。

proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
yield eval code # <= This line changed
end
end

Sandbox.secure_eval('hoge = ["hoge", "fuga"]') { |hoge| hoge[0] }
# => "hoge"

Sandbox.secure_eval('2 ** 4') { |result| result - 5 }
# => 11

回应您的评论;事实证明,在 Kernel#Binding 的帮助下,我们可以让它或多或少地像你想要的那样工作。感觉很像黑客攻击,因此请谨慎使用。

我使用 Binding 来计算代码,它可以访问所有已定义的变量。此外,我为 Binding 类定义了一个 method_missing,这样我们就可以更轻松地访问变量。没有它,您将需要执行 eval('varname') 而不仅仅是 varname。根据 @hakcho 的评论,他提到现有的猴子补丁解决方案并不理想,我现在使用仅在本地更改 Binding 行为(即 method_missing 实现)的改进。

我已经在您的方法中添加了一个明确的 block 参数,我将其与 instance_eval 一起使用,而不是 yield。然后我们可以直接在 block 中访问变量。

require 'timeout'

module Sandbox
refine Binding do
def method_missing(meth, *args, &block)
self.eval(meth.to_s)
end
end

def self.secure_eval(code, timeout: 5, safe_level: 2, &block)
raise ArgumentError, 'please set call back by block' unless block_given?

proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
binding = binding()
binding.eval(code)
binding.instance_eval(&block)
end
end

proc.call
end
end

using Sandbox # Activate the refinement so we can use x, y, z directly
Sandbox.secure_eval('x = [1,2,3]; y = 0; z = { key: "Hello!" }') do
x[1] # => 2
y # => 0
z[:key] # => "Hello!"
end

关于ruby - 如何获取传递给 eval 方法的 block 的返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24734297/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com