Found different in behavior of SocketInputStream#read in JDK13
Szalay-Bekő Máté
szalay.beko.mate at gmail.com
Wed Jul 31 08:41:39 UTC 2019
Hi Alan,
As Alan mentioned, it is not a big deal in Zookeeper's perspective. We
don't rely on this specific socket behaviour anywhere in our codebase, we
only faced it when trying to emulate an erroneous client behaviour and try
to assert on the way how the connection is not established successfully...
Some background info:
The test in Zookeeper (
https://github.com/apache/zookeeper/blob/e043c322f12d56da0fc88131628edf0731c0f8e4/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java#L398)
simulates the case, when a client without using SSL tries to connect to the
server which requires SSL. Before starting the test, we don't set the
"jdk.net.usePlainSocketImpl" (so we use the new NioSocket while emulating
the client behaviour), and also we set
"jdk.tls.rejectClientInitiatedRenegotiation=true" to disable
client-initiated TLS renegotiation (although I am not sure if that is
relevant in this case or not).
Using OpenJDK 13.30 on Xenial ubuntu, we saw that the socket.read()
returned with -1 without throwing an exception, indicating the end of the
stream.
The old behaviour (e.g. using openJDK 12.0.2 on xenial) was to get a
SocketException ("Connection reset") with this stack trace:
[junit] 2019-07-31 08:30:54,457 [myid:] - INFO
[main:UnifiedServerSocketTest at 419] - We get the expected exception:
[junit] java.net.SocketException: Connection reset
[junit] at
org.apache.zookeeper.server.quorum.UnifiedServerSocketTest$UnifiedServerThread.run(UnifiedServerSocketTest.java:204)
[junit] at
java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
[junit] Caused by: java.net.SocketException: Socket closed
[junit] at
java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
[junit] at java.base/java.net.PlainSocketImpl.socketAccept(Native
Method)
[junit] at
java.base/java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:458)
[junit] at
java.base/java.net.ServerSocket.implAccept(ServerSocket.java:556)
[junit] at
org.apache.zookeeper.server.quorum.UnifiedServerSocketTest.testConnectWithoutSSLToStrictServer(UnifiedServerSocketTest.java:417)
[junit] at
org.apache.zookeeper.server.quorum.UnifiedServerSocket.accept(UnifiedServerSocket.java:146)
[junit] at
org.apache.zookeeper.server.quorum.UnifiedServerSocketTest$UnifiedServerThread.run(UnifiedServerSocketTest.java:167)
[junit] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
[junit] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[junit] at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[junit] at java.base/java.lang.reflect.Method.invoke(Method.java:567)
[junit] at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
[junit] at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
[junit] at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
[junit] at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
[junit] at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
[junit] at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
[junit] at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
[junit] at org.junit.rules.RunRules.evaluate(RunRules.java:20)
[junit] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
[junit] at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
[junit] at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
[junit] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
[junit] at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
[junit] at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
[junit] at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
[junit] at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
[junit] at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
[junit] at org.junit.runners.Suite.runChild(Suite.java:128)
[junit] at org.junit.runners.Suite.runChild(Suite.java:27)
[junit] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
[junit] at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
[junit] at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
[junit] at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
[junit] at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
[junit] at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
[junit] at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
[junit] at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
[junit] at
junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.java:38)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:535)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1182)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:1033)
[junit] 2019-07-31 08:30:54,465 [myid:] - INFO [main:ZKTestCase$1 at 70]
- SUCCEEDED testConnectWithoutSSLToStrictServer[0]
Interestingly, if I execute the very same test with OpenJDK 13.30 on my
macbook, I also get a similar exception SocketException using the NioSocket
implementation. Could this suggests some differences in the native code?
[junit] 2019-07-31 10:33:44,926 [myid:] - INFO
[main:UnifiedServerSocketTest at 419] - We get the expected exception:
[junit] java.net.SocketException: Connection reset
[junit] at
java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:324)
[junit] at
java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:351)
[junit] at
java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:802)
[junit] at
java.base/java.net.Socket$SocketInputStream.read(Socket.java:919)
[junit] at
org.apache.zookeeper.server.quorum.UnifiedServerSocketTest.testConnectWithoutSSLToStrictServer(UnifiedServerSocketTest.java:417)
[junit] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
[junit] at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[junit] at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[junit] at java.base/java.lang.reflect.Method.invoke(Method.java:567)
[junit] at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
[junit] at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
[junit] at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
[junit] at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
[junit] at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
[junit] at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
[junit] at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
[junit] at org.junit.rules.RunRules.evaluate(RunRules.java:20)
[junit] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
[junit] at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
[junit] at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
[junit] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
[junit] at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
[junit] at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
[junit] at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
[junit] at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
[junit] at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
[junit] at org.junit.runners.Suite.runChild(Suite.java:128)
[junit] at org.junit.runners.Suite.runChild(Suite.java:27)
[junit] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
[junit] at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
[junit] at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
[junit] at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
[junit] at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
[junit] at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
[junit] at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
[junit] at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
[junit] at
junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.java:38)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:535)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1182)
[junit] at
org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:1033)
[junit] 2019-07-31 10:33:44,931 [myid:] - INFO [main:ZKTestCase$1 at 70]
- SUCCEEDED testConnectWithoutSSLToStrictServer[0]
Cheers,
Mate
>> On Jul 30, 2019, at 18:53 PM, Alan Bateman <Alan.Bateman at oracle.com
<mailto:Alan.Bateman at oracle.com>> wrote:
>> Hello,
>> in Apache ZooKeeper community we discovered a difference in behavior
>> in SocketInputStream.
>>
>> The problem is that SocketInputStream#read used to throw a
>> SocketException instead of returning -1.
>>
>> I see that this was cited in https://openjdk.java.net/jeps/353
>>
>> "The |InputStream| and |OutputStream| returned by the old
>> implementation tests the stream for EOF and returns -1 before other
>> checks. The new implementation does |null| and bounds checks before
>> checking if the stream is at EOF. It is possible, but unlikely, that
>> there is fragile code that will trip up due to the order of the checks."
>>
>> We are talking about a unit test, no a big deal.
>>
>> This is the fix, provided by Mate Szalay-Beko
>> https://github.com/apache/zookeeper/pull/1029
>>
>Thanks for the mail. What is the exception you see with the legacy
>implementation? The note you cite would lead to an
>IndexOutOfBoundException due to the bad input and I don't think this is
>what you are seeing.
>
>-Alan.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/nio-dev/attachments/20190731/a3e7f388/attachment-0001.html>
More information about the nio-dev
mailing list