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"
...
SSAInstruction
sif (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
JavaScriptConstructorFunctions
private 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 Id
Id
prototype of SubId
id
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
SDG
Statement
final 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; }