Skip to content

fix(libc): correct transient-errno predicate in js_waker_signal#1480

Merged
bnoordhuis merged 1 commit into
quickjs-ng:masterfrom
nordstjernen-web:claude/sec-waker-errno-predicate
May 17, 2026
Merged

fix(libc): correct transient-errno predicate in js_waker_signal#1480
bnoordhuis merged 1 commit into
quickjs-ng:masterfrom
nordstjernen-web:claude/sec-waker-errno-predicate

Conversation

@andreasrosdal
Copy link
Copy Markdown
Contributor

The retry loop in js_waker_signal used errno != EAGAIN || errno != EINTR, which is always true (any single errno value is unequal to at least one of the two), so the loop bailed on the first short-write error and silently dropped the wakeup. Replace with && so the loop only exits on a fatal errno.

No test: js_waker_signal's transient-error path is reached only when the pipe is full or the syscall is interrupted by a signal, neither of which is reliably reproducible in a portable unit test.

The retry loop in js_waker_signal used `errno != EAGAIN || errno != EINTR`,
which is always true (any single errno value is unequal to at least one of
the two), so the loop bailed on the first short-write error and silently
dropped the wakeup. Replace with `&&` so the loop only exits on a fatal
errno.

No test: js_waker_signal's transient-error path is reached only when the
pipe is full or the syscall is interrupted by a signal, neither of which
is reliably reproducible in a portable unit test.
Comment thread quickjs-libc.c
if (ret == 1)
break;
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
if (ret < 0 && errno != EAGAIN && errno != EINTR)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems to be a buglet that predates quickjs-ng (also present in OG quickjs) but, on closer inspection, I think it should only be checking for EINTR, not EAGAIN.

The file descriptors are in blocking mode so EAGAIN is unexpected and should never happen. If it does, then a) something is wrong, and b) we'd be busy-looping.

Having said that, pre-existing condition. Doesn't need to hold up this PR.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It is indeed a pre-existing condition and it seems to go back to 2020-09-06.

The condition simplifies as if (ret < 0) which ignores the potential need for restarting the write in case of a signal.

I wonder what it would take for clang to catch the constant expression (errno != EAGAIN || errno != EINTR))

@bnoordhuis bnoordhuis merged commit 14892f8 into quickjs-ng:master May 17, 2026
124 checks passed
mochaaP pushed a commit to mcha-forks/quickjs that referenced this pull request May 20, 2026
The retry loop in js_waker_signal used `errno != EAGAIN || errno != EINTR`,
which is always true (any single errno value is unequal to at least one of
the two), so the loop bailed on the first short-write error and silently
dropped the wakeup. Replace with `&&` so the loop only exits on a fatal
errno.

No test: js_waker_signal's transient-error path is reached only when the
pipe is full or the syscall is interrupted by a signal, neither of which
is reliably reproducible in a portable unit test.

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 14892f8)
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.

4 participants