Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8237858

PlainSocketImpl.socketAccept() handles EINTR incorrectly

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 11.0.6, 13.0.2, 14
    • Fix Version/s: 16
    • Component/s: core-libs
    • Labels:
      None
    • Subcomponent:
    • Resolved In Build:
      b07
    • OS:
      linux

      Description

      On Linux, ServerSocket.accept() throws "java.net.SocketTimeoutException: Accept timed out" if the call is interrupted by a signal.

      To see the error, run the following program:

      public class SocketAcceptTest {
          public static void main(String[] args) throws Exception {
              new ServerSocket(0).accept();
          }
      }

      Then find tid of the main thread, and send a signal to it, e.g. SIGPIPE which is caught but ignored by the JVM:

      kill -SIGPIPE <tid>

      Usually <tid> = <pid> + 1

      The program will terminate with SocketTimeoutException, although the operation should never time out.

      Exception in thread "main" java.net.SocketTimeoutException: Accept timed out
              at java.base/java.net.PlainSocketImpl.socketAccept(Native Method)
              at java.base/java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:458)
              at java.base/java.net.ServerSocket.implAccept(ServerSocket.java:565)
              at java.base/java.net.ServerSocket.accept(ServerSocket.java:533)
              at Test.main(Test.java:6)

      The problem always happens on JDK 11 and also on JDK 13/14, if run with -Djdk.net.usePlainSocketImpl=true

      Works fine on JDK 8 and on JDK 13/14, if run with new Socket implementation (JEP 353).

      The original problem was encountered when profiling Tomcat with async-profiler, see https://github.com/jvm-profiling-tools/async-profiler/issues/295

      Evaluation:

      PlainSocketImpl_socketAccept() calls NET_Timeout (i.e. poll) with a negative timeout, which should mean "wait infinitely". However, a signal may interrupt a call, it returns EINTR, and then the loop in NET_Timeout immediately breaks because of the negative value:

              if (rv < 0 && errno == EINTR) {
                  jlong newNanoTime = JVM_NanoTime(env, 0);
                  nanoTimeout -= newNanoTime - prevNanoTime;
                  if (nanoTimeout < NET_NSEC_PER_MSEC) {
                      return 0;
                  }
                  prevNanoTime = newNanoTime;
              }

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              vtewari Vyom Tewari
              Reporter:
              apangin Andrei Pangin
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: