From 75d33113d5c5b2f9ec09e46c129306e9ede96a58 Mon Sep 17 00:00:00 2001 From: Deepak Bhole Date: Feb 06 2013 20:11:23 +0000 Subject: Backed out 6664509 and 7201064.patch which cause regressions --- diff --git a/java-1.7.0-openjdk.spec b/java-1.7.0-openjdk.spec index 0622f1f..b1ad23c 100644 --- a/java-1.7.0-openjdk.spec +++ b/java-1.7.0-openjdk.spec @@ -153,7 +153,7 @@ Name: java-%{javaver}-%{origin} Version: %{javaver}.%{buildver} -Release: %{icedtea_version}%{?dist} +Release: %{icedtea_version}%{?dist}.1 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons, # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -424,6 +424,15 @@ Patch302: systemtap.patch # Rhino support Patch400: rhino-icedtea-2.1.1.patch +# Temporary patches +# Patches to reverse 2 2012-02-01 security update + +# Back out 6664509 which bnreaks custom log managers +Patch1000: sec-2013-02-01-6664509.patch + +# Back out 7201064 which breaks TCK +Patch1001: sec-2013-02-01-7201064.patch + BuildRequires: autoconf BuildRequires: automake BuildRequires: alsa-lib-devel @@ -675,6 +684,11 @@ for TP in $TMPPATCHES ; do fi; done ; +pushd openjdk/jdk/ +%patch1000 -p1 -R +%patch1001 -p1 -R +popd + # If bootstrapping, apply additional patches %if %{gcjbootstrap} @@ -1473,6 +1487,9 @@ exit 0 %doc %{buildoutputdir}/j2sdk-image/jre/LICENSE %changelog +* Wed Feb 06 2013 Deepak Bhole - 1.7.0.9-2.3.5.fc18.1 +- Backed out 6664509 and 7201064.patch which cause regressions + * Sun Feb 03 2013 Deepak Bhole - 1.7.0.9-2.3.5.fc18 - Updated to 2.3.5 - Removed unnecessary GENSRCDIR flag diff --git a/sec-2013-02-01-6664509.patch b/sec-2013-02-01-6664509.patch new file mode 100644 index 0000000..cd55ce7 --- /dev/null +++ b/sec-2013-02-01-6664509.patch @@ -0,0 +1,1365 @@ +# HG changeset patch +# User mchung +# Date 1353965537 28800 +# Node ID f26def552d2c4873aeaee00241f60efc462a11a7 +# Parent 6f9dde55bd49829cf41bd45b766780c2ec7e0bc1 +6664509: Add logging context +6664528: Find log level matching its name or value given at construction time +Reviewed-by: alanb, ahgross, jgish, hawtin + +diff --git a/src/share/classes/java/util/logging/Level.java b/src/share/classes/java/util/logging/Level.java +--- a/src/share/classes/java/util/logging/Level.java ++++ b/src/share/classes/java/util/logging/Level.java +@@ -24,6 +24,10 @@ + */ + + package java.util.logging; ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; + import java.util.ResourceBundle; + + /** +@@ -59,7 +63,6 @@ import java.util.ResourceBundle; + */ + + public class Level implements java.io.Serializable { +- private static java.util.ArrayList known = new java.util.ArrayList<>(); + private static String defaultBundle = "sun.util.logging.resources.logging"; + + /** +@@ -76,6 +79,9 @@ public class Level implements java.io.Se + * @serial The resource bundle name to be used in localizing the level name. + */ + private final String resourceBundleName; ++ ++ // localized level name ++ private String localizedLevelName; + + /** + * OFF is a special level that can be used to turn off logging. +@@ -202,9 +208,8 @@ public class Level implements java.io.Se + this.name = name; + this.value = value; + this.resourceBundleName = resourceBundleName; +- synchronized (Level.class) { +- known.add(this); +- } ++ this.localizedLevelName = resourceBundleName == null ? name : null; ++ KnownLevel.add(this); + } + + /** +@@ -236,12 +241,76 @@ public class Level implements java.io.Se + * @return localized name + */ + public String getLocalizedName() { ++ return getLocalizedLevelName(); ++ } ++ ++ // package-private getLevelName() is used by the implementation ++ // instead of getName() to avoid calling the subclass's version ++ final String getLevelName() { ++ return this.name; ++ } ++ ++ final synchronized String getLocalizedLevelName() { ++ if (localizedLevelName != null) { ++ return localizedLevelName; ++ } ++ + try { + ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName); +- return rb.getString(name); ++ localizedLevelName = rb.getString(name); + } catch (Exception ex) { +- return name; ++ localizedLevelName = name; + } ++ return localizedLevelName; ++ } ++ ++ // Returns a mirrored Level object that matches the given name as ++ // specified in the Level.parse method. Returns null if not found. ++ // ++ // It returns the same Level object as the one returned by Level.parse ++ // method if the given name is a non-localized name or integer. ++ // ++ // If the name is a localized name, findLevel and parse method may ++ // return a different level value if there is a custom Level subclass ++ // that overrides Level.getLocalizedName() to return a different string ++ // than what's returned by the default implementation. ++ // ++ static Level findLevel(String name) { ++ if (name == null) { ++ throw new NullPointerException(); ++ } ++ ++ KnownLevel level; ++ ++ // Look for a known Level with the given non-localized name. ++ level = KnownLevel.findByName(name); ++ if (level != null) { ++ return level.mirroredLevel; ++ } ++ ++ // Now, check if the given name is an integer. If so, ++ // first look for a Level with the given value and then ++ // if necessary create one. ++ try { ++ int x = Integer.parseInt(name); ++ level = KnownLevel.findByValue(x); ++ if (level == null) { ++ // add new Level ++ Level levelObject = new Level(name, x); ++ level = KnownLevel.findByValue(x); ++ } ++ return level.mirroredLevel; ++ } catch (NumberFormatException ex) { ++ // Not an integer. ++ // Drop through. ++ } ++ ++ level = KnownLevel.findByLocalizedLevelName(name); ++ if (level != null) { ++ return level.mirroredLevel; ++ } ++ ++ return null; + } + + /** +@@ -268,21 +337,15 @@ public class Level implements java.io.Se + // Serialization magic to prevent "doppelgangers". + // This is a performance optimization. + private Object readResolve() { +- synchronized (Level.class) { +- for (int i = 0; i < known.size(); i++) { +- Level other = known.get(i); +- if (this.name.equals(other.name) && this.value == other.value +- && (this.resourceBundleName == other.resourceBundleName || +- (this.resourceBundleName != null && +- this.resourceBundleName.equals(other.resourceBundleName)))) { +- return other; +- } +- } +- // Woops. Whoever sent us this object knows +- // about a new log level. Add it to our list. +- known.add(this); +- return this; ++ KnownLevel o = KnownLevel.matches(this); ++ if (o != null) { ++ return o.levelObject; + } ++ ++ // Woops. Whoever sent us this object knows ++ // about a new log level. Add it to our list. ++ Level level = new Level(this.name, this.value, this.resourceBundleName); ++ return level; + } + + /** +@@ -296,6 +359,7 @@ public class Level implements java.io.Se + *
  • "SEVERE" + *
  • "1000" + * ++ * + * @param name string to be parsed + * @throws NullPointerException if the name is null + * @throws IllegalArgumentException if the value is not valid. +@@ -315,12 +379,12 @@ public class Level implements java.io.Se + // Check that name is not null. + name.length(); + ++ KnownLevel level; ++ + // Look for a known Level with the given non-localized name. +- for (int i = 0; i < known.size(); i++) { +- Level l = known.get(i); +- if (name.equals(l.name)) { +- return l; +- } ++ level = KnownLevel.findByName(name); ++ if (level != null) { ++ return level.levelObject; + } + + // Now, check if the given name is an integer. If so, +@@ -328,14 +392,13 @@ public class Level implements java.io.Se + // if necessary create one. + try { + int x = Integer.parseInt(name); +- for (int i = 0; i < known.size(); i++) { +- Level l = known.get(i); +- if (l.value == x) { +- return l; +- } ++ level = KnownLevel.findByValue(x); ++ if (level == null) { ++ // add new Level ++ Level levelObject = new Level(name, x); ++ level = KnownLevel.findByValue(x); + } +- // Create a new Level. +- return new Level(name, x); ++ return level.levelObject; + } catch (NumberFormatException ex) { + // Not an integer. + // Drop through. +@@ -344,11 +407,9 @@ public class Level implements java.io.Se + // Finally, look for a known level with the given localized name, + // in the current default locale. + // This is relatively expensive, but not excessively so. +- for (int i = 0; i < known.size(); i++) { +- Level l = known.get(i); +- if (name.equals(l.getLocalizedName())) { +- return l; +- } ++ level = KnownLevel.findByLocalizedName(name); ++ if (level != null) { ++ return level.levelObject; + } + + // OK, we've tried everything and failed +@@ -375,4 +436,124 @@ public class Level implements java.io.Se + public int hashCode() { + return this.value; + } ++ ++ // KnownLevel class maintains the global list of all known levels. ++ // The API allows multiple custom Level instances of the same name/value ++ // be created. This class provides convenient methods to find a level ++ // by a given name, by a given value, or by a given localized name. ++ // ++ // KnownLevel wraps the following Level objects: ++ // 1. levelObject: standard Level object or custom Level object ++ // 2. mirroredLevel: Level object representing the level specified in the ++ // logging configuration. ++ // ++ // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods ++ // are non-final but the name and resource bundle name are parameters to ++ // the Level constructor. Use the mirroredLevel object instead of the ++ // levelObject to prevent the logging framework to execute foreign code ++ // implemented by untrusted Level subclass. ++ // ++ // Implementation Notes: ++ // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods ++ // were final, the following KnownLevel implementation can be removed. ++ // Future API change should take this into consideration. ++ static final class KnownLevel { ++ private static Map> nameToLevels = new HashMap<>(); ++ private static Map> intToLevels = new HashMap<>(); ++ final Level levelObject; // instance of Level class or Level subclass ++ final Level mirroredLevel; // instance of Level class ++ KnownLevel(Level l) { ++ this.levelObject = l; ++ if (l.getClass() == Level.class) { ++ this.mirroredLevel = l; ++ } else { ++ this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName); ++ } ++ } ++ ++ static synchronized void add(Level l) { ++ // the mirroredLevel object is always added to the list ++ // before the custom Level instance ++ KnownLevel o = new KnownLevel(l); ++ List list = nameToLevels.get(l.name); ++ if (list == null) { ++ list = new ArrayList<>(); ++ nameToLevels.put(l.name, list); ++ } ++ list.add(o); ++ ++ list = intToLevels.get(l.value); ++ if (list == null) { ++ list = new ArrayList<>(); ++ intToLevels.put(l.value, list); ++ } ++ list.add(o); ++ } ++ ++ // Returns a KnownLevel with the given non-localized name. ++ static synchronized KnownLevel findByName(String name) { ++ List list = nameToLevels.get(name); ++ if (list != null) { ++ return list.get(0); ++ } ++ return null; ++ } ++ ++ // Returns a KnownLevel with the given value. ++ static synchronized KnownLevel findByValue(int value) { ++ List list = intToLevels.get(value); ++ if (list != null) { ++ return list.get(0); ++ } ++ return null; ++ } ++ ++ // Returns a KnownLevel with the given localized name matching ++ // by calling the Level.getLocalizedLevelName() method (i.e. found ++ // from the resourceBundle associated with the Level object). ++ // This method does not call Level.getLocalizedName() that may ++ // be overridden in a subclass implementation ++ static synchronized KnownLevel findByLocalizedLevelName(String name) { ++ for (List levels : nameToLevels.values()) { ++ for (KnownLevel l : levels) { ++ String lname = l.levelObject.getLocalizedLevelName(); ++ if (name.equals(lname)) { ++ return l; ++ } ++ } ++ } ++ return null; ++ } ++ ++ // Returns a KnownLevel with the given localized name matching ++ // by calling the Level.getLocalizedName() method ++ static synchronized KnownLevel findByLocalizedName(String name) { ++ for (List levels : nameToLevels.values()) { ++ for (KnownLevel l : levels) { ++ String lname = l.levelObject.getLocalizedName(); ++ if (name.equals(lname)) { ++ return l; ++ } ++ } ++ } ++ return null; ++ } ++ ++ static synchronized KnownLevel matches(Level l) { ++ List list = nameToLevels.get(l.name); ++ if (list != null) { ++ for (KnownLevel level : list) { ++ Level other = level.mirroredLevel; ++ if (l.value == other.value && ++ (l.resourceBundleName == other.resourceBundleName || ++ (l.resourceBundleName != null && ++ l.resourceBundleName.equals(other.resourceBundleName)))) { ++ return level; ++ } ++ } ++ } ++ return null; ++ } ++ } ++ + } +diff --git a/src/share/classes/java/util/logging/LogManager.java b/src/share/classes/java/util/logging/LogManager.java +--- a/src/share/classes/java/util/logging/LogManager.java ++++ b/src/share/classes/java/util/logging/LogManager.java +@@ -34,6 +34,8 @@ import java.beans.PropertyChangeListener + import java.beans.PropertyChangeListener; + import java.beans.PropertyChangeSupport; + import java.net.URL; ++import sun.misc.JavaAWTAccess; ++import sun.misc.SharedSecrets; + import sun.security.action.GetPropertyAction; + + /** +@@ -155,10 +157,9 @@ public class LogManager { + = new PropertyChangeSupport(LogManager.class); + private final static Level defaultLevel = Level.INFO; + +- // Table of named Loggers that maps names to Loggers. +- private Hashtable namedLoggers = new Hashtable<>(); +- // Tree of named Loggers +- private LogNode root = new LogNode(null); ++ // LoggerContext for system loggers and user loggers ++ private final LoggerContext systemContext = new SystemLoggerContext(); ++ private final LoggerContext userContext = new UserLoggerContext(); + private Logger rootLogger; + + // Have we done the primordial reading of the configuration file? +@@ -196,12 +197,13 @@ public class LogManager { + + // Create and retain Logger for the root of the namespace. + manager.rootLogger = manager.new RootLogger(); +- manager.addLogger(manager.rootLogger); ++ manager.systemContext.addLogger(manager.rootLogger); ++ manager.userContext.addLogger(manager.rootLogger); + + // Adding the global Logger. Doing so in the Logger. + // would deadlock with the LogManager.. + Logger.global.setLogManager(manager); +- manager.addLogger(Logger.global); ++ manager.systemContext.addLogger(Logger.global); + + // We don't call readConfiguration() here, as we may be running + // very early in the JVM startup sequence. Instead readConfiguration +@@ -279,14 +281,14 @@ public class LogManager { + return; + } + readPrimordialConfiguration = true; ++ + try { +- AccessController.doPrivileged(new PrivilegedExceptionAction() { +- public Object run() throws Exception { ++ AccessController.doPrivileged(new PrivilegedExceptionAction() { ++ public Void run() throws Exception { + readConfiguration(); + + // Platform loggers begin to delegate to java.util.logging.Logger + sun.util.logging.PlatformLogger.redirectPlatformLoggers(); +- + return null; + } + }); +@@ -337,62 +339,290 @@ public class LogManager { + changes.removePropertyChangeListener(l); + } + +- // Package-level method. +- // Find or create a specified logger instance. If a logger has +- // already been created with the given name it is returned. +- // Otherwise a new logger instance is created and registered +- // in the LogManager global namespace. ++ // Returns the LoggerContext for the user code (i.e. application or AppContext). ++ // Loggers are isolated from each AppContext. ++ LoggerContext getUserContext() { ++ LoggerContext context = null; + +- // This method will always return a non-null Logger object. +- // Synchronization is not required here. All synchronization for +- // adding a new Logger object is handled by addLogger(). +- Logger demandLogger(String name) { +- Logger result = getLogger(name); +- if (result == null) { +- // only allocate the new logger once +- Logger newLogger = new Logger(name, null); +- do { +- if (addLogger(newLogger)) { +- // We successfully added the new Logger that we +- // created above so return it without refetching. +- return newLogger; ++ SecurityManager sm = System.getSecurityManager(); ++ JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess(); ++ if (sm != null && javaAwtAccess != null) { ++ synchronized (javaAwtAccess) { ++ // AppContext.getAppContext() returns the system AppContext if called ++ // from a system thread but Logger.getLogger might be called from ++ // an applet code. Instead, find the AppContext of the applet code ++ // from the execution stack. ++ Object ecx = javaAwtAccess.getExecutionContext(); ++ if (ecx == null) { ++ // fall back to AppContext.getAppContext() ++ ecx = javaAwtAccess.getContext(); + } +- +- // We didn't add the new Logger that we created above +- // because another thread added a Logger with the same +- // name after our null check above and before our call +- // to addLogger(). We have to refetch the Logger because +- // addLogger() returns a boolean instead of the Logger +- // reference itself. However, if the thread that created +- // the other Logger is not holding a strong reference to +- // the other Logger, then it is possible for the other +- // Logger to be GC'ed after we saw it in addLogger() and +- // before we can refetch it. If it has been GC'ed then +- // we'll just loop around and try again. +- result = getLogger(name); +- } while (result == null); ++ context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); ++ if (context == null) { ++ if (javaAwtAccess.isMainAppContext()) { ++ context = userContext; ++ } else { ++ context = new UserLoggerContext(); ++ context.addLogger(manager.rootLogger); ++ } ++ javaAwtAccess.put(ecx, LoggerContext.class, context); ++ } ++ } ++ } else { ++ context = userContext; + } +- return result; ++ return context; + } + +- // If logger.getUseParentHandlers() returns 'true' and any of the logger's +- // parents have levels or handlers defined, make sure they are instantiated. +- private void processParentHandlers(Logger logger, String name) { +- int ix = 1; +- for (;;) { +- int ix2 = name.indexOf(".", ix); +- if (ix2 < 0) { +- break; ++ LoggerContext getSystemContext() { ++ return systemContext; ++ } ++ ++ private List contexts() { ++ List cxs = new ArrayList<>(); ++ cxs.add(systemContext); ++ cxs.add(getUserContext()); ++ return cxs; ++ } ++ ++ static class LoggerContext { ++ // Table of named Loggers that maps names to Loggers. ++ private final Hashtable namedLoggers = new Hashtable<>(); ++ // Tree of named Loggers ++ private final LogNode root; ++ ++ private LoggerContext() { ++ this.root = new LogNode(null, this); ++ } ++ ++ synchronized Logger findLogger(String name) { ++ LoggerWeakRef ref = namedLoggers.get(name); ++ if (ref == null) { ++ return null; + } +- String pname = name.substring(0,ix2); ++ Logger logger = ref.get(); ++ if (logger == null) { ++ // Hashtable holds stale weak reference ++ // to a logger which has been GC-ed. ++ removeLogger(name); ++ } ++ return logger; ++ } + +- if (getProperty(pname+".level") != null || +- getProperty(pname+".handlers") != null) { +- // This pname has a level/handlers definition. +- // Make sure it exists. +- demandLogger(pname); ++ synchronized boolean addLogger(Logger logger) { ++ final String name = logger.getName(); ++ if (name == null) { ++ throw new NullPointerException(); + } +- ix = ix2+1; ++ ++ // cleanup some Loggers that have been GC'ed ++ manager.drainLoggerRefQueueBounded(); ++ ++ LoggerWeakRef ref = namedLoggers.get(name); ++ if (ref != null) { ++ if (ref.get() == null) { ++ // It's possible that the Logger was GC'ed after the ++ // drainLoggerRefQueueBounded() call above so allow ++ // a new one to be registered. ++ removeLogger(name); ++ } else { ++ // We already have a registered logger with the given name. ++ return false; ++ } ++ } ++ ++ // We're adding a new logger. ++ // Note that we are creating a weak reference here. ++ ref = manager.new LoggerWeakRef(logger); ++ namedLoggers.put(name, ref); ++ ++ // Apply any initial level defined for the new logger. ++ Level level = manager.getLevelProperty(name + ".level", null); ++ if (level != null) { ++ doSetLevel(logger, level); ++ } ++ ++ // Do we have a per logger handler too? ++ // Note: this will add a 200ms penalty ++ manager.loadLoggerHandlers(logger, name, name + ".handlers"); ++ processParentHandlers(logger, name); ++ ++ // Find the new node and its parent. ++ LogNode node = getNode(name); ++ node.loggerRef = ref; ++ Logger parent = null; ++ LogNode nodep = node.parent; ++ while (nodep != null) { ++ LoggerWeakRef nodeRef = nodep.loggerRef; ++ if (nodeRef != null) { ++ parent = nodeRef.get(); ++ if (parent != null) { ++ break; ++ } ++ } ++ nodep = nodep.parent; ++ } ++ ++ if (parent != null) { ++ doSetParent(logger, parent); ++ } ++ // Walk over the children and tell them we are their new parent. ++ node.walkAndSetParent(logger); ++ // new LogNode is ready so tell the LoggerWeakRef about it ++ ref.setNode(node); ++ return true; ++ } ++ ++ void removeLogger(String name) { ++ namedLoggers.remove(name); ++ } ++ ++ synchronized Enumeration getLoggerNames() { ++ return namedLoggers.keys(); ++ } ++ ++ Logger demandLogger(String name) { ++ return demandLogger(name, null); ++ } ++ ++ // Find or create a specified logger instance. If a logger has ++ // already been created with the given name it is returned. ++ // Otherwise a new logger instance is created and registered ++ // in the LogManager global namespace. ++ ++ // This method will always return a non-null Logger object. ++ // Synchronization is not required here. All synchronization for ++ // adding a new Logger object is handled by addLogger(). ++ Logger demandLogger(String name, String resourceBundleName) { ++ Logger result = findLogger(name); ++ if (result == null) { ++ // only allocate the new logger once ++ Logger newLogger = new Logger(name, resourceBundleName); ++ do { ++ if (addLogger(newLogger)) { ++ // We successfully added the new Logger that we ++ // created above so return it without refetching. ++ return newLogger; ++ } ++ ++ // We didn't add the new Logger that we created above ++ // because another thread added a Logger with the same ++ // name after our null check above and before our call ++ // to addLogger(). We have to refetch the Logger because ++ // addLogger() returns a boolean instead of the Logger ++ // reference itself. However, if the thread that created ++ // the other Logger is not holding a strong reference to ++ // the other Logger, then it is possible for the other ++ // Logger to be GC'ed after we saw it in addLogger() and ++ // before we can refetch it. If it has been GC'ed then ++ // we'll just loop around and try again. ++ result = findLogger(name); ++ } while (result == null); ++ } ++ return result; ++ } ++ ++ // If logger.getUseParentHandlers() returns 'true' and any of the logger's ++ // parents have levels or handlers defined, make sure they are instantiated. ++ private void processParentHandlers(Logger logger, String name) { ++ int ix = 1; ++ for (;;) { ++ int ix2 = name.indexOf(".", ix); ++ if (ix2 < 0) { ++ break; ++ } ++ String pname = name.substring(0, ix2); ++ ++ if (manager.getProperty(pname + ".level") != null || ++ manager.getProperty(pname + ".handlers") != null) { ++ // This pname has a level/handlers definition. ++ // Make sure it exists. ++ demandLogger(pname); ++ } ++ ix = ix2+1; ++ } ++ } ++ ++ // Gets a node in our tree of logger nodes. ++ // If necessary, create it. ++ LogNode getNode(String name) { ++ if (name == null || name.equals("")) { ++ return root; ++ } ++ LogNode node = root; ++ while (name.length() > 0) { ++ int ix = name.indexOf("."); ++ String head; ++ if (ix > 0) { ++ head = name.substring(0, ix); ++ name = name.substring(ix + 1); ++ } else { ++ head = name; ++ name = ""; ++ } ++ if (node.children == null) { ++ node.children = new HashMap<>(); ++ } ++ LogNode child = node.children.get(head); ++ if (child == null) { ++ child = new LogNode(node, this); ++ node.children.put(head, child); ++ } ++ node = child; ++ } ++ return node; ++ } ++ } ++ ++ static class SystemLoggerContext extends LoggerContext { ++ // Default resource bundle for all system loggers ++ Logger demandLogger(String name) { ++ // default to use the system logger's resource bundle ++ return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); ++ } ++ } ++ ++ static class UserLoggerContext extends LoggerContext { ++ /** ++ * Returns a Logger of the given name if there is one registered ++ * in this context. Otherwise, it will return the one registered ++ * in the system context if there is one. The returned Logger ++ * instance may be initialized with a different resourceBundleName. ++ * If no such logger exists, a new Logger instance will be created ++ * and registered in this context. ++ */ ++ Logger demandLogger(String name, String resourceBundleName) { ++ Logger result = findLogger(name); ++ if (result == null) { ++ // use the system logger if exists; or allocate a new logger. ++ // The system logger is added to the app logger context so that ++ // any child logger created in the app logger context can have ++ // a system logger as its parent if already exist. ++ Logger logger = manager.systemContext.findLogger(name); ++ Logger newLogger = ++ logger != null ? logger : new Logger(name, resourceBundleName); ++ do { ++ if (addLogger(newLogger)) { ++ // We successfully added the new Logger that we ++ // created above so return it without refetching. ++ return newLogger; ++ } ++ ++ // We didn't add the new Logger that we created above ++ // because another thread added a Logger with the same ++ // name after our null check above and before our call ++ // to addLogger(). We have to refetch the Logger because ++ // addLogger() returns a boolean instead of the Logger ++ // reference itself. However, if the thread that created ++ // the other Logger is not holding a strong reference to ++ // the other Logger, then it is possible for the other ++ // Logger to be GC'ed after we saw it in addLogger() and ++ // before we can refetch it. If it has been GC'ed then ++ // we'll just loop around and try again. ++ result = findLogger(name); ++ } while (result == null); ++ } ++ return result; + } + } + +@@ -415,18 +645,19 @@ public class LogManager { + for (int i = 0; i < names.length; i++) { + String word = names[i]; + try { +- Class clz = ClassLoader.getSystemClassLoader().loadClass(word); +- Handler hdl = (Handler) clz.newInstance(); +- try { +- // Check if there is a property defining the +- // this handler's level. +- String levs = getProperty(word + ".level"); +- if (levs != null) { +- hdl.setLevel(Level.parse(levs)); ++ Class clz = ClassLoader.getSystemClassLoader().loadClass(word); ++ Handler hdl = (Handler) clz.newInstance(); ++ // Check if there is a property defining the ++ // this handler's level. ++ String levs = getProperty(word + ".level"); ++ if (levs != null) { ++ Level l = Level.findLevel(levs); ++ if (l != null) { ++ hdl.setLevel(l); ++ } else { ++ // Probably a bad level. Drop through. ++ System.err.println("Can't set level for " + word); + } +- } catch (Exception ex) { +- System.err.println("Can't set level for " + word); +- // Probably a bad level. Drop through. + } + // Add this Handler to the logger + logger.addHandler(hdl); +@@ -482,7 +713,7 @@ public class LogManager { + if (node != null) { + // if we have a LogNode, then we were a named Logger + // so clear namedLoggers weak ref to us +- manager.namedLoggers.remove(name); ++ node.context.removeLogger(name); + name = null; // clear our ref to the Logger's name + + node.loggerRef = null; // clear LogNode's weak ref to us +@@ -571,70 +802,15 @@ public class LogManager { + * false if a logger of that name already exists. + * @exception NullPointerException if the logger name is null. + */ +- public synchronized boolean addLogger(Logger logger) { ++ public boolean addLogger(Logger logger) { + final String name = logger.getName(); + if (name == null) { + throw new NullPointerException(); + } +- +- // cleanup some Loggers that have been GC'ed +- drainLoggerRefQueueBounded(); +- +- LoggerWeakRef ref = namedLoggers.get(name); +- if (ref != null) { +- if (ref.get() == null) { +- // It's possible that the Logger was GC'ed after the +- // drainLoggerRefQueueBounded() call above so allow +- // a new one to be registered. +- namedLoggers.remove(name); +- } else { +- // We already have a registered logger with the given name. +- return false; +- } ++ if (systemContext.findLogger(name) != null) { ++ return false; + } +- +- // We're adding a new logger. +- // Note that we are creating a weak reference here. +- ref = new LoggerWeakRef(logger); +- namedLoggers.put(name, ref); +- +- // Apply any initial level defined for the new logger. +- Level level = getLevelProperty(name+".level", null); +- if (level != null) { +- doSetLevel(logger, level); +- } +- +- // Do we have a per logger handler too? +- // Note: this will add a 200ms penalty +- loadLoggerHandlers(logger, name, name+".handlers"); +- processParentHandlers(logger, name); +- +- // Find the new node and its parent. +- LogNode node = findNode(name); +- node.loggerRef = ref; +- Logger parent = null; +- LogNode nodep = node.parent; +- while (nodep != null) { +- LoggerWeakRef nodeRef = nodep.loggerRef; +- if (nodeRef != null) { +- parent = nodeRef.get(); +- if (parent != null) { +- break; +- } +- } +- nodep = nodep.parent; +- } +- +- if (parent != null) { +- doSetParent(logger, parent); +- } +- // Walk over the children and tell them we are their new parent. +- node.walkAndSetParent(logger); +- +- // new LogNode is ready so tell the LoggerWeakRef about it +- ref.setNode(node); +- +- return true; ++ return getUserContext().addLogger(logger); + } + + +@@ -676,36 +852,6 @@ public class LogManager { + }}); + } + +- // Find a node in our tree of logger nodes. +- // If necessary, create it. +- private LogNode findNode(String name) { +- if (name == null || name.equals("")) { +- return root; +- } +- LogNode node = root; +- while (name.length() > 0) { +- int ix = name.indexOf("."); +- String head; +- if (ix > 0) { +- head = name.substring(0,ix); +- name = name.substring(ix+1); +- } else { +- head = name; +- name = ""; +- } +- if (node.children == null) { +- node.children = new HashMap<>(); +- } +- LogNode child = node.children.get(head); +- if (child == null) { +- child = new LogNode(node); +- node.children.put(head, child); +- } +- node = child; +- } +- return node; +- } +- + /** + * Method to find a named logger. + *

    +@@ -721,18 +867,16 @@ public class LogManager { + * @param name name of the logger + * @return matching logger or null if none is found + */ +- public synchronized Logger getLogger(String name) { +- LoggerWeakRef ref = namedLoggers.get(name); +- if (ref == null) { +- return null; +- } +- Logger logger = ref.get(); +- if (logger == null) { +- // Hashtable holds stale weak reference +- // to a logger which has been GC-ed. +- namedLoggers.remove(name); +- } +- return logger; ++ public Logger getLogger(String name) { ++ // return the first logger added ++ // ++ // once a system logger is added in the system context, no one can ++ // adds a logger with the same name in the global context ++ // (see LogManager.addLogger). So if there is a logger in the global ++ // context with the same name as one in the system context, it must be ++ // added before the system logger was created. ++ Logger logger = getUserContext().findLogger(name); ++ return logger != null ? logger : systemContext.findLogger(name); + } + + /** +@@ -751,8 +895,11 @@ public class LogManager { + *

    + * @return enumeration of logger name strings + */ +- public synchronized Enumeration getLoggerNames() { +- return namedLoggers.keys(); ++ public Enumeration getLoggerNames() { ++ // only return unique names ++ Set names = new HashSet<>(Collections.list(systemContext.getLoggerNames())); ++ names.addAll(Collections.list(getUserContext().getLoggerNames())); ++ return Collections.enumeration(names); + } + + /** +@@ -837,20 +984,20 @@ public class LogManager { + // the global handlers, if they haven't been initialized yet. + initializedGlobalHandlers = true; + } +- Enumeration enum_ = getLoggerNames(); +- while (enum_.hasMoreElements()) { +- String name = (String)enum_.nextElement(); +- resetLogger(name); ++ for (LoggerContext cx : contexts()) { ++ Enumeration enum_ = cx.getLoggerNames(); ++ while (enum_.hasMoreElements()) { ++ String name = enum_.nextElement(); ++ Logger logger = cx.findLogger(name); ++ if (logger != null) { ++ resetLogger(logger); ++ } ++ } + } + } + +- + // Private method to reset an individual target logger. +- private void resetLogger(String name) { +- Logger logger = getLogger(name); +- if (logger == null) { +- return; +- } ++ private void resetLogger(Logger logger) { + // Close all the Logger's handlers. + Handler[] targets = logger.getHandlers(); + for (int i = 0; i < targets.length; i++) { +@@ -862,6 +1009,7 @@ public class LogManager { + // Problems closing a handler? Keep going... + } + } ++ String name = logger.getName(); + if (name != null && name.equals("")) { + // This is the root logger. + logger.setLevel(defaultLevel); +@@ -1009,11 +1157,8 @@ public class LogManager { + if (val == null) { + return defaultValue; + } +- try { +- return Level.parse(val.trim()); +- } catch (Exception ex) { +- return defaultValue; +- } ++ Level l = Level.findLevel(val.trim()); ++ return l != null ? l : defaultValue; + } + + // Package private method to get a filter property. +@@ -1104,9 +1249,11 @@ public class LogManager { + HashMap children; + LoggerWeakRef loggerRef; + LogNode parent; ++ final LoggerContext context; + +- LogNode(LogNode parent) { ++ LogNode(LogNode parent, LoggerContext context) { + this.parent = parent; ++ this.context = context; + } + + // Recursive method to walk the tree below a node and set +@@ -1165,7 +1312,7 @@ public class LogManager { + // Private method to be called when the configuration has + // changed to apply any level settings to any pre-existing loggers. + synchronized private void setLevelsOnExistingLoggers() { +- Enumeration enum_ = props.propertyNames(); ++ Enumeration enum_ = props.propertyNames(); + while (enum_.hasMoreElements()) { + String key = (String)enum_.nextElement(); + if (!key.endsWith(".level")) { +@@ -1179,11 +1326,13 @@ public class LogManager { + System.err.println("Bad level value for property: " + key); + continue; + } +- Logger l = getLogger(name); +- if (l == null) { +- continue; ++ for (LoggerContext cx : contexts()) { ++ Logger l = cx.findLogger(name); ++ if (l == null) { ++ continue; ++ } ++ l.setLevel(level); + } +- l.setLevel(level); + } + } + +diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java +--- a/src/share/classes/java/util/logging/Logger.java ++++ b/src/share/classes/java/util/logging/Logger.java +@@ -30,6 +30,7 @@ import java.util.concurrent.CopyOnWriteA + import java.util.concurrent.CopyOnWriteArrayList; + import java.security.*; + import java.lang.ref.WeakReference; ++import java.util.logging.LogManager.LoggerContext; + + /** + * A Logger object is used to log messages for a specific +@@ -283,6 +284,26 @@ public class Logger { + } + } + ++ // Until all JDK code converted to call sun.util.logging.PlatformLogger ++ // (see 7054233), we need to determine if Logger.getLogger is to add ++ // a system logger or user logger. ++ // ++ // As an interim solution, if the immediate caller whose caller loader is ++ // null, we assume it's a system logger and add it to the system context. ++ private static LoggerContext getLoggerContext() { ++ LogManager manager = LogManager.getLogManager(); ++ SecurityManager sm = System.getSecurityManager(); ++ if (sm != null) { ++ // 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller ++ final int SKIP_FRAMES = 3; ++ Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); ++ if (caller.getClassLoader() == null) { ++ return manager.getSystemContext(); ++ } ++ } ++ return manager.getUserContext(); ++ } ++ + /** + * Find or create a logger for a named subsystem. If a logger has + * already been created with the given name it is returned. Otherwise +@@ -324,8 +345,8 @@ public class Logger { + // would throw an IllegalArgumentException in the second call + // because the wrapper would result in an attempt to replace + // the existing "resourceBundleForFoo" with null. +- LogManager manager = LogManager.getLogManager(); +- return manager.demandLogger(name); ++ LoggerContext context = getLoggerContext(); ++ return context.demandLogger(name); + } + + /** +@@ -372,8 +393,8 @@ public class Logger { + // Synchronization is not required here. All synchronization for + // adding a new Logger object is handled by LogManager.addLogger(). + public static Logger getLogger(String name, String resourceBundleName) { +- LogManager manager = LogManager.getLogManager(); +- Logger result = manager.demandLogger(name); ++ LoggerContext context = getLoggerContext(); ++ Logger result = context.demandLogger(name, resourceBundleName); + if (result.resourceBundleName == null) { + // Note: we may get a MissingResourceException here. + result.setupResourceInfo(resourceBundleName); +@@ -384,6 +405,18 @@ public class Logger { + return result; + } + ++ // package-private ++ // Add a platform logger to the system context. ++ // i.e. caller of sun.util.logging.PlatformLogger.getLogger ++ static Logger getPlatformLogger(String name) { ++ LogManager manager = LogManager.getLogManager(); ++ LoggerContext context = manager.getSystemContext(); ++ ++ // all loggers in the system context will default to ++ // the system logger's resource bundle ++ Logger result = context.demandLogger(name); ++ return result; ++ } + + /** + * Create an anonymous Logger. The newly created Logger is not +@@ -536,7 +569,7 @@ public class Logger { + private void doLog(LogRecord lr) { + lr.setLoggerName(name); + String ebname = getEffectiveResourceBundleName(); +- if (ebname != null) { ++ if (ebname != null && !ebname.equals(SYSTEM_LOGGER_RB_NAME)) { + lr.setResourceBundleName(ebname); + lr.setResourceBundle(findResourceBundle(ebname)); + } +@@ -1285,6 +1318,22 @@ public class Logger { + // May also return null if we can't find the resource bundle and + // there is no suitable previous cached value. + ++ static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; ++ ++ private static ResourceBundle findSystemResourceBundle(final Locale locale) { ++ // the resource bundle is in a restricted package ++ return AccessController.doPrivileged(new PrivilegedAction() { ++ public ResourceBundle run() { ++ try { ++ return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, ++ locale); ++ } catch (MissingResourceException e) { ++ throw new InternalError(e.toString()); ++ } ++ } ++ }); ++ } ++ + private synchronized ResourceBundle findResourceBundle(String name) { + // Return a null bundle for a null name. + if (name == null) { +@@ -1296,6 +1345,13 @@ public class Logger { + // Normally we should hit on our simple one entry cache. + if (catalog != null && currentLocale == catalogLocale + && name == catalogName) { ++ return catalog; ++ } ++ ++ if (name.equals(SYSTEM_LOGGER_RB_NAME)) { ++ catalog = findSystemResourceBundle(currentLocale); ++ catalogName = name; ++ catalogLocale = currentLocale; + return catalog; + } + +@@ -1314,7 +1370,6 @@ public class Logger { + // Woops. We can't find the ResourceBundle in the default + // ClassLoader. Drop through. + } +- + + // Fall back to searching up the call stack and trying each + // calling ClassLoader. +diff --git a/src/share/classes/java/util/logging/Logging.java b/src/share/classes/java/util/logging/Logging.java +--- a/src/share/classes/java/util/logging/Logging.java ++++ b/src/share/classes/java/util/logging/Logging.java +@@ -34,15 +34,15 @@ import java.util.ArrayList; + * + * The LoggingMXBean interface provides a standard + * method for management access to the individual +- * java.util.Logger objects available at runtime. ++ * {@code Logger} objects available at runtime. + * + * @author Ron Mann + * @author Mandy Chung + * @since 1.5 + * + * @see javax.management +- * @see java.util.Logger +- * @see java.util.LogManager ++ * @see Logger ++ * @see LogManager + */ + class Logging implements LoggingMXBean { + +@@ -75,7 +75,7 @@ class Logging implements LoggingMXBean { + if (level == null) { + return EMPTY_STRING; + } else { +- return level.getName(); ++ return level.getLevelName(); + } + } + +@@ -85,7 +85,6 @@ class Logging implements LoggingMXBean { + } + + Logger logger = logManager.getLogger(loggerName); +- + if (logger == null) { + throw new IllegalArgumentException("Logger " + loggerName + + "does not exist"); +@@ -94,7 +93,10 @@ class Logging implements LoggingMXBean { + Level level = null; + if (levelName != null) { + // parse will throw IAE if logLevel is invalid +- level = Level.parse(levelName); ++ level = Level.findLevel(levelName); ++ if (level == null) { ++ throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); ++ } + } + + logger.setLevel(level); +diff --git a/src/share/classes/java/util/logging/LoggingProxyImpl.java b/src/share/classes/java/util/logging/LoggingProxyImpl.java +--- a/src/share/classes/java/util/logging/LoggingProxyImpl.java ++++ b/src/share/classes/java/util/logging/LoggingProxyImpl.java +@@ -37,7 +37,8 @@ class LoggingProxyImpl implements Loggin + + @Override + public Object getLogger(String name) { +- return Logger.getLogger(name); ++ // always create a platform logger with the resource bundle name ++ return Logger.getPlatformLogger(name); + } + + @Override +@@ -92,12 +93,16 @@ class LoggingProxyImpl implements Loggin + + @Override + public Object parseLevel(String levelName) { +- return Level.parse(levelName); ++ Level level = Level.findLevel(levelName); ++ if (level == null) { ++ throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); ++ } ++ return level; + } + + @Override + public String getLevelName(Object level) { +- return ((Level) level).getName(); ++ return ((Level) level).getLevelName(); + } + + @Override +diff --git a/src/share/classes/java/util/logging/SimpleFormatter.java b/src/share/classes/java/util/logging/SimpleFormatter.java +--- a/src/share/classes/java/util/logging/SimpleFormatter.java ++++ b/src/share/classes/java/util/logging/SimpleFormatter.java +@@ -162,7 +162,7 @@ public class SimpleFormatter extends For + dat, + source, + record.getLoggerName(), +- record.getLevel().getLocalizedName(), ++ record.getLevel().getLocalizedLevelName(), + message, + throwable); + } +diff --git a/src/share/classes/sun/awt/AppContext.java b/src/share/classes/sun/awt/AppContext.java +--- a/src/share/classes/sun/awt/AppContext.java ++++ b/src/share/classes/sun/awt/AppContext.java +@@ -327,19 +327,25 @@ public final class AppContext { + // Before we return the main "system" AppContext, check to + // see if there's an AWTSecurityManager installed. If so, + // allow it to choose the AppContext to return. +- SecurityManager securityManager = System.getSecurityManager(); +- if ((securityManager != null) && +- (securityManager instanceof AWTSecurityManager)) +- { +- AWTSecurityManager awtSecMgr = (AWTSecurityManager)securityManager; +- AppContext secAppContext = awtSecMgr.getAppContext(); +- if (secAppContext != null) { +- appContext = secAppContext; // Return what we're told +- } ++ AppContext secAppContext = getExecutionAppContext(); ++ if (secAppContext != null) { ++ appContext = secAppContext; // Return what we're told + } + } + + return appContext; ++ } ++ ++ private final static AppContext getExecutionAppContext() { ++ SecurityManager securityManager = System.getSecurityManager(); ++ if ((securityManager != null) && ++ (securityManager instanceof AWTSecurityManager)) ++ { ++ AWTSecurityManager awtSecMgr = (AWTSecurityManager) securityManager; ++ AppContext secAppContext = awtSecMgr.getAppContext(); ++ return secAppContext; // Return what we're told ++ } ++ return null; + } + + /** +@@ -806,6 +812,21 @@ public final class AppContext { + public boolean isMainAppContext() { + return (numAppContexts == 1); + } ++ public Object getContext() { ++ return getAppContext(); ++ } ++ public Object getExecutionContext() { ++ return getExecutionAppContext(); ++ } ++ public Object get(Object context, Object key) { ++ return ((AppContext)context).get(key); ++ } ++ public void put(Object context, Object key, Object value) { ++ ((AppContext)context).put(key, value); ++ } ++ public void remove(Object context, Object key) { ++ ((AppContext)context).remove(key); ++ } + }); + } + } +diff --git a/src/share/classes/sun/misc/JavaAWTAccess.java b/src/share/classes/sun/misc/JavaAWTAccess.java +--- a/src/share/classes/sun/misc/JavaAWTAccess.java ++++ b/src/share/classes/sun/misc/JavaAWTAccess.java +@@ -26,6 +26,14 @@ package sun.misc; + package sun.misc; + + public interface JavaAWTAccess { ++ public Object getContext(); ++ public Object getExecutionContext(); ++ ++ public Object get(Object context, Object key); ++ public void put(Object context, Object key, Object value); ++ public void remove(Object context, Object key); ++ ++ // convenience methods whose context is the object returned by getContext() + public Object get(Object key); + public void put(Object key, Object value); + public void remove(Object key); +diff --git a/src/share/lib/security/java.security b/src/share/lib/security/java.security +--- a/src/share/lib/security/java.security ++++ b/src/share/lib/security/java.security +@@ -126,6 +126,9 @@ package.access=sun.,\ + package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ ++ com.sun.istack.internal.,\ ++ com.sun.jmx.default.,\ ++ com.sun.jmx.remote.util.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ +@@ -144,6 +147,9 @@ package.definition=sun.,\ + package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ ++ com.sun.istack.internal.,\ ++ com.sun.jmx.default.,\ ++ com.sun.jmx.remote.util.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ diff --git a/sec-2013-02-01-7201064.patch b/sec-2013-02-01-7201064.patch new file mode 100644 index 0000000..4fef618 --- /dev/null +++ b/sec-2013-02-01-7201064.patch @@ -0,0 +1,123 @@ +# HG changeset patch +# User denis +# Date 1353673652 -14400 +# Node ID 6f9dde55bd49829cf41bd45b766780c2ec7e0bc1 +# Parent 49a37df9e80fae205a7b70d862cd303a62049c2c +7201064: Better dialogue checking +Reviewed-by: serb, skoivu + +diff --git a/src/share/classes/java/awt/Dialog.java b/src/share/classes/java/awt/Dialog.java +--- a/src/share/classes/java/awt/Dialog.java ++++ b/src/share/classes/java/awt/Dialog.java +@@ -39,6 +39,7 @@ import sun.awt.util.IdentityArrayList; + import sun.awt.util.IdentityArrayList; + import sun.awt.util.IdentityLinkedList; + import sun.security.util.SecurityConstants; ++import java.security.AccessControlException; + + /** + * A Dialog is a top-level window with a title and a border +@@ -127,6 +128,8 @@ public class Dialog extends Window { + * @since 1.4 + */ + boolean undecorated = false; ++ ++ private transient boolean initialized = false; + + /** + * Modal dialogs block all input to some top-level windows. +@@ -671,6 +674,7 @@ public class Dialog extends Window { + this.title = title; + setModalityType(modalityType); + SunToolkit.checkAndSetPolicy(this); ++ initialized = true; + } + + /** +@@ -722,6 +726,7 @@ public class Dialog extends Window { + this.title = title; + setModalityType(modalityType); + SunToolkit.checkAndSetPolicy(this); ++ initialized = true; + } + + /** +@@ -851,12 +856,9 @@ public class Dialog extends Window { + if (modalityType == type) { + return; + } +- if (type == ModalityType.TOOLKIT_MODAL) { +- SecurityManager sm = System.getSecurityManager(); +- if (sm != null) { +- sm.checkPermission(SecurityConstants.AWT.TOOLKIT_MODALITY_PERMISSION); +- } +- } ++ ++ checkModalityPermission(type); ++ + modalityType = type; + modal = (modalityType != ModalityType.MODELESS); + } +@@ -1025,6 +1027,9 @@ public class Dialog extends Window { + */ + @Deprecated + public void show() { ++ if (!initialized) throw new IllegalStateException( ++ "The dialog component has not been initialized properly"); ++ + beforeFirstShow = false; + if (!isModal()) { + conditionalShow(null, null); +@@ -1600,18 +1605,50 @@ public class Dialog extends Window { + } + } + ++ private void checkModalityPermission(ModalityType mt) { ++ if (mt == ModalityType.TOOLKIT_MODAL) { ++ SecurityManager sm = System.getSecurityManager(); ++ if (sm != null) { ++ sm.checkPermission( ++ SecurityConstants.AWT.TOOLKIT_MODALITY_PERMISSION ++ ); ++ } ++ } ++ } ++ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException, HeadlessException + { + GraphicsEnvironment.checkHeadless(); +- s.defaultReadObject(); ++ ++ java.io.ObjectInputStream.GetField fields = ++ s.readFields(); ++ ++ ModalityType localModalityType = (ModalityType)fields.get("modalityType", null); ++ ++ try { ++ checkModalityPermission(localModalityType); ++ } catch (AccessControlException ace) { ++ localModalityType = DEFAULT_MODALITY_TYPE; ++ } + + // in 1.5 or earlier modalityType was absent, so use "modal" instead +- if (modalityType == null) { ++ if (localModalityType == null) { ++ this.modal = fields.get("modal", false); + setModal(modal); + } + ++ this.resizable = fields.get("resizable", true); ++ this.undecorated = fields.get("undecorated", false); ++ this.title = (String)fields.get("title", ""); ++ this.modalityType = localModalityType; ++ + blockedWindows = new IdentityArrayList(); ++ ++ SunToolkit.checkAndSetPolicy(this); ++ ++ initialized = true; ++ + } + + /*