Dynamic Analysis With Babel

Matt Zeunert

@mattzeunert

What is Dynamic Analysis?

if (arr.length = 1){
    // do something
}
if (arr.length === 1){
    // do something
}
if (arr.length === 1){
    // do something
}
var a = 5
console.log(a)

a = 10
console.log(a)

Instrumentation

var a = 5
a = 10
var a = 5
console.log(a)

a = 10
console.log(a)

Babel

Babel

6to5

var square = (n) => n * n
"use strict";

var square = function (n) {
  return n * n;
};

Babel

ES6

ES7

JSX

...

.babelrc

{
    "plugins": [
        "check-es2015-constants",
        "transform-es2015-arrow-functions",
        "transform-es2015-block-scoped-functions",
        "transform-es2015-block-scoping",
        "transform-es2015-classes",
        "transform-es2015-computed-properties",
        "transform-es2015-destructuring",
        "transform-es2015-duplicate-keys",
        "transform-es2015-for-of",
        "transform-es2015-function-name",
        "transform-es2015-literals",
        "transform-es2015-modules-commonjs",
        "and 9 other plugins"
    ]
}

.babelrc

{
    "plugins": [],
    "presets": ["es2015"]
}

Compilation

Parse

Traverse & Transform

Generate

Plugins

Plugin Example

var greeting = "Hello"
var greeting = "Hi";

Parse

var greeting = "Hello"

Traverse & Transform

module.exports = function(babel) {
    return {
        visitor: {
            StringLiteral: function(path) {
                path.node.value = "Hi"
            }
        }
    }
}

Generate

var greeting = "Hi";
StringLiteral: function(path) {




          
}
var greeting = getGreeting()
var greeting = "Hi";
    var call = babel.types.callExpression(
        babel.types.identifier("getGreeting"),
        []
    )
    path.replaceWith(call)

Dynamic Analysis With Babel

How It Should Work

Problem

Where did the commitsByAuthor object change?

Our End Goal

obj.a = 55
obj.a = 55
trackAssignment(obj, "a", 55)
obj.a = 55
assignProperty(obj, "a", 55)
obj.a = 55

AssignmentExpression

Left

Right

obj.a

MemberExpression

Object

Property

Demo

AssignmentExpression(path) {
    var assignmentExpression = path.node
    if (assignmentExpression.left.type !== "MemberExpression") {
        return
    }

    var memberExpression = assignmentExpression.left
    var value = assignmentExpression.right

    var propertyName = memberExpression.property
    if (!memberExpression.computed) {
        propertyName = t.stringLiteral(propertyName.name)
    }

    var call = t.callExpression(
        t.identifier("assignProperty"), [
            memberExpression.object,
            propertyName,
            assignmentExpression.right
        ]
    )
    path.replaceWith(call)
}
function assignProperty(obj, propName, value){
    obj[propName] = value

    if (!obj[propName + "__history__"]){
        Object.defineProperty(obj, propName + "__history__", {
            enumerable: false,
            value: []
        })
    }

    obj[propName + "__history__"].push({
        value: value,
        stack: Error().stack
    })
}

Other Examples

Visualizing Program Execution - Jan Paul Posma

DLint

https://github.com/Berkeley-Correctness-Group/DLint

JITProf

FromJS

Instrumentation

Compilation

Method Patching

Instrumentation Through Method Patching

var nativeCreateElement = document.createElement
document.createElement = function(tagName){
    var el = nativeCreateElement.call(document, tagName)
    el.createdAtStackTrace = Error().stack
    return el
}

Limitations

Execution Speed

Memory

Breaking Functionality

Node-ChakraCore

node -TTRecord:log test.js 

Jan Paul Posma: Visualizing program execution

Ariya Hidayat: Dynamic Code Analysis for JavaScript

Time-Travel Debugging for JavaScript/HTML Applications

Resources

FromJS

Twitter: @mattzeunert

Thank You

Slides

Dynamic Analysis with Babel - Rolling Scopes Minks

By Matt Zeunert

Dynamic Analysis with Babel - Rolling Scopes Minks

  • 1,350