Found different in behavior of SocketInputStream#read in JDK13

Enrico Olivelli eolivelli at gmail.com
Wed Jul 31 13:01:52 UTC 2019


Il giorno mer 31 lug 2019 alle ore 14:39 Alan Bateman <
Alan.Bateman at oracle.com> ha scritto:

> Thanks for additional info. Although it may not be a "a big deal" for the
> Zookeeper test, it would be great if you and Enrico have time to help us
> diagnose this a big further.
>

Sure, We are reporting this error because JDK13 release will happen soon
and such anomalies are quite scary.


> At a high-level, the SocketException: "Connection reset" means the peer
> has terminated the connection (hard reset). When you are using new
> SocketImpl the peer appears to be closely the connection gracefully, help
> -1 is read. Would I be correct to say that UnifiedServerSocketTest is
> connecting to the Zookeeper server and it terminates the connection due to
> the SSL connection. Is the Zookeeper running on JDK 13 too? I'm just
> wondering if the scenario intermittently leads to a hard reset on some
> occasions and a graceful close at some times and switching implementation
> has changed the timing a bit to cause the latter to be more likely.
>

Server and client are running inside the same JVM

The server side implementation is here, is mostly a wrapper round
ServerSocket, it tries to detect if the client is willing to use SSL or not.

https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/UnifiedServerSocket.java




>
> Is there any way to turn this test in a reproducer that we could study
> more closely?
>

The specific test has nothing to do with ZooKeeper itself, it is a test
over  UnifiedServerSocket
<https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/UnifiedServerSocket.java>
,
so it can be extracted from ZooKeeper code base, but it is using a bunch of
shared utilities for configuration and SSL.

I am really sorry I don't have much time these days, I hope that
Szalay-Bekő Máté can help.
Otherwise I will try to set up a repo next week

Enrico



>
> -Alan
>
>
>
> On 31/07/2019 01:41, Szalay-Bekő Máté wrote:
>
> 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/2e62746d/attachment-0001.html>


More information about the nio-dev mailing list