From 23b669a6914a1acee41119f8bc19907caad27952 Mon Sep 17 00:00:00 2001 From: dolby-oss Date: Fri, 5 Nov 2010 00:36:44 +0000 Subject: [PATCH] more work and tests on Web page model git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@3991 f5eafffb-2e1d-0410-98e4-8ec43c5233c4 --- .../examples-src/pages/2.js | 60 +++++++++++++++ .../examples-src/pages/apollo-example.html | 27 +++++++ .../examples-src/pages/page3.html | 8 ++ .../examples-src/tests/214631.js | 17 +++++ .../js/test/TestSimpleCallGraphShape.java | 71 +++++++++++++++++- .../js/test/TestSimplePageCallGraphShape.java | 30 ++++++++ com.ibm.wala.cast.js/dat/preamble.js | 73 +++---------------- .../ibm/wala/cast/js/util/HTMLCallback.java | 57 ++++++++++++++- 8 files changed, 276 insertions(+), 67 deletions(-) create mode 100644 com.ibm.wala.cast.js.test/examples-src/pages/2.js create mode 100644 com.ibm.wala.cast.js.test/examples-src/pages/apollo-example.html create mode 100644 com.ibm.wala.cast.js.test/examples-src/pages/page3.html create mode 100644 com.ibm.wala.cast.js.test/examples-src/tests/214631.js diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/2.js b/com.ibm.wala.cast.js.test/examples-src/pages/2.js new file mode 100644 index 000000000..dbf8299e0 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/2.js @@ -0,0 +1,60 @@ + + + (function () { + + + var jQuery = window.jQuery = window.$ = function (selector, context) { + return new jQuery.fn.init(selector, context); + }; + + + var undefined; + + jQuery.extend = jQuery.fn.extend = function () { + var target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false, + options; + if (target.constructor == Boolean) { + deep = target; + target = arguments[1] || {}; + i = 2; + } + if (typeof target != "object" && typeof target != "function") target = {}; + if (length == i) { + target = this; + --i; + } + for (; i < length; i++) if ((options = arguments[i]) != null) for (var name in options) { + var src = target[name], + copy = options[name]; + if (target === copy) continue; + if (deep && copy && typeof copy == "object" && !copy.nodeType) { + target[name] = jQuery.extend(deep, src || (copy.length != null ? [] : {}), copy); + } + else if (copy !== undefined) target[name] = copy; +// else target[name] = copy; + } + return target; + }; + + jQuery.extend({ + speed: function (speed, easing, fn) { + var opt = speed && speed.constructor == Object ? speed : { + complete: fn || !fn && easing || jQuery.isFunction(speed) && speed, + duration: speed, + easing: fn && easing || easing && easing.constructor != Function && easing + }; + opt.duration = (opt.duration && opt.duration.constructor == Number ? opt.duration : jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def; + opt.old = opt.complete; + opt.complete = function () { + if (opt.queue !== false) jQuery(this).dequeue(); + if (jQuery.isFunction(opt.old)) opt.old.call(this); + }; + return opt; + }, + }); + + })(); + diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/apollo-example.html b/com.ibm.wala.cast.js.test/examples-src/pages/apollo-example.html new file mode 100644 index 000000000..4592a1a19 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/apollo-example.html @@ -0,0 +1,27 @@ + + + Login + + +
+ User Name:
+ Password:
+ Query + Update
+ +
+ + + + diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/page3.html b/com.ibm.wala.cast.js.test/examples-src/pages/page3.html new file mode 100644 index 000000000..9921c0c94 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/page3.html @@ -0,0 +1,8 @@ + + + + + +asdasd + + \ No newline at end of file diff --git a/com.ibm.wala.cast.js.test/examples-src/tests/214631.js b/com.ibm.wala.cast.js.test/examples-src/tests/214631.js new file mode 100644 index 000000000..231105ae5 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/tests/214631.js @@ -0,0 +1,17 @@ +// $Id: drupal.js,v 1.41.2.4 2009/07/21 08:59:10 goba Exp $ + +var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} }; + +/** + * Set the variable that indicates if JavaScript behaviors should be applied + */ +Drupal.jsEnabled = document.getElementsByTagName && document.createElement && document.createTextNode && document.documentElement && document.getElementById; + + + +// Global Killswitch on the element +if (Drupal.jsEnabled) { + //Do some code +} + + diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java index f5855c401..d87811476 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java @@ -11,12 +11,27 @@ package com.ibm.wala.cast.js.test; import java.io.IOException; +import java.util.Iterator; +import java.util.Set; import org.junit.Test; +import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; +import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; +import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.IVector; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.collections.SparseVector; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.OrdinalSet; public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { @@ -267,5 +282,59 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { Util.makeScriptCG("tests", "stack_overflow_on_ssa_conversion.js"); // all we need is for it to finish building CG successfully. } - + + private IVector>> computeIkIdToVns(PointerAnalysis pa) { + + // Created by reversing the points to mapping for local pointer keys. + // Instead of mapping (local) pointer keys to instance keys (with id), we + // map instance keys to VnInContext (which carry the same information as + // local pointer keys) + + final IVector>> ret = new SparseVector>>(); + + for (PointerKey pk : pa.getPointerKeys()) { + if (pk instanceof LocalPointerKey) { + + final LocalPointerKey lpk = (LocalPointerKey) pk; + // we filter out local pointer keys that have no uses. + // NOTE: do to some weird behavior, we get pointer keys with vns that + // don't exist, so we have to filter those before asking about uses. + if (lpk.getNode().getDU().getDef(lpk.getValueNumber()) != null) { + Iterator uses = lpk.getNode().getDU().getUses(lpk.getValueNumber()); + if (uses.hasNext()) { + OrdinalSet pointsToSet = pa.getPointsToSet(pk); + if (pointsToSet == null || pointsToSet.getBackingSet() == null) + continue; + pointsToSet.getBackingSet().foreach(new IntSetAction() { + public void act(int ikId) { + Set> s = ret.get(ikId); + if (s == null) { + s = HashSetFactory.make(); + ret.set(ikId, s); + } + s.add(Pair.make(lpk.getNode(), lpk.getValueNumber())); + } + }); + } else { + int i = 0; + i++; + } + } else { + int i = 0; + i++; + } + } + } + + return ret; + } + + @Test public void test214631() throws IOException, IllegalArgumentException, CancelException { + JSCFABuilder b = Util.makeScriptCGBuilder("tests", "214631.js"); + b.makeCallGraph(b.getOptions()); + PointerAnalysis PA = b.getPointerAnalysis(); + // just make sure this does not crash + computeIkIdToVns(PA); + } + } diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java index 3c7b5e4c0..bb479fb87 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java @@ -51,6 +51,16 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape verifyGraphAssertions(CG, assertionsForPage2); } + private static final Object[][] assertionsForPage3 = new Object[][] { + new Object[] { ROOT, new String[] { "page3.html" } } + }; + + @Test public void testPage3() throws IOException, IllegalArgumentException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/page3.html"); + CallGraph CG = Util.makeHTMLCG(url); + verifyGraphAssertions(CG, assertionsForPage3); + } + @Test public void testCrawl() throws IOException, IllegalArgumentException, CancelException { URL url = getClass().getClassLoader().getResource("pages/crawl.html"); CallGraph CG = Util.makeHTMLCG(url); @@ -192,4 +202,24 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape verifyGraphAssertions(CG, assertionsForPage17); } + /* + @Test public void testDojoTest() throws IllegalArgumentException, IOException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/dojo/test.html"); + CallGraph CG = Util.makeHTMLCG(url); + verifyGraphAssertions(CG, null); + } + */ + + private static final Object[][] assertionsForApolloExample = new Object[][] { + new Object[] { ROOT, new String[] { "apollo-example.html" } }, + new Object[] { "apollo-example.html", new String[] { "apollo-example.html/signon" } }, + new Object[] { "apollo-example.html/signon", new String[] { "preamble.js/DOMWindow/window_open" } } + }; + + @Test public void testApolloExample() throws IOException, IllegalArgumentException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/apollo-example.html"); + CallGraph CG = Util.makeHTMLCG(url); + verifyGraphAssertions(CG, assertionsForApolloExample); + } + } diff --git a/com.ibm.wala.cast.js/dat/preamble.js b/com.ibm.wala.cast.js/dat/preamble.js index 7a95abd0f..589415202 100644 --- a/com.ibm.wala.cast.js/dat/preamble.js +++ b/com.ibm.wala.cast.js/dat/preamble.js @@ -77,7 +77,6 @@ function NamedNodeList() { } function DOMNode() { // An impostor for the Node class - this.attributes = new NamedNodeList(); this.childNodes = new NamedNodeList(); this.insertBefore = function insertBefore(newChild, refChild) { this.childNodes.insertBefore(newChild, refChild); @@ -138,6 +137,7 @@ function DOMHTMLDocument() { this.temp(); this.URL = new String(); this.body = new HTMLBody(); + this.forms = new Array(); } @@ -183,6 +183,7 @@ document.defaultView = window; window.XMLHttpRequest = XMLHttpRequest; var dojo = new DOJOObj(); + function DOMElement() { // An impostor for the Element class // inherits from Node this.temp = DOMNode; @@ -192,14 +193,14 @@ function DOMElement() { // An impostor for the Element class // since that would be used as a workaround for eval this.getAttribute = function getAttribute(name) { - this.attributes.get(name); + return this[name]; } this.setAttribute = function setAttribute(name, value) { - this.attributes.set(name, value); + this[name] = value; } this.removeAttribute = function removeAttribute(name) { - this.attributes.remove(name); + this[name] = undefined; } } @@ -215,34 +216,6 @@ function DOMHTMLElement() { // An impostor for the HTMLElement class this.lang = null; this.dir = null; this.className = null; - - // Set Javascript properties - this.getAttribute = function getAttribute(name) { - if(name == "id") return this.id; - else if(name == "title") return this.title; - else if(name == "lang") return this.lang; - else if(name == "dir") return this.dir; - else if(name == "class") return this.className; - else return this.attributes.get(name); - } - - this.setAttribute = function setAttribute(name, value) { - if(name == "id") this.id = value; - else if(name == "title") this.title = value; - else if(name == "lang") this.lang = value; - else if(name == "dir") this.dir = value; - else if(name == "class") this.className = value; - else return this.attributes.set(name, value); - } - - this.removeAttribute = function removeAttribute(name) { - if(name == "id") this.id = null; - else if(name == "title") this.title = null; - else if(name == "lang") this.lang = null; - else if(name == "dir") this.dir = null; - else if(name == "class") this.className = null; - else return this.attributes.remove(name); - } } var dynamic_node = 0; @@ -265,11 +238,16 @@ function DOMHTMLGenericElement(tagName) { this.src.loadFile(); } +var formCount = 0; + function DOMHTMLFormElement() { // inherits from HTMLElement this.temp = DOMHTMLElement; this.temp(); + // add to 'forms' property + document.forms[formCount++] = this; + // Set Javascript properties this.nodeName = "FORM"; this.elements = new NamedNodeList(); @@ -288,37 +266,6 @@ function DOMHTMLFormElement() { this.enctype = "application/x-www-form-urlencoded"; this.method = "get"; this.target = null; - - // Set Javascript properties - this.getAttribute = function getAttribute(name) { - if(name == "name") return this.name; - else if(name == "accept-charset") return this.acceptCharset; - else if(name == "action") return this.action; - else if(name == "enctype") return this.enctype; - else if(name == "method") return this.method; - else if(name == "target") return this.target; - else return this.prototype.getAttribute(name); - } - - this.setAttribute = function setAttribute(name, value) { - if(name == "name") this.name = value; - else if(name == "accept-charset") this.acceptCharset = value; - else if(name == "action") this.action = value; - else if(name == "enctype") this.enctype = value; - else if(name == "method") this.method = value; - else if(name == "target") this.target = value; - else return this.prototype.setAttribute(name, value); - } - - this.removeAttribute = function removeAttribute(name) { - if(name == "name") this.name = null; - else if(name == "accept-charset") this.acceptCharset = null; - else if(name == "action") this.action = null; - else if(name == "enctype") this.enctype = null; - else if(name == "method") this.method = null; - else if(name == "target") this.target = null; - else return this.prototype.removeAttribute(name); - } } function DOMHTMLTableElement () { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/util/HTMLCallback.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/util/HTMLCallback.java index 1227dfe9b..bfc44eb0d 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/util/HTMLCallback.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/util/HTMLCallback.java @@ -15,7 +15,9 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -23,6 +25,8 @@ import java.util.regex.Pattern; import com.ibm.wala.cast.js.html.IHtmlCallback; import com.ibm.wala.cast.js.html.ITag; import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; public class HTMLCallback implements IHtmlCallback { private final URL input; @@ -132,6 +136,9 @@ public class HTMLCallback implements IHtmlCallback { return varName; } + private Stack forms = new Stack(); + private Set> sets = new HashSet>(); + protected void writeElement(ITag tag, String cons, String varName) throws IOException { indent(); domTreeFile.write("function make_" + varName + "(parent) {\n"); @@ -144,6 +151,34 @@ public class HTMLCallback implements IHtmlCallback { writeAttribute(tag, attr, value, "this", varName); } + if (tag.getName().equalsIgnoreCase("FORM")) { + forms.push(tag); + indent(); domTreeFile.write(" var currentForm = this;\n"); + } if (tag.getName().equalsIgnoreCase("INPUT")) { + String prop = tag.getAttributeByName("NAME"); + if (prop == null) { + prop = tag.getAttributeByName("name"); + } + assert prop != null; + + String type = tag.getAttributeByName("TYPE"); + if (type == null) { + type = tag.getAttributeByName("type"); + } + assert type != null; + + if (type.equalsIgnoreCase("RADIO")) { + if (! sets.contains(Pair.make(forms.peek(), prop))) { + sets.add(Pair.make(forms.peek(), prop)); + indent(); domTreeFile.write(" currentForm." + prop + " = new Array();\n"); + indent(); domTreeFile.write(" currentForm." + prop + "Counter = 0;\n"); + } + indent(); domTreeFile.write(" currentForm." + prop + "[currentForm." + prop + "Counter++] = this;\n"); + } else { + indent(); domTreeFile.write(" currentForm." + prop + " = this;\n"); + } + } + indent(); domTreeFile.write(" " + varName + " = this;\n"); indent(); domTreeFile.write(" dom_nodes." + varName + " = this;\n"); indent(); domTreeFile.write(" parent.appendChild(this);\n"); @@ -159,17 +194,21 @@ public class HTMLCallback implements IHtmlCallback { indent(); domTreeFile.write("function " + attr + "_" + varName2 + "(event) {" + value + "};\n"); indent(); domTreeFile.write(varName + "." + attr + " = " + attr + "_" + varName2 + ";\n"); entrypointFile.write("\n\n " + varName2 + "." + attr + "(null);\n\n"); - } else if (value.startsWith("javascript:") || value.startsWith("javaScript:")) { + /*} else if (value.startsWith("javascript:") || value.startsWith("javaScript:")) { indent(); domTreeFile.write("var " + varName + attr + " = " + value.substring(11) + "\n"); indent(); domTreeFile.write(varName + ".setAttribute('" + attr + "', " + varName + attr + ");\n"); - } else { + */} else { if (value.indexOf('\'') > 0) { value = value.replaceAll("\\'", "\\\\'"); } if (value.indexOf('\n') > 0) { value = value.replaceAll("\\n", "\\\\n"); } - indent(); domTreeFile.write(varName + ".setAttribute('" + attr + "', '" + value + "');\n"); + if (attr.equals(attr.toUpperCase())) { + attr = attr.toLowerCase(); + } + // indent(); domTreeFile.write(varName + ".setAttribute('" + attr + "', '" + value + "');\n"); + indent(); domTreeFile.write(varName + "['" + attr + "'] = '" + value + "';\n"); } } @@ -200,6 +239,18 @@ public class HTMLCallback implements IHtmlCallback { public void handleEndTag(ITag tag) { endElement(stack.pop()); + if (tag.getName().equalsIgnoreCase("FORM")) { + forms.pop(); + } + for(String v : tag.getAllAttributes().values()) { + if (v.startsWith("javascript:")) { + try { + entrypointFile.write( v.substring(11) ); + } catch (IOException e) { + Assertions.UNREACHABLE(e.toString()); + } + } + } } public void handleStartTag(ITag tag) {