Skip to content

libutil: treat EIO as EOF in readLine#15323

Merged
Ericson2314 merged 1 commit intoNixOS:masterfrom
obsidiansystems:fix-eio-readline
Feb 23, 2026
Merged

libutil: treat EIO as EOF in readLine#15323
Ericson2314 merged 1 commit intoNixOS:masterfrom
obsidiansystems:fix-eio-readline

Conversation

@amaanq
Copy link
Member

@amaanq amaanq commented Feb 23, 2026

Motivation

Reading from a pty master returns EIO once the slave side closes, however, readLine lets it propagate as an uncaught SysError, which causes spurious build failures in gvisor and similar sandboxed environments where pty teardown races differently. This commit catches EIO inside the read lambda and maps it to a zero-length read, reusing the existing EOF path.

Context

When pty support was first added in #2878, EIO was handled at the call site, but a later refactor moved reading to the generic readLine which didn't carry the handling over, though muxable-pipe.cc still has it.

Note that the test is skipped on macOS, because macOS returns EOF with 0 immediately and discards all buffered data (ref).


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@amaanq amaanq requested a review from edolstra as a code owner February 23, 2026 18:03
Reading from a pty master returns `EIO` once the slave side closes, however, `readLine` lets it propagate as an uncaught `SysError`, which causes spurious build failures in gvisor and similar sandboxed environments where pty teardown races differently. This commit catches `EIO` inside the read lambda and maps it to a zero-length read, reusing the existing EOF path.
@Ericson2314 Ericson2314 added this pull request to the merge queue Feb 23, 2026
Merged via the queue into NixOS:master with commit 3bfd64c Feb 23, 2026
17 checks passed
@Ericson2314 Ericson2314 deleted the fix-eio-readline branch February 23, 2026 20:14
Comment on lines +80 to +89
try {
return read(fd, {reinterpret_cast<std::byte *>(&ch), 1});
} catch (SystemError & e) {
// On pty masters, EIO signals that the slave side closed,
// which is semantically EOF. Map it to a zero-length read
// so the existing EOF path handles it.
if (e.is(std::errc::io_error))
return 0;
throw;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we apply the same treatment to FdSource::readLine/readUnbuffered under a certain flag maybe? I don't think we want to keep the one-byte-at-a-time reading function for too long anyway.

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.

Getting EIO errors from nix build

3 participants