8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory

Tue, 16 Dec 2014 17:02:54 +0100

author
hannesw
date
Tue, 16 Dec 2014 17:02:54 +0100
changeset 1354
24a72d0aef36
parent 1353
b9dda83d984b
child 1355
e3af6a3cd761

8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory
Reviewed-by: attila, sundar

src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8066226.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8066226.js.EXPECTED file | annotate | diff | comparison | revisions
     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 +

mercurial