lachrist / aran

JavaScript Code Instrumenter
https://lachrist.github.io/aran
MIT License
36 stars 4 forks source link

Problem with for key in object #5

Closed turkja closed 5 years ago

turkja commented 7 years ago

Following simple code fails with unknown key when instrumented:

function ktest(myObj) {
    for (myKey in myObj) {
        console.log(myObj[myKey]);
    }
}
ktest([1, "foo", {"a":"bar"}]);

Seems like the problem is in instrument.js visitors.ForInStatement, where aran inserts the counter expression after the BlockExpression. I experimented changing the order like this:

  var res = ctx.traps.expression(ctx.traps.primitive("void 0", ast.__min__), ast.__min__) + ";"
    + "{" + ctx.traps.Enter(ast.__min__) + arr.join("")
    + (lbl?lbl+":":"") + "while(" + obj.counter + "<" + obj.enumerate + ".length){"
    + ctx.traps.expression(str, ast.__min__) + ";"
    + (ast.body.type === "BlockStatement"
      ? ast.body.body.map(visit.bind(null, ctx, ast)).join("")
      : visit(ctx, ast, ast.body))
    + obj.counter +"++;}"
    + ctx.traps.Leave(ast.__min__) + "}";

Seems to work, but please check..

lachrist commented 7 years ago

Dear Jarko, I could not reproduce your bug in the demo page. The code transformation looks fine as far as I can tell... As you can see below, _meta_20 is incremented inside the block. Plus in your code, ctx.traps.expression(str, ast.__min__) disappeared, which would lead to the removal of (myKey = _meta_1[_meta_2]);.

Are you sure it is not related to your analysis? Or am I missing something here?

_meta_.__global__ = _meta_.__global__ || (function() {
    return this
}());
_meta_.__eval__ = _meta_.__eval__ || eval;
_meta_.__apply__ = _meta_.__apply__ || (typeof Reflect === 'object' ? Reflect.apply : function(f, t, xs) {
    return f.apply(t, xs)
});
_meta_.__defineProperty__ = _meta_.__defineProperty__ || Object.defineProperty;
(ktest = function ktest(myObj) {
    var _meta_1, _meta_2, _meta_3;
    void 0; {
        _meta_1 = (function(o) {
            var ks = [];
            for (var k in o) ks[ks.length] = k;
            return ks;
        }(myObj));
        _meta_2 = 0;
        while (_meta_2 < _meta_1.length) {
            _meta_.__apply__((_meta_3 = console)["log"], _meta_3, [myObj[myKey]]);
            (myKey = _meta_1[_meta_2]);
            _meta_2++;
        }
    }
    return void 0
});
void 0;
var ktest;
(ktest([1, "foo", {
    "a": "bar"
}]));
turkja commented 7 years ago

Thanks for the reply!

Strange thing this cannot be reproduced with the demo. I cannot explain it!

Could you please try out this code in node.js (with npm install aran):

var Aran = require("aran");
global._meta_ = {};
global._meta_.apply = function (fct, ths, args, idx) {
    var loc = aran.node(idx).loc.start;
    return fct.apply(ths, args);
};
var aran = Aran({
    namespace:"_meta_", traps:["apply"], loc:true });

var code = 'function ktest(myObj) {\n'+
'    for (myKey in myObj) {\n'+
'        console.log(myObj[myKey]);\n'+
'    }\n'+
'}\n'+
'ktest([1, \"foo\", {\"a\":\"bar\"}]);\n';

global.eval(aran.instrument(code,  "target.js"));
lachrist commented 5 years ago

Works fine in aran@3.0.0

var Aran = require("aran");
const Acorn = require("Acorn");
global._meta_ = {};
global._meta_.apply = function (fct, ths, args, idx) {
    var loc = aran.nodes[idx].loc.start;
    return fct.apply(ths, args);
};
var aran = Aran({
    namespace:"_meta_",
    format: "script"
});

var code = 'function ktest(myObj) {\n'+
'    for (myKey in myObj) {\n'+
'        console.log(myObj[myKey]);\n'+
'    }\n'+
'}\n'+
'ktest([1, \"foo\", {\"a\":\"bar\"}]);\n';

global.eval(aran.setup());
global.eval(aran.weave(Acorn.parse(code, {locations:true}),  ["apply"]));
1
foo
{ undefined: 'bar' }
lachrist commented 5 years ago

Solved in aran@3.0.1