JDK-8158851 : MH.publicLookup() init circularity, triggered by custom SecurityManager with String concat and -limitmods java.base
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-06-06
  • Updated: 2016-06-16
  • Resolved: 2016-06-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b123Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
If java/lang/String/concat/WithSecurityManager.java test is run with "-limitmods":
$ jtreg -javaoptions:"-limitmods java.base" java/lang/String/concat/WithSecurityManager.java
it fails with
java.lang.BootstrapMethodError: call site initialization exception
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:347)
	at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base@9-internal/MethodHandleNatives.java:250)
	at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base@9-internal/MethodHandleNatives.java:240)
	at WithSecurityManager$1.checkPermission(WithSecurityManager.java:47)
	at java.lang.SecurityManager.checkPropertiesAccess(java.base@9-internal/SecurityManager.java:1253)
	at java.lang.System.getProperties(java.base@9-internal/System.java:675)
	at sun.security.action.GetPropertyAction$1.run(java.base@9-internal/GetPropertyAction.java:153)
	at sun.security.action.GetPropertyAction$1.run(java.base@9-internal/GetPropertyAction.java:151)
	at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
	at sun.security.action.GetPropertyAction.privilegedGetProperties(java.base@9-internal/GetPropertyAction.java:150)
	at java.lang.invoke.StringConcatFactory.<clinit>(java.base@9-internal/StringConcatFactory.java:200)
	at jdk.internal.misc.Unsafe.ensureClassInitialized0(java.base@9-internal/Native Method)
	at jdk.internal.misc.Unsafe.ensureClassInitialized(java.base@9-internal/Unsafe.java:1054)
	at java.lang.invoke.DirectMethodHandle.shouldBeInitialized(java.base@9-internal/DirectMethodHandle.java:304)
	at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(java.base@9-internal/DirectMethodHandle.java:168)
	at java.lang.invoke.DirectMethodHandle.make(java.base@9-internal/DirectMethodHandle.java:86)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.base@9-internal/MethodHandles.java:1972)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(java.base@9-internal/MethodHandles.java:1929)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(java.base@9-internal/MethodHandles.java:2160)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(java.base@9-internal/MethodHandles.java:2109)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(java.base@9-internal/MethodHandleNatives.java:499)
	at WithSecurityManager$1.checkPermission(WithSecurityManager.java:47)
	at java.lang.SecurityManager.checkRead(java.base@9-internal/SecurityManager.java:880)
	at java.io.File.exists(java.base@9-internal/File.java:815)
	at jdk.internal.loader.URLClassPath$FileLoader.getResource(java.base@9-internal/URLClassPath.java:1039)
	at jdk.internal.loader.URLClassPath.getResource(java.base@9-internal/URLClassPath.java:216)
	at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:463)
	at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:460)
	at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
	at jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(java.base@9-internal/BuiltinClassLoader.java:459)
	at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@9-internal/BuiltinClassLoader.java:406)
	at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@9-internal/BuiltinClassLoader.java:364)
	at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@9-internal/ClassLoaders.java:185)
	at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:419)
	at WithSecurityManager.main(WithSecurityManager.java:51)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-internal/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@9-internal/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-internal/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(java.base@9-internal/Method.java:531)
	at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:110)
	at java.lang.Thread.run(java.base@9-internal/Thread.java:843)
Caused by: java.lang.invoke.StringConcatException: Generator failed
	at java.lang.invoke.StringConcatFactory.generate(java.base@9-internal/StringConcatFactory.java:732)
	at java.lang.invoke.StringConcatFactory.doStringConcat(java.base@9-internal/StringConcatFactory.java:637)
	at java.lang.invoke.StringConcatFactory.makeConcatWithConstants(java.base@9-internal/StringConcatFactory.java:552)
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:300)
	... 40 more
Caused by: java.lang.BootstrapMethodError: call site initialization exception
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:347)
	at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base@9-internal/MethodHandleNatives.java:250)
	at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base@9-internal/MethodHandleNatives.java:240)
	at WithSecurityManager$1.checkPermission(WithSecurityManager.java:47)
	at java.lang.SecurityManager.checkCreateClassLoader(java.base@9-internal/SecurityManager.java:603)
	at java.lang.ClassLoader.checkCreateClassLoader(java.base@9-internal/ClassLoader.java:334)
	at java.lang.ClassLoader.<init>(java.base@9-internal/ClassLoader.java:378)
	at java.lang.invoke.MethodHandles$LookupHelper$1.<init>(java.base@9-internal/MethodHandles.java:2193)
	at java.lang.invoke.MethodHandles$LookupHelper.createClass(java.base@9-internal/MethodHandles.java:2193)
	at java.lang.invoke.MethodHandles$LookupHelper.access$200(java.base@9-internal/MethodHandles.java:2177)
	at java.lang.invoke.MethodHandles$LookupHelper$2.run(java.base@9-internal/MethodHandles.java:2211)
	at java.lang.invoke.MethodHandles$LookupHelper$2.run(java.base@9-internal/MethodHandles.java:2209)
	at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
	at java.lang.invoke.MethodHandles$LookupHelper.<clinit>(java.base@9-internal/MethodHandles.java:2214)
	at java.lang.invoke.MethodHandles.publicLookup(java.base@9-internal/MethodHandles.java:140)
	at java.lang.invoke.StringConcatFactory$Stringifiers$1.apply(java.base@9-internal/StringConcatFactory.java:1740)
	at java.lang.invoke.StringConcatFactory$Stringifiers$1.apply(java.base@9-internal/StringConcatFactory.java:1737)
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@9-internal/ConcurrentHashMap.java:1716)
	at java.lang.invoke.StringConcatFactory$Stringifiers.forMost(java.base@9-internal/StringConcatFactory.java:1796)
	at java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy.generate(java.base@9-internal/StringConcatFactory.java:1494)
	at java.lang.invoke.StringConcatFactory.generate(java.base@9-internal/StringConcatFactory.java:727)
	... 43 more
Caused by: java.lang.invoke.StringConcatException: Generator failed
	at java.lang.invoke.StringConcatFactory.generate(java.base@9-internal/StringConcatFactory.java:732)
	at java.lang.invoke.StringConcatFactory.doStringConcat(java.base@9-internal/StringConcatFactory.java:637)
	at java.lang.invoke.StringConcatFactory.makeConcatWithConstants(java.base@9-internal/StringConcatFactory.java:552)
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:300)
	... 63 more
Caused by: java.lang.IllegalStateException: Recursive update
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@9-internal/ConcurrentHashMap.java:1767)
	at java.lang.invoke.StringConcatFactory$Stringifiers.forMost(java.base@9-internal/StringConcatFactory.java:1796)
	at java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy.generate(java.base@9-internal/StringConcatFactory.java:1494)
	at java.lang.invoke.StringConcatFactory.generate(java.base@9-internal/StringConcatFactory.java:727)
	... 66 more




Exception: java.lang.BootstrapMethodError thrown from the UncaughtExceptionHandler in thread "MainThread"
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:347)
	at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base@9-internal/MethodHandleNatives.java:250)
	at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base@9-internal/MethodHandleNatives.java:240)
	at WithSecurityManager$1.checkPermission(WithSecurityManager.java:47)
	at java.lang.SecurityManager.checkRead(java.base@9-internal/SecurityManager.java:880)
	at java.io.File.exists(java.base@9-internal/File.java:815)
	at jdk.internal.loader.URLClassPath$FileLoader.getResource(java.base@9-internal/URLClassPath.java:1039)
	at jdk.internal.loader.URLClassPath.getResource(java.base@9-internal/URLClassPath.java:216)
	at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:463)
	at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:460)
	at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
	at jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(java.base@9-internal/BuiltinClassLoader.java:459)
	at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@9-internal/BuiltinClassLoader.java:406)
	at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@9-internal/BuiltinClassLoader.java:364)
	at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@9-internal/ClassLoaders.java:185)
	at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:419)
	at com.sun.javatest.regtest.agent.MainWrapper.main(MainWrapper.java:81)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class java.lang.invoke.StringConcatFactory
	at java.lang.invoke.StringConcatFactory.makeConcatWithConstants(java.base@9-internal/StringConcatFactory.java:548)
	at java.lang.invoke.CallSite.makeSite(java.base@9-internal/CallSite.java:300)
	... 16 more


Comments
Actually, changing the transient strategy to BC_SB does only help during initial phases. If we try to run with MH_INLINE_SIZED_EXACT afterwards, we still fail with a circularity: during String concat linkage, we need to resolve MH.publicLookup() with an installed SM, which links up String concat, and thus doubles-back on SCF and MH.publicLookup resolution. Adding the same block in WithSecurityManager test makes test fail with that circularity. It would have manifested as StackOverflowError, but it is short-circuited earlier by CHM cache that detects recursive update in computeIfAbsent, that resolves the MHs in Stringifier cache. We have seen that in other java.lang.invoke uses, like JDK-8155659 and JDK-8156930.
07-06-2016

This passes the test: http://cr.openjdk.java.net/~shade/8158851/webrev.01/
07-06-2016

I think -limitmods java.base opens up the code path that brings the circularity in StringConcatFactory. The circularity unfolds like this: a) Very early after VM startup we try to load the class, which steps into checking the permissions in our custom string-concat-bearing SecurityManager; b) This forces the initialization of StringConcatFactory, which has to read properties in SCF::<clinit>, this doubles-back on the same SecurityManager (similar to JDK-8155090); c) After JDK-8155090 fix, SCF can proceed with producing *some* transient concat stub, and indeed it proceeds well into generating the stub; d) But, after JDK-8148604, SCF default policy is to use the MethodHandle-based strategy (MH_INLINE_SIZED_EXACT). This forces initialization of lazy CHM cache that holds MHs pointing to JDK "stringifier" methods, like String.valueOf; e) SCF stringifiers cache is empty at this point, and so the updater code is called via computeIfAbsent, which does the MethodHandle.Lookup.* lookup, which doubles back on installed SecurityManager; f) This circles back via (c)-(e) at SCF stringifier cache again, where computeIfAbsent detects a circular update and fails. The most probable answer is to make the transient strategy in JDK-8155090 a more simple one, e.g. BC_SB, to avoid the cycle
07-06-2016

Assigning for initial evaluation.
06-06-2016