Racket提供protect-out以防止模块导出与eval(或解构的语法对象)一起使用,除非模块具有足够的权限(也就是说,具有strong enough code inspector) . 文档也为它的作用提供了一个很好的例子:
> (module nest racket
(provide num-eggs (protect-out num-chicks))
(define num-eggs 2)
(define num-chicks 3))
> (define weak-inspector (make-inspector (current-code-inspector)))
> (define (weak-eval x)
(parameterize ([current-code-inspector weak-inspector])
(define weak-ns (make-base-namespace))
(namespace-attach-module (current-namespace)
''nest
weak-ns)
(parameterize ([current-namespace weak-ns])
(namespace-require ''nest)
(eval x))))
> (require 'nest)
> (list num-eggs num-chicks)
'(2 3)
> (weak-eval 'num-eggs)
2
> (weak-eval 'num-chicks)
?: access disallowed by code inspector to protected variable
from module: 'nest
at: num-chicks
也就是说, eval
有一个足够强大的代码检查器(因为它在最初需要模块的同一范围内调用),因此能够获得导出 . 但是, weak-eval
没有,因为它有相同的模块实例,但是有一个较弱的检查器用于 eval
ing .
我的问题是,我们什么时候应该使用 protect-out
?它应该始终使用(或至少在可能的情况下使用)?或者 protect-out
是否有针对特定的工作流程?
1 回答
将
protect-out
用于不安全的导出,其中不安全意味着能够违反Racket语言或虚拟机规则的内容 . 特别是,通常可能会因滥用不安全功能而导致Racket VM崩溃 .不安全功能的示例:
unsafe-vector-set!
或多或少允许您写入任意内存位置,可能违反GC的不变量,Racket在内存中的值表示的不变量等unsafe-vector-ref
似乎不那么危险,但你可以使用它来从闭包中提取自由变量的值,即使Racket语言不允许检查过程的实现ffi/unsafe
的大部分显然是不安全的这是一个不太明显的不安全程序的例子:
考虑
append-to-file
程序 . 它是使用不安全功能(FFI)定义的,但FFI类型_path
和_bytes
将拒绝不良的Racket值,因此不应该使用append-to-file
来使Racket崩溃 .append-to-file
程序仍然不安全(尽管可能不像unsafe-vector-set!
那样灾难性不安全)因为它绕过了Racket的安全防护机制 . 该过程以另一种方式是不安全的,因为fopen
和fwrite
可以阻止,并且不应该阻止Racket代码 .Racket核心库中的不安全操作随
protect-out
一起提供 . 如果您使用它们来定义自己的不安全操作,则应使用protect-out
提供派生的不安全操作 . 如果您使用不安全的功能来定义安全功能,那么您可以正常提供(即没有protect-out
),但请先仔细考虑!如果您捕获特权代码检查器(直接或间接通过
#%variable-reference
),您还应该保护它,因为它可以用于动态获取对不安全功能的访问 .目标是:如果命名空间仅包含具有属性的模块保护其不安全的导出,那么使用较弱的代码检查器评估的任何其他代码都不应该违反Racket VM的不变量(例如,使其崩溃,绕过安全保护检查等) .