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

PlainSocketImpl.socketAccept() handles EINTR incorrectly

    XMLWordPrintable

Details

    • b07
    • linux

    Backports

      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

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

                Dates

                  Created:
                  Updated:
                  Resolved: