This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new b279b9f5ca Guard pre-init log wakeups (#13472)
b279b9f5ca is described below
commit b279b9f5cad5f4bdbe13fe3b86bad45cbc8109c9
Author: Brian Neradt <[email protected]>
AuthorDate: Mon Aug 3 17:39:15 2026 -0500
Guard pre-init log wakeups (#13472)
Plugins can fill a text log buffer during TSPluginInit before logging
preprocessing threads and their notification objects exist. This causes
a null dereference that crashes traffic_server during startup.
This problem is addressed in this patch by queuing those buffers without
signaling until the logging workers exist. Their initial queue scan then
flushes the pending data. A regression test forces a rollover during
plugin initialization and verifies ATS stays up and preserves the log
entry.
With the production fix removed, the regression test caused
traffic_server to crash with SIGSEGV at address zero while signaling the
preprocessing notification. With the fix applied, the identical test
passes.
---
src/proxy/logging/LogObject.cc | 8 +++--
tests/gold_tests/logging/log_plugin_init.test.py | 38 ++++++++++++++++++++++++
tests/tools/plugins/test_log_interface.cc | 11 ++++++-
3 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/src/proxy/logging/LogObject.cc b/src/proxy/logging/LogObject.cc
index 9269ed3136..741019140b 100644
--- a/src/proxy/logging/LogObject.cc
+++ b/src/proxy/logging/LogObject.cc
@@ -395,7 +395,9 @@ LogObject::_checkout_write(size_t *write_offset, size_t
bytes_needed)
int idx = m_buffer_manager_idx++ % m_flush_threads;
Dbg(dbg_ctl_log_logbuffer, "adding buffer %d to flush list after
checkout", buffer->get_id());
m_buffer_manager[idx].add_to_flush_queue(buffer);
- Log::preproc_notify[idx].signal();
+ if (Log::preproc_notify != nullptr) {
+ Log::preproc_notify[idx].signal();
+ }
buffer = nullptr;
}
@@ -574,7 +576,9 @@ LogObject::flush_buffer(LogBuffer *buffer)
int idx = m_buffer_manager_idx++ % m_flush_threads;
Dbg(dbg_ctl_log_logbuffer, "adding buffer %d to flush list after checkout",
buffer->get_id());
m_buffer_manager[idx].add_to_flush_queue(buffer);
- Log::preproc_notify[idx].signal();
+ if (Log::preproc_notify != nullptr) {
+ Log::preproc_notify[idx].signal();
+ }
}
int
diff --git a/tests/gold_tests/logging/log_plugin_init.test.py
b/tests/gold_tests/logging/log_plugin_init.test.py
new file mode 100644
index 0000000000..24fa59ac72
--- /dev/null
+++ b/tests/gold_tests/logging/log_plugin_init.test.py
@@ -0,0 +1,38 @@
+'''
+Verify text logging during plugin initialization.
+'''
+# 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.
+
+import os
+
+Test.Summary = '''
+Verify plugins can fill a text log buffer before logging threads start.
+'''
+
+ts = Test.MakeATSProcess('ts')
+ts.Disk.records_config.update({'proxy.config.log.log_buffer_size': 9216})
+Test.PrepareTestPlugin(os.path.join(Test.Variables.AtsTestPluginsDir,
'test_log_interface.so'), ts, '--write-during-init')
+
+plugin_log = Test.Disk.File(os.path.join(ts.Variables.LOGDIR,
'test_log_interface.log'), exists=True)
+plugin_log.Content = Testers.ContainsExpression(
+ 'Writing during plugin initialization', 'The pre-initialization log buffer
should be flushed')
+
+tr = Test.AddTestRun('Start ATS with a plugin that fills a text log buffer
during initialization')
+tr.Processes.Default.Command = 'printf "traffic_server remained running"'
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.StartBefore(ts)
+tr.StillRunningAfter = ts
diff --git a/tests/tools/plugins/test_log_interface.cc
b/tests/tools/plugins/test_log_interface.cc
index c61d54fbfb..1378acc678 100644
--- a/tests/tools/plugins/test_log_interface.cc
+++ b/tests/tools/plugins/test_log_interface.cc
@@ -73,7 +73,7 @@ global_handler(TSCont /* continuation ATS_UNUSED */, TSEvent
event, void *data)
}
void
-TSPluginInit(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+TSPluginInit(int argc, const char **argv)
{
TSPluginRegistrationInfo info;
@@ -87,5 +87,14 @@ TSPluginInit(int /* argc ATS_UNUSED */, const char ** /*
argv ATS_UNUSED */)
}
TSAssert(TS_SUCCESS == TSTextLogObjectCreate(plugin_name,
TS_LOG_MODE_ADD_TIMESTAMP, &pluginlog));
+
+ if (argc > 1 && strcmp(argv[1], "--write-during-init") == 0) {
+ const std::string long_line(5000, 'i');
+
+ for (int i = 0; i < 2; ++i) {
+ TSAssert(TS_SUCCESS == TSTextLogObjectWrite(pluginlog, "Writing during
plugin initialization: %s", long_line.c_str()));
+ }
+ }
+
TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(global_handler,
nullptr));
}