Skip to content

Comments

Add failing tests for #403: File Handle Resource Leak in SyncLock.acquire()#405

Merged
gltanaka merged 2 commits intopromptdriven:mainfrom
Serhan-Asad:fix/issue-403
Jan 27, 2026
Merged

Add failing tests for #403: File Handle Resource Leak in SyncLock.acquire()#405
gltanaka merged 2 commits intopromptdriven:mainfrom
Serhan-Asad:fix/issue-403

Conversation

@Serhan-Asad
Copy link
Collaborator

@Serhan-Asad Serhan-Asad commented Jan 26, 2026

Summary

Fixes the file handle resource leak bug in SyncLock.acquire() reported in #403.

Changes

Code Fix

File: pdd/sync_determine_operation.py (lines 185-202)

Added nested try-except block to ensure file descriptors are properly closed on ANY exception:

self.fd = open(self.lock_file, 'w')
try:
    # Critical section - must close file if anything fails
    if HAS_FCNTL:
        fcntl.flock(self.fd.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    # ... write PID ...
except:
    # Close file on ANY exception (not just IOError/OSError)
    if self.fd:
        self.fd.close()
        self.fd = None
    raise

Tests Added

File: tests/test_sync_determine_operation.py

  • test_file_handle_cleanup_on_keyboard_interrupt - Verifies fd cleanup on Ctrl+C
  • test_file_handle_cleanup_on_runtime_error - Verifies fd cleanup on unexpected errors
  • test_file_handle_cleanup_on_exception_during_write - Verifies fd cleanup during write failures

Testing

All 11 SyncLock unit tests pass
All 88 tests in test_sync_determine_operation.py pass
5/5 manual comprehensive tests pass

Manual Testing Performed

  1. Normal lock acquisition and release - ✅ No leaks
  2. KeyboardInterrupt during acquisition - ✅ FD properly closed
  3. RuntimeError during acquisition - ✅ FD properly closed
  4. Exception during PID write - ✅ FD properly closed
  5. Context manager usage - ✅ FD properly closed

Impact

  • Prevents file descriptor exhaustion in long-running processes
  • Fixes crashes with OSError: [Errno 24] Too many open files
  • Improves reliability for PDD server, CI/CD pipelines, and automated scripts

Root Cause Fixed

The original code only caught (IOError, OSError) for cleanup, allowing other exceptions like KeyboardInterrupt, RuntimeError, or ValueError to leak file descriptors. The fix uses a bare except: clause to catch ALL exceptions and ensure cleanup.

Fixes #403

…ak in SyncLock.acquire()

This commit adds comprehensive unit and E2E tests that detect the file handle
resource leak in SyncLock.acquire() when non-IOError/OSError exceptions occur.

Tests added:
- Unit tests in test_sync_determine_operation.py (6 tests)
  - KeyboardInterrupt during lock acquisition
  - RuntimeError during lock acquisition
  - Exception during file operations
  - IOError/OSError regression tests
  - Normal operation regression tests
  - Context manager exception handling

- E2E tests in test_e2e_issue_403_file_handle_leak.py (4 tests)
  - Real-world KeyboardInterrupt scenario (Ctrl+C)
  - RuntimeError leak detection
  - Normal operation verification
  - Context manager interrupt handling

All tests correctly fail on current code, detecting the bug where file
descriptors remain open when exceptions other than IOError/OSError occur
during lock acquisition.

Related to promptdriven#403

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@gltanaka gltanaka requested a review from Copilot January 26, 2026 17:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive test coverage to detect a file descriptor resource leak in SyncLock.acquire() when interrupted by exceptions other than IOError or OSError. The tests verify that the current exception handling is insufficient and demonstrate that the proposed fix (nested try-finally block) will resolve the issue.

Changes:

  • Added 6 unit tests covering KeyboardInterrupt, RuntimeError, write failures, and regression scenarios
  • Added 4 E2E tests that simulate real-world interrupt scenarios using subprocess isolation
  • Included the fix implementation showing nested try-finally pattern for guaranteed cleanup

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
tests/test_sync_determine_operation.py Unit tests for file handle cleanup under various exception conditions
tests/test_e2e_issue_403_file_handle_leak.py E2E tests simulating real-world KeyboardInterrupt and RuntimeError scenarios
pdd/sync_determine_operation.py Implementation of nested try-finally fix for guaranteed file descriptor cleanup

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Serhan-Asad Serhan-Asad marked this pull request as ready for review January 27, 2026 00:52
@gltanaka gltanaka merged commit afa48bb into promptdriven:main Jan 27, 2026
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: File Handle Resource Leak in SyncLock.acquire()

2 participants