Safe, Closure-free, Serializable functions

Andrea Giammarchi andrea.giammarchi at gmail.com
Wed Sep 25 17:53:37 PDT 2013


Sorry* *François,
  I didn't mean to say your goals were those but I see your problem as safe
evaluation over a "must be safe" sort of local environment confined closure
per closure which is actually similar to the 'use native' directive
proposed in the other thread.

My idea is that functions can be serialized/unserialized without problems:

```javascript

function serializable() {
  alert('Hello World');
}
serializable.toJSON = function () {
  return '\x01' + this.toString();
};

var serialized = JSON.stringify({method:serializable});

var unserialized = JSON.parse(serialized, function revive(k, v) {
  return k && v[0] === '\x01' ? Function('return ' + v.slice(1))() : v;
});

```

so your extra problem would simply be to grant access to local scope
variables and clean natives.

Cheers



On Wed, Sep 25, 2013 at 5:08 PM, François REMY <
francois.remy.dev at outlook.com> wrote:

> > similar thread proposing 'use native' for the very similar problem safe
> > closures would like to solve ... I wonder if it wouldn't be good enough
> > to retrieve in a "read-only" fashion all original exposed function
> > prototypes through a constant or read-only global property for the
> > current realm ...
> >
> > something like `window.env.Array.prototype.slice` VS
> > `window.Array.prototype.slice`
>
> This is not the real issue I want to solve here. The real problem here is
> not that I want to get the barebone ES6 environment, but that I don't want
> to be even possible to access any object that has not been given as
> argument by the caller.
>
> As specified in the TLDR, the objective is to create functions that can be
> serialized or run in contexts where the JS environment is not ready (for
> example, during a style recalc (animation-timing-function) or a layout) or
> not available (workers...), and this requires barebone ES environment,
> otherwise you can detect the effect of another script mutating the
> environment objects.
>
>
>
> If it also solves the JS "mutated environment paranoia" at the same time,
> it makes me happy but this is not my objective. As I said, I would settle
> on making it impossible to return any environment-based function (make them
> unserializable) if it can make this proposal more robust.
>
>
>
> > On Wed, Sep 25, 2013 at 4:29 PM, François REMY
> > <francois.remy.dev at outlook.com<mailto:francois.remy.dev at outlook.com>>
> > wrote:
> > Hi,
> >
> > TLDR ==> The web needs a way to express executable code that does not
> > rely on its parent context, is guaranteed to be side-effect-free, and
> > can be executed safely anywhere (even in a different
> > thread/worker/window/device, or as callback for browser code being
> > executed while the DOM is not ready to be accessed)
> >
> >
> > It's been some time I've been working on this idea of a Closure-free,
> > Serializable function. This kind of function would have no access to
> > the parent closures they are defined in, and only limited (read-only)
> > access to the enclosing environment (read-only Math, Object, Array,
> > others...).
> >
> > To the difference of other functions, those objects would not be
> > affected by the JavaScript running elsewhere on the page, so in this
> > closure-free function, Array.prototype.slice is guaranteed to be the
> > native slice function, not some kind of polyfill or replaced function.
> >
> > |    function sort(array) as serializable {
> > |        Array.prototype.sort.call(array);
> > |    }
> >
> > |    function sqrt(number) as serializable {
> > |        return Math.sqrt(number);
> > |    }
> >
> > |    function __BAD_CODE__() as serializable {
> > |        return new XMLHttpRequest(); // xhr not defined in ES6
> > |    }
> >
> > Trying to export a global variable or modify any of the host
> > environment-defined objects would fail.
> >
> > |    function __BAD_CODE__(number) as serializable {
> > |        globalNumber = number; // cannot write into the global object
> > |    }
> >
> > |    function __BAD_CODE__() as serializable {
> > |        Object.prototype.doSomething=function() {}; // cannot write
> > into the native objects
> > |    }
> >
> > It's also important to note that any Object or Array created inside
> > this context will be passed to the calling context by deep-cloning (or
> > by replacing the "safe" Math object by the host Math object of the
> > calling code in the case of environmental objects). Objects that can't
> > be cloned (non-serializable functions, for example) are just
> > transformed into null. We could also maybe use the idea of a proxy
> > though deep-cloning seems safer.
> >
> > This makes sure it's impossible to leak the "safe" objects to the
> > calling context in any way (ie: the calling code can leak anything to
> > the called code, but not the reverse).
> >
> > |    var RealSin = Math.sin;
> > |    Math.sin=function() {};
> > |
> > |    function giveMeMath() as serializable {
> > |        return [Math, Math.sin];
> > |    }
> > |
> > |    var [m,s] = giveMeMath();
> > |    // s === RealSin
> > |    // m === Math
> > |    // m.sin !== RealSin
> > |
> > |    // note that another possibility here
> > |    // would be to have giveMeMath return [null,null]
> > |    // (ie: consider host objects unserializable)
> >
> > To be honest, those functions are not really meant to expose new
> > objects: even if they need some internally, they should just keep them
> > internally and avoid distributing them. The deep-cloning algorithm is
> > just there for the cases where you want to return multiple values at
> > the end of a function, or when you need an options object.
> >
> > Still, the fact they run in a "safe" environment makes them a good
> > candidate for further optimization and inlining, so we may end up
> > seeing codes written as serializable to benefit from performance boost
> > and safety from external attacks.
> >
> > |    function Point(x,y) as serializable {
> > |        x = +x;
> > |        y = +y;
> > |        return {
> > |            x:x,
> > |            y:y,
> > |            r: Math.sqrt(x*x+y*y),
> > |            t: Math.atan(x,y)
> > |        };
> > |    }
> >
> > The arguments, however, could be any object, and those act totally
> > normally. If an object is given as argument to the function that is an
> > Object, the function can access the "real" Object.prototype by using
> > Object.getPrototypeOf(...).
> >
> > |    window.newXHR = function newXHR(window) as serializable {
> > |        return new this.XMLHttpRequest();
> > |    }
> > |
> > |    var xhr = window.newXHR();
> >
> > However, it's also possible for the calling code not to give such
> > information by passing only primitive values like string and numbers. I
> > believe this is the most likely usage of this kind of function, at
> > least from the web platform point of view.
> >
> >
> >
> > The good thing about those functions, is that they can safely be sent
> > over the wires to another thread, or to another web page, because they
> > do not possibly rely on any state or context.
> >
> > Formalizing those functions is also an important step towards enabling
> > JS code to run safely deeper into the browser stack, by avoiding any
> > possible use of objects that are not supposed to be interacted with at
> > a given time (the calling code can control exactly what the called
> > function has access to).
> >
> > A possible use case would be to defined arbitrary timing function for
> > animations:
> >
> > |    function x2(x) as serializable { return x*x; }
> > |
> > |    // this is safe because SomeWebAnim knows he will call the function
> >   only with numbers, so the code cannot access the DOM while it's still
> > being computed, or because the DOM actually lives in another thread than
> >   the animation code.
> > |    SomeWebAnim.timingFunction = x2;
> >
> >
> >
> > Is there some interest from anyone else in formalizing this for a
> > future version of EcmaScript? Or any comment?
> > Francois
> >
> >
> >
> > PS: for the purposes of safety, we may want to disallow "eval" and
> > "Function" inside this environment to make sure the code can be
> > compiled ahead of time in all cases, and not force the usage of an
> > interpreter. this could also be let to the choice of the author but be
> > exposed as a slightly different concept (ie: compilable + serializable
> > vs serializable only).
> > _______________________________________________
> > es-discuss mailing list
> > es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>
> > https://mail.mozilla.org/listinfo/es-discuss
> >
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130925/6ed15bdd/attachment.html>


More information about the es-discuss mailing list