@Test public void testComplexStack() { try { eval( "", "var x = { one: function() { bar() } };", "var y = { two: x.one };", "function foo() {", " throw TypeError();", "}", "function bar() {", " foo();", "}", "", "try {", " (function(){y.two();})();", "} catch(e) {", " print(e.stack);", " throw e;", "}"); throw new AssertionError("Should have thrown"); } catch (ThrowException e) { JSObject o = (JSObject) e.getValue(); String stack = (String) o.get(getContext(), "stack"); assertThat(stack.contains("TypeError\n")).isTrue(); assertThat(stack.contains("at foo (<eval>:5)")).isTrue(); assertThat(stack.contains("at bar (<eval>:8)")).isTrue(); assertThat(stack.contains("at Object.one (<eval>:2)")).isTrue(); assertThat(stack.contains("at <anonymous> (<eval>:12)")).isTrue(); assertThat(stack.contains("at <eval> (<eval>:12)")).isTrue(); } }
private boolean isDummy(Location obj) { JSObject heapObj = this.get(obj); if (heapObj == null) return false; ObjectValue val = heapObj.get("at_Dummy"); if (val != null) return true; else return false; }
public Object construct(JSFunction function, Object... args) { if (!function.isConstructor()) { throw new ThrowException(this, createTypeError("not a constructor")); } // 13.2.2 // 1. create the new object JSObject obj = function.createNewObject(this); // 2. set internal methods per 8.12 [DynObject] // 3. set class name [DynObject subclass (defaults true)] // 4. Set Extensible [DynObject subclass (defaults true)] // 5. Get the function's prototype // 6. If prototype is an object make that the new object's prototype // 7. If prototype is not an object set to the standard builtin object prototype 15.2.4 // [AbstractJavascriptFunction] // [AbstractJavascriptFunction] handles #7, subclasses may handle #6 if necessary (see // BuiltinArray#createNewObject) Object p = function.get(this, "prototype"); if (p != Types.UNDEFINED && p instanceof JSObject) { obj.setPrototype((JSObject) p); } else { JSObject defaultObjectProto = getPrototypeFor("Object"); obj.setPrototype(defaultObjectProto); } // 8. Call the function with obj as self Object result = internalCall(null, function, obj, args); // 9. If result is a JSObject return it if (result instanceof JSObject) { return (JSObject) result; } // Otherwise return obj return obj; }
private static String _getString(String name, JSObject... places) { for (JSObject o : places) { if (o == null) continue; Object temp = o.get(name); if (temp == null) continue; return temp.toString(); } return null; }
/** * Removes the property with property name i * * @param l : location in the heap * @param property : property name */ public void delete(Location l, String property) { if (heap == null) return; // get the object set for the location l JSObject os = this.get(l); // if the object exists, then delete the property from each object in the ObjectSet if (os != null) os.remove(property); return; }
/** * Prototype Lookup * * @param currentLoc * @param property_name * @return null if the prototype chain leads to null when looking for the property or a location * if the object at that location contains the property */ public Location Prototype(Location currentLoc, String property_name) { if (currentLoc != null) { JSObject obj = this.get(currentLoc); if (obj != null) { if (obj.isin(property_name)) return currentLoc; else { Location proto = (Location) obj.get("__proto__"); return Prototype(proto, property_name); } } } return null; }
/** * Returns a property within this object. * * @param path Property names separated by dots ('.') * @return The string representation of the requested property or <strong>null</strong>, if it * doesn't exist */ public String access(String path) { JSObject current = this; String[] nodes = (path != null) ? path.split("\\.") : new String[0]; for (int i = 0; i < nodes.length; i++) { if (current != null) { current = current.get(nodes[i]); } else { break; } } return (current == null) ? null : current.toString(); }
/** * Returns the scope object enclosing the desired property * * @param currentLoc * @param property_name * @return */ public Location Scope(Location currentLoc, String property_name) { if (currentLoc == null) return null; if (this.hasProperty( currentLoc, property_name)) // Check if the prototype chain has the property return currentLoc; else { // if not, then check if the scope chain has the property JSObject obj = this.get(currentLoc); if (obj != null) { Location sc = (Location) obj.get("at_Scope"); return Scope(sc, property_name); } else { return null; } } }
public static void main(String[] args) { try { JSObject js1 = new JSObject(); JSObject js2 = new JSObject(); JSObject js3 = new JSObject(); js1.put("x", new ObjectValue("Y")); js2.put(new String("a"), new SecurityType(SecurityType.high, null)); js2.put(new String("u"), null); js3.put(new String("b"), null); // Testing the alloc function Heap h = new Heap(); Location l0 = h.alloc(Location.generateLocString(), js1); Location l1 = h.alloc("0", js1); Location l2 = h.alloc("10", js2); System.out.println("loc 1: " + l1); System.out.println("loc 2: " + l2); System.out.println("Heap : " + h); Heap h0 = h.deepClone(); Heap h1 = h.clone(); // Location l3 = h.alloc("5", js3); System.out.println("Heap comparison: " + h.equals(h0)); System.out.println("Heap comparison: " + h.equals(h1)); } catch (Exception e) { e.printStackTrace(); } }
/** * updates the context to the correct branch based on environment and to the latest version of the * code if name or environemnt is missing, does nothing */ public String updateCode() { if (!_git.isValid()) throw new RuntimeException(_rootFile + " is not a git repository"); _logger.info("going to update code"); _git.fullUpdate(); if (_name == null || _environment == null) return getCurrentGitBranch(); JSObject env = getEnvironmentObject(); if (env == null) return null; String branch = env.get("branch").toString(); _logger.info("updating to [" + branch + "]"); _git.checkout(branch); Python.deleteCachedJythonFiles(_rootFile); return getCurrentGitBranch(true); }
private void performFunctionDeclarationBindings( final JSCode code, final boolean configurableBindings) { // 10.5 Function Declaration Binding List<FunctionDeclaration> decls = code.getFunctionDeclarations(); EnvironmentRecord env = this.variableEnvironment.getRecord(); for (FunctionDeclaration each : decls) { String identifier = each.getIdentifier(); if (!env.hasBinding(this, identifier)) { env.createMutableBinding(this, identifier, configurableBindings); } else if (env.isGlobal()) { JSObject globalObject = ((ObjectEnvironmentRecord) env).getBindingObject(); PropertyDescriptor existingProp = (PropertyDescriptor) globalObject.getProperty(this, identifier); if (existingProp.isConfigurable()) { PropertyDescriptor newProp = new PropertyDescriptor() { { set("Value", Types.UNDEFINED); set("Writable", true); set("Enumerable", true); set("Configurable", configurableBindings); } }; globalObject.defineOwnProperty(this, identifier, newProp, true); } else if (existingProp.isAccessorDescriptor() || (!existingProp.isWritable() && !existingProp.isEnumerable())) { throw new ThrowException( this, createTypeError("unable to bind function '" + identifier + "'")); } } JSFunction function = getCompiler() .compileFunction( this, identifier, each.getFormalParameters(), each.getBlock(), each.isStrict()); function.setDebugContext(identifier); env.setMutableBinding(this, identifier, function, code.isStrict()); } }
/** * Method used to create dummy objects * * <p>The Object name contains the filename and line number at which the undefined variable is * being accessed * * <p>A new property at_Dummy is introduced to mark this node * * <p>TODO: Should the dummy object be marked tainted?? * * @param pre * @return */ public Location createDummyObjectInHeap(CommonTree ast, SecurityType dummy_type) { String taint_val = dummy_type.getObjValue(); if (taint_val == null) { taint_val = "@High"; } Location dummy_loc = this.dummyObjectMap.get(taint_val); if (dummy_loc == null) { Location second_result; // Add the low security type to the dummy object JSObject dummy_obj = PredefinedObjectTemplates.new_object("Object", NativeObjects.ObjectProt, dummy_type); dummy_obj.put("at_Dummy", new ObjectValue(true)); // current filename sans the path // String[] fn = currentfilename.split("/"); second_result = new Location("dummy_" + ast.getLine()); this.put(second_result, dummy_obj); this.dummyObjectMap.put(taint_val, second_result); return second_result; } else { return dummy_loc; } }
/** * add a (property, value) pair to an object at a given location * * @param l * @param property * @param ov */ public void add(Location l, String property, ObjectValue ov) { JSObject os; if (heap == null) { // if the heap is null heap = new TreeMap<Location, JSObject>(); } // if there are no entries in the heap or if there are no entries for the particular location if (heap.isEmpty() || !heap.containsKey(l)) { // create a new object for the location os = new JSObject(); // add the newly created object to the heap this.put(l, os); } // get the object for the heap location os = this.get(l); // add the current object value to every object in the ObjectSet os.put(property, ov); }
/** * Create a deep clone of the heap and return it * * @return */ public Heap deepClone() { Heap hp = new Heap(); if (this.heap == null) { hp.setHeap(null); return hp; } // set the clone global element hp.setGlobal(this.getGlobal()); Set<Location> keys = this.getKeySet(); for (Location key : keys) { JSObject old_ov = this.get(key); // create a deep clone of the old object value JSObject new_ov = old_ov.deepClone(); hp.put(key, new_ov); } hp.setStrValueMap((HashMap<String, Location>) this.strValueMap.clone()); hp.setDummyObjectMap((HashMap<String, Location>) this.dummyObjectMap.clone()); return hp; }
/** * @param other * @return */ private boolean checkHeapObjectEquality(Heap other) { Set<Location> this_keyset = this.getKeySet(); Set<Location> other_keyset = other.getKeySet(); if (this_keyset != null && other_keyset != null) { if (this_keyset.containsAll(other_keyset) && other_keyset.containsAll( this_keyset)) { // check if both the keysets have the same keys // If true, compare value sets boolean retval = true; for (Location key : this_keyset) { JSObject this_value = this.get(key); JSObject other_value = other.get(key); retval = retval && (this_value.isomorphic(other_value)); } return retval; } else { // If false, the maps don't match return false; } } else { if (this_keyset == null && other_keyset == null) return true; else return false; } }
protected Object primitiveGet(ExecutionContext context, JSObject o, String name) { // 8.7.1 primitive [[Get]] Object d = o.getProperty(context, name, false); if (d == Types.UNDEFINED) { return Types.UNDEFINED; } PropertyDescriptor desc = (PropertyDescriptor) d; if (desc.isDataDescriptor()) { Object value = desc.getValue(); if (value == null) { value = Types.UNDEFINED; } return value; } Object getter = desc.getGetter(); if (getter == Types.UNDEFINED) { return Types.UNDEFINED; } return context.call((JSFunction) getter, o); }
@Test public void testDeleteOper() { check("var x = {a:'lol'}; var result = delete x.a;", true); JSObject x = (JSObject) getContext().resolve("x").getValue(getContext()); assertThat(x.get(getContext(), "a")).isEqualTo(Types.UNDEFINED); }
/** * Displays the heap so that it can be visualized as a graph * * @return */ public String toGraphRep() { Location global = this.getGlobal(); String graphviz = "digraph G{"; Set<Location> locs = heap.keySet(); for (Location l : locs) { JSObject lj = heap.get(l); if (l == global) { graphviz += l.getObjValue() + "[ fillcolor = \"green\", style = \"filled\"];"; } if (lj.isin("at_Taint")) { if (lj.get("at_Taint") != null) { if (((SecurityType) lj.get("at_Taint")).isTainted()) { graphviz += l.getObjValue() + "[ fillcolor = \"red\", style = \"filled\"];"; } else { graphviz += l.getObjValue() + "[ fillcolor = \"lightblue\", style = \"filled\"];"; } } } Set<String> keys = lj.getKeySet(); for (String key : keys) { ObjectValue ov = lj.get(key); if (ov != null) { if (ov instanceof Location) { if (key.equals("innerHTML")) { graphviz += ov.getObjValue() + "[ fillcolor = \"lightblue\", style = \"filled\"];"; } JSObject jsov = heap.get(ov); if (jsov != null) { if (jsov.isin("at_Taint")) { if (jsov.get("at_Taint") != null) { if (((SecurityType) jsov.get("at_Taint")).isTainted()) { graphviz += ov.getObjValue() + "[ fillcolor = \"red\", style = \"filled\"];"; } else { graphviz += ov.getObjValue() + "[ fillcolor = \"lightblue\", style = \"filled\"];"; } } } } String key_new = key; if (key.endsWith("\"")) { key_new = key.substring(1, key.length() - 1); key = key_new; } // if(!key_new.equals("at_Class") && !key_new.equals("__constructor__") && // !key_new.equals("at_FScope") && !key_new.equals("at_Scope") ){ graphviz += "\n" + l.getObjValue() + " -> " + ov.getObjValue() + " [ label = \"" + key_new + "\" ];"; // } } } } } graphviz += "}"; return graphviz; }
/** * Recursive function to check if the JSObjects in both the heaps match * * @param other * @param this_global * @param other_global * @return */ private boolean checkContentEquality(Heap other, Location this_obj, Location other_obj) { JSObject curr_obj = this.get(this_obj); JSObject test_obj = other.get(other_obj); if (curr_obj == null && test_obj == null) return true; if ((curr_obj != null && test_obj == null) || (curr_obj == null && test_obj != null)) return false; SecurityType curr_taint = (SecurityType) curr_obj.get("at_Taint"); SecurityType test_taint = (SecurityType) test_obj.get("at_Taint"); // Proceed further only if the JSObject taints match if (curr_taint.equals(test_taint)) { // If the location is a dummy object, it suffices to just check the taints if (other.isDummy(other_obj) && this.isDummy(this_obj)) { return true; } Set<String> this_keyset = curr_obj.getKeySet(); Set<String> other_keyset = test_obj.getKeySet(); // Proceed further only if the keys in both the JSObjects match if (this_keyset.containsAll(other_keyset) && other_keyset.containsAll(this_keyset)) { // For each key compare the object values boolean retval = true; for (String key : this_keyset) { // we don't want to go into libraryProperties as they will lead to the parents // creating a circular check and infinite recursion if (ProgramAnalyzerC.libraryProperties.contains(key)) continue; if (key.equals("at_Taint")) // we already compared taints continue; ObjectValue this_val = curr_obj.get(key); ObjectValue other_val = test_obj.get(key); if (this_val == null && other_val == null) { continue; } if ((this_val == null && other_val != null) || (this_val != null && other_val == null)) { retval = false; return retval; } if (this_val.getClass() != other_val.getClass()) { retval = false; // If the class types don't match return retval; } if (this_val instanceof Location) retval = retval && checkContentEquality(other, (Location) this_val, (Location) other_val); if (this_val instanceof FunctionValue) retval = retval && ((FunctionValue) this_val).equals((FunctionValue) other_val); if (this_val instanceof ObjectValue) retval = retval && this_val.equals(other_val); if (retval == false) return false; } return retval; } } return false; }
private Arguments createArgumentsObject(final JSFunction function, final Object[] arguments) { // 10.6 Arguments obj = new Arguments(getGlobalObject()); PropertyDescriptor desc = new PropertyDescriptor() { { set("Value", arguments.length); set("Writable", true); set("Enumerable", false); set("Configurable", true); } }; obj.defineOwnProperty(this, "length", desc, false); String[] names = function.getFormalParameters(); JSObject map = new DynObject(getGlobalObject()); List<String> mappedNames = new ArrayList<>(); final LexicalEnvironment env = getVariableEnvironment(); for (int i = 0; i < arguments.length; ++i) { final Object val = arguments[i]; desc = new PropertyDescriptor() { { set("Value", val); set("Writable", true); set("Enumerable", true); set("Configurable", true); } }; obj.defineOwnProperty(this, "" + i, desc, false); if (i < names.length) { if (!function.isStrict()) { final String name = names[i]; if (i < names.length) { if (!mappedNames.contains(name)) { mappedNames.add(name); desc = new PropertyDescriptor() { { set("Set", new ArgSetter(env, name)); set("Get", new ArgGetter(env, name)); set("Configurable", true); } }; map.defineOwnProperty(this, "" + i, desc, false); } } } } } if (!mappedNames.isEmpty()) { obj.setParameterMap(map); } if (function.isStrict()) { final JSFunction thrower = (JSFunction) getGlobalObject().get(this, "__throwTypeError"); obj.defineOwnProperty( this, "caller", new PropertyDescriptor() { { set("Get", thrower); set("Set", thrower); set("Enumerable", false); set("Configurable", false); } }, false); obj.defineOwnProperty( this, "callee", new PropertyDescriptor() { { set("Get", thrower); set("Set", thrower); set("Enumerable", false); set("Configurable", false); } }, false); } else { obj.defineOwnProperty( this, "callee", new PropertyDescriptor() { { set("Value", function); set("Writable", true); set("Enumerable", false); set("Configurable", true); } }, false); } return obj; }
private void _loadConfigFromCloudObject(JSObject o) { if (o == null) return; _configScope.putAll((JSObject) o.get("config")); }