8002070: Remove the stack search for a resource bundle for Logger to use
The fragile, vulnerable, stack crawling has been eliminated from findResourceBundle(String) Reviewed-by: mchung, alanb
This commit is contained in:
parent
0bcb468549
commit
709f67b8f9
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2013, 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
|
||||
@ -26,10 +26,13 @@
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.security.*;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@ -104,7 +107,7 @@ import java.util.function.Supplier;
|
||||
* unnecessary message construction. For example, if the developer wants to
|
||||
* log system health status for diagnosis, with the String-accepting version,
|
||||
* the code would look like:
|
||||
<code><pre>
|
||||
<pre><code>
|
||||
|
||||
class DiagnosisMessages {
|
||||
static String systemHealthStatus() {
|
||||
@ -114,26 +117,20 @@ import java.util.function.Supplier;
|
||||
}
|
||||
...
|
||||
logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
|
||||
</pre></code>
|
||||
</code></pre>
|
||||
* With the above code, the health status is collected unnecessarily even when
|
||||
* the log level FINER is disabled. With the Supplier-accepting version as
|
||||
* below, the status will only be collected when the log level FINER is
|
||||
* enabled.
|
||||
<code><pre>
|
||||
<pre><code>
|
||||
|
||||
logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
|
||||
</pre></code>
|
||||
</code></pre>
|
||||
* <p>
|
||||
* When mapping ResourceBundle names to ResourceBundles, the Logger
|
||||
* will first try to use the Thread's ContextClassLoader. If that
|
||||
* is null it will try the SystemClassLoader instead. As a temporary
|
||||
* transition feature in the initial implementation, if the Logger is
|
||||
* unable to locate a ResourceBundle from the ContextClassLoader or
|
||||
* SystemClassLoader the Logger will also search up the class stack
|
||||
* and use successive calling ClassLoaders to try to locate a ResourceBundle.
|
||||
* (This call stack search is to allow containers to transition to
|
||||
* using ContextClassLoaders and is likely to be removed in future
|
||||
* versions.)
|
||||
* is null it will try the
|
||||
* {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader} instead.
|
||||
* <p>
|
||||
* Formatting (including localization) is the responsibility of
|
||||
* the output Handler, which will typically call a Formatter.
|
||||
@ -1541,12 +1538,16 @@ public class Logger {
|
||||
return useParentHandlers;
|
||||
}
|
||||
|
||||
// Private utility method to map a resource bundle name to an
|
||||
// actual resource bundle, using a simple one-entry cache.
|
||||
// Returns null for a null name.
|
||||
// May also return null if we can't find the resource bundle and
|
||||
// there is no suitable previous cached value.
|
||||
|
||||
/**
|
||||
* Private utility method to map a resource bundle name to an
|
||||
* actual resource bundle, using a simple one-entry cache.
|
||||
* Returns null for a null name.
|
||||
* May also return null if we can't find the resource bundle and
|
||||
* there is no suitable previous cached value.
|
||||
*
|
||||
* @param name the ResourceBundle to locate
|
||||
* @return ResourceBundle specified by name or null if not found
|
||||
*/
|
||||
private synchronized ResourceBundle findResourceBundle(String name) {
|
||||
// Return a null bundle for a null name.
|
||||
if (name == null) {
|
||||
@ -1556,13 +1557,13 @@ public class Logger {
|
||||
Locale currentLocale = Locale.getDefault();
|
||||
|
||||
// Normally we should hit on our simple one entry cache.
|
||||
if (catalog != null && currentLocale == catalogLocale
|
||||
&& name == catalogName) {
|
||||
if (catalog != null && currentLocale.equals(catalogLocale)
|
||||
&& name.equals(catalogName)) {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
// Use the thread's context ClassLoader. If there isn't one,
|
||||
// use the SystemClassloader.
|
||||
// Use the thread's context ClassLoader. If there isn't one, use the
|
||||
// {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl == null) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
@ -1573,45 +1574,8 @@ public class Logger {
|
||||
catalogLocale = currentLocale;
|
||||
return catalog;
|
||||
} catch (MissingResourceException ex) {
|
||||
// Woops. We can't find the ResourceBundle in the default
|
||||
// ClassLoader. Drop through.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Fall back to searching up the call stack and trying each
|
||||
// calling ClassLoader.
|
||||
for (int ix = 0; ; ix++) {
|
||||
Class clz = sun.reflect.Reflection.getCallerClass(ix);
|
||||
if (clz == null) {
|
||||
break;
|
||||
}
|
||||
ClassLoader cl2 = clz.getClassLoader();
|
||||
if (cl2 == null) {
|
||||
cl2 = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
if (cl == cl2) {
|
||||
// We've already checked this classloader.
|
||||
continue;
|
||||
}
|
||||
cl = cl2;
|
||||
try {
|
||||
catalog = ResourceBundle.getBundle(name, currentLocale, cl);
|
||||
catalogName = name;
|
||||
catalogLocale = currentLocale;
|
||||
return catalog;
|
||||
} catch (MissingResourceException ex) {
|
||||
// Ok, this one didn't work either.
|
||||
// Drop through, and try the next one.
|
||||
}
|
||||
}
|
||||
|
||||
if (name.equals(catalogName)) {
|
||||
// Return the previous cached value for that name.
|
||||
// This may be null.
|
||||
return catalog;
|
||||
}
|
||||
// Sorry, we're out of luck.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Private utility method to initialize our one entry
|
||||
@ -1638,8 +1602,7 @@ public class Logger {
|
||||
resourceBundleName + " != " + name);
|
||||
}
|
||||
|
||||
ResourceBundle rb = findResourceBundle(name);
|
||||
if (rb == null) {
|
||||
if (findResourceBundle(name) == null) {
|
||||
// We've failed to find an expected ResourceBundle.
|
||||
throw new MissingResourceException("Can't find " + name + " bundle", name, "");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2013, 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
|
||||
@ -23,13 +23,14 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7045594
|
||||
* @bug 7045594 8002070
|
||||
* @summary ResourceBundle setting race in Logger.getLogger(name, rbName)
|
||||
* @author Daniel D. Daugherty
|
||||
* @build RacingThreadsTest LoggerResourceBundleRace
|
||||
* @run main LoggerResourceBundleRace
|
||||
* @run main/othervm LoggerResourceBundleRace
|
||||
*
|
||||
* (In samevm mode, the bundle classes don't end up in the classpath.)
|
||||
*/
|
||||
|
||||
import java.util.ListResourceBundle;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
Loading…
x
Reference in New Issue
Block a user