undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
370
test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/BasicTest.java
Normal file
370
test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/BasicTest.java
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
*
|
||||
* @library /testlibrary/asm
|
||||
* @library /vmTestbase /test/lib
|
||||
*
|
||||
* @comment build retransform.jar in current dir
|
||||
* @run driver vm.runtime.defmeth.shared.BuildJar
|
||||
*
|
||||
* @run driver jdk.test.lib.FileInstaller . .
|
||||
* @run main/othervm/native
|
||||
* -agentlib:redefineClasses
|
||||
* -javaagent:retransform.jar
|
||||
* vm.runtime.defmeth.BasicTest
|
||||
*/
|
||||
|
||||
package vm.runtime.defmeth;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import nsk.share.TestFailure;
|
||||
import vm.runtime.defmeth.shared.MemoryClassLoader;
|
||||
import vm.runtime.defmeth.shared.annotation.NotApplicableFor;
|
||||
import vm.runtime.defmeth.shared.builder.TestBuilder;
|
||||
import vm.runtime.defmeth.shared.data.*;
|
||||
import vm.runtime.defmeth.shared.DefMethTest;
|
||||
import vm.runtime.defmeth.shared.executor.TestExecutor;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static vm.runtime.defmeth.shared.ExecutionMode.*;
|
||||
|
||||
/**
|
||||
* Basic tests on some of the assertions from JVMS.
|
||||
*/
|
||||
public class BasicTest extends DefMethTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
DefMethTest.runTest(BasicTest.class,
|
||||
/* majorVer */ Set.of(MIN_MAJOR_VER, MAX_MAJOR_VER),
|
||||
/* flags */ Set.of(0, ACC_SYNCHRONIZED),
|
||||
/* redefine */ Set.of(false, true),
|
||||
/* execMode */ Set.of(DIRECT, REFLECTION, INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY));
|
||||
}
|
||||
|
||||
/*
|
||||
* JVMS 6.5 invokevirtual
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Runtime Exceptions
|
||||
*
|
||||
* Otherwise, if the resolved method is not signature polymorphic:
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* ...
|
||||
*
|
||||
* If the resolved method is declared in an interface and the class of
|
||||
* objectref does not implement the resolved interface, invokevirtual throws
|
||||
* an IncompatibleClassChangeError.
|
||||
*/
|
||||
public void testInterfaceNotImplemented(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("m", "()V").emptyBody().build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").build();
|
||||
|
||||
Class expectedClass;
|
||||
if (factory.getExecutionMode().equals("REFLECTION")) {
|
||||
expectedClass = IllegalArgumentException.class;
|
||||
} else if (factory.getExecutionMode().equals("INVOKE_WITH_ARGS")) {
|
||||
// Notes from JDK-8029926 which details reasons behind CCE.
|
||||
// The code below demonstrates the use of a MethodHandle
|
||||
// of kind REF_invokeInterface pointing to method I.m.
|
||||
// Because 'invoke' is called, this MethodHandle is effectively
|
||||
// wrapped in the type adaptations necessary to accept a C
|
||||
// as the first argument. ***Before we even get to the point
|
||||
// of the invokeinterface call to I.m***, the adaptation
|
||||
// code must run, and that is where the ClassCastException occurs.
|
||||
// This exception can be thrown from code that is cleanly
|
||||
// compiled and does no bytecode generation, so an ICCE would
|
||||
// be inappropriate since no classes are changed.
|
||||
expectedClass = ClassCastException.class;
|
||||
} else {
|
||||
expectedClass = IncompatibleClassChangeError.class;
|
||||
}
|
||||
|
||||
b.test().callSite(I, C, "m", "()V").throws_(expectedClass).done();
|
||||
}
|
||||
|
||||
/*
|
||||
* ...
|
||||
*
|
||||
* Otherwise, if no method matching the resolved name and descriptor is
|
||||
* selected, invokevirtual throws an NoSuchMethodError.
|
||||
*
|
||||
* ...
|
||||
*/
|
||||
public void testNoMatch(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("m", "(Ljava/lang/Object;)V").emptyBody().build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I).build();
|
||||
|
||||
b.test().callSite(C, C, "m", "()I").throws_(NoSuchMethodError.class).done()
|
||||
.test().callSite(C, C, "m1", "()V").throws_(NoSuchMethodError.class).done()
|
||||
.test().callSite(C, C, "m", "(I)V").throws_(NoSuchMethodError.class).done();
|
||||
}
|
||||
|
||||
/*
|
||||
* ...
|
||||
*
|
||||
* 8025604: Updated specification text for both 5.4.3.3 and 5.4.4.4
|
||||
* "Otherwise, if any superinterface of C declares a method with the name and
|
||||
* descriptor specified by the method reference that has set neither
|
||||
* its ACC_PRIVATE flag nor its ACC_STATIC flag, one of these is arbitrarily
|
||||
* chosen and method lookup succeeds."
|
||||
* If method lookup fails, method resolution throws a NoSuchMethodError
|
||||
*
|
||||
* ...
|
||||
*/
|
||||
public void testNonPublic(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("m1", "()V").private_().emptyBody().build()
|
||||
.defaultMethod("m2", "()I").private_().returns(1).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I).build();
|
||||
|
||||
b.test().callSite(C, C, "m1", "()V").throws_(NoSuchMethodError.class).done()
|
||||
.test().callSite(C, C, "m2", "()I").throws_(NoSuchMethodError.class).done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Default method override attempt w/ non-public concrete method.
|
||||
* Private methods never override any other method.
|
||||
*
|
||||
* interface I { int m() default { returns 1; } }
|
||||
* class C/D/E implements I {
|
||||
* [private/protected/package-private]
|
||||
* int m() { returns 2;}
|
||||
* }
|
||||
*
|
||||
*/
|
||||
public void testNonPublicOverride(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("m", "()I").returns(1).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I)
|
||||
.concreteMethod("m", "()I").private_().returns(2).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass D = b.clazz("D").implement(I)
|
||||
.concreteMethod("m", "()I").protected_().returns(2).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass E = b.clazz("E").implement(I)
|
||||
.concreteMethod("m", "()I").package_private().returns(2).build()
|
||||
.build();
|
||||
|
||||
b.test().callSite(I, C, "m", "()I").returns(1).done()
|
||||
.test().callSite(I, D, "m", "()I").throws_(IllegalAccessError.class).done()
|
||||
.test().callSite(I, E, "m", "()I").throws_(IllegalAccessError.class).done();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* interface I {
|
||||
* static { throw new RE(); }
|
||||
* public default void m() {}
|
||||
* }
|
||||
*
|
||||
* class C implements I {}
|
||||
*
|
||||
* TEST: C c = new C(); ==> ExceptionInInitializerError
|
||||
* Static initialization of class C will trigger
|
||||
* I's static initialization due to I's default method.
|
||||
*/
|
||||
public void testStaticInit(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("<clinit>", "()V")
|
||||
.flags(ACC_STATIC)
|
||||
.throw_(RuntimeException.class)
|
||||
.build()
|
||||
|
||||
.defaultMethod("m", "()V")
|
||||
.emptyBody().build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I).build();
|
||||
|
||||
boolean isReflectionMode = factory.getExecutionMode().equals("REFLECTION");
|
||||
Class expectedError = isReflectionMode ? RuntimeException.class
|
||||
: ExceptionInInitializerError.class;
|
||||
|
||||
b.test().new_(C).throws_(expectedError).done();
|
||||
}
|
||||
|
||||
/**
|
||||
* interface I {
|
||||
* static { throw new RE(); }
|
||||
* private default void m() {}
|
||||
* }
|
||||
*
|
||||
* class C implements I {}
|
||||
*
|
||||
* TEST: C c = new C(); ==> ExceptionInInitializerError
|
||||
* Static initialization of class C will trigger
|
||||
* I's static initialization due to I's private concrete method.
|
||||
*/
|
||||
public void testStaticInitPrivate(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("<clinit>", "()V")
|
||||
.flags(ACC_STATIC)
|
||||
.throw_(RuntimeException.class)
|
||||
.build()
|
||||
|
||||
.defaultMethod("m", "()V")
|
||||
.flags(ACC_PRIVATE)
|
||||
.emptyBody().build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I).build();
|
||||
|
||||
boolean isReflectionMode = factory.getExecutionMode().equals("REFLECTION");
|
||||
Class expectedError = isReflectionMode ? RuntimeException.class
|
||||
: ExceptionInInitializerError.class;
|
||||
|
||||
b.test().new_(C).throws_(expectedError).done();
|
||||
}
|
||||
|
||||
/**
|
||||
* interface I {
|
||||
* static { throw new RE()}
|
||||
* }
|
||||
* interface J {
|
||||
* public default int m() { return 1}
|
||||
*
|
||||
* class C implements I,J {}
|
||||
*
|
||||
* TEST: C c = new C()
|
||||
* c.m() returns 1
|
||||
* Static initialization of class C will not trigger
|
||||
* I's static initialization since I has no concrete methods.
|
||||
*/
|
||||
public void testNotStaticInitNoDefault(TestBuilder b) {
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("<clinit>", "()V")
|
||||
.flags(ACC_STATIC)
|
||||
.throw_(RuntimeException.class)
|
||||
.build()
|
||||
.build();
|
||||
|
||||
Interface J = b.intf("J")
|
||||
.defaultMethod("m", "()I")
|
||||
.returns(1).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I,J).build();
|
||||
|
||||
b.test().callSite(C, C, "m", "()I").returns(1).done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Example A.10
|
||||
*
|
||||
* Let L1 and L2 be class loaders with different interpretations of the type "A".
|
||||
*
|
||||
* Loaded by L1:
|
||||
* public interface I { public default A m() { return null; } }
|
||||
*
|
||||
* Loaded by L2:
|
||||
* public class C implements I {}
|
||||
*
|
||||
* TEST: I o = new C(); o.m() ==> LinkageError;
|
||||
* TEST: C o = new C(); o.m() ==> LinkageError;
|
||||
*/
|
||||
// disabling this test for REFLECTION and INVOKE for now until
|
||||
// loader constraint issue associated with those modes has been resolved
|
||||
@NotApplicableFor(modes = { REFLECTION, INVOKE_WITH_ARGS, INVOKE_EXACT, INVOKE_GENERIC, INDY })
|
||||
public void testLoaderConstraint() {
|
||||
TestBuilder b = factory.getBuilder();
|
||||
ConcreteClass A = b.clazz("A").build();
|
||||
|
||||
Interface I = b.intf("I")
|
||||
.defaultMethod("m", "()LA;").returnsNewInstance(A).build()
|
||||
.build();
|
||||
|
||||
ConcreteClass C = b.clazz("C").implement(I).build();
|
||||
|
||||
b.test().callSite(I, C, "m", "()LA;").throws_(LinkageError.class).done();
|
||||
b.test().callSite(C, C, "m", "()LA;").throws_(LinkageError.class).done();
|
||||
|
||||
TestExecutor executor = b.prepare(new TestBuilder.LoaderConstructor() {
|
||||
@Override
|
||||
public MemoryClassLoader construct(Map<String, byte[]> classFiles) {
|
||||
final byte[] cfI = classFiles.get("I");
|
||||
final byte[] cfC = classFiles.get("C");
|
||||
final byte[] cfA = classFiles.get("A");
|
||||
final byte[] cfT1 = classFiles.get("Test1_I_C_m");
|
||||
final byte[] cfT2 = classFiles.get("Test2_C_C_m");
|
||||
|
||||
final ClassLoader l1 = new ClassLoader() {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
switch (name) {
|
||||
case "I":
|
||||
return defineClass(name, cfI, 0, cfI.length);
|
||||
case "A":
|
||||
return defineClass(name, cfA, 0, cfA.length);
|
||||
default:
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final MemoryClassLoader l2 = new MemoryClassLoader(classFiles) {
|
||||
@Override
|
||||
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if ("I".equals(name)) {
|
||||
return l1.loadClass(name);
|
||||
} else {
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
// Need to preload classes, otherwise A will be resolved in the same loader
|
||||
l1.loadClass("A"); l1.loadClass("I");
|
||||
l2.loadClass("A"); l2.loadClass("C");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new TestFailure(e);
|
||||
}
|
||||
|
||||
return l2;
|
||||
}
|
||||
});
|
||||
|
||||
executor.run();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue