mmckegg / notevil

Evalulate javascript like the built-in javascript eval() method but safely.
195 stars 24 forks source link

Hoisting is naïve #18

Closed kumavis closed 10 years ago

kumavis commented 10 years ago

naïve hoisting causes problem when attempting to safeEval the following code

var names = [ ... ]
var primitives = names.map(getGlobal);
function getGlobal(){ ... }

Here is this project's own primitives.js after hoisting

{
    var global = self;
    var names = [
            'Object',
            'String',
            'Boolean',
            'Number',
            'RegExp',
            'Date',
            'Array'
        ];
    var immutable = {
            string: 'String',
            boolean: 'Boolean',
            number: 'Number'
        };
    var primitives = names.map(getGlobal);
    var protos = primitives.map(getProto);
    var protoReplacements = {};
    module.exports = Primitives;
    function Primitives(context) {
        if (this instanceof Primitives) {
            this.context = context;
            for (var i = 0; i < names.length; i++) {
                if (!this.context[names[i]]) {
                    this.context[names[i]] = wrap(primitives[i]);
                }
            }
        } else {
            return new Primitives(context);
        }
    }
    Primitives.prototype.replace = function (value) {
        var primIndex = primitives.indexOf(value);
        var protoIndex = protos.indexOf(value);
        if (~primIndex) {
            var name = names[primIndex];
            return this.context[name];
        } else if (~protoIndex) {
            var name = names[protoIndex];
            return this.context[name].prototype;
        } else {
            return value;
        }
    };
    Primitives.prototype.getPropertyObject = function (object, property) {
        if (immutable[typeof object]) {
            return this.getPrototypeOf(object);
        }
        return object;
    };
    Primitives.prototype.isPrimative = function (value) {
        return !!~primitives.indexOf(value) || !!~protos.indexOf(value);
    };
    Primitives.prototype.getPrototypeOf = function (value) {
        if (value == null) {
            return value;
        }
        var immutableType = immutable[typeof value];
        if (immutableType) {
            var proto = this.context[immutableType].prototype;
        } else {
            var proto = Object.getPrototypeOf(value);
        }
        if (!proto || proto === Object.prototype) {
            return null;
        } else {
            var replacement = this.replace(proto);
            if (replacement === value) {
                replacement = this.replace(Object.prototype);
            }
            return replacement;
        }
    };
    function getProto(func) {
        return func.prototype;
    }
    function getGlobal(str) {
        return global[str];
    }
    function setProto(obj, proto) {
        obj.__proto__ = proto;
    }
    function wrap(prim) {
        var proto = Object.create(prim.prototype);
        var result = function () {
            if (this instanceof result) {
                prim.apply(this, arguments);
            } else {
                var instance = prim.apply(null, arguments);
                setProto(instance, proto);
                return instance;
            }
        };
        setProto(result, prim);
        result.prototype = proto;
        return result;
    }
}
kumavis commented 10 years ago

Reopening in correct repo https://github.com/mmckegg/hoister/issues/1