Skip to content

Fix race condition when deleting pidfile#3657

Merged
schneems merged 1 commit intopuma:masterfrom
marksmith:fix-delete-pidfile-race-condition
Oct 16, 2025
Merged

Fix race condition when deleting pidfile#3657
schneems merged 1 commit intopuma:masterfrom
marksmith:fix-delete-pidfile-race-condition

Conversation

@marksmith
Copy link
Copy Markdown

@marksmith marksmith commented May 21, 2025

Description

In a concurrent environment, a race condition can occur if the file is deleted between the call to File.exist? and the call to File.unlink. In this case, File.unlink will raise an Errno::ENOENT exception because the file no longer exists. This change removes the explicit File.exist? check and instead safely rescues Errno::ENOENT.

Your checklist for this pull request

  • I have reviewed the guidelines for contributing to this repository.
  • I have added (or updated) appropriate tests if this PR fixes a bug or adds a feature.
  • My pull request is 100 lines added/removed or less so that it can be easily reviewed.
  • If this PR doesn't need tests (docs change), I added [ci skip] to the title of the PR.
  • If this closes any issues, I have added "Closes #issue" to the PR description or my commit messages.
  • I have updated the documentation accordingly.
  • All new and existing tests passed, including Rubocop.

When the pidfile is removed between File.exist? and File.unlink.
@bitterpanda63
Copy link
Copy Markdown

This was an issue when running benchmarks with puma, subscribed to this PR

Comment thread lib/puma/launcher.rb
path = @options[:pidfile]
File.unlink(path) if path && File.exist?(path)
begin
File.unlink(path) if path
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
File.unlink(path) if path
File.unlink(path) if path && File.exist?(path)

Only do the rescue if race conditions occur, this would make it rescue even without race conditions (which I assume would have a performance impact)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should commonly be the case that the pidfile exists; in the expected case that path is non-nil and the file exists then the single syscall to unlink(2) should be cheaper than the two syscalls, and in the unexpected case where path is non-nil and the file doesn't exist, the syscall to stat(2) should not be cheaper than the syscall to unlink(2). Any difference should come from raising the exception, but as stated this should already be the exceptional case. We should also not expect the call to delete_pidfile to be called in a performance-critical path, but if this is a concern, this should be verified.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree if this is the edge case that the file does not exist.

@github-actions github-actions Bot added the waiting-for-review Waiting on review from anyone label May 21, 2025
Comment thread lib/puma/launcher.rb
path = @options[:pidfile]
File.unlink(path) if path && File.exist?(path)
begin
File.unlink(path) if path
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are still making a change to how this function works regardless of whether there are race conditions or not. So the question is if there are other errors that arise when not checking File.exist?(...) apart from the ENOENT.

ENOENT: A component in pathname does not exist or is a dangling
symbolic link, or pathname is empty.

Given the definition of the error after the syscall, I am assuming the behaviour is the same as the File.exist? but just without race conditions

@marksmith marksmith changed the title Fix race condition when deleting pidfile Fix race condition when deleting pidfile [ci skip] Jul 18, 2025
@MSP-Greg
Copy link
Copy Markdown
Member

In a concurrent environment, a race condition can occur

and

This was an issue when running benchmarks

Not sure what is causing the above, but the changes in this PR are reasonable.

@MSP-Greg MSP-Greg changed the title Fix race condition when deleting pidfile [ci skip] Fix race condition when deleting pidfile Jul 28, 2025
@github-actions github-actions Bot added waiting-for-merge and removed waiting-for-review Waiting on review from anyone labels Jul 28, 2025
@schneems schneems merged commit cc7dc1e into puma:master Oct 16, 2025
83 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants