You are looking at historical revision 9611 of this page. It may differ significantly from its current revision.

sandbox

Description

Safe evaluation of basic Scheme expressions.

Author

felix winkelmann

Requirements

None

Download

sandbox.egg

Documentation

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.

current-fuel

[parameter] current-fuel

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.

current-allocation-limit

[parameter] current-allocation-limit

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.

current-safe-environment

[parameter] current-safe-environment

A parameter holding the current evaluation environment. The initial value is the value of default-safe-environment.

default-safe-environment

[constant] 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.

Example

<example> <expr>(safe-eval 123)</expr> <result>123</result> <expr>(safe-eval 'abc)</expr> <output>error</output> <expr> (define env (make-safe-environment)) (safe-eval '(+ 3 4) environment: env) </expr> <output>error: environment is empty and has no parent</output> <expr> (define env2 (make-safe-environment parent: default-safe-environment)) (safe-eval '(+ 3 4) environment: env2) </expr> <result>7</result> <expr> (safe-eval '(define abc 99) environment: env2) (safe-eval 'abc environment: env2) </expr> <result>99</result> <expr>(safe-eval '(define abc 99) environment: (make-safe-environment extendable: #f))</expr> <output>error</output> <expr>(safe-eval '(set! + 100))</expr> <output>error: binding not mutable</output> <expr>(safe-eval '(set! + 100) environment: env2)</expr> <output>error: the same (binding is inherited)</output> <expr>(safe-eval '(set! abc 100) environment: env2)</expr> <output>error</output> <expr>(safe-eval '(let loop () (loop))) ; never terminates</expr> <expr>(safe-eval '(let loop () (loop)) fuel: 1000)</expr> <output>error ("out of fuel")</output> <expr>(safe-eval '(make-vector 100))</expr> <output>; a 100-element vector</output> <expr>(safe-eval '(make-vector 100) allocation-limit: 100)</expr> <output>error ("allocation limit exceeded")</output> </example>

Changelog

License

 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.