JDK-7045594 : fix for 6977677 introduced a ResourceBundle race
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.logging
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-05-17
  • Updated: 2013-08-07
  • Resolved: 2011-07-06
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 8
8 b01Fixed
Related Reports
Relates :  
Relates :  
Description
Here's part of David's reply to my reply:

Right - the most likely thing to fail because of this is a test that
wants to see the IllegalArgumentException. Even then the test would
have to be deliberately attempting this via multiple threads - which
seems unlikely. A basic test of the form:

    getLogger("A", "foo");
    try {
       getLogger("A", "bar");
       fail();
    }
    catch (IllegalArgumentException iae) {
       // success
    }

will be ok.

The only other thing, I just checked, is whether two threads racing
to define the same logger will encounter a problem. Other than
consuming time unnecessarily it appears that findResourceBundle is
idempotent if called with the same bundle name. So this seems to be
safe as well (famous last words)
Here's part of my reply to David's sighting e-mail:

My gut says that this race is not that critical because
in a properly functioning system one of the threads would
get an IllegalArgumentException. Please let me know if
I'm misunderstanding what you're saying here...
The fix for the following bug:

    6977677 3/2 Deadlock on logging subsystem initialization

has introduced a race condition in ResourceBundle initialization.

Here's the sighting info from David H:

But this method now has a race condition:

 372     // Synchronization is not required here. All synchronization for
 373     // adding a new Logger object is handled by LogManager.addLogger().
 374     public static Logger getLogger(String name, String resourceBundleName) {
 375         LogManager manager = LogManager.getLogManager();
 376         Logger result = manager.demandLogger(name);
 377         if (result.resourceBundleName == null) {
 378             // Note: we may get a MissingResourceException here.
 379             result.setupResourceInfo(resourceBundleName);
 380         } else if (!result.resourceBundleName.equals(resourceBundleName)) {
 381             throw new IllegalArgumentException(result.resourceBundleName +
 382                                 " != " + resourceBundleName);
 383         }
 384         return result;
 385     }

Two threads calling this method with the same name but different resource bundle names can both see null at line 377 and install their different resource bundles. That section needs to be atomic.

Comments
EVALUATION http://hg.openjdk.java.net/jdk8/tl/jdk/rev/4a221501079a
02-06-2011

SUGGESTED FIX See the attached 7045594-webrev-cr0.tgz, 7045594-webrev-cr1.tgz, 7045594-webrev-cr2.tgz, and 7045594-webrev-cr3.tgz files for the proposed fix, test and test infrastructure as it went through Code Review Round 0 -> Round 3. Code Review Round 2 and Code Review Round 3 have links to the JavaDoc for the new test infrastructure.
01-06-2011

EVALUATION Here's part of my reply to Mandy's analysis e-mail: Basically move the sanity checking that it currently in getLogger(String, String) down into setupResourceInfo() where it's protected by the lock. Make sure that I don't change any of the implied semantics of getLogger(String, String) or Logger(String, String)...
17-05-2011

EVALUATION Here's Mandy's evaluation e-mail: The setupResourceInfo method synchronizes on this Logger instance. The resourceBundleName should only be set up to once or same resource bundle name. I think it should check if this.resourceBundleName is null or same as the given resourceBundleName; if not, throw IAE. The if-then-else in L377-383 above is no longer needed and can simply call result.setupResourceInfo(resourceBundleName).
17-05-2011