Tue, 16 Dec 2014 17:02:54 +0100
8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory
Reviewed-by: attila, sundar
1.1 --- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed May 13 15:41:46 2015 +0200 1.2 +++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Dec 16 17:02:54 2014 +0100 1.3 @@ -26,17 +26,23 @@ 1.4 package jdk.nashorn.internal.runtime.linker; 1.5 1.6 import static jdk.nashorn.internal.lookup.Lookup.MH; 1.7 +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 1.8 + 1.9 import java.lang.invoke.MethodHandle; 1.10 +import java.lang.invoke.MethodHandles; 1.11 import java.lang.invoke.MethodType; 1.12 import java.lang.invoke.SwitchPoint; 1.13 import jdk.internal.dynalink.CallSiteDescriptor; 1.14 import jdk.internal.dynalink.linker.GuardedInvocation; 1.15 import jdk.internal.dynalink.linker.LinkRequest; 1.16 +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; 1.17 import jdk.internal.dynalink.support.Guards; 1.18 import jdk.nashorn.internal.runtime.Context; 1.19 import jdk.nashorn.internal.runtime.FindProperty; 1.20 import jdk.nashorn.internal.runtime.GlobalConstants; 1.21 +import jdk.nashorn.internal.runtime.JSType; 1.22 import jdk.nashorn.internal.runtime.ScriptObject; 1.23 +import jdk.nashorn.internal.runtime.ScriptRuntime; 1.24 import jdk.nashorn.internal.runtime.UserAccessorProperty; 1.25 1.26 /** 1.27 @@ -46,6 +52,11 @@ 1.28 */ 1.29 public final class PrimitiveLookup { 1.30 1.31 + /** Method handle to link setters on primitive base. See ES5 8.7.2. */ 1.32 + private static final MethodHandle PRIMITIVE_SETTER = findOwnMH("primitiveSetter", 1.33 + MH.type(void.class, ScriptObject.class, Object.class, Object.class, boolean.class, Object.class)); 1.34 + 1.35 + 1.36 private PrimitiveLookup() { 1.37 } 1.38 1.39 @@ -87,40 +98,58 @@ 1.40 final ScriptObject wrappedReceiver, final MethodHandle wrapFilter, 1.41 final MethodHandle protoFilter) { 1.42 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 1.43 + final String name; 1.44 + final FindProperty find; 1.45 1.46 - //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem) 1.47 - //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be. 1.48 - //so in that case we can skip creation of primitive wrapper and start our search with the prototype. 1.49 if (desc.getNameTokenCount() > 2) { 1.50 - final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1.51 - final FindProperty find = wrappedReceiver.findProperty(name, true); 1.52 + name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1.53 + find = wrappedReceiver.findProperty(name, true); 1.54 + } else { 1.55 + name = null; 1.56 + find = null; 1.57 + } 1.58 1.59 - if (find == null) { 1.60 - // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it. 1.61 - return null; 1.62 - } 1.63 + final String firstOp = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); 1.64 1.65 - final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter 1.66 - if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) { 1.67 - return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null); 1.68 - } 1.69 + switch (firstOp) { 1.70 + case "getProp": 1.71 + case "getElem": 1.72 + case "getMethod": 1.73 + //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem) 1.74 + //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be. 1.75 + //so in that case we can skip creation of primitive wrapper and start our search with the prototype. 1.76 + if (name != null) { 1.77 + if (find == null) { 1.78 + // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it. 1.79 + return null; 1.80 + } 1.81 1.82 - if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { 1.83 - // If property is found in the prototype object bind the method handle directly to 1.84 - // the proto filter instead of going through wrapper instantiation below. 1.85 - final ScriptObject proto = wrappedReceiver.getProto(); 1.86 - final GuardedInvocation link = proto.lookup(desc, request); 1.87 + final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter 1.88 + if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) { 1.89 + return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null); 1.90 + } 1.91 1.92 - if (link != null) { 1.93 - final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint 1.94 + if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { 1.95 + // If property is found in the prototype object bind the method handle directly to 1.96 + // the proto filter instead of going through wrapper instantiation below. 1.97 + final ScriptObject proto = wrappedReceiver.getProto(); 1.98 + final GuardedInvocation link = proto.lookup(desc, request); 1.99 1.100 - final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class)); 1.101 - final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter); 1.102 - final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter); 1.103 - 1.104 - return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard)); 1.105 + if (link != null) { 1.106 + final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint 1.107 + final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class)); 1.108 + final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter); 1.109 + final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter); 1.110 + return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard)); 1.111 + } 1.112 } 1.113 } 1.114 + break; 1.115 + case "setProp": 1.116 + case "setElem": 1.117 + return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc)); 1.118 + default: 1.119 + break; 1.120 } 1.121 1.122 final GuardedInvocation link = wrappedReceiver.lookup(desc, request); 1.123 @@ -138,4 +167,41 @@ 1.124 1.125 return null; 1.126 } 1.127 + 1.128 + private static GuardedInvocation getPrimitiveSetter(final String name, final MethodHandle guard, 1.129 + final MethodHandle wrapFilter, final boolean isStrict) { 1.130 + MethodHandle filter = MH.asType(wrapFilter, wrapFilter.type().changeReturnType(ScriptObject.class)); 1.131 + final MethodHandle target; 1.132 + 1.133 + if (name == null) { 1.134 + filter = MH.dropArguments(filter, 1, Object.class, Object.class); 1.135 + target = MH.insertArguments(PRIMITIVE_SETTER, 3, isStrict); 1.136 + } else { 1.137 + filter = MH.dropArguments(filter, 1, Object.class); 1.138 + target = MH.insertArguments(PRIMITIVE_SETTER, 2, name, isStrict); 1.139 + } 1.140 + 1.141 + return new GuardedInvocation(MH.foldArguments(target, filter), guard); 1.142 + } 1.143 + 1.144 + 1.145 + @SuppressWarnings("unused") 1.146 + private static void primitiveSetter(final ScriptObject wrappedSelf, final Object self, final Object key, 1.147 + final boolean strict, final Object value) { 1.148 + // See ES5.1 8.7.2 PutValue (V, W) 1.149 + final String name = JSType.toString(key); 1.150 + final FindProperty find = wrappedSelf.findProperty(name, true); 1.151 + if (find == null || !(find.getProperty() instanceof UserAccessorProperty) || !find.getProperty().isWritable()) { 1.152 + if (strict) { 1.153 + throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self)); 1.154 + } 1.155 + return; 1.156 + } 1.157 + // property found and is a UserAccessorProperty 1.158 + find.setValue(value, strict); 1.159 + } 1.160 + 1.161 + private static MethodHandle findOwnMH(final String name, final MethodType type) { 1.162 + return MH.findStatic(MethodHandles.lookup(), PrimitiveLookup.class, name, type); 1.163 + } 1.164 }
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/script/basic/JDK-8066226.js Tue Dec 16 17:02:54 2014 +0100 2.3 @@ -0,0 +1,132 @@ 2.4 +/* 2.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/** 2.28 + * 2.29 + JDK-8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory 2.30 + * 2.31 + * @test 2.32 + * @run 2.33 + */ 2.34 + 2.35 +Object.defineProperty(Object.prototype, "accessor", { 2.36 + set: function(value) { 2.37 + print("Setting accessor on " + this + " to " + value); 2.38 + } 2.39 +}); 2.40 + 2.41 +Object.defineProperty(Object.prototype, "getterOnly", { 2.42 + get: function() { 2.43 + return 1; 2.44 + } 2.45 +}); 2.46 + 2.47 +function set(o) { 2.48 + print("set(" + o + ")"); 2.49 + o.foo = 1; 2.50 + o.constructor = 1; 2.51 + o.accessor = 1; 2.52 + o.getterOnly = 1; 2.53 + print(); 2.54 +} 2.55 + 2.56 +function setStrict(o) { 2.57 + "use strict"; 2.58 + print("setStrict(" + o + ")") 2.59 + try { 2.60 + o.foo = 1; 2.61 + } catch (e) { 2.62 + print(e); 2.63 + } 2.64 + try { 2.65 + o.constructor = 1; 2.66 + } catch (e) { 2.67 + print(e); 2.68 + } 2.69 + try { 2.70 + o.accessor = 1; 2.71 + } catch (e) { 2.72 + print(e); 2.73 + } 2.74 + try { 2.75 + o.getterOnly = 1; 2.76 + } catch (e) { 2.77 + print(e); 2.78 + } 2.79 + print(); 2.80 +} 2.81 + 2.82 +function setAttr(o, id) { 2.83 + print("setAttr(" + o + ", " + id + ")") 2.84 + o[id] = 1; 2.85 + print(); 2.86 +} 2.87 + 2.88 +function setAttrStrict(o, id) { 2.89 + "use strict"; 2.90 + print("setAttrStrict(" + o + ", " + id + ")") 2.91 + try { 2.92 + o[id] = 1; 2.93 + } catch (e) { 2.94 + print(e); 2.95 + } 2.96 + print(); 2.97 +} 2.98 + 2.99 +set(1); 2.100 +set("str"); 2.101 +set(true); 2.102 +set({}); 2.103 +set([]); 2.104 + 2.105 +setStrict(1); 2.106 +setStrict("str"); 2.107 +setStrict(true); 2.108 +setStrict({}); 2.109 +setStrict([]); 2.110 + 2.111 +setAttr(1, "foo"); 2.112 +setAttr(1, "constructor"); 2.113 +setAttr(1, "accessor"); 2.114 +setAttr(1, "getterOnly"); 2.115 +setAttr("str", "foo"); 2.116 +setAttr("str", "constructor"); 2.117 +setAttr("str", "accessor"); 2.118 +setAttr("str", "getterOnly"); 2.119 +setAttr(true, "foo"); 2.120 +setAttr(true, "constructor"); 2.121 +setAttr(true, "accessor"); 2.122 +setAttr(true, "getterOnly"); 2.123 + 2.124 +setAttrStrict(1, "foo"); 2.125 +setAttrStrict(1, "constructor"); 2.126 +setAttrStrict(1, "accessor"); 2.127 +setAttrStrict(1, "getterOnly"); 2.128 +setAttrStrict("str", "foo"); 2.129 +setAttrStrict("str", "constructor"); 2.130 +setAttrStrict("str", "accessor"); 2.131 +setAttrStrict("str", "getterOnly"); 2.132 +setAttrStrict(true, "foo"); 2.133 +setAttrStrict(true, "constructor"); 2.134 +setAttrStrict(true, "accessor"); 2.135 +setAttrStrict(true, "getterOnly");
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/script/basic/JDK-8066226.js.EXPECTED Tue Dec 16 17:02:54 2014 +0100 3.3 @@ -0,0 +1,104 @@ 3.4 +set(1) 3.5 +Setting accessor on 1 to 1 3.6 + 3.7 +set(str) 3.8 +Setting accessor on str to 1 3.9 + 3.10 +set(true) 3.11 +Setting accessor on true to 1 3.12 + 3.13 +set([object Object]) 3.14 +Setting accessor on [object Object] to 1 3.15 + 3.16 +set() 3.17 +Setting accessor on to 1 3.18 + 3.19 +setStrict(1) 3.20 +TypeError: "foo" is not a writable property of 1 3.21 +TypeError: "constructor" is not a writable property of 1 3.22 +Setting accessor on 1 to 1 3.23 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.24 + 3.25 +setStrict(str) 3.26 +TypeError: "foo" is not a writable property of str 3.27 +TypeError: "constructor" is not a writable property of str 3.28 +Setting accessor on str to 1 3.29 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.30 + 3.31 +setStrict(true) 3.32 +TypeError: "foo" is not a writable property of true 3.33 +TypeError: "constructor" is not a writable property of true 3.34 +Setting accessor on true to 1 3.35 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.36 + 3.37 +setStrict([object Object]) 3.38 +Setting accessor on [object Object] to 1 3.39 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.40 + 3.41 +setStrict() 3.42 +Setting accessor on to 1 3.43 +TypeError: Cannot set property "getterOnly" of [object Array] that has only a getter 3.44 + 3.45 +setAttr(1, foo) 3.46 + 3.47 +setAttr(1, constructor) 3.48 + 3.49 +setAttr(1, accessor) 3.50 +Setting accessor on 1 to 1 3.51 + 3.52 +setAttr(1, getterOnly) 3.53 + 3.54 +setAttr(str, foo) 3.55 + 3.56 +setAttr(str, constructor) 3.57 + 3.58 +setAttr(str, accessor) 3.59 +Setting accessor on str to 1 3.60 + 3.61 +setAttr(str, getterOnly) 3.62 + 3.63 +setAttr(true, foo) 3.64 + 3.65 +setAttr(true, constructor) 3.66 + 3.67 +setAttr(true, accessor) 3.68 +Setting accessor on true to 1 3.69 + 3.70 +setAttr(true, getterOnly) 3.71 + 3.72 +setAttrStrict(1, foo) 3.73 +TypeError: "foo" is not a writable property of 1 3.74 + 3.75 +setAttrStrict(1, constructor) 3.76 +TypeError: "constructor" is not a writable property of 1 3.77 + 3.78 +setAttrStrict(1, accessor) 3.79 +Setting accessor on 1 to 1 3.80 + 3.81 +setAttrStrict(1, getterOnly) 3.82 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.83 + 3.84 +setAttrStrict(str, foo) 3.85 +TypeError: "foo" is not a writable property of str 3.86 + 3.87 +setAttrStrict(str, constructor) 3.88 +TypeError: "constructor" is not a writable property of str 3.89 + 3.90 +setAttrStrict(str, accessor) 3.91 +Setting accessor on str to 1 3.92 + 3.93 +setAttrStrict(str, getterOnly) 3.94 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.95 + 3.96 +setAttrStrict(true, foo) 3.97 +TypeError: "foo" is not a writable property of true 3.98 + 3.99 +setAttrStrict(true, constructor) 3.100 +TypeError: "constructor" is not a writable property of true 3.101 + 3.102 +setAttrStrict(true, accessor) 3.103 +Setting accessor on true to 1 3.104 + 3.105 +setAttrStrict(true, getterOnly) 3.106 +TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter 3.107 +