Close all inherited file descriptors in restartServer() by Mohak51234 · Pull Request #15992 · redis/redis · GitHub
Skip to content

Close all inherited file descriptors in restartServer() - #15992

Open
Mohak51234 wants to merge 1 commit into
redis:unstablefrom
Mohak51234:fix-debug-restart-fds
Open

Mohak51234 wants to merge 1 commit into
redis:unstablefrom
Mohak51234:fix-debug-restart-fds

Conversation

@Mohak51234

@Mohak51234 Mohak51234 commented Oct 17, 2026 •

Copy link
Copy Markdown

Fixes #15860

Problem

restartServer() (used by DEBUG RESTART) is meant to close every inherited file descriptor except stdin/stdout/stderr before execve(), but its loop only covered [3, maxclients + 1024). A descriptor inherited from the parent at a higher number, without FD_CLOEXEC, stayed open in the restarted process.

Change

Added closeInheritedFds() in src/server.c:

  1. On Linux, close_range(3, ~0U, 0) closes everything in one syscall.
  2. If that is unavailable, list /proc/self/fd (or /dev/fd), find the highest open descriptor, and close up to it.
  3. If neither can be read, fall back to the previous bound.

restartServer() now calls it instead of the fixed-bound loop.

Testing

  • Reproduced with the script from the issue (fd 1500 with maxclients 100): before the change fd 1500 stays open after DEBUG RESTART, after the change both fds are closed.
  • Added a regression test in tests/unit/other.tcl that starts a server from a shell with fd 1500 open and maxclients 100, runs DEBUG RESTART, and checks the descriptor is gone. It fails without the change and passes with it.
  • Tested the fallback path by temporarily compiling out the close_range branch; both fds still closed.
  • Tested on Linux (WSL2) only. The /dev/fd path for macOS/BSD is untested. The new test is Linux-only (reads /proc).

Note

Medium Risk
Changes process restart/exec hygiene; wrong FD closure could affect restart or child processes, but scope is limited to DEBUG RESTART rather than normal request handling.

Overview
Fixes incomplete FD cleanup before execve() in restartServer() (used by DEBUG RESTART): the old loop only closed descriptors up to maxclients + 1024, so inherited fds above that could leak into the restarted process.

closeInheritedFds() replaces that loop—on Linux it tries close_range(3, UINT_MAX) first, otherwise scans /proc/self/fd or /dev/fd for the highest open fd and closes through it, with the previous bound as a last resort. Valgrind-safe fcntl/close behavior is unchanged.

A Linux-only regression test in tests/unit/other.tcl starts a server with fd 1500 inherited and asserts it is gone after DEBUG RESTART.

Reviewed by Cursor Bugbot for commit 89c7a76. Bugbot is set up for automated code reviews on this repo. Configure here.

@CLAassistant

CLAassistant commented Oct 17, 2026 •

Copy link
Copy Markdown

@Mohak51234

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] DEBUG RESTART leaves inherited file descriptors above maxclients + 1024 open

2 participants