Skip to content

Stop wire close from SMBRawIO finalizer#353

Open
henrik-nil-acc wants to merge 1 commit into
jborean93:masterfrom
henrik-nil-acc:pr/raw-io-finalizer-deadlock
Open

Stop wire close from SMBRawIO finalizer#353
henrik-nil-acc wants to merge 1 commit into
jborean93:masterfrom
henrik-nil-acc:pr/raw-io-finalizer-deadlock

Conversation

@henrik-nil-acc

Copy link
Copy Markdown
Contributor

Fixes #352.

io.IOBase.del would call self.close() during GC, which
issues SMB I/O and waits on Connection.receive(). On the
worker thread that wait self-deadlocks. Override
SMBRawIO.del to skip the wire close and emit
ResourceWarning instead, mirroring asyncio.BaseEventLoop
and subprocess.Popen, which warn rather than perform
cleanup that would be unsafe in the finalizer's thread.

Add a Connection.receive guard that raises SMBException if
called from the worker thread, so the same mistake fails
loudly elsewhere.

The warning fires only when an SMBRawIO is dropped without
being closed. The usual idioms (with open_file(...) as f:
or explicit f.close()) prevent it; the smbclient.shutil
helpers manage their own handles.

The inherited io.IOBase.__del__ calls close(), which sends
an SMB2 CLOSE and waits on Connection.receive(). When GC
schedules the finalizer on the SMB worker thread, the wait
self-deadlocks: only the worker can set the event it is
waiting on.
@codecov

codecov Bot commented May 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.78%. Comparing base (fef0d8f) to head (d0a5004).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #353   +/-   ##
=======================================
  Coverage   98.78%   98.78%           
=======================================
  Files          24       24           
  Lines        5273     5285   +12     
=======================================
+ Hits         5209     5221   +12     
  Misses         64       64           
Flag Coverage Δ
macOS 68.62% <91.66%> (+0.43%) ⬆️
py3.10 98.78% <100.00%> (+<0.01%) ⬆️
py3.11 98.78% <100.00%> (+<0.01%) ⬆️
py3.12 98.78% <100.00%> (+<0.01%) ⬆️
py3.13 98.78% <100.00%> (+<0.01%) ⬆️
py3.14 98.78% <100.00%> (+<0.01%) ⬆️
ubuntu 96.63% <100.00%> (+<0.01%) ⬆️
windows 98.71% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/smbclient/_io.py
return
if closed:
return
_warn(f"unclosed SMB handle {self._name!r}", ResourceWarning, source=self)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

_warn doesn't seem to be defined so it sounds like this would fail? Is the goal for this to be a no-op with the warning added?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

_warn is defined at line 428.
Yes, it's supposed to be warning and no-op.
This means a resource leak, not good but better than deadlock.
There are multiple locations that needs fixes in the error paths to avoid that and I plan follow-up PR's once this is merged.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Is there a reason why you used the pattern to define the function as a kwarg default? Why not just do warnings.warn(...) instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The pattern was copied from subprocess.Popen.__del__. I guess there is a theoretical chance the "warnings" is teared down at the time of calling del if not holding a reference. But I can remove that part if you want me to? I have not seen it happen.

@henrik-nil-acc

Copy link
Copy Markdown
Contributor Author

Anything I can do to help to git this merged? The issue has a reproducer, it will trigger a bunch of other issues that I have fixes for once this is merged.

@jborean93

Copy link
Copy Markdown
Owner

Sorry I've been away for a bit so have had limited GitHub interaction. Just added another reply to the change.

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.

Concurrent rmtree deadlocks the SMB connection on garbage collection

2 participants