Skip to content

Commit a4613d4

Browse files
author
Brent Christian
committed
8212117: Class.forName may return a reference to a loaded but not linked Class
Reviewed-by: dholmes, mchung
1 parent 10e4fd4 commit a4613d4

13 files changed

Lines changed: 342 additions & 16 deletions

File tree

make/hotspot/symbols/symbols-unix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
33
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
#
55
# This code is free software; you can redistribute it and/or modify it
@@ -149,6 +149,7 @@ JVM_IsSupportedJNIVersion
149149
JVM_IsThreadAlive
150150
JVM_IsVMGeneratedMethodIx
151151
JVM_LatestUserDefinedLoader
152+
JVM_LinkClass
152153
JVM_LoadLibrary
153154
JVM_MaxMemory
154155
JVM_MaxObjectInspectionAge

src/hotspot/share/include/jvm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ JVM_GetCallerClass(JNIEnv *env);
345345
JNIEXPORT jclass JNICALL
346346
JVM_FindPrimitiveClass(JNIEnv *env, const char *utf);
347347

348+
/*
349+
* Link the 'arg' class
350+
*/
351+
JNIEXPORT void JNICALL
352+
JVM_LinkClass(JNIEnv *env, jclass classClass, jclass arg);
348353

349354
/*
350355
* Find a class from a boot class loader. Returns NULL if class not found.

src/hotspot/share/prims/jni.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name))
417417
}
418418

419419
TempNewSymbol sym = SymbolTable::new_symbol(name);
420-
result = find_class_from_class_loader(env, sym, true, loader,
420+
result = find_class_from_class_loader(env, sym, true, true, loader,
421421
protection_domain, true, thread);
422422

423423
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
@@ -3289,7 +3289,7 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) {
32893289
Handle protection_domain; // null protection domain
32903290

32913291
TempNewSymbol sym = SymbolTable::new_symbol(name);
3292-
jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL);
3292+
jclass result = find_class_from_class_loader(env, sym, true, true, loader, protection_domain, true, CHECK_NULL);
32933293

32943294
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
32953295
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));

src/hotspot/share/prims/jvm.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,17 @@ JVM_END
717717
// Misc. class handling ///////////////////////////////////////////////////////////
718718

719719

720+
JVM_ENTRY(void, JVM_LinkClass(JNIEnv* env, jclass classClass, jclass arg))
721+
JVMWrapper("JVM_LinkClass");
722+
723+
oop r = JNIHandles::resolve(arg);
724+
Klass* klass = java_lang_Class::as_Klass(r);
725+
726+
if (!ClassForNameDeferLinking && klass->is_instance_klass()) {
727+
InstanceKlass::cast(klass)->link_class(CHECK);
728+
}
729+
JVM_END
730+
720731
JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env))
721732
JVMWrapper("JVM_GetCallerClass");
722733

@@ -827,9 +838,10 @@ JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name,
827838

828839
Handle h_loader(THREAD, loader_oop);
829840
Handle h_prot(THREAD, protection_domain);
830-
jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
831-
h_prot, false, THREAD);
832841

842+
jboolean link = !ClassForNameDeferLinking;
843+
jclass result = find_class_from_class_loader(env, h_name, init, link, h_loader,
844+
h_prot, false, THREAD);
833845
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
834846
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
835847
}
@@ -866,7 +878,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name,
866878
}
867879
Handle h_loader(THREAD, class_loader);
868880
Handle h_prot (THREAD, protection_domain);
869-
jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
881+
jclass result = find_class_from_class_loader(env, h_name, init, false, h_loader,
870882
h_prot, true, thread);
871883

872884
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
@@ -3424,9 +3436,12 @@ JNIEXPORT void JNICALL JVM_RawMonitorExit(void *mon) {
34243436

34253437
// Shared JNI/JVM entry points //////////////////////////////////////////////////////////////
34263438

3427-
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init,
3439+
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, jboolean link,
34283440
Handle loader, Handle protection_domain,
34293441
jboolean throwError, TRAPS) {
3442+
// Initialization also implies linking - check for coherent args
3443+
assert((init && link) || !init, "incorrect use of init/link arguments");
3444+
34303445
// Security Note:
34313446
// The Java level wrapper will perform the necessary security check allowing
34323447
// us to pass the NULL as the initiating class loader. The VM is responsible for
@@ -3435,9 +3450,11 @@ jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init,
34353450
// if there is no security manager in 3-arg Class.forName().
34363451
Klass* klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);
34373452

3438-
// Check if we should initialize the class
3453+
// Check if we should initialize the class (which implies linking), or just link it
34393454
if (init && klass->is_instance_klass()) {
34403455
klass->initialize(CHECK_NULL);
3456+
} else if (link && klass->is_instance_klass()) {
3457+
InstanceKlass::cast(klass)->link_class(CHECK_NULL);
34413458
}
34423459
return (jclass) JNIHandles::make_local(env, klass->java_mirror());
34433460
}

src/hotspot/share/prims/jvm_misc.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
// Useful entry points shared by JNI and JVM interface.
3232
// We do not allow real JNI or JVM entry point to call each other.
3333

34-
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS);
34+
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, jboolean link,
35+
Handle loader, Handle protection_domain, jboolean throwError, TRAPS);
3536

3637
void trace_class_resolution(Klass* to_class);
3738

src/hotspot/share/runtime/globals.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,9 @@ const size_t minimumSymbolTableSize = 1024;
21642164
"Maximum total size of NIO direct-buffer allocations") \
21652165
range(0, max_jlong) \
21662166
\
2167+
product(bool, ClassForNameDeferLinking, false, \
2168+
"Revert to not linking in Class.forName()") \
2169+
\
21672170
/* Flags used for temporary code during development */ \
21682171
\
21692172
diagnostic(bool, UseNewCode, false, \

src/java.base/share/classes/java/lang/Class.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ public static Class<?> forName(String className)
392392
*
393393
* @see java.lang.Class#forName(String)
394394
* @see java.lang.ClassLoader
395+
*
396+
* @jls 12.2 Loading of Classes and Interfaces
397+
* @jls 12.3 Linking of Classes and Interfaces
398+
* @jls 12.4 Initialization of Classes and Interfaces
395399
* @since 1.2
396400
*/
397401
@CallerSensitive
@@ -438,6 +442,10 @@ private static native Class<?> forName0(String name, boolean initialize,
438442
* <p> This method does not check whether the requested class is
439443
* accessible to its caller. </p>
440444
*
445+
* <p> Note that this method throws errors related to loading and linking as
446+
* specified in Sections 12.2 and 12.3 of <em>The Java Language
447+
* Specification</em>.
448+
*
441449
* @apiNote
442450
* This method returns {@code null} on failure rather than
443451
* throwing a {@link ClassNotFoundException}, as is done by
@@ -465,6 +473,8 @@ private static native Class<?> forName0(String name, boolean initialize,
465473
* in a module.</li>
466474
* </ul>
467475
*
476+
* @jls 12.2 Loading of Classes and Interfaces
477+
* @jls 12.3 Linking of Classes and Interfaces
468478
* @since 9
469479
* @spec JPMS
470480
*/
@@ -488,13 +498,21 @@ public static Class<?> forName(Module module, String name) {
488498
cl = module.getClassLoader();
489499
}
490500

501+
Class<?> ret;
491502
if (cl != null) {
492-
return cl.loadClass(module, name);
503+
ret = cl.loadClass(module, name);
493504
} else {
494-
return BootLoader.loadClass(module, name);
505+
ret = BootLoader.loadClass(module, name);
495506
}
507+
if (ret != null) {
508+
// The loaded class should also be linked
509+
linkClass(ret);
510+
}
511+
return ret;
496512
}
497513

514+
private static native void linkClass(Class<?> c);
515+
498516
/**
499517
* Creates a new instance of the class represented by this {@code Class}
500518
* object. The class is instantiated as if by a {@code new}

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,12 +1927,17 @@ public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuc
19271927
}
19281928

19291929
/**
1930-
* Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
1930+
* Looks up a class by name from the lookup context defined by this {@code Lookup} object.
1931+
* This method attempts to locate, load, and link the class, and then determines whether
1932+
* the class is accessible to this {@code Lookup} object. The static
19311933
* initializer of the class is not run.
19321934
* <p>
19331935
* The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class
1934-
* loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to
1935-
* load the requested class, and then determines whether the class is accessible to this lookup object.
1936+
* loader, and the {@linkplain #lookupModes() lookup modes}.
1937+
* <p>
1938+
* Note that this method throws errors related to loading and linking as
1939+
* specified in Sections 12.2 and 12.3 of <em>The Java Language
1940+
* Specification</em>.
19361941
*
19371942
* @param targetName the fully qualified name of the class to be looked up.
19381943
* @return the requested class.
@@ -1944,6 +1949,9 @@ public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuc
19441949
* modes.
19451950
* @exception SecurityException if a security manager is present and it
19461951
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
1952+
*
1953+
* @jls 12.2 Loading of Classes and Interfaces
1954+
* @jls 12.3 Linking of Classes and Interfaces
19471955
* @since 9
19481956
*/
19491957
public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException {

src/java.base/share/classes/sun/launcher/LauncherHelper.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,7 @@
6262
import java.nio.file.DirectoryStream;
6363
import java.nio.file.Files;
6464
import java.nio.file.Path;
65+
import java.security.AccessControlException;
6566
import java.text.Normalizer;
6667
import java.text.MessageFormat;
6768
import java.util.ArrayList;
@@ -724,6 +725,9 @@ private static Class<?> loadModuleMainClass(String what) {
724725
} catch (LinkageError le) {
725726
abort(null, "java.launcher.module.error3", mainClass, m.getName(),
726727
le.getClass().getName() + ": " + le.getLocalizedMessage());
728+
} catch (AccessControlException ace) {
729+
abort(ace, "java.launcher.module.error5", mainClass, m.getName(),
730+
ace.getClass().getName(), ace.getLocalizedMessage());
727731
}
728732
if (c == null) {
729733
abort(null, "java.launcher.module.error2", mainClass, mainModule);
@@ -780,6 +784,9 @@ private static Class<?> loadMainClass(int mode, String what) {
780784
} catch (LinkageError le) {
781785
abort(le, "java.launcher.cls.error6", cn,
782786
le.getClass().getName() + ": " + le.getLocalizedMessage());
787+
} catch (AccessControlException ace) {
788+
abort(ace, "java.launcher.cls.error7", cn,
789+
ace.getClass().getName(), ace.getLocalizedMessage());
783790
}
784791
return mainClass;
785792
}

src/java.base/share/native/libjava/Class.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static JNINativeMethod methods[] = {
7676
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
7777
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
7878
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
79+
{"linkClass", "(" CLS ")V", (void *)&JVM_LinkClass},
7980
};
8081

8182
#undef OBJ

0 commit comments

Comments
 (0)