Safe evaluation of basic Scheme expressions.
This extension provides a safe evaluation context for basic Scheme expressions (R5RS without optional, input- or output forms). The following standard Scheme procedures are not available:
display write read read-char peek-char write-char eof-object? char-ready? newline open-input-file open-output-file close-input-port close-output-port with-input-from-file with-output-from-file call-with-input-file call-with-output-file input-port? output-port? current-input-port current-output-port load transcript-on transcript-off null-environment scheme-report-environment interaction-environment
eval is provided but does only accept a single argument.
Runaway evaluation (for example by executing endless loops) and excessive allocation can be caught by specifying appropriate limits on execution time and storage. The execution environment is fully thread safe.
safe-eval[procedure] (safe-eval EXPRESSION #!key ENVIRONMENT FUEL ALLOCATION-LIMIT)
Evaluates EXPRESSION in a safe evaluation context. FUEL specifies how much fuel the pre-translation and evaluation has before an exception will be raised. ALLOCATION-LIMIT gives (a rough) estimation over the maximal size of storage that may be allocated during the evalution of EXPRESSION. FUEL and ALLOCATION-LIMIT default to #f, meaning no limit is given.
ENVIRONMENT specifies the evaluation environment that should be used, and defaults to the value of default-safe-environment.
Should an error occur during the execution of EXPRESSION, a composite condition of the original error condition and a condition of the kind sandbox will be signalled.
Note that de-allocation is not tracked, only allocation.
A parameter holding the current amount fuel. If this counter reaches zero during the pre-translation or execution of an evaluated expression an error is signalled. The initial value is #f, meaning no limit is given.
A parameter holding the current maximum storage that an evaluated expression may allocate. If the total size of allocated storage exceeds this limit (given in bytes) and error is signalled. The initial value is #f, meaning no limit is given.
Note that this limit is a rough estimate.
safe-environment?[procedure] (safe-environment? X)
Returns #t if X is a safe environment object or #f otherwise.
A parameter holding the current evaluation environment. The initial value is the value of default-safe-environment.
An evaluation environment containing a basic R5RS environment without I/O procedures.</dd>
make-safe-environment[procedure] (make-safe-environment #!key NAME PARENT MUTABLE EXTENDABLE)
Creates a fresh evaluation environment with a given NAME and parent environment PARENT. Whn a binding is looked up and can not be found in the current environment, then the chain of parent environments will be checked for a matching binding.
If MUTABLE is not given or false, then this environment is not mutable and bindings in this environment may not be changed with set!. If EXTENDABLE is not given or true, then the environment may be extended with new global bindings.
safe-environment-ref[procedure] (safe-environment-ref ENVIRONMENT ID [DEFAULT])
Returns the current value of the variable named ID in ENVIRONMENT or DEFAULT if the ENVIRONMENT or it's parent environments do not contain a binding with this name. If DEFAULT is not given, #f will be returned.
safe-environment-set![procedure] (safe-environment-set! ENVIRONMENT ID VALUE)
Sets the value of the variable named ID in ENVIRONMENT to value, creating a new binding if no variable with this name exists (it doesn't check the parent environment). Use this procedure to add additional primitives to an evaluation context:
(define my-env (make-safe-environment parent: default-safe-environment) ) (safe-environment-set! my-env 'hello (lambda (arg) (display "Hello, ") (display arg) (display "!\n") ) ) (safe-eval '(hello "you") environment: my-env) ; prints: Hello, you!
This procedure doesn't care whether an environment is mutable (or extendable) or not.
safe-environment-remove![procedure] (safe-environment-remove! ENVIRONMENT ID)
Removes the binding for ID in the given environment or does nothing if no such binding exists.
safe-environment-macro-set![procedure] (safe-environment-macro-set! ENVIRONMENT ID PROC)
Defines or changes the macro-expander procedure for the macro with the name ID to PROC, which should be a procedure of one argument, the list of arguments (unevaluated) passed to the macro.
safe-environment-macro-remove![procedure] (safe-environment-macro-remove! ENVIRONMENT ID)
Removes the macro-binding for ID in the given environment or does nothing if no such binding exists.
(use sandbox) (safe-eval 123) => 123 (safe-eval 'abc) => error (define env (make-safe-environment)) (safe-eval '(+ 3 4) environment: env) ;; error: environment is empty and has no parent (define env2 (make-safe-environment parent: default-safe-environment)) (safe-eval '(+ 3 4) environment: env2) => 7 (safe-eval '(define abc 99) environment: env2) (safe-eval 'abc environment: env2) => 99 (safe-eval '(define abc 99) environment: (make-safe-environment extendable: #f)) ;; error (safe-eval '(set! + 100)) ;; error: binding not mutable (safe-eval '(set! + 100) environment: env2) ;; error: the same (binding is inherited) (safe-eval '(set! abc 100) environment: env2) ;; error (safe-eval '(let loop () (loop))) ;; never terminates (safe-eval '(let loop () (loop)) fuel: 1000) ;; error ("out of fuel") (safe-eval '(make-vector 100)) => ;; a 100-element vector (safe-eval '(make-vector 100) allocation-limit: 100) ;; error ("allocation limit exceeded")
- 1.5 apply didn't handle circular lists [Thanks to Goran Weinholt]
- 1.4 Added proper setup script; uses trace-buffer and lambda-info
- 1.3 Fixed problem with older chicken versions [Thanks to Alejandro Forero Cuervo]
- 1.2 Keyword fix was incorrect [Thanks to Alex again]
- 1.1 safe-eval now handles keywords [Thanks to Alex Shinn]; added internal support for extended number types
- 1.0 Initial release
Copyright (c) 2004, Felix L. Winkelmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.