Skip to content

Conversation

edolstra
Copy link
Collaborator

@edolstra edolstra commented Sep 18, 2025

Motivation

Context

Summary by CodeRabbit

  • New Features
    • Adds “daemon” and “local” shorthand store references; normalization maps unix:// → daemon and local:// → local. Rendering uses “daemon”/“local” when no parameters.
  • Bug Fixes
    • Improves parsing of SSH URLs with unbracketed IPv6 addresses and better handling of scheme/authority edge cases.
    • Increases default connection timeout from 5s to 15s for more reliable networking.
  • Tests
    • Expands test coverage for new shorthands and IPv6 URL cases; updates expectations accordingly.
  • Chores
    • Bumps version to 2.31.2.

edolstra and others added 27 commits September 2, 2025 11:22
…/pr-13900

Fix downstream MinGW build by not looking for Boost Regex (backport NixOS#13900)
On macOS, poll() is fundamentally broken for HUP detection. It loses event
subscriptions when EVFILT_READ fires without matching the requested events
in the pollfd. This causes daemon processes to linger after client disconnect.

This commit replaces poll() with kqueue on macOS, which is what poll()
uses internally but without the bugs. The kqueue implementation uses
EVFILT_READ which works for both sockets and pipes, avoiding EVFILT_SOCK
which only works for sockets.

On Linux and other platforms, we continue using poll() with the standard
POSIX behavior where POLLHUP is always reported regardless of requested events.

Based on work from the Lix project (https://git.lix.systems/lix-project/lix)
commit 69ba3c92db3ecca468bcd5ff7849fa8e8e0fc6c0

Fixes: NixOS#13847
Related: https://git.lix.systems/lix-project/lix/issues/729
Apple bugs: rdar://37537852 (poll), FB17447257 (poll)

Co-authored-by: Jade Lovelace <[email protected]>
(cherry picked from commit 1286d5d)
…/pr-13901

Fix macOS HUP detection using kqueue instead of poll (backport NixOS#13901)
This is relied upon (specifically the `local` store) by existing
tooling [1] and we broke this in 3e7879e (which
was first released in 2.31).

To lessen the scope of the breakage we should not normalize "auto" references
and explicitly specified references like "local" or "daemon". It also makes
sense to canonicalize local://,daemon:// to be more compatible with prior
behavior.

[1]: https://github.com/maralorn/nix-output-monitor/blob/05e1b3cba2fa328a1781390a4e4515e9c432229e/lib/NOM/Builds.hs#L60-L64

(cherry picked from commit 3513ab1)
…/pr-13911

libstore: Do not normalize daemon -> unix://, local -> local:// (backport NixOS#13911)
This implements a special back-compat shim to specifically allow
unbracketed IPv6 addresses in store references. This is something
that is relied upon in the wild and the old parsing logic accepted
both ways (brackets were optional). This patch restores this behavior.
As always, we didn't have any tests for this.

Addresses NixOS#13937.

(cherry picked from commit 7cc654a)
…/pr-13940

libstore: Reallow unbracketed IPv6 addresses in store references (backport NixOS#13940)
This broke in e3042f1.

(cherry picked from commit bccdb95)
I couldn't come up with a test that failed before this, but my existing
test still passes so 🤷

(cherry picked from commit 9c832a0)
…/pr-13934

Fix flake registry ignoring `dir` parameter (backport NixOS#13934)
Will not pass until the next commit.

(cherry picked from commit ed6ef7c)
This is handled similarly in the handler for `--override-flake` in
`MixEvalArgs`.

(cherry picked from commit 38663fb)
…/pr-13939

Pass `dir` in extraAttrs when overriding the registry (backport NixOS#13939)
…/pr-13966

meson: add soversion to libraries (NixOS#13960) (backport NixOS#13966)
This reverts commit bdbc739.

Such a change needs more thought put into it. By versioning
shared libraries we'd make a false impression that libraries
themselves are actually versioned and have some sort of stable
ABI, which is not the case.

This will be useful when C bindings become stable, but as long
as they are experimental it does not make sense to set SONAME.

Also this change should not have been backported, since it's
severely breaking.

(cherry picked from commit 0db2b8c)
This allows the weird network or DNS server fallback mechanism inside
glibc to work, and prevents a "Resolving timed out after 5000
milliseconds" error. Read on for details.

The DNS request stuff (dns-hosts) in glibc uses this fallback procedure
to minimize network RTT in the ideal case while dealing with
ill-behaving networks and DNS servers gracefully (see resolv.conf(5)):

- Use sendmmsg() to send UDP DNS requests for IPv4 and IPv6 in parallel
- If that times out (meaning that none or only one of the responses have
  been received), send the requests one by one, waiting for the response
  before sending the next request ("single-request")
- If that still times out, try to use a different socket (hence
  different address) for each request ("single-request-reopen")

The default timeout inside glibc is 5 seconds. Therefore, setting
connect-timeout, and therefore CURLOPT_CONNECTTIMEOUT to 5 seconds
prevents the single-request fallback, and setting it to even 10 seconds
prevents the single-request-reopen fallback as well.

The fallback decision is saved by glibc, but only thread-locally, and
libcurl starts a new thread for getaddrinfo() for each connection.
Therefore for every connection the fallback starts from sendmmsg() all
over again. And since these are considered to have timed out by libcurl,
even though getaddrinfo() might return a successful result, it is not
cached in libcurl.

While a user could tweak these with resolv.conf(5) options (e.g. using
networking.resolvconf.extraOptions in NixOS), and indeed that is
probably needed to avoid annoying delays, it still means that the
default connect-timeout of 5 is too low. Raise it to give fallback a
chance.

(cherry picked from commit 7295034)
…/pr-13985

libstore: Raise default connect-timeout to 15 secs (backport NixOS#13985)
With the migration to /nix/var/nix/builds we now have failing builds
when the derivation name is too long.
This change removes the derivation name from the temporary build to have
a predictable prefix length:

Also see: NixOS/infra#764
for context.

(cherry picked from commit 725a2f3)
…/pr-13839

don't include derivation name in temporary build directories (backport NixOS#13839)
…/pr-14009

Revert "tests/nixos: Fix daemon store reference in authorization test" (backport NixOS#14009)
Tagging release 2.31.2
Copy link

coderabbitai bot commented Sep 18, 2025

Walkthrough

Introduces new StoreReference variants (Daemon, Local) and updates parsing/rendering to normalize certain URIs to “daemon” and “local”. Adjusts LocalStore/UDSRemoteStore to emit these variants. Refactors MonitorFdHup into OS-specific thread routines. Tweaks Boost modules in Meson. Raises file-transfer connectTimeout. Adds tests and data; bumps version.

Changes

Cohort / File(s) Summary
Version metadata
\.version``
Bump version from 2.31.1 to 2.31.2.
Build system (Meson)
\src/libexpr/meson.build`, `src/libstore/meson.build`, `src/libutil/meson.build``
Reformat modules lists; in libstore, replace Boost ‘regex’ with ‘url’ and comment out ‘regex’. No logic changes elsewhere.
StoreReference API (header)
\src/libstore/include/nix/store/store-reference.hh``
Add StoreReference::Daemon and ::Local (derive from Specified); expand Variant to include them.
StoreReference parsing/rendering
\src/libstore/store-reference.cc`, `src/libstore/store-api.cc``
Implement parsing back-compat and IPv6 handling; render “daemon”/“local” for new variants; switch to std::visit for Specified extraction.
Local/UDS store config
\src/libstore/local-store.cc`, `src/libstore/uds-remote-store.cc``
Return Local when no params in LocalStore; return Daemon for daemon socket path in UDSRemoteStore; otherwise Specified with authority=path.
File transfer settings
\src/libstore/include/nix/store/filetransfer.hh``
Increase connectTimeout default from 5 to 15; add rationale comment.
Unit tests (logic)
\src/libstore-tests/local-store.cc`, `src/libstore-tests/store-reference.cc`, `src/libstore-tests/uds-remote-store.cc``
Add tests for Local/Daemon shorthand rendering and SSH/IPv6 authority cases; add new URI read tests.
Test data fixtures
\src/libstore-tests/data/store-reference/*``.../daemon_shorthand.txt`, `.../local_shorthand_3.txt`, `.../ssh_unbracketed_ipv6_{1,2,3}.txt``
Add fixture files for daemon/local shorthand and unbracketed IPv6 SSH URLs.
Functional/integration tests
\tests/functional/store-info.sh`, `tests/nixos/authorization.nix``
Normalize local/local:// → local, daemon/unix:// → daemon; update expected error string to “…'daemon'”.
Monitor FD refactor (Unix)
\src/libutil/unix/include/nix/util/monitor-fd.hh``
Extract threaded watch into runThread(); add kqueue path on macOS and poll path elsewhere; move constructor out-of-class; adjust includes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant LSC as LocalStoreConfig
  participant URC as UDSRemoteStoreConfig
  participant SR as StoreReference
  Note over SR: New variants: Daemon, Local

  Caller->>LSC: getReference()
  LSC->>LSC: getQueryParams()
  alt params empty
    LSC-->>Caller: SR::Local
  else params present
    LSC-->>Caller: SR::Specified(scheme, params)
  end

  Caller->>URC: getReference(path)
  alt path == nixDaemonSocketFile
    URC-->>Caller: SR::Daemon
  else
    URC-->>Caller: SR::Specified(scheme="unix", authority=path)
  end

  Caller->>SR: render()
  alt Variant = Local
    SR-->>Caller: "local"
  else Variant = Daemon
    SR-->>Caller: "daemon"
  else Variant = Specified
    SR-->>Caller: "scheme://authority[?params]"
  else Variant = Auto
    SR-->>Caller: "auto"
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant MFH as MonitorFdHup
  participant Thr as Watch Thread
  participant OS as OS I/O (kqueue|poll)

  User->>MFH: new MonitorFdHup(fd)
  MFH->>MFH: create notifyPipe()
  MFH->>Thr: start(runThread(fd, notifyFd))
  Thr->>OS: wait(watchFd, notifyFd)
  alt watchFd HUP/EOF
    OS-->>Thr: event(HUP/EOF)
    Thr-->>MFH: exit thread
  else notifyFd closed
    OS-->>Thr: event(notify)
    Thr-->>MFH: exit thread
  end
  User->>MFH: ~MonitorFdHup()
  MFH->>MFH: close notify write end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • cole-h

Poem

In burrows of code I hop and scan,
New “daemon” paths, “local” I can!
IPv6 tunnels, bracketed neat—
Kqueue or poll, I’m light on my feet.
Timeouts stretched, tests nibble and pass—
Thump-thump! This rabbit ships with class. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Sync with upstream 2.31.2" is concise and directly reflects the primary change in the PR (synchronizing with upstream and bumping the version to 2.31.2), making it clear to reviewers scanning history. It avoids noise and accurately summarizes the main intent of the changeset.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sync-2.31.2

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@github-actions github-actions bot temporarily deployed to pull request September 18, 2025 15:17 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.version (1)

1-2: Version bump to 2.31.2 — update leftover 2.31.1 references

Found explicit 2.31.1 references; replace with 2.31.2 or confirm they intentionally reference upstream 2.31.1:

  • doc/manual/source/release-notes-determinate/v3.11.2.md:3 — "* Based on upstream Nix 2.31.1."
  • doc/manual/source/release-notes-determinate/v3.11.0.md:3 — "- Based on upstream Nix 2.31.1."
  • doc/manual/source/release-notes-determinate/v3.10.1.md:3 — "* Based on upstream Nix 2.31.1."
  • doc/manual/source/release-notes-determinate/v3.10.1.md:6 — "This release rebases Determinate Nix on upstream Nix 2.31.1."
  • doc/manual/source/release-notes-determinate/v3.11.1.md:3 — "* Based on upstream Nix 2.31.1."
🧹 Nitpick comments (6)
tests/nixos/authorization.nix (1)

85-85: Updated expected error to 'daemon': LGTM; make grep a touch stricter.

Limit to first match to reduce flakiness in noisy logs.

Apply:

-          grep -F "cannot open connection to remote store 'daemon'" diag
+          grep -F -m1 "cannot open connection to remote store 'daemon'" diag
tests/functional/store-info.sh (1)

16-21: Normalization rules look good; tiny pattern consistency nit.

Optional: quote bare words for symmetry with other patterns.

-        local | 'local://' )
+        'local' | 'local://' )
@@
-        daemon | 'unix://' )
+        'daemon' | 'unix://' )
src/libutil/unix/include/nix/util/monitor-fd.hh (2)

31-36: Join-guard for destructor (defensive).

If construction ever evolves to conditional thread start, guard join.

     ~MonitorFdHup()
     {
         // Close the write side to signal termination via POLLHUP
         notifyPipe.writeSide.close();
-        thread.join();
+        if (thread.joinable()) thread.join();
     }

55-95: macOS kqueue path: consider EV_ERROR handling.

If kevent reports EV_ERROR on the watched fds, current loop ignores it and spins. Optionally handle EV_ERROR similarly to EOF (exit, maybe with a debug log).

src/libstore/uds-remote-store.cc (1)

60-71: "daemon" rendering is fine; watch live-reload semantics

LGTM. Minor: constructor eagerly copies settings.nixDaemonSocketFile into path; if that setting can change at runtime, getReference() won’t reflect it. Consider tracking “uses default daemon path” as a flag to keep behavior aligned with the comment above the delegating ctor.

src/libstore/store-reference.cc (1)

22-45: Render/parse updates are sensible; consider handling authority/path split in legacy IPv6 forms

  • Rendering of Daemon/Local is correct.
  • Fallback parser and IPv6 bracketization look good.

Minor enhancement: when handling legacy forms without "://", split authority from path before IPv6 detection so inputs like "ssh:user@fe80::1/some/path" can be normalized instead of rejected.

Example tweak (conceptual; adjust to local helpers):

-    auto authorityString = schemeAndAuthority->authority;
+    auto authorityString = schemeAndAuthority->authority;
+    auto slashPos = authorityString.find('/');
+    std::string_view authorityOnly = slashPos == std::string::npos
+        ? authorityString
+        : authorityString.substr(0, slashPos);
+    std::string_view pathRemainder = slashPos == std::string::npos
+        ? std::string_view{}
+        : authorityString.substr(slashPos);
-    auto maybeIpv6 = boost::urls::parse_ipv6_address(authorityString);
+    auto maybeIpv6 = boost::urls::parse_ipv6_address(authorityOnly);
     if (maybeIpv6) {
         std::string fixedAuthority;
         if (userinfo) {
             fixedAuthority += *userinfo;
             fixedAuthority += '@';
         }
         fixedAuthority += '[';
-        fixedAuthority += authorityString;
+        fixedAuthority += authorityOnly;
         fixedAuthority += ']';
         return {
             .variant =
                 Specified{
                     .scheme = std::string(schemeAndAuthority->scheme),
-                    .authority = fixedAuthority,
+                    .authority = fixedAuthority + std::string(pathRemainder),
                 },
             .params = std::move(params),
         };
     }

Add a test exercising "ssh:user@fe80::1/path" legacy input and expected normalized output.

Also applies to: 47-69, 97-110, 119-145

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 044c43c and 14c3cee.

📒 Files selected for processing (21)
  • .version (1 hunks)
  • src/libexpr/meson.build (1 hunks)
  • src/libstore-tests/data/store-reference/daemon_shorthand.txt (1 hunks)
  • src/libstore-tests/data/store-reference/local_shorthand_3.txt (1 hunks)
  • src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt (1 hunks)
  • src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt (1 hunks)
  • src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt (1 hunks)
  • src/libstore-tests/local-store.cc (1 hunks)
  • src/libstore-tests/store-reference.cc (2 hunks)
  • src/libstore-tests/uds-remote-store.cc (1 hunks)
  • src/libstore/include/nix/store/filetransfer.hh (1 hunks)
  • src/libstore/include/nix/store/store-reference.hh (1 hunks)
  • src/libstore/local-store.cc (1 hunks)
  • src/libstore/meson.build (1 hunks)
  • src/libstore/store-api.cc (1 hunks)
  • src/libstore/store-reference.cc (5 hunks)
  • src/libstore/uds-remote-store.cc (1 hunks)
  • src/libutil/meson.build (1 hunks)
  • src/libutil/unix/include/nix/util/monitor-fd.hh (2 hunks)
  • tests/functional/store-info.sh (2 hunks)
  • tests/nixos/authorization.nix (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/libstore/local-store.cc (3)
src/libstore/http-binary-cache-store.cc (2)
  • uriSchemes (12-19)
  • uriSchemes (12-12)
src/libstore/dummy-store.cc (1)
  • uriSchemes (36-44)
src/libstore/local-binary-cache-store.cc (2)
  • uriSchemes (118-124)
  • uriSchemes (118-118)
src/libstore/uds-remote-store.cc (3)
src/libstore/http-binary-cache-store.cc (2)
  • uriSchemes (12-19)
  • uriSchemes (12-12)
src/libstore/dummy-store.cc (1)
  • uriSchemes (36-44)
src/libstore/local-binary-cache-store.cc (2)
  • uriSchemes (118-124)
  • uriSchemes (118-118)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_aarch64-darwin / build
  • GitHub Check: build_x86_64-linux / build
🔇 Additional comments (17)
src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt (1)

1-1: IPv6 unbracketed authority test input: LGTM.

Pairs well with normalization to bracketed form in parser.

src/libstore-tests/data/store-reference/local_shorthand_3.txt (1)

1-1: Local shorthand fixture: LGTM.

Matches new Local variant rendering.

src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt (1)

1-1: IPv6 with userinfo (unbracketed) fixture: LGTM.

Complements coverage of authority parsing.

src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt (1)

1-1: IPv6 with query (unbracketed) fixture: LGTM.

Good edge-case for preserving query during normalization.

src/libstore-tests/data/store-reference/daemon_shorthand.txt (1)

1-1: Fixture added: LGTM — trailing newline present.
All listed fixtures end with a newline; no changes needed.

src/libutil/meson.build (1)

60-65: Formatting-only Boost modules change: LGTM — verify CI Boost >= 1.82 provides the 'url' module

rg returned no Boost dependency declarations in the repo; confirm CI images/install provide Boost >= 1.82 with the url component enabled and that all meson.build files declare the same modules list.

src/libexpr/meson.build (1)

43-47: LGTM: formatting-only Boost modules list.

No functional changes; consistent with Meson style.

src/libstore/include/nix/store/filetransfer.hh (1)

33-49: Behavior change: connect-timeout default raised to 15s; note release/test impact.

This affects network behavior and potentially test timings. Please:

  • Call out in release notes and update any docs/examples that mention defaults.
  • Verify CI flakes/timeouts relying on the prior 5s don’t regress.
tests/functional/store-info.sh (2)

26-31: Canonicalization for query forms is correct.

local? → local://?... and daemon? → unix://?... match the new normalization behavior.


47-55: Tests align with new local/daemon normalization.

Good coverage of both shorthand and scheme forms.

src/libstore/meson.build (1)

111-116: Verify removal of Boost.Regex and addition of Boost.URL.

Automated search produced no output — manual verification required. Confirm no sources or targets still include/use Boost.Regex and that Boost.URL is present/supported on every CI builder.

Run locally:

  • rg -n --hidden -S '(^\s*#\sinclude\s<boost/regex.hpp>|\bboost::regex\b|\bboost::smatch\b|\bboost::regex_match\b|\bboost::regex_search\b)'
  • rg -n --hidden -S '(^\s*#\sinclude\s<boost/(url|urls).hpp>|\bboost::urls?::)'

Check: src/libstore/meson.build (lines 111–116).

src/libstore-tests/uds-remote-store.cc (1)

19-24: Test covers daemon shorthand; consider adding explicit-path case

LGTM. Please also add a case where authority equals settings.nixDaemonSocketFile to ensure getReference() renders "daemon" when the daemon path is explicitly provided.

src/libstore-tests/local-store.cc (1)

36-41: Good coverage of local shorthand; add a params case

LGTM. Add a test with a non-empty query param (e.g., trusted=true) to assert rendering becomes "local://?trusted=true".

src/libstore/local-store.cc (1)

460-471: Return Local variant on empty params — looks good

Change is correct and reduces churn in rendered URIs for legacy tooling.

src/libstore-tests/store-reference.cc (1)

110-116: Solid new cases; add write-path tests for IPv6 normalization

Tests for Local/Daemon shorthands and IPv6 parsing look good. Please add URI_TEST_WRITE for the IPv6 cases to assert we render bracketed hosts consistently.

Also applies to: 144-185

src/libstore/include/nix/store/store-reference.hh (1)

67-90: New Daemon/Local variants are clean and minimal

Deriving from Specified keeps compatibility. No issues.

src/libstore/store-api.cc (1)

826-833: Incorrect — Specified overload already covers Daemon/Local

Daemon and Local publicly derive from Specified (src/libstore/include/nix/store/store-reference.hh), so the lambda taking const StoreReference::Specified& will bind to Daemon/Local values; the std::visit here is correct and no change is required.

Likely an incorrect or invalid review comment.

Comment on lines +10 to 17
#ifdef __APPLE__
# include <sys/types.h>
# include <sys/event.h>
#endif

#include "nix/util/signals.hh"
#include "nix/util/file-descriptor.hh"

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing header for std::array (compile break on macOS path).

runThread(…) uses std::array but isn’t included.

Apply:

 #include <thread>
 #include <cassert>
+#include <array>
 
 #include <poll.h>
 #include <errno.h>
@@
 #include "nix/util/signals.hh"
+#include "nix/util/error.hh" // for SysError in inline definitions
 #include "nix/util/file-descriptor.hh"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#ifdef __APPLE__
# include <sys/types.h>
# include <sys/event.h>
#endif
#include "nix/util/signals.hh"
#include "nix/util/file-descriptor.hh"
#include <thread>
#include <cassert>
#include <array>
#include <poll.h>
#include <errno.h>
#ifdef __APPLE__
# include <sys/types.h>
# include <sys/event.h>
#endif
#include "nix/util/signals.hh"
#include "nix/util/error.hh" // for SysError in inline definitions
#include "nix/util/file-descriptor.hh"
🤖 Prompt for AI Agents
In src/libutil/unix/include/nix/util/monitor-fd.hh around lines 10 to 17, the
code uses std::array in runThread(...) but never includes the <array> header
which breaks compilation on macOS; add a single line including <array> (e.g.,
#include <array>) alongside the other system/standard includes (place it before
the file's declarations or before any use of std::array) so the type is
available on all platforms.

Comment on lines +128 to +133
inline MonitorFdHup::MonitorFdHup(int fd)
{
notifyPipe.create();
int notifyFd = notifyPipe.readSide.get();
thread = std::thread([this, fd, notifyFd]() { this->runThread(fd, notifyFd); });
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Unhandled exceptions in thread will call std::terminate.

runThread(…) throws on syscall errors; exceptions escaping a std::thread end function crash the process. Catch inside the thread.

-    thread = std::thread([this, fd, notifyFd]() { this->runThread(fd, notifyFd); });
+    thread = std::thread([this, fd, notifyFd]() noexcept {
+        try {
+            this->runThread(fd, notifyFd);
+        } catch (...) {
+            // Cannot propagate from a background thread; exit quietly.
+        }
+    });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
inline MonitorFdHup::MonitorFdHup(int fd)
{
notifyPipe.create();
int notifyFd = notifyPipe.readSide.get();
thread = std::thread([this, fd, notifyFd]() { this->runThread(fd, notifyFd); });
};
inline MonitorFdHup::MonitorFdHup(int fd)
{
notifyPipe.create();
int notifyFd = notifyPipe.readSide.get();
thread = std::thread([this, fd, notifyFd]() noexcept {
try {
this->runThread(fd, notifyFd);
} catch (...) {
// Cannot propagate from a background thread; exit quietly.
}
});
};
🤖 Prompt for AI Agents
In src/libutil/unix/include/nix/util/monitor-fd.hh around lines 128 to 133, the
thread lambda launches runThread(fd, notifyFd) without catching exceptions so
any exception escaping the thread will call std::terminate; modify the lambda to
wrap the call to this->runThread(fd, notifyFd) in a try/catch(...) block that
catches all exceptions, logs the error (or propagate an error condition) and
ensures resources are cleaned up (close notifyFd/pipe if needed and signal any
waiter) before returning from the thread so exceptions never escape the thread
function.

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.

7 participants