fix(ipi): complete socket writes and bound paths - #5831
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughi-PI socket handling now bounds Unix socket paths, completes partial writes with retry and error handling, validates negative lengths, and adds C regression tests registered through CTest. Changesi-PI socket I/O hardening
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant iPI as writebuffer_
participant Helper as deepmd_write_all
participant Socket as socket write callback
iPI->>Helper: provide buffer and length
Helper->>Socket: write remaining bytes
Socket-->>Helper: partial count, EINTR, or error
Helper->>Socket: retry until complete
Helper-->>iPI: success or errno-based failure
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reject Unix socket names that do not fit sockaddr_un, and retry interrupted or partial stream writes until the complete protocol message is sent. Add deterministic C tests with injected write behavior because the existing ASE integration tests use a short localhost path and small blocking writes that normally complete in one call. Coding-Agent: Codex Codex-Version: codex-cli 0.144.4 Model: gpt-5.6-sol Reasoning-Effort: xhigh
909c00f to
b70e643
Compare
|
Possible reviewers based on changed lines, exact file history, and exact-file review history:
No review request was made automatically. Coding agent: Codex |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5831 +/- ##
==========================================
+ Coverage 78.57% 78.63% +0.05%
==========================================
Files 1049 1055 +6
Lines 120650 121850 +1200
Branches 4348 4421 +73
==========================================
+ Hits 94806 95820 +1014
- Misses 24285 24460 +175
- Partials 1559 1570 +11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
wanghan-iapcm
left a comment
There was a problem hiding this comment.
The write-side and path fixes are correct and well-verified: the path arithmetic is byte-identical to the old code and to what the i-PI server constructs (the > bound reserves the NUL exactly — no off-by-one), and deepmd_write_all handles EINTR / partial / empty-buffer / signedness correctly. The injected-callback test genuinely fails on the pre-fix one-shot write(). One incomplete-fix note (the coverage note is inline below):
The symmetric read path is left with the mirror-image bug. readbuffer_ (
deepmd-kit/source/ipi/src/sockets.c
Lines 137 to 160 in b70e643
EINTR, and its only error guard is if (n == 0). So if the first read() returns -1 (EINTR or error), n == -1, the nr > 0 loop is skipped and the n == 0 check is false — the function returns having left data uninitialized (silent garbage forces/energies to the driver). A mid-transfer peer close (0 < n < len) is likewise silently accepted as a short buffer. Since the whole motivation here is EINTR/partial-syscall hardening, readbuffer_ deserves the same treatment (retry on EINTR, treat any final n < len as an error) — either in this PR or a follow-up. It's pre-existing and outside the diff, so non-blocking.
Coding-Agent: Codex Codex-Version: codex-cli 0.144.6 Model: gpt-5.6-sol Reasoning-Effort: xhigh
for more information, see https://pre-commit.ci
wanghan-iapcm
left a comment
There was a problem hiding this comment.
All four branches I listed are covered now: both deepmd_write_all preconditions, the EIO over-report guard via a writer that returns len + 1, both NULL arguments to deepmd_build_unix_socket_address, and a forked child that calls writebuffer_ with a negative length and checks the error text. That last one is the case nothing touched at all before, so it is good to see it reached directly rather than inferred.
I built and ran this rather than reading it. The suite compiles under gnu11 against sockets.c and passes. Since deepmd_write_all is new, it cannot be run against master to show it fails there, so I did the next best thing: I substituted a faithful one-shot implementation -- preconditions kept, the loop and the EINTR retry removed -- and the suite fails cleanly at
CHECK failed at tests/test_sockets.c:108: deepmd_write_all(123, payload, sizeof(payload) - 1, partial_writer) == 0
which is exactly the regression this PR exists to prevent. That works because of how partial_writer is built: EINTR on the first call, then at most three bytes per call, so passing requires both retrying without advancing the source pointer and looping until the buffer is drained. The comment explaining that choice is worth keeping -- it is the reason the test has teeth.
Two things I checked because they are easy to get wrong and often are. The test is registered with add_test(NAME test_ipi_sockets COMMAND test_ipi_sockets) inside if(CMAKE_TESTING_ENABLED), CI configures with BUILD_TESTING:BOOL=TRUE and runs ctest, and the job log confirms it actually executes:
Start 4: test_ipi_sockets
4/4 Test #4: test_ipi_sockets ................. Passed 0.00 sec
100% tests passed out of 4
All four Test C++ jobs are green. And the rationale in the CMake comment is the right one -- deterministic short-write injection is not something an end-to-end socket test can ask the kernel for, so a small C regression beside the library is the correct shape for this rather than a driver-level test.
Approving.
feb234e
Fixes #5626
Summary
/tmp/ipi_<host>names that cannot fit insockaddr_un.sun_pathinstead of overflowing or truncating the addresswrite()afterEINTRand after partial progress until the full i-PI protocol buffer has been sentWhy existing tests missed this
The existing i-PI tests are ASE end-to-end tests configured with the short name
localhost. Their force and virial messages are also small and sent through blocking local sockets, where a singlewrite()normally accepts the whole buffer. They therefore never approachsun_pathcapacity and cannot force the kernel to return a deterministic short write orEINTR.The new C regression injects the write behavior directly: its writer first returns
EINTRand then accepts at most three bytes per call. As a negative control, temporarily restoring one-shot behavior made this test fail at the first complete-write assertion; restoring the loop makes the full payload comparison pass.Validation
cmake --build source/build --target test_ipi_sockets dp_ipi -j$(nproc --all)ctest --test-dir source/build -R ^test_ipi_sockets$ --output-on-failurepytest source/ipi/tests/test_driver.py::TestDPIPI::test_ase_unix -vv -s-Wall -Wextra -Werrorruff format .ruff check .clang-formatapplied to the changed C sources and headergit diff --checkCoding agent: Codex
Codex version: codex-cli 0.144.4
Model: gpt-5.6-sol
Reasoning effort: xhigh
Summary by CodeRabbit
/tmp/ipi_<host>paths and fail fast when the hostname is too long.test_ipi_sockets) covering Unix-socket path length enforcement and reliable full-buffer write behavior.