Lei*_*sen 7 macros module eval racket
Racket提供protect-out
了防止模块导出与eval(或解构的语法对象)一起使用,除非模块具有足够的权限(也就是说,具有足够强大的代码检查器).该文档还提供了一个很好的例子是什么它:
> (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
Run Code Online (Sandbox Code Playgroud)
也就是说,eval
有一个足够强大的代码检查器(因为它在最初需要模块的同一范围内调用),因此能够获得导出.但是,weak-eval
没有,因为它有相同的模块实例,但有一个较弱的检查员用于eval
ing.
我的问题是,我们protect-out
什么时候应该使用?它应该始终使用(或至少在可能的情况下使用)?或者是否有针对特定的工作流程protect-out
?
使用protect-out
了不安全的出口,在不安全的手段的东西,有违反球拍语言或虚拟机的规则的能力.特别是,通常可能会因滥用不安全功能而导致Racket VM崩溃.
不安全功能的示例:
unsafe-vector-set!
或多或少允许您写入任意内存位置,可能违反GC的不变量,Racket在内存中的值表示的不变量等unsafe-vector-ref
似乎不那么危险,但你可以使用它来从闭包中提取自由变量的值,即使Racket语言不允许检查过程的实现ffi/unsafe
显然,大多数是不安全的这是一个不太明显的不安全程序的例子:
#lang racket
(require ffi/unsafe ffi/unsafe/define)
(define-ffi-definer define-c #f) ;; searches libc, etc
(define-c fopen (_fun _path (_bytes = #"a") -> _pointer))
(define-c fclose (_fun _pointer -> _void))
(define-c fwrite (_fun _bytes _size _size _pointer -> _size))
(define (append-to-file path buf)
(define fp (fopen path))
(unless fp (error "couldn't open file"))
(fwrite buf (bytes-length buf) 1 fp)
(fclose fp))
(provide append-to-file)
Run Code Online (Sandbox Code Playgroud)
考虑一下append-to-file
程序.它使用了不安全的功能(在FFI)定义,但FFI类型_path
和_bytes
将拒绝坏球拍值,所以它不应该是可以通过使用崩溃球拍append-to-file
.该append-to-file
程序仍然不安全(尽管可能不像灾难性的那样不安全unsafe-vector-set!
)因为它绕过了Racket的安全防范机制.该过程以另一种方式是不安全的,因为fopen
并且fwrite
可以阻止,并且不应该阻止Racket代码.
随机提供了Racket核心库中的不安全操作protect-out
.如果您使用它们来定义自己的不安全操作,则还应使用派生的不安全操作protect-out
.如果您使用不安全的功能来定义安全功能,那么您可以正常(即没有protect-out
)提供,但请先仔细考虑!
如果您捕获特权代码检查器(直接或间接通过#%variable-reference
),您还应该保护它,因为它可以用于动态获取对不安全功能的访问.
目标是:如果命名空间仅包含具有属性的模块保护其不安全的导出,那么使用较弱的代码检查器评估的任何其他代码都不应该违反Racket VM的不变量(例如,使其崩溃,绕过安全保护检查等).