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

git-hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 7cf8e6422 fix(server): add O_TRUNC when creating PID file to avoid 
stale content (#3598)
7cf8e6422 is described below

commit 7cf8e642274ad47a606859f4e3d940ffa1532c76
Author: weimeng <[email protected]>
AuthorDate: Thu Sep 3 12:32:34 2026 +0800

    fix(server): add O_TRUNC when creating PID file to avoid stale content 
(#3598)
    
    What problem does this change solve?
    
    CreatePidFile opens the PID file with O_RDWR | O_CREAT but without
    O_TRUNC. If a stale PID file already exists from a previous run and the
    old PID string is longer than the new one, open() + write() will only
    overwrite the first N bytes of the file, leaving the trailing bytes from
    the old content intact. This results in a corrupted PID file.
    
    Example:
    Step File content Note
    Previous run (PID=12345) 12345 correct
    New run (PID=678), without O_TRUNC 67845 corrupted — trailing 45 is
    stale
    New run (PID=678), with O_TRUNC            678                 correct
    
    A corrupted PID file can cause process management tools (e.g., kill
    $(cat pidfile), systemd, init scripts) to target the wrong process or
    fail to stop/restart the service.
    
    How does this change fix the problem?
    
    Add O_TRUNC to the open() flags in CreatePidFile so the file is
    truncated to zero length before writing the new PID, ensuring no stale
    bytes remain.
    
    Changes
    
    - src/cli/pid_util.h: Add O_TRUNC flag to the open() call in
    CreatePidFile.
    - tests/cppunit/pid_util_test.cc: Add unit tests covering:
    - - Truncation on existing file: Write a longer fake PID first, then
    call CreatePidFile and verify the content matches exactly the current
    PID with no leftover bytes.
    - - Creation from scratch: Verify CreatePidFile works correctly when no
    file exists.
    - - RemovePidFile: Verify the PID file is properly removed.
    
    ---------
    
    Co-authored-by: weimeng <[email protected]>
    Co-authored-by: Twice <[email protected]>
    Co-authored-by: hulk <[email protected]>
---
 src/cli/pid_util.h             |  2 +-
 tests/cppunit/pid_util_test.cc | 60 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/cli/pid_util.h b/src/cli/pid_util.h
index eb7c41b2c..bbf73c492 100644
--- a/src/cli/pid_util.h
+++ b/src/cli/pid_util.h
@@ -27,7 +27,7 @@
 #include "unique_fd.h"
 
 inline Status CreatePidFile(const std::string &path) {
-  auto fd = UniqueFD(open(path.data(), O_RDWR | O_CREAT, 0660));
+  auto fd = UniqueFD(open(path.data(), O_RDWR | O_CREAT | O_TRUNC, 0660));
   if (!fd) {
     return Status::FromErrno();
   }
diff --git a/tests/cppunit/pid_util_test.cc b/tests/cppunit/pid_util_test.cc
new file mode 100644
index 000000000..56681b2ae
--- /dev/null
+++ b/tests/cppunit/pid_util_test.cc
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ */
+
+#include "cli/pid_util.h"
+
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <fstream>
+#include <string>
+
+TEST(PidUtil, CreatePidFileTruncatesExistingContent) {
+  // Simulate a stale PID file whose content is longer than the current PID.
+  // Without O_TRUNC, CreatePidFile would overwrite only the first N bytes,
+  // leaving trailing characters from the old content and producing an
+  // incorrect PID string (e.g. old "12345678" + new "999" => "99945678").
+  const std::string path = "/tmp/kvrocks_pid_util_test.pid";
+
+  // Write a fake old PID that is guaranteed to be longer than any real PID.
+  {
+    auto fd = UniqueFD(open(path.data(), O_RDWR | O_CREAT | O_TRUNC, 0660));
+    ASSERT_TRUE(fd);
+    const std::string old_pid = "99999999";  // 8 chars
+    ASSERT_TRUE(util::Write(*fd, old_pid).IsOK());
+  }
+
+  // Now call CreatePidFile which should overwrite with the real (shorter) PID.
+  auto status = CreatePidFile(path);
+  ASSERT_TRUE(status.IsOK());
+
+  // Read back and verify the content is exactly the current PID.
+  std::ifstream ifs(path);
+  std::string content((std::istreambuf_iterator<char>(ifs)), 
std::istreambuf_iterator<char>());
+  ifs.close();
+
+  std::string expected = std::to_string(getpid());
+  EXPECT_EQ(content, expected);
+  EXPECT_EQ(content.size(), expected.size()) << "PID file should not contain 
leftover bytes from previous content";
+
+  RemovePidFile(path);
+}

Reply via email to