This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 83d64b4bb8326717b6fb0cff9fd7feb009a976ad 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 20bbc70e90..9138be7d3a 100644 --- a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java +++ b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java @@ -131,7 +131,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]
