IBM Thomas J. Watson Research Center

Over 100 publications use WALA, e.g.
S. Huang, J. Huang, Speeding Up Maximal Causality Reduction with Static Dependency Analysis, ECOOP 17
E. Wittern et al., Statically checking web API requests in JavaScript, ICSE 2017
M. Rapoport et al., Who you gonna call? Analyzing Web Requests in Android Applications, MSR 2017
S. Lee et al., HybriDroid: static analysis framework for Android hybrid applications, ASE 2016
W. Huang et al., Scalable and precise taint analysis for Android, ISSTA 2015
Y. Ko et al., Practically Tunable Static Analysis Framework for Large-Scale JavaScript Applications, ASE 2015
| 2004 | ASTk | J2EE optimization |
| 2005 | ITM | Tivoli JavaScript to DB queries |
| 2006 | Open source release | |
| 2008 | GBS | ABAP analysis + tooling |
| 2010 | AppScan | JSA security analysis |
| 2012 | ECOOP | Correlation tracking |
| 2013 | ICSE | Approximate call graphs |
| 2013 | Android analysis support | |
| 2014 | AppScan | Approximate call graphs in AppScan |
| 2016 | ICSE+API Harmony | Web API bug detection |
| 2017 | WCS | Dialog bug finding analysis |
var document = { URL: "whatever",
write: function Document_prototype_write(x) { } };
var id = function _id(x) { return x; };
function Id() { this.id = id; }
function SubId() { }; SubId.prototype = new Id();
if (Math.random.call(null) > 0) {
var id1 = new Id();
var text = id1.id.call(document, document.URL);
} else {
var id2 = new SubId();
var text = id2.id("not a url");
}
document.write(text);
BLOCK
BLOCK
...
FUNCTION_STMT
"CAst: Id"
...
DECL_STMT
"text"
VAR "undefined"
BLOCK
ASSIGN
VAR "document"
OBJECT_LITERAL
CALL
VAR "Object"
"ctor"
"URL"
"whatever"
"write"
FUNCTION_EXPR
"CAst: ..._write"
...
IF_STMT
BINARY_EXPR
">"
SCOPE
...
BLOCK_EXPR
ASSIGN
VAR "$$destructure$rcvr1"
OBJECT_REF
VAR "Math"
"random"
ASSIGN
VAR "$$destructure$elt1"
"call"
CALL
VAR "$$destructure$elt1"
"dispatch"
VAR "$$destructure$rcvr1"
CONSTANT
"0.0"
...
SSAInstructionsif (Math.random.call(null) > 0) {
var id1 = new Id();
var text = id1.id.call(document, document.URL);
} else {
var id2 = new Id();
var text = id2.id("not a url");
}
document.write(text);
if (Math.random.call(null) > 0) {
var id1 = new Id();
var text1 = id1.id.call(document, document.URL);
} else {
var id2 = new Id();
var text2 = id2.id("not a url");
}
text3 = 𝜙(text1, text2);
document.write(text3);
BB1 0 v2 = new <JavaScriptLoader,LArray>@0 [1:4]->[14:19] [2=[arguments]] ... 4 lexical:id@Ldemo2.js = v6 [1:4]->[14:19] ... 8 v16 = global:global Function [1:4]->[14:19] 9 v13 = construct v16@9 v15:#Ldemo2.js/SubId exception:v14[1:4]->[14:19] 10 global:global SubId = v13 [1:4]->[14:19] ... 19 v27 = global:global Object [1:22]->[2:41] ... 21 v25 = construct v27@21 exception:v28 [1:22]->[2:41] [25=[document]] BB3 22 fieldref v25.v29:#URL = v30:#whatever [1:22]->[2:41] [25=[document]] ... 28 v36 = construct v39@28 v38:#Ldemo2.js/_id exception:v37[3:18]->[3:20] 29 lexical:id@Ldemo2.js = v36 [3:4]->[3:5] ... 35 fieldref v44.v45:#prototype = v41 [5:38]->[5:38]
38 v51 = global:global Math [7:4]->[7:7] ... 41 v5 = prototype_values(v51) [7:4]->[7:14] 42 v49 = getfield ...random... v5 [7:4]->[7:14] BB11 45 v55 = dispatch v54:#call@45 v49,v40:#null exception:v56[7:4]->[7:25] BB12 46 v46 = binaryop(gt) v55 , v57:#0.0 [7:4]->[7:29] 47 conditional branch(eq, to iindex=65) v46,v58:#0[7:0]->[7:1] ... 65 v72 = global:global SubId [11:18]->[11:22] ... 67 v71 = construct v72@67 exception:v73 [11:18]->[11:22] [71=[id2]] BB21 73 v76 = dispatch v65:#id@73 v71,v77:#not a url exception:v78[12:15]->[12:33] [76=[text]71=[id2]] BB23 v23 = phi v67,v76 79 v81 = dispatch v31:#write@79 v25,v23 exception:v82[14:0]->[14:19] [25=[document]23=[text]]
new takes an expression, not type
var x = (...)? Object: Array;
var y = new x();
new has diverse semantics
| new Object() | → | fresh object |
| new Object(5) | → | the value 5 |
| new Array(3) | → | array of length 3 |
| new Array(1,2,3) | → | array containing [1, 2, 3] |
new expressions as special calls
new expressions as call expressionsJavaScriptConstructorFunctions
JavaScriptConstructorFunctionsprivate IMethod makeUnaryObjectConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)
cls.getClassLoader().getInstructionFactory();
MethodReference ref =
JavaScriptMethods
.makeCtorReference(JavaScriptTypes.Object);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(
insts.ReturnInstruction(
S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls,
cha.lookupClass(JavaScriptTypes.Object));
}
0 v2 = new <JavaScriptLoader,LArray>@0 BB1 1 v4 = getfield ...prototype... v1 BB2 2 v5 = new <JavaScriptLoader,LObject>@2 BB3 3 set_prototype(v5, v4) 4 v7 = invoke v1@4 v5 exception:v8 BB4 5 conditional branch(eq, to iindex=7) v7,v9 BB5 6 return v7 BB6 7 return v5
function Obj(x) {
var state = x;
this.get = function() { return state; } ;
};
var obj = new Obj(function(){return 3;});
var test1 = ( obj.get() )();
function Id
demo2.js
BB0
BB1
0 v3 = new <JavaScriptLoader,LArray>@0 [4:9]->[4:10] [3=[arguments]]
1 v5 = lexical:id@Ldemo2.js [4:26]->[4:27]
2 check v5 [4:26]->[4:27]
BB2
3 fieldref v2.v6:#id = v5 [4:24]->[4:24] [2=[this]]
BB3
function Id() { this.id = id; }
function SubId() { };
SubId.prototype = new Id();
if (...) { SubId.prototype = new Id(); }
30 v42 = global:global Id [5:44]->[5:45] ... 32 v41 = construct v42@32 exception:v43 [5:44]->[5:45] ... 33 v44 = global:global SubId [5:22]->[5:26] ... 35 fieldref v44.v45:#prototype = v41 [5:38]->[5:38] ... 65 v72 = global:global SubId [11:18]->[11:22] ... 67 v71 = construct v72@67 exception:v73 [11:18]->[11:22] [71=[id2]] BB21 73 v76 = dispatch v65:#id@73 v71,v77:#not a url exception:v78[12:15]->[12:33] [76=[text]71=[id2]]
id assigned as property of IdId prototype of SubIdid called as method on a SubId var x = new SubId();
var y = x.id("not a url");
this
x
var x = new SubId();
var f = x.id;
var y = f("not a url");
Global object
if (...) {
var x = new Id();
} else {
var x = new SubId();
}
var y = x.id("not a url");
if (...) {
var x = new Id();
} else {
var x = new SubId();
}
var f = x.id;
var y = f.call(x, "not a url");
65 v72 = global:global SubId [11:18]->[11:22] ... 67 v71 = construct v72@67 exception:v73 [11:18]->[11:22] [71=[id2]] BB21 73 v76 = dispatch v65:#id@73 v71,v77:#not a url exception:v78[12:15]->[12:33] [76=[text]71=[id2]]
dispatch instruction links this and method
this
var id2 = new SubId();
var text = id2.id("not a url");
var x = new SubId();
var id2 = x;
var text = id2.id("not a url");
var x = new SubId();
// var id2 = x;
var text = x.id("not a url");
_id function is called here:
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;</span>
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
...
var id = function _id(x) {
return x;
};
function Id() {
this.id = id;
}
function SubId() { };
SubId.prototype = new Id();
...
var id2 = new SubId();
var text = id2.id("not a url");
JSCFABuilder B =
JSCallGraphBuilderUtil
.makeScriptCGBuilder(..., file);
CallGraph CG =
B.makeCallGraph(B.getOptions());
Function.call call on function objects
Method.call in Javavar id1 = new Id();
var text = id1.id.call(document, document.URL);
this object in trampoline is function to callif (Math.random.call(null) > 0) {
var id1 = new Id();
var text = id1.id.call(document, document.URL);
} else {
var id2 = new SubId();
var text = id2.id("not a url");
}
_id
var o1 = { a: 1, b: 2 };
var o2 = { }
for(var p in o1) {
var x = o1[p];
o2[p] = x;
}
| var | values |
|---|---|
| o1 | o1 |
| o2 | o2 |
| p | “a”, “b” |
| x | 1, 2 |
var o1 = { a: 1, b: 2 };
var o2 = { }
for(var p in o1) {
var x = o1[p];
// o2[p] = x;
}
| var | values |
|---|---|
| o1 | o |
| o2 | o |
| p | “a”, “b” |
| x | 1, 2 |
var document = { URL: "whatever",
write: function Document_prototype_write(x) { } };
var id = function _id(x) { return x; };
function Id() { this.id = id; }
function SubId() { }; SubId.prototype = new Id();
if (Math.random.call(null) > 0) {
var id1 = new Id();
var text = id1.id.call(document, document.URL);
} else {
var id2 = new SubId();
var text = id2.id("not a url");
}
document.write(text);
com.ibm.wala.ipa.slicer
SDGStatementfinal JSCallGraph cg =
cgBuilder.extract(interpreter, flowGraph, eps, monitor);
...
PointerAnalysis<ObjectVertex> ptrs =
flowGraph.getPointerAnalysis(cg, cache, monitor);
SDG<ObjectVertex> sdg =
new SDG<ObjectVertex>(cg, ptrs,
DataDependenceOptions.NO_BASE_NO_HEAP_NO_EXCEPTIONS,
ControlDependenceOptions.NONE);
public static EndpointFinder<Statement> documentUrlSource =
(Statement s) -> {
if (s.getKind()==Kind.NORMAL) {
NormalStatement ns = (NormalStatement) s;
SSAInstruction inst = ns.getInstruction();
if (inst instanceof SSAGetInstruction) {
if (((SSAGetInstruction)inst)
.getDeclaredField().getName()
.toString().equals("URL")) {
return true;
} } }
return false;
};
var text = id1.id.call(document, document.URL);
public static EndpointFinder<Statement> documentWriteSink =
(Statement s) -> {
if (s.getKind()==Kind.PARAM_CALLEE) {
String ref = ((ParamCallee)s).getNode()
.getMethod().toString();
if (ref.contains("Document_prototype_write")) {
return true; } }
return false;
};
document.write(text);
public static <T> Set<List<T>> getPaths(Graph<T> G, EndpointFinder<T> sources, EndpointFinder<T> sinks) {
Set<List<T>> result = HashSetFactory.make();
for(T src : G) {
if (sources.endpoint(src)) {
for(final T dst : G) {
if (sinks.endpoint(dst)) {
BFSPathFinder<T> paths =
new BFSPathFinder<T>(G, new NonNullSingletonIterator<T>(src), new Predicate<T>() {
public boolean test(T t) {
return t.equals(dst); }});
List<T> path;
if ((path = paths.find()) != null) {
result.add(path); }}}}}
return result; }