From 1bcb7f93c06c2bf75f4a371bfbbc78a2a864b15b Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Wed, 7 Dec 2016 15:32:31 -0500 Subject: [PATCH] 8170291: Unpredictable results of j.i.ObjectInputFilter::createFilter Reviewed-by: dfuchs --- .../classes/java/io/ObjectInputFilter.java | 51 ++++++++++-------- .../classes/java/io/ObjectInputStream.java | 12 ++++- .../serialFilter/SerialFilterTest.java | 54 ++++++++++++++----- 3 files changed, 79 insertions(+), 38 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java b/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java index e222f47c41a..a0e998c7b29 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java @@ -350,16 +350,24 @@ public interface ObjectInputFilter { * The first pattern that matches, working from left to right, determines * the {@link Status#ALLOWED Status.ALLOWED} * or {@link Status#REJECTED Status.REJECTED} result. - * If nothing matches, the result is {@link Status#UNDECIDED Status.UNDECIDED}. + * If the limits are not exceeded and no pattern matches the class, + * the result is {@link Status#UNDECIDED Status.UNDECIDED}. * * @param pattern the pattern string to parse; not null - * @return a filter to check a class being deserialized; may be null; + * @return a filter to check a class being deserialized; * {@code null} if no patterns - * @throws IllegalArgumentException - * if a limit is missing the name, or the long value - * is not a number or is negative, - * or the module name is missing if the pattern contains "/" - * or if the package is missing for ".*" and ".**" + * @throws IllegalArgumentException if the pattern string is illegal or + * malformed and cannot be parsed. + * In particular, if any of the following is true: + * */ public static ObjectInputFilter createFilter(String pattern) { Objects.requireNonNull(pattern, "pattern"); @@ -402,14 +410,19 @@ public interface ObjectInputFilter { * Returns an ObjectInputFilter from a string of patterns. * * @param pattern the pattern string to parse - * @return a filter to check a class being deserialized; not null + * @return a filter to check a class being deserialized; + * {@code null} if no patterns * @throws IllegalArgumentException if the parameter is malformed * if the pattern is missing the name, the long value * is not a number or is negative. */ static ObjectInputFilter createFilter(String pattern) { - Global filter = new Global(pattern); - return filter.isEmpty() ? null : filter; + try { + return new Global(pattern); + } catch (UnsupportedOperationException uoe) { + // no non-empty patterns + return null; + } } /** @@ -417,8 +430,10 @@ public interface ObjectInputFilter { * * @param pattern a pattern string of filters * @throws IllegalArgumentException if the pattern is malformed + * @throws UnsupportedOperationException if there are no non-empty patterns */ private Global(String pattern) { + boolean hasLimits = false; this.pattern = pattern; maxArrayLength = Long.MAX_VALUE; // Default values are unlimited @@ -436,6 +451,7 @@ public interface ObjectInputFilter { } if (parseLimit(p)) { // If the pattern contained a limit setting, i.e. type=value + hasLimits = true; continue; } boolean negate = p.charAt(0) == '!'; @@ -510,18 +526,9 @@ public interface ObjectInputFilter { filters.add(c -> moduleName.equals(c.getModule().getName()) ? patternFilter.apply(c) : Status.UNDECIDED); } } - } - - /** - * Returns if this filter has any checks. - * @return {@code true} if the filter has any checks, {@code false} otherwise - */ - private boolean isEmpty() { - return filters.isEmpty() && - maxArrayLength == Long.MAX_VALUE && - maxDepth == Long.MAX_VALUE && - maxReferences == Long.MAX_VALUE && - maxStreamBytes == Long.MAX_VALUE; + if (filters.isEmpty() && !hasLimits) { + throw new UnsupportedOperationException("no non-empty patterns"); + } } /** diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index eac811d9fe2..ed033d685e9 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -1164,6 +1164,13 @@ public class ObjectInputStream * for each class and reference in the stream. * The filter can check any or all of the class, the array length, the number * of references, the depth of the graph, and the size of the input stream. + * The depth is the number of nested {@linkplain #readObject readObject} + * calls starting with the reading of the root of the graph being deserialized + * and the current object being deserialized. + * The number of references is the cumulative number of objects and references + * to objects already read from the stream including the current object being read. + * The filter is invoked only when reading objects from the stream and for + * not primitives. *

* If the filter returns {@link ObjectInputFilter.Status#REJECTED Status.REJECTED}, * {@code null} or throws a {@link RuntimeException}, @@ -1178,8 +1185,9 @@ public class ObjectInputStream * * @implSpec * The filter, when not {@code null}, is invoked during {@link #readObject readObject} - * and {@link #readUnshared readUnshared} for each object - * (regular or class) in the stream including the following: + * and {@link #readUnshared readUnshared} for each object (regular or class) in the stream. + * Strings are treated as primitives and do not invoke the filter. + * The filter is called for: *