* Added `exn:fail:sandbox-terminated' for all sandbox termination

kinds.
* The default exit handler kills the sandbox, with an appropriate
  termination message.
* Also, sending an eof to the sandbox shows 'eof as the reason
* Added some tests for these.
* Still need to deal with termination messages for evaluator suicide.

svn: r12837
This commit is contained in:
Eli Barzilay 2008-12-13 22:12:16 +00:00
parent bdf71f1b46
commit 188489b34f
3 changed files with 60 additions and 16 deletions

View File

@ -39,6 +39,8 @@
call-in-nested-thread* call-in-nested-thread*
call-with-limits call-with-limits
with-limits with-limits
exn:fail:sandbox-terminated?
exn:fail:sandbox-terminated-reason
exn:fail:resource? exn:fail:resource?
exn:fail:resource-resource) exn:fail:resource-resource)
@ -152,8 +154,8 @@
'sandbox-security-guard 'sandbox-security-guard
"security-guard or a security-guard translator procedure" x))))) "security-guard or a security-guard translator procedure" x)))))
(define (default-sandbox-exit-handler _) ;; this is never really used (see where it's used in the evaluator)
(error 'exit "sandboxed code cannot exit")) (define (default-sandbox-exit-handler _) (error 'exit "sandbox exits"))
(define sandbox-exit-handler (make-parameter default-sandbox-exit-handler)) (define sandbox-exit-handler (make-parameter default-sandbox-exit-handler))
@ -516,6 +518,14 @@
(define-evaluator-messenger (get-uncovered-expressions . xs) 'uncovered) (define-evaluator-messenger (get-uncovered-expressions . xs) 'uncovered)
(define-evaluator-messenger (call-in-sandbox-context thunk) 'thunk) (define-evaluator-messenger (call-in-sandbox-context thunk) 'thunk)
(define-struct (exn:fail:sandbox-terminated exn:fail) (reason) #:transparent)
(define (make-terminated reason)
(make-exn:fail:sandbox-terminated
(format "evaluator: terminated (~a)" reason)
(current-continuation-marks)
reason))
(define (make-evaluator* init-hook allow program-maker) (define (make-evaluator* init-hook allow program-maker)
(define orig-code-inspector (current-code-inspector)) (define orig-code-inspector (current-code-inspector))
(define orig-cust (current-custodian)) (define orig-cust (current-custodian))
@ -532,6 +542,12 @@
(define limits (sandbox-eval-limits)) (define limits (sandbox-eval-limits))
(define user-thread #t) ; set later to the thread (define user-thread #t) ; set later to the thread
(define user-done-evt #t) ; set in the same place (define user-done-evt #t) ; set in the same place
(define terminated? #f) ; set to an exception value when the sandbox dies
(define (terminated! reason)
(unless terminated?
(set! terminated?
(make-terminated ; use #f to detect internal errors
(or reason "internal error: no termination reason")))))
(define (limit-thunk thunk) (define (limit-thunk thunk)
(let* ([sec (and limits (car limits))] (let* ([sec (and limits (car limits))]
[mb (and limits (cadr limits))]) [mb (and limits (cadr limits))])
@ -540,6 +556,7 @@
(when user-thread (when user-thread
(let ([t user-thread]) (let ([t user-thread])
(set! user-thread #f) (set! user-thread #f)
(terminated! #f)
(custodian-shutdown-all user-cust) (custodian-shutdown-all user-cust)
(kill-thread t))) ; just in case (kill-thread t))) ; just in case
(void)) (void))
@ -560,7 +577,8 @@
(let ([n 0]) (let ([n 0])
(let loop () (let loop ()
(let ([expr (channel-get input-ch)]) (let ([expr (channel-get input-ch)])
(when (eof-object? expr) (channel-put result-ch expr) (user-kill)) (when (eof-object? expr)
(terminated! 'eof) (channel-put result-ch expr) (user-kill))
(with-handlers ([void (lambda (exn) (with-handlers ([void (lambda (exn)
(channel-put result-ch (cons 'exn exn)))]) (channel-put result-ch (cons 'exn exn)))])
(define run (define run
@ -585,9 +603,12 @@
(loop))]) (loop))])
(sync user-done-evt result-ch)))) (sync user-done-evt result-ch))))
eof)]) eof)])
(cond [(eof-object? r) (error 'evaluator "terminated~a" (cond [(eof-object? r)
(unless terminated?
(if (custodian-box-value memory-cust-box) (if (custodian-box-value memory-cust-box)
"" " (memory exceeded)"))] (terminated! 'out-of-memory)
(terminated! #f)))
(raise terminated?)]
[(eq? (car r) 'exn) (raise (cdr r))] [(eq? (car r) 'exn) (raise (cdr r))]
[else (apply values (cdr r))]))) [else (apply values (cdr r))])))
(define get-uncovered (define get-uncovered
@ -617,7 +638,7 @@
(let ([msg (evaluator-message-msg expr)]) (let ([msg (evaluator-message-msg expr)])
(case msg (case msg
[(alive?) (and user-thread (not (thread-dead? user-thread)))] [(alive?) (and user-thread (not (thread-dead? user-thread)))]
[(kill) (user-kill)] [(kill) (terminated! 'evaluator-killed) (user-kill)]
[(break) (user-break)] [(break) (user-break)]
[(limits) (set! limits (evaluator-message-args expr))] [(limits) (set! limits (evaluator-message-args expr))]
[(input) (apply input-putter (evaluator-message-args expr))] [(input) (apply input-putter (evaluator-message-args expr))]
@ -687,7 +708,11 @@
;; restrict the sandbox context from this point ;; restrict the sandbox context from this point
[current-security-guard [current-security-guard
(let ([g (sandbox-security-guard)]) (if (security-guard? g) g (g)))] (let ([g (sandbox-security-guard)]) (if (security-guard? g) g (g)))]
[exit-handler (sandbox-exit-handler)] [exit-handler
(let ([h (sandbox-exit-handler)])
(if (eq? h default-sandbox-exit-handler)
(lambda _ (terminated! 'exited) (user-kill))
h))]
[current-inspector ((sandbox-make-inspector))] [current-inspector ((sandbox-make-inspector))]
[current-logger ((sandbox-make-logger))] [current-logger ((sandbox-make-logger))]
[current-code-inspector (make-inspector)] [current-code-inspector (make-inspector)]

View File

@ -243,6 +243,19 @@ used from a module (by using a new namespace):
} }
@defproc*[([(exn:fail:sandbox-terminated? [v any/c]) boolean?]
[(exn:fail:sandbox-terminated-reason [exn exn:fail:sandbox-terminated?])
symbol/c])]{
A predicate and accessor for exceptions that are raised when a sandbox
is terminated. Once a sandbox raises such an exception, it will
continue to raise it on further evaluation attempts.
@scheme[call-with-limits]. The @scheme[resource] field holds a symbol,
either @scheme['time] or @scheme['memory].}
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section{Customizing Evaluators} @section{Customizing Evaluators}
@ -472,7 +485,9 @@ network connection.}
@defparam[sandbox-exit-handler handler (any/c . -> . any)]{ @defparam[sandbox-exit-handler handler (any/c . -> . any)]{
A parameter that determines the initial @scheme[(exit-handler)] for A parameter that determines the initial @scheme[(exit-handler)] for
sandboxed evaluations. The default handler simply throws an error.} sandboxed evaluations. The default kills the evaluator with an
appropriate error message (see
@scheme[exn:fail:sandbox-terminated-reason]).}
@defparam[sandbox-memory-limit limit (or/c exact-nonnegative-integer? #f)]{ @defparam[sandbox-memory-limit limit (or/c exact-nonnegative-integer? #f)]{

View File

@ -130,12 +130,16 @@
(thread (lambda () (sleep 1) (break-evaluator ev))) (thread (lambda () (sleep 1) (break-evaluator ev)))
--eval-- --eval--
(sleep 2) =err> "user break" (sleep 2) =err> "user break"
(printf "x = ~s\n" x) => (void)
;; termination ;; termination
--eval-- --eval--
(printf "x = ~s\n" x) => (void) ,eof =err> "terminated .eof.$"
,eof =err> "terminated" 123 =err> "terminated .eof.$"
x =err> "terminated" ,eof =err> "terminated .eof.$"
,eof =err> "terminated"
;; other termination messages
--top-- (set! ev (make-evaluator 'scheme/base)) (kill-evaluator ev)
--eval-- 123 =err> "terminated .evaluator-killed."
;; eval-limits apply to the sandbox creation too ;; eval-limits apply to the sandbox creation too
--top-- --top--
@ -198,9 +202,9 @@
--top-- --top--
(kill-evaluator ev) => (void) (kill-evaluator ev) => (void)
--eval-- --eval--
x =err> "terminated" x =err> "terminated .evaluator-killed."
y =err> "terminated" y =err> "terminated .evaluator-killed."
,eof =err> "terminated" ,eof =err> "terminated .evaluator-killed."
--top-- --top--
(let-values ([(i1 o1) (make-pipe)] [(i2 o2) (make-pipe)]) (let-values ([(i1 o1) (make-pipe)] [(i2 o2) (make-pipe)])
;; o1 -> i1 -ev-> o2 -> i2 ;; o1 -> i1 -ev-> o2 -> i2