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

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

commit 10024c954ef56ab9daf5d09280cebfd72e49c846
Author: opencode <[email protected]>
AuthorDate: Mon Oct 12 10:44:39 2026 +0200

    Fix NPE in ExtendedAccessLogValve.open() after a failed open
    
    The base AccessLogValve.open() tolerates a failure to open the log
    file: it logs the error and leaves the writer and the current log file
    null, so the container starts without an access log and log calls are
    skipped. The ExtendedAccessLogValve override dereferenced the current
    log file to decide whether the file header had to be written, which
    threw a NullPointerException when the open had failed. At startup, that
    failure propagated out of startInternal() as a LifecycleException and
    the container failed to start instead of running without the access
    log. On the rotation paths, including the checkExists retry in log(),
    the NPE was thrown on the request thread and swallowed by
    CoyoteAdapter, dropping the log entry.
    
    The override now writes the header only when the open succeeded,
    matching the null writer guards used elsewhere. A regression test
    points the valve at a path that cannot exist as a directory and
    asserts that opening fails gracefully, leaving the writer null.
---
 .../catalina/valves/ExtendedAccessLogValve.java    |  4 +-
 .../valves/TestExtendedAccessLogValveOpen.java     | 45 ++++++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java 
b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
index ff60efa82a..cb3919125a 100644
--- a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
+++ b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
@@ -132,7 +132,9 @@ public class ExtendedAccessLogValve extends AccessLogValve {
     @Override
     protected synchronized void open() {
         super.open();
-        if (currentLogFile.length() == 0) {
+        // The base class tolerates a failed open and leaves the writer null
+        // in which case there is nothing to write the header to
+        if (writer != null && currentLogFile.length() == 0) {
             writer.println("#Fields: " + pattern);
             writer.println("#Version: 2.0");
             writer.println("#Software: " + ServerInfo.getServerInfo());
diff --git 
a/test/org/apache/catalina/valves/TestExtendedAccessLogValveOpen.java 
b/test/org/apache/catalina/valves/TestExtendedAccessLogValveOpen.java
new file mode 100644
index 0000000000..36f52d5ffe
--- /dev/null
+++ b/test/org/apache/catalina/valves/TestExtendedAccessLogValveOpen.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.valves;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestExtendedAccessLogValveOpen {
+
+    /*
+     * The base class tolerates a failure to open the log file and leaves the 
writer null. Opening a log file under a
+     * path that cannot exist as a directory must not throw and must leave the 
writer null so that log writing is
+     * skipped, matching the behaviour of the base class.
+     */
+    @Test
+    public void testOpenFailureLeavesWriterNull() throws IOException {
+        File notADirectory = File.createTempFile("tomcat-not-a-directory", 
".txt");
+        notADirectory.deleteOnExit();
+
+        ExtendedAccessLogValve valve = new ExtendedAccessLogValve();
+        valve.setDirectory(new File(notADirectory, "logs").getPath());
+
+        // Must not throw, since the base class open() tolerates the failure
+        valve.open();
+
+        Assert.assertNull("The writer must be null after a failed open", 
valve.writer);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to