From 5630a3a1cab8d7953bfbb290bd6ae63c84ead605 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 2 Mar 2012 07:47:16 -0700 Subject: [PATCH] racket/sandbox: use `gui-available?' at sandbox creation Previously, sandbox creation used `gui?', which is the result of `gui-available?' at the time that `racket/sandbox' is instanited. This change makes sandbox behavior less sensitive tothe order in which modules `require'd into a program are intiantiated. The change depends on a new `sandbox-make-namespace' default function for `sandbox-namespace-specs'. The new function uses either `make-base-namespace' or `make-gui-namespace', depending on whether the GUI library is available at that point. A new `sandbox-gui-enabled' parameter can disable use of the GUI library even if it is available. The `gui?' binding is still exported for backward compatibility, but it shouldn't be used anymore. --- collects/racket/sandbox.rkt | 40 ++++++++++------ collects/scribblings/reference/sandbox.scrbl | 44 +++++++++++++----- collects/tests/racket/sandbox-gui.rkt | 48 ++++++++++++++++++++ doc/release-notes/racket/HISTORY.txt | 5 ++ 4 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 collects/tests/racket/sandbox-gui.rkt diff --git a/collects/racket/sandbox.rkt b/collects/racket/sandbox.rkt index 70aed425a8..b4097773c5 100644 --- a/collects/racket/sandbox.rkt +++ b/collects/racket/sandbox.rkt @@ -10,6 +10,7 @@ setup/dirs) (provide gui? + sandbox-gui-available sandbox-init-hook sandbox-reader sandbox-input @@ -23,6 +24,7 @@ sandbox-security-guard sandbox-network-guard sandbox-exit-handler + sandbox-make-namespace sandbox-make-inspector sandbox-make-code-inspector sandbox-make-logger @@ -53,12 +55,16 @@ exn:fail:resource? exn:fail:resource-resource) +; for backward compatibility; maybe it should be removed: (define gui? (gui-available?)) +;; When this parameter is #t, it is adjusted when creating a sandbox: +(define sandbox-gui-available (make-parameter #t (lambda (v) (and v #t)))) + (define-syntax mz/mr ; use a value for plain racket, or pull a gui binding (syntax-rules () [(mz/mr mzval mrsym) - (if gui? (gui-dynamic-require 'mrsym) mzval)])) + (if (sandbox-gui-available) (gui-dynamic-require 'mrsym) mzval)])) ;; Configuration ------------------------------------------------------------ @@ -85,8 +91,11 @@ [sandbox-eval-handlers '(#f #f)]) (thunk))) +(define (sandbox-make-namespace) + ((mz/mr make-base-namespace make-gui-namespace))) + (define sandbox-namespace-specs - (make-parameter `(,(mz/mr make-base-namespace make-gui-namespace) + (make-parameter `(,sandbox-make-namespace #| no modules here by default |#))) (define (default-sandbox-reader source) @@ -613,15 +622,7 @@ (uncovered! (list (get) get))) (when (namespace? ns) (current-namespace ns))) -(define current-eventspace (mz/mr (make-parameter #f) current-eventspace)) -(define make-eventspace (mz/mr void make-eventspace)) -(define run-in-bg (mz/mr thread queue-callback)) (define null-input (open-input-bytes #"")) -(define bg-run->thread - (if gui? - (lambda (ignored) - ((mz/mr void eventspace-handler-thread) (current-eventspace))) - values)) ;; special message values for the evaluator procedure, also inside the user ;; context they're used for function applications. @@ -879,6 +880,8 @@ memory-cust)) (parameterize* ; the order in these matters (;; create a sandbox context first + [sandbox-gui-available (and (sandbox-gui-available) + (gui-available?))] [current-custodian user-cust] [current-thread-group (make-thread-group)] ;; paths @@ -944,17 +947,24 @@ [current-command-line-arguments '#()] ;; Finally, create the namespace in the restricted environment (in ;; particular, it must be created under the new code inspector) - [current-namespace (make-evaluation-namespace)] + [current-namespace (make-evaluation-namespace)]) + (define current-eventspace (mz/mr (make-parameter #f) current-eventspace)) + (parameterize* ;; Note the above definition of `current-eventspace': in Racket, it ;; is an unused parameter. Also note that creating an eventspace ;; starts a thread that will eventually run the callback code (which ;; evaluates the program in `run-in-bg') -- so this parameterization ;; must be nested in the above (which is what paramaterize* does), or ;; it will not use the new namespace. - [current-eventspace (parameterize-break #f (make-eventspace))]) - (define t (bg-run->thread (run-in-bg user-process))) - (set! user-done-evt (handle-evt t (lambda (_) (terminate+kill! #t #t)))) - (set! user-thread t)) + ([current-eventspace (parameterize-break #f ((mz/mr void make-eventspace)))]) + (define run-in-bg (mz/mr thread queue-callback)) + (define bg-run->thread (if (sandbox-gui-available) + (lambda (ignored) + ((mz/mr void eventspace-handler-thread) (current-eventspace))) + values)) + (define t (bg-run->thread (run-in-bg user-process))) + (set! user-done-evt (handle-evt t (lambda (_) (terminate+kill! #t #t)))) + (set! user-thread t))) (define r (get-user-result)) (if (eq? r 'ok) ;; initial program executed ok, so return an evaluator diff --git a/collects/scribblings/reference/sandbox.scrbl b/collects/scribblings/reference/sandbox.scrbl index 3070721bf2..7147b86690 100644 --- a/collects/scribblings/reference/sandbox.scrbl +++ b/collects/scribblings/reference/sandbox.scrbl @@ -128,8 +128,10 @@ argument: In this case, a new namespace is created using @racket[sandbox-namespace-specs], which by default creates a - new namespace using @racket[make-base-namespace] or - @racket[make-gui-namespace] (depending on @racket[gui?]). + new namespace using @racket[sandbox-make-namespace] (which, in + turn, uses @racket[make-base-namespace] or + @racket[make-gui-namespace] depending on + @racket[sandbox-gui-available] and @racket[gui-available?]). In the new namespace, @racket[language] is evaluated as an expression to further initialize the namespace.} @@ -188,7 +190,8 @@ In all cases, the evaluator operates in an isolated and limited environment: @itemize[ - @item{It uses a new custodian and namespace. When @racket[gui?] is + @item{It uses a new custodian and namespace. When + @racket[gui-available?] and @racket[sandbox-gui-available] produce true, it is also runs in its own eventspace.} @item{The evaluator works under the @racket[sandbox-security-guard], @@ -463,9 +466,7 @@ that creates the namespace, and the rest are module paths for modules to be attached to the created namespace using @racket[namespace-attach-module]. -The default is @racket[(list make-base-namespace)] if @racket[gui?] is -@racket[#f], @racket[(list make-gui-namespace)] if @racket[gui?] is -@racket[#t]. +The default is @racket[(list sandbox-make-namespace)]. The module paths are needed for sharing module instantiations between the sandbox and the caller. For example, sandbox code that returns @@ -484,10 +485,28 @@ of code can be helpful: `(,(car specs) ,@(cdr specs) lang/posn - ,@(if gui? '(mrlib/cache-image-snip) '())))) + ,@(if (gui-available?) '(mrlib/cache-image-snip) '())))) ]} +@defproc[(sandbox-make-namespace) namespace?]{ + +Calls @racket[make-gui-namespace] when @racket[(sandbox-gui-available)] +produces true, @racket[make-base-namespace] otherwise.} + + +@defboolparam[sandbox-gui-available avail?]{ + +Determines whether the @racketmodname[racket/gui] module can be used +when a sandbox evaluator is created. If @racket[gui-available?] +produces @racket[#f] during the creation of a sandbox evaluator, this +parameter is forced to @racket[#f] during initialization of the +sandbox. The default value of the parameter is @racket[#t]. + +Various aspects of the library change when the GUI library is +available, such as using a new eventspace for each evaluator.} + + @defparam[sandbox-override-collection-paths paths (listof path-string?)]{ A parameter that determines a list of collection directories to prefix @@ -922,12 +941,13 @@ your own permissions, for example, @defthing[gui? boolean?]{ -True if the @racketmodname[racket/gui] module can be used, @racket[#f] -otherwise; see @racket[gui-available?]. +For backward compatibility, only: the result of @racket[gui-available?] +at the time that @racketmodname[racket/sandbox] was instantiated. -Various aspects of the @racketmodname[racket/sandbox] library change -when the GUI library is available, such as using a new eventspace for -each evaluator.} +The value of @racket[gui?] is no longer used by +@racketmodname[racket/sandbox] itself. Instead, +@racket[gui-available?] and @racket[sandbox-gui-available] are +checked at the time that a sandbox evaluator is created.} @defproc[(call-with-limits [secs (or/c exact-nonnegative-integer? #f)] diff --git a/collects/tests/racket/sandbox-gui.rkt b/collects/tests/racket/sandbox-gui.rkt new file mode 100644 index 0000000000..3c6aaaa326 --- /dev/null +++ b/collects/tests/racket/sandbox-gui.rkt @@ -0,0 +1,48 @@ +#lang racket +(require racket/sandbox + racket/gui/dynamic) + +(define-syntax-rule (test expect expr) + (do-test 'expr expect expr)) + +(define (do-test which expect got) + (unless (equal? expect got) + (error 'test "failed: ~s expect: ~e got: ~e" which expect got))) + +;; GUI is initialled allowed by sandbox, but not initially available: + +(test #t (sandbox-gui-available)) +(test #f (gui-available?)) + +;; Create a pre-GUI evaluator: + +(define e (call-with-trusted-sandbox-configuration + (lambda () + (make-evaluator 'racket)))) +(test (void) (e '(require racket/gui/dynamic))) +(test #f (e '(gui-available?))) + +;; Load GUI library + +(test (void) (dynamic-require 'racket/gui #f)) + +;; Now the GUI is available: + +(test #t (gui-available?)) + +;; Create a post-GUI evaluator: + +(define ge (call-with-trusted-sandbox-configuration + (lambda () + (make-evaluator 'racket)))) +(test (void) (ge '(require racket/gui/dynamic))) +(test #t (ge '(gui-available?))) + +;; A post-GUI evaluator, but with GUI disabled: + +(define pe (parameterize ([sandbox-gui-available #f]) + (call-with-trusted-sandbox-configuration + (lambda () + (make-evaluator 'racket))))) +(test (void) (pe '(require racket/gui/dynamic))) +(test #f (pe '(gui-available?))) diff --git a/doc/release-notes/racket/HISTORY.txt b/doc/release-notes/racket/HISTORY.txt index ea688847a5..a5d2fd5d29 100644 --- a/doc/release-notes/racket/HISTORY.txt +++ b/doc/release-notes/racket/HISTORY.txt @@ -1,3 +1,8 @@ +Version 5.2.1.7 +racket/sandbox: added sandbox-gui-enabled and sandbox-make-namespace; + deprecated gui?, which is no long used internally; changed the default + for sandbox-namespace-specs to sandbox-make-namespsace + Version 5.2.1.6 Added prop:cpointer Fixed handle-evt to disallow a handle-evt