[racket] instantiating multiple sandboxes with gui's

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Apr 5 10:04:22 EDT 2014

Oh, and I see a second issue that you're probably getting at: in the case
you decide you are going to run GUI programs (via the emacs-level variable
if you don't find a better way than my recommendation) you need to share
'(lib "mred/mred.rkt") (or maybe it is okay to share racket/gui/base)
between the original namespace that your code created and the user program
you wish to run.

This library is designed to support this form of sharing and is carefully
implemented not to leak, no matter what nastiness the user program might
try to do to it (most libraries do not provide such guarantees).

Robby


On Sat, Apr 5, 2014 at 8:25 AM, Greg Hendershott
<greghendershott at gmail.com>wrote:

> Thank you Robby. I've spent some time thinking about your response,
> trying to make use of it, and even looking at some
> mred/private/common/wx code.
>
> First, I don't grok the need for an extra thread. This is for an Emacs
> mode REPL. It's quite similar to Racket's xrepl, which doesn't use an
> extra thread. Although I could create one if necessary, I think it
> would complicate things when I have a more basic issue regarding
> `main-eventspace`, custodians, and how/when racket/gui/base gets
> loaded:
>
> As an Emacs mode (unlike DrRacket, which is a GUI that needs
> racket/gui/base itself), I don't want to statically `require`
> racket/gui/base, because I don't want it loaded until/unless it's
> actually needed by a user program. (Otherwise, e.g. on OS X, running a
> non-GUI program, you would get a weird windowless menu bar, and it
> steals the focus from Emacs.)  So the way that racket/gui/base _first_
> gets required, is via the dynamic-require of the first user program
> that happens to require it. As a result the `main-eventspace` state in
> mred/private/wx/common/queue.rkt (IIUC) is associated with
> `user-cust`, not `orig-cust`. As a result, custodian-shutdown-all
> blows that away. And I don't know how to recreate it correctly.
> Symptom: Subsequent runs of a user program like `(require plot) (plot
> __)`, result in windows that sit there un-drawn and/or unresponsive to
> mouse input.
>
>
> Seems like it could be solved on either "end":
>
> 1. Somehow try to manage the load process so that the first-ever load
> of racket/gui/base gets its stuff on orig-cust but the user's stuff on
> user-cust.
>
> 2. Somehow re-initialize the main eventspace sufficiently.
>
> Although 2 seems more plausible and less kludgy, I can't work out how
> to do it either way.
>
>
> Some code snippets that might be more understandable than prose:
>
> ;; (or/c #f path?) -> any
> (define (run path-str)
>   (define-values (mod load-dir) (path-string->mod-path&load-dir path-str))
>
>   ;; Use custodian to release resources.
>   ;;
>   ;; The problem here is that this seems to be "too thorough" -- it
>   ;; boinks `main-eventspace` in mred/private/queue.rkt. Why?  How
>   ;; racket/gui/base first got loaded was at end of this function,
>   ;; in the dynamic-require of whatever user module first happened to
>   ;; use racket/gui/base. (We don't want to load racket/gui/base
>   ;; in the Emacs mode until/unless it's actually needed). Therefore
>   ;; `main-eventspace` is created on `user-cust`, and gets blown away
>   ;; here. Ideally, instead `main-eventspace` would be managed by
>   ;; `orig-cust`, and everything else about the user program would be
>   ;; on `user-cust`. But how to do that??
>   (custodian-shutdown-all user-cust)
>   ;; New custodian
>   (set! user-cust (make-custodian orig-cust))
>   (current-custodian user-cust)
>
>   ;; Save the current namespace. Save whether it uses racket/gui/base.
>   (define orig-ns (current-namespace))
>   (define had-gui? (module-declared? 'racket/gui/base))
>   ;; Fresh, clear racket/base namespace.
>   (current-namespace (make-base-namespace))
>
>   (when had-gui?
>     (displayln "had-gui? #t")
>     ;; If racket/gui/base module was instantiated in orig-ns, attach
>     ;; and require it into the new namespace, and _before_ requiring
>     ;; the new module. Avoids "cannot instantiate `racket/gui/base' a
>     ;; second time in the same process" problem.
>     (namespace-attach-module orig-ns 'racket/gui/base)
>     (namespace-require 'racket/gui/base)
>
>     ;; Also need to create an eventspace.  FIXME: Not working with
>     ;; plot.rkt example. custodian-shutdown-all seems to have borked
>     ;; the original main eventspace state, and our newly-created one
>     ;; ain't good enough.
>     (define (gdr sym)
>       (dynamic-require 'racket/gui/base sym))
>     (define current-eventspace (gdr 'current-eventspace))
>     (define make-eventspace    (gdr 'make-eventspace))
>     (current-eventspace (make-eventspace)))
>
>   ;; Load the user module, if any
>   (when mod
>     (parameterize ([current-load-relative-directory load-dir])
>       (dynamic-require mod 0)
>       (current-namespace (module->namespace mod))))
>   (current-prompt-read (make-prompt-read mod)))
>
> Example GUI user program:
>
> #lang racket
> (require plot math)
> (plot-new-window? #t)
> (plot (function sin (- pi) pi #:label "y = sin(x)"))
>
>
>
> On Thu, Apr 3, 2014 at 5:49 PM, Robby Findler
> <robby at eecs.northwestern.edu> wrote:
> > I think the main missing thing is that the thread you're requiriing the
> > user's program on should be under the control of the custodian. In other
> > words, you'll want to create a new eventspace (under the new custodian)
> and
> > queue a callback over to it to require the user's program.
> >
> > Robby
> >
> >
> > On Thu, Apr 3, 2014 at 4:26 PM, Greg Hendershott <
> greghendershott at gmail.com>
> > wrote:
> >>
> >> So the background for Spencer's question was a problem with my Emacs
> >> racket-mode when using racket/gui/base.
> >>
> >> There's a long-ish bug report comment thread. If you want to read it,
> >> at all, you might want to skip to the last few comments, here:
> >>
> >>
> >>
> https://github.com/greghendershott/racket-mode/issues/26#issuecomment-39494285
> >>
> >> Or the TL;DR: I probably don't need racket/sandbox at all. I probably
> >> just need a new namespace and a custodian -- in order to do a
> >> DrRacket-style "reset the REPL to the source file".
> >>
> >> Matthew and Robby I know you're both incredibly busy, but if either of
> >> you had a chance to look at this code, I'd be grateful. Although part
> >> of me hopes you'll say "perfect!", the older/wiser part of me hopes
> >> you'll point out X Y and Z problems I don't yet realize I have. It's
> >> just these 30 lines of code here:
> >>
> >>
> >>
> https://github.com/greghendershott/racket-mode/blob/experimental/sandbox.rkt#L30-L66
> >>
> >> On Sun, Mar 23, 2014 at 8:35 PM, Robby Findler
> >> <robby at eecs.northwestern.edu> wrote:
> >> > It is safe, however, to share the racket/gui/base that you get with
> the
> >> > one
> >> > in the sandbox.
> >> >
> >> > Robby
> >> >
> >> >
> >> > On Sun, Mar 23, 2014 at 7:25 PM, Matthew Flatt <mflatt at cs.utah.edu>
> >> > wrote:
> >> >>
> >> >> Yes, this is a limitation of `racket/gui/base`. On initialization,
> the
> >> >> library must register in various non-composable ways with an
> underlying
> >> >> GUI toolkit (callbacks, Objective-C classes, Win32 classes, etc.),
> and
> >> >> so `racket/gui/base` cannot be instantiated multiple times.
> >> >>
> >> >> At Sun, 23 Mar 2014 20:12:43 -0400, Spencer Florence wrote:
> >> >> > I'm attempting to launch multiple evaluators which require
> >> >> > `racket/gui`,
> >> >> > however I get the error:
> >> >> >
> >> >> > cannot instantiate `racket/gui/base` a second time in the same
> >> >> > process
> >> >> >
> >> >> > Is `racket/gui/base` maintaining some kind of state thats escaping
> >> >> > the
> >> >> > sandbox?
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> > Example of the problem:
> >> >> >
> >> >> > #lang racket/base
> >> >> > (require racket/sandbox)
> >> >> >
> >> >> > (call-with-trusted-sandbox-configuration
> >> >> >  (lambda ()
> >> >> >    (define (make)
> >> >> >      (make-evaluator 'racket/base
> >> >> >                      #:requires '(racket/gui/base)))
> >> >> >
> >> >> >    (make)
> >> >> >    (make)))
> >> >> > ____________________
> >> >> >   Racket Users list:
> >> >> >   http://lists.racket-lang.org/users
> >> >> ____________________
> >> >>   Racket Users list:
> >> >>   http://lists.racket-lang.org/users
> >> >
> >> >
> >> >
> >> > ____________________
> >> >   Racket Users list:
> >> >   http://lists.racket-lang.org/users
> >> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140405/c28ae593/attachment.html>

Posted on the users mailing list.