On 12/13/16 11:30 AM, Adam Petcher wrote:
Thanks for the review.

After thinking about this some more, I don't like the idea of using
Optional for a member variable due to the limitations of this class and
the lack of support for this usage of it. I'll send out a new diff that
uses a standard null check.

See below for other comments.


On 12/12/2016 9:20 PM, Wang Weijun wrote:
Hi Adam

The only behavior change is with the debug output, right?
Yes. This will be more obvious in my next diff.

Is this a new pattern that internal optional fields should be defined
as an Optional?

And, when there is no provider the string form "from: " looks strange,
I would rather make it "from nowhere". I would also move the space
before "from" to where the method is called, say, " verification
algorithm " + getProvidedByString().
It doesn't print the "from: " when there is no provider. So the string
will look like "Signature.DSA verification algorithm" in this case. I
don't have a strong opinion on whether we should print "from: no
provider" (for example), but Sean expressed a preference for leaving
this entire part blank when there is no provider (as it is in my last
diff).

Maybe "from: (no provider)" would be better. I think a previous version had "from: none", but thinking about it more, "from: (no provider)" is probably better than not printing anything for a null provider.

--Sean


Thanks
Max

On Dec 13, 2016, at 4:05 AM, Adam Petcher <adam.petc...@oracle.com>
wrote:

Okay. I changed getProvider() to return this.provider.orElse(null),
which will allow this method to return null. For consistency, I allow
all other providers (in Instance and Service) to be null using
Optional.ofNullable(). Hopefully, I found and fixed all the
whitespace issues, too. Here is the corrected diff:

diff --git a/src/java.base/share/classes/java/security/Signature.java
b/src/java.base/share/classes/java/security/Signature.java
--- a/src/java.base/share/classes/java/security/Signature.java
+++ b/src/java.base/share/classes/java/security/Signature.java
@@ -134,7 +134,7 @@
     private String algorithm;

     // The provider
-    Provider provider;
+    Optional<Provider> provider = Optional.empty();

     /**
      * Possible {@link #state} value, signifying that
@@ -266,7 +266,7 @@
             SignatureSpi spi = (SignatureSpi)instance.impl;
             sig = new Delegate(spi, algorithm);
         }
-        sig.provider = instance.provider;
+        sig.provider = Optional.ofNullable(instance.provider);
         return sig;
     }

@@ -449,13 +449,17 @@
      */
     public final Provider getProvider() {
         chooseFirstProvider();
-        return this.provider;
+        return this.provider.orElse(null);
     }

     void chooseFirstProvider() {
         // empty, overridden in Delegate
     }

+    private String getProvidedByString() {
+        return provider.map(x -> " from: " + x.getName()).orElse("");
+    }
+
     /**
      * Initializes this object for verification. If this method is
called
      * again with a different argument, it negates the effect
@@ -473,7 +477,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " +
this.provider.getName());
+                " verification algorithm" + getProvidedByString());
         }
     }

@@ -522,7 +526,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " +
this.provider.getName());
+                " verification algorithm" + getProvidedByString());
         }
     }

@@ -543,7 +547,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm" + getProvidedByString());
         }
     }

@@ -566,7 +570,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm" + getProvidedByString());
         }
     }

@@ -1087,7 +1091,7 @@
                     }
                     try {
                         sigSpi = newInstance(s);
-                        provider = s.getProvider();
+                        provider =
Optional.ofNullable(s.getProvider());
                         // not needed any more
                         firstService = null;
                         serviceIterator = null;
@@ -1132,7 +1136,7 @@
                     try {
                         SignatureSpi spi = newInstance(s);
                         init(spi, type, key, random);
-                        provider = s.getProvider();
+                        provider =
Optional.ofNullable(s.getProvider());
                         sigSpi = spi;
                         firstService = null;
                         serviceIterator = null;
diff --git a/test/java/security/Signature/NoProvider.java
b/test/java/security/Signature/NoProvider.java
new file mode 100644
--- /dev/null
+++ b/test/java/security/Signature/NoProvider.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License
+ * version 2 for more details (a copy is included in the LICENSE
file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
version
+ * 2 along with this work; if not, write to the Free Software
Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA
94065 USA
+ * or visit www.oracle.com if you need additional information or
have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8165751
+ * @summary Verify that that a subclass of Signature that does not
contain a
+ *     provider can be used verify.
+ * @run main/othervm -Djava.security.debug=provider NoProvider
+ */
+
+import java.security.*;
+
+public class NoProvider {
+
+    private static class NoProviderPublicKey implements PublicKey {
+
+        public String getAlgorithm() {
+            return "NoProvider";
+        }
+        public String getFormat() {
+            return "none";
+        }
+        public byte[] getEncoded() {
+            return new byte[1];
+        }
+    }
+
+    private static class NoProviderSignature extends Signature {
+
+        public NoProviderSignature() {
+            super("NoProvider");
+        }
+
+        protected void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+            // do nothing
+        }
+
+        protected void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+            // do nothing
+        }
+
+        protected void engineUpdate(byte b) throws SignatureException {
+            // do nothing
+        }
+
+        protected void engineUpdate(byte[] b, int off, int len)
+            throws SignatureException {
+            // do nothing
+        }
+
+        protected byte[] engineSign() throws SignatureException {
+            return new byte[1];
+        }
+
+        protected boolean engineVerify(byte[] sigBytes)
+            throws SignatureException {
+            return false;
+        }
+
+        @Deprecated
+        protected void engineSetParameter(String param, Object value)
+            throws InvalidParameterException {
+            // do nothing
+        }
+
+        @Deprecated
+        protected Object engineGetParameter(String param)
+            throws InvalidParameterException {
+            return null;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new NoProviderSignature().initVerify(new
NoProviderPublicKey());
+    }
+}


On 12/12/2016 1:44 PM, Sean Mullan wrote:
On 12/8/16 11:17 AM, Adam Petcher wrote:
Subclasses of Signature may have a null provider. In this case, the
debug logging code will throw a NPE when attempting to call
getName() on
it. Since this member may be null, I would like to change its type to
Optional to ensure that code checks whether it is present before using
it. I have assumed that getProvider() methods (in both Signature and
Service) always return non-null---if this assumption is incorrect,
then
I'll need to change some of the uses of Optional in/around these
methods.
I think we would want to preserve the current behavior of
getProvider returning null for one of these subclasses (even though
it isn't specified that null is an acceptable return value). Better
to be safe here, otherwise NoSuchElementException would be thrown
which would be unexpected and not specified by getProvider.

Other than that, just a minor style comment on a few lines of the test:

+    private static class NoProviderPublicKey implements PublicKey{
space before "{"

--Sean

Note that this issue of missing null checks for providers exists in
several classes (e.g. Cipher, MessageDigest). Once this patch is
reviewed and committed, I will apply the same solution to all other
affected classes.

Bug: https://bugs.openjdk.java.net/browse/JDK-8165751

Diff:

diff --git a/src/java.base/share/classes/java/security/Signature.java
b/src/java.base/share/classes/java/security/Signature.java
--- a/src/java.base/share/classes/java/security/Signature.java
+++ b/src/java.base/share/classes/java/security/Signature.java
@@ -134,7 +134,7 @@
     private String algorithm;

     // The provider
-    Provider provider;
+    Optional<Provider> provider = Optional.empty();

     /**
      * Possible {@link #state} value, signifying that
@@ -266,7 +266,7 @@
             SignatureSpi spi = (SignatureSpi)instance.impl;
             sig = new Delegate(spi, algorithm);
         }
-        sig.provider = instance.provider;
+        sig.provider = Optional.of(instance.provider);
         return sig;
     }

@@ -449,13 +449,17 @@
      */
     public final Provider getProvider() {
         chooseFirstProvider();
-        return this.provider;
+        return this.provider.get();
     }

     void chooseFirstProvider() {
         // empty, overridden in Delegate
     }

+    private String getProvidedByString(){
+        return provider.map(x -> " from: " + x.getName()).orElse("");
+    }
+
     /**
      * Initializes this object for verification. If this method is
called
      * again with a different argument, it negates the effect
@@ -473,7 +477,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " +
this.provider.getName());
+                " verification algorithm" + getProvidedByString());
         }
     }

@@ -522,7 +526,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " +
this.provider.getName());
+                " verification algorithm" + getProvidedByString());
         }
     }

@@ -543,7 +547,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " +
this.provider.getName());
+                " signing algorithm" + getProvidedByString());
         }
     }

@@ -566,7 +570,7 @@

         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " +
this.provider.getName());
+                " signing algorithm" + getProvidedByString());
         }
     }

@@ -1087,7 +1091,7 @@
                     }
                     try {
                         sigSpi = newInstance(s);
-                        provider = s.getProvider();
+                        provider = Optional.of(s.getProvider());
                         // not needed any more
                         firstService = null;
                         serviceIterator = null;
@@ -1132,7 +1136,7 @@
                     try {
                         SignatureSpi spi = newInstance(s);
                         init(spi, type, key, random);
-                        provider = s.getProvider();
+                        provider = Optional.of(s.getProvider());
                         sigSpi = spi;
                         firstService = null;
                         serviceIterator = null;
diff --git a/test/java/security/Signature/NoProvider.java
b/test/java/security/Signature/NoProvider.java
new file mode 100644
--- /dev/null
+++ b/test/java/security/Signature/NoProvider.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, 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
+ * under the terms of the GNU General Public License version 2
only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License
+ * version 2 for more details (a copy is included in the LICENSE
file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
version
+ * 2 along with this work; if not, write to the Free Software
Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA
94065 USA
+ * or visit www.oracle.com if you need additional information or
have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8165751
+ * @summary Verify that that a subclass of Signature that does not
contain a
+ *     provider can be used verify.
+ * @run main/othervm -Djava.security.debug=provider NoProvider
+ */
+
+import java.security.*;
+
+public class NoProvider {
+
+    private static class NoProviderPublicKey implements PublicKey{
+        public String getAlgorithm(){
+            return "NoProvider";
+        }
+        public String getFormat(){
+            return "none";
+        }
+        public byte[] getEncoded(){
+            return new byte[1];
+        }
+    }
+
+    private static class NoProviderSignature extends Signature{
+
+        public NoProviderSignature(){
+            super("NoProvider");
+        }
+
+        protected void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException{
+            // do nothing
+        }
+
+        protected void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException{
+            // do nothing
+        }
+
+        protected void engineUpdate(byte b) throws
SignatureException{
+            // do nothing
+        }
+
+        protected void engineUpdate(byte[] b, int off, int len)
+            throws SignatureException{
+            // do nothing
+        }
+
+        protected byte[] engineSign() throws SignatureException{
+            return new byte[1];
+        }
+
+        protected boolean engineVerify(byte[] sigBytes)
+            throws SignatureException{
+            return false;
+        }
+
+        @Deprecated
+        protected void engineSetParameter(String param, Object value)
+            throws InvalidParameterException{
+            // do nothing
+        }
+
+        @Deprecated
+        protected Object engineGetParameter(String param)
+            throws InvalidParameterException{
+            return null;
+        }
+
+    }
+
+    public static void main(String[] args) throws Exception {
+        new NoProviderSignature().initVerify(new
NoProviderPublicKey());
+    }
+}

Reply via email to