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

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

commit ad81d14f840d8cff161cc741ac0f398280a8d1cf
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 a622fbf32e..25e4e413ac 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