Skip to content

Fix TypeError when processing a detached watcher#88

Merged
ioquatix merged 3 commits intosocketry:mainfrom
Watson1978:fix-race-condition
Feb 9, 2026
Merged

Fix TypeError when processing a detached watcher#88
ioquatix merged 3 commits intosocketry:mainfrom
Watson1978:fix-race-condition

Conversation

@Watson1978
Copy link
Contributor

@Watson1978 Watson1978 commented Dec 19, 2025

Fix #87

This patch will fix a race condition where Coolio_Loop_process_event attempts to process an event for a watcher that has already been detached.

When detach is called (e.g., from another thread or a preceding callback in the same loop cycle), the watcher's loop reference is cleared to nil.
If an event for this watcher was already pending in the libev queue, the subsequent processing step causes an TypeError:

TypeError: wrong argument type nil (expected Coolio::Loop)

The patch will add a check to ensure the watcher is still enabled before accessing the loop data. If the watcher is detached (enabled == 0), the pending event is ignored.

Types of Changes

  • Bug fix.

Contribution

This patch will fix a race condition where `Coolio_Loop_process_event` attempts to process an event for a watcher that has already been detached.

When detach is called (e.g., from another thread or a preceding callback in the same loop cycle),
the watcher's loop reference is cleared to nil.
If an event for this watcher was already pending in the libev queue,
the subsequent processing step causes an TypeError:

```
TypeError: wrong argument type nil (expected Coolio::Loop)
```

The patch will add a check to ensure the watcher is still enabled before accessing the loop data.
If the watcher is detached (enabled == 0), the pending event is ignored.
@Watson1978
Copy link
Contributor Author

@ioquatix Can you look this PR?
Thanks.

@ioquatix
Copy link
Member

Do you think you can add a test?

@Watson1978
Copy link
Contributor Author

Do you think you can add a test?

I will try to add test. Thanks.

@Watson1978
Copy link
Contributor Author

@ioquatix Sorry for late. I added the test for this PR.

@ioquatix
Copy link
Member

ioquatix commented Feb 1, 2026

Hmm, is the segfault related?

-- C level backtrace information -------------------------------------------
/Users/runner/hostedtoolcache/Ruby/3.3.10/arm64/lib/libruby.3.3.dylib(rb_vm_bugreport+0xb4c) [0x1017c1814]
/Users/runner/hostedtoolcache/Ruby/3.3.10/arm64/lib/libruby.3.3.dylib(rb_bug_for_fatal_signal+0x100) [0x101601abc]
/Users/runner/hostedtoolcache/Ruby/3.3.10/arm64/lib/libruby.3.3.dylib(sig_do_nothing+0x0) [0x1017284e4]
/usr/lib/system/libsystem_platform.dylib(_sigtramp+0x38) [0x18750d6a4]
/Users/runner/work/cool.io/cool.io/lib/cool.io_ext.bundle(Coolio_IOWatcher_detach+0x34) [0x101485a88]

@Watson1978
Copy link
Contributor Author

It is difficult to say for sure without seeing the stack trace, but it is highly likely related.

Since macOS uses kqueue (whereas Linux uses epoll), the behavior of libev regarding detached watchers might differ.
In Linux, accessing watcher_data->enabled was safe (it just prevented the TypeError), but on macOS, if the watcher_data structure itself is corrupted or freed immediately after detach, accessing its member could trigger a SEGV.

I will look the SEGV later.

@ioquatix
Copy link
Member

ioquatix commented Feb 3, 2026

When Object X is freed (during finalizer) you cannot usually access other objects it referenced, as they may also be freed at the same time (and before the current object is finalized). Not sure if that applies here, but it's something I've run into in the past.

@Watson1978
Copy link
Contributor Author

I have updated the PR to fix the SEGV issue on macOS as well.
See 290370b

The crash on macOS was caused by a race condition where detach was called multiple times (or concurrently with loop processing), leading to a NULL pointer dereference in ev_io_stop.

@ioquatix ioquatix merged commit 9f2dd44 into socketry:main Feb 9, 2026
15 checks passed
@ioquatix ioquatix added this to the v1.9.2 milestone Feb 9, 2026
@Watson1978 Watson1978 deleted the fix-race-condition branch February 9, 2026 08:21
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.

TypeError: wrong argument type nil (expected Data) when processing a detached watcher

2 participants