8227601: Better collection of references
authorrriggs
Thu, 17 Jan 2019 10:44:17 -0500
changeset 58635 06d7236d6ef6
parent 58634 da71aa13f86b
child 58636 dbca9d2b4080
8227601: Better collection of references Reviewed-by: smarks, ahgross, skoivu, rhalade
src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java
src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java
src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java
src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java
src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
test/jdk/java/rmi/testlibrary/TestSocketFactory.java
--- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java	Thu Jan 17 10:44:17 2019 -0500
@@ -27,13 +27,8 @@
 package sun.rmi.registry;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.rmi.AccessException;
-import java.rmi.server.RemoteCall;
 
-import sun.rmi.transport.Connection;
 import sun.rmi.transport.StreamRemoteCall;
-import sun.rmi.transport.tcp.TCPConnection;
 
 /**
  * Skeleton to dispatch RegistryImpl methods.
@@ -56,7 +51,7 @@
         return operations.clone();
     }
 
-    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash)
             throws java.lang.Exception {
         if (opnum < 0) {
             if (hash == 7583982177005850366L) {
@@ -78,6 +73,7 @@
         }
 
         sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj;
+        StreamRemoteCall call = (StreamRemoteCall) remoteCall;
         switch (opnum) {
             case 0: // bind(String, Remote)
             {
@@ -90,7 +86,8 @@
                     java.io.ObjectInput in = call.getInputStream();
                     $param_String_1 = (java.lang.String) in.readObject();
                     $param_Remote_2 = (java.rmi.Remote) in.readObject();
-                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
@@ -123,7 +120,8 @@
                 try {
                     java.io.ObjectInput in = call.getInputStream();
                     $param_String_1 = (java.lang.String) in.readObject();
-                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
@@ -149,7 +147,8 @@
                     java.io.ObjectInput in = call.getInputStream();
                     $param_String_1 = (java.lang.String) in.readObject();
                     $param_Remote_2 = (java.rmi.Remote) in.readObject();
-                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | java.lang.ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
@@ -172,7 +171,8 @@
                 try {
                     java.io.ObjectInput in = call.getInputStream();
                     $param_String_1 = (java.lang.String) in.readObject();
-                } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
--- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java	Thu Jan 17 10:44:17 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -24,6 +24,11 @@
  */
 
 package sun.rmi.registry;
+
+import java.io.IOException;
+
+import sun.rmi.transport.StreamRemoteCall;
+
 /**
  * Stubs to invoke RegistryImpl remote methods.
  * Originally generated from RMIC but frozen to match RegistryImpl_Skel.
@@ -57,7 +62,7 @@
     public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
             throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 0, interfaceHash);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_String_1);
@@ -82,15 +87,14 @@
     public java.lang.String[] list()
             throws java.rmi.AccessException, java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 1, interfaceHash);
             ref.invoke(call);
             java.lang.String[] $result;
             try {
                 java.io.ObjectInput in = call.getInputStream();
                 $result = (java.lang.String[]) in.readObject();
-            } catch (java.io.IOException e) {
-                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
-            } catch (java.lang.ClassNotFoundException e) {
+            } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                call.discardPendingRefs();
                 throw new java.rmi.UnmarshalException("error unmarshalling return", e);
             } finally {
                 ref.done(call);
@@ -109,7 +113,7 @@
     public java.rmi.Remote lookup(java.lang.String $param_String_1)
             throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 2, interfaceHash);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_String_1);
@@ -121,9 +125,8 @@
             try {
                 java.io.ObjectInput in = call.getInputStream();
                 $result = (java.rmi.Remote) in.readObject();
-            } catch (java.io.IOException e) {
-                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
-            } catch (java.lang.ClassNotFoundException e) {
+            } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                call.discardPendingRefs();
                 throw new java.rmi.UnmarshalException("error unmarshalling return", e);
             } finally {
                 ref.done(call);
@@ -144,7 +147,7 @@
     public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
             throws java.rmi.AccessException, java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 3, interfaceHash);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_String_1);
@@ -167,7 +170,7 @@
     public void unbind(java.lang.String $param_String_1)
             throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 4, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 4, interfaceHash);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_String_1);
--- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java	Thu Jan 17 10:44:17 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -25,6 +25,8 @@
 
 package sun.rmi.transport;
 
+import java.io.IOException;
+
 /**
  * Skeleton to dispatch DGC methods.
  * Originally generated by RMIC but frozen to match the stubs.
@@ -43,12 +45,13 @@
         return operations.clone();
     }
 
-    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash)
             throws java.lang.Exception {
         if (hash != interfaceHash)
             throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
 
         sun.rmi.transport.DGCImpl server = (sun.rmi.transport.DGCImpl) obj;
+        StreamRemoteCall call = (StreamRemoteCall) remoteCall;
         switch (opnum) {
             case 0: // clean(ObjID[], long, VMID, boolean)
             {
@@ -62,9 +65,8 @@
                     $param_long_2 = in.readLong();
                     $param_VMID_3 = (java.rmi.dgc.VMID) in.readObject();
                     $param_boolean_4 = in.readBoolean();
-                } catch (java.io.IOException e) {
-                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
-                } catch (java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
@@ -88,9 +90,8 @@
                     $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
                     $param_long_2 = in.readLong();
                     $param_Lease_3 = (java.rmi.dgc.Lease) in.readObject();
-                } catch (java.io.IOException e) {
-                    throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
-                } catch (java.lang.ClassNotFoundException e) {
+                } catch (ClassCastException | IOException | ClassNotFoundException e) {
+                    call.discardPendingRefs();
                     throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
                 } finally {
                     call.releaseInputStream();
--- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java	Thu Jan 17 10:44:17 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -25,16 +25,17 @@
 
 package sun.rmi.transport;
 
+import sun.rmi.transport.tcp.TCPConnection;
+
+import java.io.IOException;
 import java.io.ObjectInputFilter;
-import java.io.ObjectInputStream;
+import java.rmi.RemoteException;
 import java.rmi.dgc.Lease;
 import java.rmi.dgc.VMID;
 import java.rmi.server.UID;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-
-import sun.rmi.server.UnicastRef;
-import sun.rmi.transport.tcp.TCPConnection;
+import java.util.ArrayList;
 
 /**
  * Stubs to invoke DGC remote methods.
@@ -72,7 +73,9 @@
     public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4)
             throws java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+            StreamRemoteCall call = (StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this,
+                    operations, 0, interfaceHash);
+            call.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_arrayOf_ObjID_1);
@@ -97,7 +100,10 @@
     public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3)
             throws java.rmi.RemoteException {
         try {
-            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+            StreamRemoteCall call =
+                    (StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this,
+                            operations, 1, interfaceHash);
+            call.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
             try {
                 java.io.ObjectOutput out = call.getOutputStream();
                 out.writeObject($param_arrayOf_ObjID_1);
@@ -108,26 +114,16 @@
             }
             ref.invoke(call);
             java.rmi.dgc.Lease $result;
-            Connection connection = ((StreamRemoteCall) call).getConnection();
+            Connection connection = call.getConnection();
             try {
                 java.io.ObjectInput in = call.getInputStream();
-
-                if (in instanceof ObjectInputStream) {
-                    /**
-                     * Set a filter on the stream for the return value.
-                     */
-                    ObjectInputStream ois = (ObjectInputStream) in;
-                    AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
-                        ois.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
-                        return null;
-                    });
-                }
                 $result = (java.rmi.dgc.Lease) in.readObject();
-            } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+            } catch (ClassCastException | IOException | ClassNotFoundException e) {
                 if (connection instanceof TCPConnection) {
                     // Modified to prevent re-use of the connection after an exception
                     ((TCPConnection) connection).getChannel().free(connection, false);
                 }
+                call.discardPendingRefs();
                 throw new java.rmi.UnmarshalException("error unmarshalling return", e);
             } finally {
                 ref.done(call);
@@ -146,6 +142,11 @@
      * ObjectInputFilter to filter DGCClient return value (a Lease).
      * The list of acceptable classes is very short and explicit.
      * The depth and array sizes are limited.
+     * <p>
+     * The filter must accept normal and exception returns.
+     * A DGC server may throw exceptions that may have a cause
+     * and suppressed exceptions.
+     * Only exceptions in {@code java.base} and {@code java.rmi} are allowed.
      *
      * @param filterInfo access to class, arrayLength, etc.
      * @return  {@link ObjectInputFilter.Status#ALLOWED} if allowed,
@@ -172,7 +173,14 @@
             }
             return (clazz == UID.class ||
                     clazz == VMID.class ||
-                    clazz == Lease.class)
+                    clazz == Lease.class ||
+                    (Throwable.class.isAssignableFrom(clazz) &&
+                            (Object.class.getModule() == clazz.getModule() ||
+                                    RemoteException.class.getModule() == clazz.getModule())) ||
+                    clazz == StackTraceElement.class ||
+                    clazz == ArrayList.class ||     // for suppressed exceptions, if any
+                    clazz == Object.class ||
+                    clazz.getName().equals("java.util.Collections$EmptyList"))
                     ? ObjectInputFilter.Status.ALLOWED
                     : ObjectInputFilter.Status.REJECTED;
         }
--- a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java	Thu Jan 17 10:44:17 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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
@@ -29,6 +29,7 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.ObjectInput;
+import java.io.ObjectInputFilter;
 import java.io.ObjectOutput;
 import java.io.StreamCorruptedException;
 import java.rmi.RemoteException;
@@ -36,6 +37,9 @@
 import java.rmi.UnmarshalException;
 import java.rmi.server.ObjID;
 import java.rmi.server.RemoteCall;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 import sun.rmi.runtime.Log;
 import sun.rmi.server.UnicastRef;
 import sun.rmi.transport.tcp.TCPEndpoint;
@@ -50,6 +54,7 @@
     private ConnectionInputStream in = null;
     private ConnectionOutputStream out = null;
     private Connection conn;
+    private ObjectInputFilter filter = null;
     private boolean resultStarted = false;
     private Exception serverException = null;
 
@@ -123,6 +128,13 @@
         }
     }
 
+    public void setObjectInputFilter(ObjectInputFilter filter) {
+        if (in != null) {
+            throw new IllegalStateException("set filter must occur before calling getInputStream");
+        }
+        this.filter = filter;
+    }
+
     /**
      * Get the InputStream the stub/skeleton should get results/arguments
      * from.
@@ -132,6 +144,12 @@
             Transport.transportLog.log(Log.VERBOSE, "getting input stream");
 
             in = new ConnectionInputStream(conn.getInputStream());
+            if (filter != null) {
+                AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                    in.setObjectInputFilter(filter);
+                    return null;
+                });
+            }
         }
         return in;
     }
@@ -251,6 +269,7 @@
             try {
                 ex = in.readObject();
             } catch (Exception e) {
+                discardPendingRefs();
                 throw new UnmarshalException("Error unmarshaling return", e);
             }
 
@@ -259,6 +278,7 @@
             if (ex instanceof Exception) {
                 exceptionReceivedFromServer((Exception) ex);
             } else {
+                discardPendingRefs();
                 throw new UnmarshalException("Return type not Exception");
             }
             // Exception is thrown before fallthrough can occur
--- a/test/jdk/java/rmi/testlibrary/TestSocketFactory.java	Thu Jul 18 07:25:17 2019 -0700
+++ b/test/jdk/java/rmi/testlibrary/TestSocketFactory.java	Thu Jan 17 10:44:17 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -92,7 +92,8 @@
 
     static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
-    public static final boolean DEBUG = false;
+    // True to enable logging of matches and replacements.
+    private static volatile boolean debugLogging = false;
 
     /**
      * Debugging output can be synchronized with logging of RMI actions.
@@ -100,8 +101,8 @@
      * @param format a printf format
      * @param args   any args
      */
-    private static void DEBUG(String format, Object... args) {
-        if (DEBUG) {
+    public static void DEBUG(String format, Object... args) {
+        if (debugLogging) {
             System.err.printf(format, args);
         }
     }
@@ -117,6 +118,17 @@
     }
 
     /**
+     * Set debug to true to generate logging output of matches and substitutions.
+     * @param debug {@code true} to generate logging output
+     * @return the previous value
+     */
+    public static boolean setDebug(boolean debug) {
+        boolean oldDebug = debugLogging;
+        debugLogging = debug;
+        return oldDebug;
+    }
+
+    /**
      * Set the match and replacement bytes, with an empty trigger.
      * The match and replacements are propagated to all existing sockets.
      *