2727
2828import jdk .internal .access .SharedSecrets ;
2929import jdk .internal .util .StaticProperty ;
30- import sun .security .action .GetBooleanAction ;
3130
3231import java .lang .reflect .InvocationTargetException ;
3332import java .security .AccessController ;
@@ -523,10 +522,15 @@ enum Status {
523522 * {@systemProperty jdk.serialFilter}, its value is used to configure the filter.
524523 * If the system property is not defined, and the {@link java.security.Security} property
525524 * {@code jdk.serialFilter} is defined then it is used to configure the filter.
526- * The filter is created as if {@link #createFilter(String) createFilter} is called;
527- * if the filter string is invalid, an {@link ExceptionInInitializerError} is thrown.
528- * Otherwise, the filter is not configured during initialization and
529- * can be set with {@link #setSerialFilter(ObjectInputFilter) Config.setSerialFilter}.
525+ * The filter is created as if {@link #createFilter(String) createFilter} is called,
526+ * if the filter string is invalid the initialization fails and subsequent attempts to
527+ * {@linkplain Config#getSerialFilter() get the filter}, {@linkplain Config#setSerialFilter set a filter},
528+ * or create an {@linkplain ObjectInputStream#ObjectInputStream(InputStream) ObjectInputStream}
529+ * throw {@link IllegalStateException}. Deserialization is not possible with an
530+ * invalid serial filter.
531+ * If the system property {@code jdk.serialFilter} or the {@link java.security.Security}
532+ * property {@code jdk.serialFilter} is not set the filter can be set with
533+ * {@link #setSerialFilter(ObjectInputFilter) Config.setSerialFilter}.
530534 * Setting the {@code jdk.serialFilter} with {@link System#setProperty(String, String)
531535 * System.setProperty} <em>does not set the filter</em>.
532536 * The syntax for the property value is the same as for the
@@ -545,9 +549,12 @@ enum Status {
545549 * <p>The class must be public, must have a public zero-argument constructor, implement the
546550 * {@link BinaryOperator {@literal BinaryOperator<ObjectInputFilter>}} interface, provide its implementation and
547551 * be accessible via the {@linkplain ClassLoader#getSystemClassLoader() application class loader}.
548- * If the filter factory constructor is not invoked successfully, an {@link ExceptionInInitializerError}
549- * is thrown and subsequent use of the filter factory for deserialization fails with
550- * {@link IllegalStateException}.
552+ * If the filter factory constructor is not invoked successfully subsequent attempts to
553+ * {@linkplain Config#getSerialFilterFactory() get the factory},
554+ * {@linkplain Config#setSerialFilterFactory(BinaryOperator) set the factory}, or create an
555+ * {@link ObjectInputStream#ObjectInputStream(InputStream) ObjectInputStream}
556+ * throw {@link IllegalStateException}. Deserialization is not possible with an
557+ * invalid serial filter factory.
551558 * The filter factory configured using the system or security property during initialization
552559 * can NOT be replaced with {@link #setSerialFilterFactory(BinaryOperator) Config.setSerialFilterFactory}.
553560 * This ensures that a filter factory set on the command line is not overridden accidentally
@@ -582,12 +589,22 @@ final class Config {
582589 */
583590 private static volatile ObjectInputFilter serialFilter ;
584591
592+ /**
593+ * Saved message if the jdk.serialFilter property is invalid.
594+ */
595+ private static final String invalidFilterMessage ;
596+
585597 /**
586598 * Current serial filter factory.
587599 * @see Config#setSerialFilterFactory(BinaryOperator)
588600 */
589601 private static volatile BinaryOperator <ObjectInputFilter > serialFilterFactory ;
590602
603+ /**
604+ * Saved message if the jdk.serialFilterFactory property is invalid.
605+ */
606+ private static final String invalidFactoryMessage ;
607+
591608 /**
592609 * Boolean to indicate that the filter factory can not be set or replaced.
593610 * - an ObjectInputStream has already been created using the current filter factory
@@ -630,23 +647,24 @@ final class Config {
630647 Security .getProperty (SERIAL_FILTER_PROPNAME ));
631648
632649 // Initialize the static filter if the jdk.serialFilter is present
633- ObjectInputFilter filter = null ;
650+ String filterMessage = null ;
634651 if (filterString != null ) {
635652 configLog .log (DEBUG ,
636653 "Creating deserialization filter from {0}" , filterString );
637654 try {
638- filter = createFilter (filterString );
655+ serialFilter = createFilter (filterString );
639656 } catch (RuntimeException re ) {
640657 configLog .log (ERROR ,
641658 "Error configuring filter: {0}" , (Object ) re );
642- // Do not continue if configuration not initialized
643- throw re ;
659+ // serialFilter remains null
660+ filterMessage = "Invalid jdk.serialFilter: " + re . getMessage () ;
644661 }
645662 }
646- serialFilter = filter ;
663+ invalidFilterMessage = filterMessage ;
647664
648665 // Initialize the filter factory if the jdk.serialFilterFactory is defined
649666 // otherwise use the builtin filter factory.
667+ String factoryMessage = null ;
650668 if (factoryClassName == null ) {
651669 serialFilterFactory = new BuiltinFilterFactory ();
652670 } else {
@@ -671,10 +689,13 @@ final class Config {
671689 Throwable th = (ex instanceof InvocationTargetException ite ) ? ite .getCause () : ex ;
672690 configLog .log (ERROR ,
673691 "Error configuring filter factory: {0}" , (Object )th );
674- // Do not continue if configuration not initialized
675- throw new ExceptionInInitializerError (th );
692+ // Configuration not initialized
693+ // serialFilterFactory remains null and filterFactoryNoReplace == true;
694+ factoryMessage = "invalid jdk.serialFilterFactory: " +
695+ factoryClassName + ": " + th .getClass ().getName () + ": " + th .getMessage ();
676696 }
677697 }
698+ invalidFactoryMessage = factoryMessage ;
678699 // Setup shared secrets for RegistryImpl to use.
679700 SharedSecrets .setJavaObjectInputFilterAccess (Config ::createFilter2 );
680701 }
@@ -696,8 +717,14 @@ private static void traceFilter(String msg, Object... args) {
696717 * Returns the static JVM-wide deserialization filter or {@code null} if not configured.
697718 *
698719 * @return the static JVM-wide deserialization filter or {@code null} if not configured
720+ * @throws IllegalStateException if the initialization of the filter from the
721+ * system property {@code jdk.serialFilter} or
722+ * the security property {@code jdk.serialFilter} fails.
699723 */
700724 public static ObjectInputFilter getSerialFilter () {
725+ if (invalidFilterMessage != null ) {
726+ throw new IllegalStateException (invalidFilterMessage );
727+ }
701728 return serialFilter ;
702729 }
703730
@@ -707,7 +734,9 @@ public static ObjectInputFilter getSerialFilter() {
707734 * @param filter the deserialization filter to set as the JVM-wide filter; not null
708735 * @throws SecurityException if there is security manager and the
709736 * {@code SerializablePermission("serialFilter")} is not granted
710- * @throws IllegalStateException if the filter has already been set
737+ * @throws IllegalStateException if the filter has already been set or the initialization
738+ * of the filter from the system property {@code jdk.serialFilter} or
739+ * the security property {@code jdk.serialFilter} fails.
711740 */
712741 public static void setSerialFilter (ObjectInputFilter filter ) {
713742 Objects .requireNonNull (filter , "filter" );
@@ -716,6 +745,9 @@ public static void setSerialFilter(ObjectInputFilter filter) {
716745 if (sm != null ) {
717746 sm .checkPermission (ObjectStreamConstants .SERIAL_FILTER_PERMISSION );
718747 }
748+ if (invalidFilterMessage != null ) {
749+ throw new IllegalStateException (invalidFilterMessage );
750+ }
719751 synchronized (serialFilterLock ) {
720752 if (serialFilter != null ) {
721753 throw new IllegalStateException ("Serial filter can only be set once" );
@@ -749,8 +781,10 @@ public static void setSerialFilter(ObjectInputFilter filter) {
749781 * @since 17
750782 */
751783 public static BinaryOperator <ObjectInputFilter > getSerialFilterFactory () {
752- if (serialFilterFactory == null )
753- throw new IllegalStateException ("Serial filter factory initialization incomplete" );
784+ if (serialFilterFactory == null ) {
785+ // If initializing the factory failed or not yet complete, throw with the message
786+ throw new IllegalStateException (invalidFilterFactoryMessage ());
787+ }
754788 return serialFilterFactory ;
755789 }
756790
@@ -812,15 +846,26 @@ public static void setSerialFilterFactory(BinaryOperator<ObjectInputFilter> filt
812846 }
813847 if (filterFactoryNoReplace .getAndSet (true )) {
814848 final String msg = serialFilterFactory != null
815- ? serialFilterFactory .getClass ().getName ()
816- : "initialization incomplete" ;
817- throw new IllegalStateException ("Cannot replace filter factory: " + msg );
849+ ? "Cannot replace filter factory: " + serialFilterFactory .getClass ().getName ()
850+ : invalidFilterFactoryMessage () ;
851+ throw new IllegalStateException (msg );
818852 }
819853 configLog .log (DEBUG ,
820854 "Setting deserialization filter factory to {0}" , filterFactory .getClass ().getName ());
821855 serialFilterFactory = filterFactory ;
822856 }
823857
858+ /*
859+ * Return message for an invalid filter factory configuration saved from the static init.
860+ * It can be called before the static initializer is complete and has set the message/null.
861+ */
862+ private static String invalidFilterFactoryMessage () {
863+ assert serialFilterFactory == null ; // undefined if a filter factory has been set
864+ return (invalidFactoryMessage != null )
865+ ? invalidFactoryMessage
866+ : "Serial filter factory initialization incomplete" ;
867+ }
868+
824869 /**
825870 * Returns an ObjectInputFilter from a string of patterns.
826871 * <p>
0 commit comments