You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by mg...@apache.org on 2020/10/01 10:32:29 UTC

[tomcat] branch master updated: Wrap 'error' and 'applicationIOE' with AtomicReference

This is an automated email from the ASF dual-hosted git repository.

mgrigorov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new 14e5b8c  Wrap 'error' and 'applicationIOE' with AtomicReference
14e5b8c is described below

commit 14e5b8c2b1d0a88e6220a08feefba559bec2335e
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
AuthorDate: Thu Oct 1 13:29:42 2020 +0300

    Wrap 'error' and 'applicationIOE' with AtomicReference
    
    Under high load it is possible that one thread makes the check for non-null and before the copy another thread to null-fy the member field.
    
    SEVERE: Servlet.service() for servlet [plaintext] in context with path [] threw exception
    java.lang.NullPointerException: Cannot throw exception because "ioe" is null
    	at org.apache.coyote.http2.Http2UpgradeHandler.handleAppInitiatedIOException(Http2UpgradeHandler.java:797)
    	at org.apache.coyote.http2.Http2AsyncUpgradeHandler.handleAsyncException(Http2AsyncUpgradeHandler.java:276)
    	at org.apache.coyote.http2.Http2AsyncUpgradeHandler.writeWindowUpdate(Http2AsyncUpgradeHandler.java:252)
    	at org.apache.coyote.http2.Stream$StreamInputBuffer.doRead(Stream.java:1088)
    	at org.apache.coyote.Request.doRead(Request.java:555)
    	at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:336)
    	at org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuffer.java:632)
    	at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:362)
    	at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:132)
    	at org.apache.catalina.connector.Request.readPostBody(Request.java:3308)
    	at org.apache.catalina.connector.Request.parseParameters(Request.java:3241)
    	at org.apache.catalina.connector.Request.getParameter(Request.java:1124)
    	at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381)
    	at info.mgsolutions.tomcat.PlainTextServlet.doPost(PlainTextServlet.java:41)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
      ...
---
 .../coyote/http2/Http2AsyncUpgradeHandler.java     | 36 ++++++++++++----------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
index 9c274ac..defbb1c 100644
--- a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
@@ -25,6 +25,7 @@ import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 import jakarta.servlet.http.WebConnection;
 
@@ -43,8 +44,8 @@ public class Http2AsyncUpgradeHandler extends Http2UpgradeHandler {
     // Because of the compression used, headers need to be written to the
     // network in the same order they are generated.
     private final Object headerWriteLock = new Object();
-    private Throwable error = null;
-    private IOException applicationIOE = null;
+    private final AtomicReference<Throwable> error = new AtomicReference<>();
+    private final AtomicReference<IOException> applicationIOE = new AtomicReference<>();
 
     public Http2AsyncUpgradeHandler(Http2Protocol protocol, Adapter adapter,
             Request coyoteRequest) {
@@ -57,7 +58,7 @@ public class Http2AsyncUpgradeHandler extends Http2UpgradeHandler {
         }
         @Override
         public void failed(Throwable t, Void attachment) {
-            error = t;
+            error.set(t);
         }
     };
     private final CompletionHandler<Long, Void> applicationErrorCompletion = new CompletionHandler<Long, Void>() {
@@ -67,9 +68,9 @@ public class Http2AsyncUpgradeHandler extends Http2UpgradeHandler {
         @Override
         public void failed(Throwable t, Void attachment) {
             if (t instanceof IOException) {
-                applicationIOE = (IOException) t;
+                applicationIOE.set((IOException) t);
             }
-            error = t;
+            error.set(t);
         }
     };
 
@@ -109,12 +110,13 @@ public class Http2AsyncUpgradeHandler extends Http2UpgradeHandler {
                 TimeUnit.MILLISECONDS, null, SocketWrapperBase.COMPLETE_WRITE, errorCompletion,
                 ByteBuffer.wrap(localSettings.getSettingsFrameForPending()),
                 ByteBuffer.wrap(createWindowUpdateForSettings()));
-        if (error != null) {
+        Throwable err = error.get();
+        if (err != null) {
             String msg = sm.getString("upgradeHandler.sendPrefaceFail", connectionId);
             if (log.isDebugEnabled()) {
                 log.debug(msg);
             }
-            throw new ProtocolException(msg, error);
+            throw new ProtocolException(msg, err);
         }
     }
 
@@ -270,17 +272,17 @@ public class Http2AsyncUpgradeHandler extends Http2UpgradeHandler {
 
 
     private void handleAsyncException() throws IOException {
-        if (applicationIOE != null) {
-            IOException ioe = applicationIOE;
-            applicationIOE = null;
+        IOException ioe = applicationIOE.getAndSet(null);
+        if (ioe != null) {
             handleAppInitiatedIOException(ioe);
-        } else if (error != null) {
-            Throwable error = this.error;
-            this.error = null;
-            if (error instanceof IOException) {
-                throw (IOException) error;
-            } else {
-                throw new IOException(error);
+        } else {
+            Throwable err = this.error.getAndSet(null);
+            if (err != null) {
+                if (err instanceof IOException) {
+                    throw (IOException) err;
+                } else {
+                    throw new IOException(err);
+                }
             }
         }
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org