fix(tf): validate flattened multi-device op widths - #5827
Conversation
Reject partial per-atom rows and descriptor/neighbor stride mismatches before TensorFlow force and virial kernels allocate outputs or access raw pointers. Coding-Agent: Codex Codex-Version: codex-cli 0.144.4 Model: gpt-5.6-sol Reasoning-Effort: xhigh
|
Warning Review limit reached
Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds shared flattened-width validation for TensorFlow multi-device custom ops, applies descriptor and neighbor consistency checks to force and virial kernels, and adds regression tests for malformed dimensions. ChangesMulti-device shape validation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant TensorFlowCustomOp
participant GetPerAtomWidth
participant RawKernel
TensorFlowCustomOp->>GetPerAtomWidth: validate flattened width and nloc
GetPerAtomWidth-->>TensorFlowCustomOp: return width or InvalidArgument
TensorFlowCustomOp->>TensorFlowCustomOp: validate descriptor/neighbor relationship
TensorFlowCustomOp->>RawKernel: dispatch validated tensors
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 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 |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #5827 +/- ##
==========================================
+ Coverage 78.57% 78.62% +0.04%
==========================================
Files 1049 1054 +5
Lines 120650 121779 +1129
Branches 4348 4409 +61
==========================================
+ Hits 94806 95746 +940
- Misses 24285 24462 +177
- Partials 1559 1571 +12 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Possible reviewers based on changed lines, exact file history, and exact-file review history:
No review request was made automatically. Coding agent: Codex |
wanghan-iapcm
left a comment
There was a problem hiding this comment.
Nicely done — returning a Status via OP_REQUIRES_OK (rather than throwing) means the error surfaces as a clean InvalidArgumentError and avoids the safe_compute→errors::Internal downgrade. Two notes; the test-coverage one is inline below.
Incomplete fix — the forward virial op is left with the same latent OOB. ProdVirialSeAOp / ProdVirialSeROp in prod_virial_multi_device.cc still use the unchecked truncating dim_size(1) / nloc with no GetPerAtomWidth / nnei*4 == ndescrpt guard:
deepmd-kit/source/op/tf/prod_virial_multi_device.cc
Lines 75 to 79 in 4cf48fd
prod_virial_a_cpu recomputes ndescrpt = 4 * nnei internally and indexes with that, so the op's existing nloc*ndescrpt*3 == in_deriv_width / nloc*nnei*3 == rij_width checks (which only tie the buffers to the truncated widths, never ndescrpt against nnei) don't prevent a malformed net_deriv width from driving an out-of-bounds read. It runs on every inference/training step. Issue #5623 enumerated only the three ops you fixed, but the forward virial shares the identical pattern — worth applying the same helper + stride guard here (and a matching test).
Coding-Agent: Codex Codex-Version: codex-cli 0.144.6 Model: gpt-5.6-sol Reasoning-Effort: xhigh
wanghan-iapcm
left a comment
There was a problem hiding this comment.
All four gaps are closed, and I was able to verify it by running rather than reading, which is worth spelling out because it makes the result unambiguous.
The TensorFlow custom ops installed in my environment predate this change -- neither libdeepmd_op.so nor libop_grads.so contains the "should be divisible by nloc" string -- so running the new suite against them is a genuine pre-fix run. Eight of the twelve collected cases fail there, including every one of the four I asked for:
| gap I raised | new test | unpatched |
|---|---|---|
GetPerAtomWidth nloc < 0 |
test_negative_nloc_is_rejected |
fails |
nloc == 0 |
test_zero_nloc_rejects_nonempty_flattened_width |
fails |
prod_force_se_r_grad untested |
test_prod_force_r_grad_rejects_partial_nlist_atom |
fails |
prod_virial_se_r_grad untested |
test_prod_virial_r_grad_rejects_partial_net_deriv_atom |
fails |
Including test_zero_nloc_accepts_empty_flattened_widths was a good call -- the zero-nloc guard has a legitimate accepting case, and without it a future change could satisfy every rejection test by simply refusing all zero-nloc input.
Two of the remaining cases, test_prod_force_rejects_in_deriv_width_mismatch and test_prod_virial_grad_rejects_rij_width_mismatch, already pass on the unpatched ops, because an existing check rejects those inputs. That is not a problem and I am not asking for anything -- they are regression guards for behaviour that already worked rather than demonstrations of the bug -- but it is worth knowing which of these tests would actually catch a revert of this PR and which would not.
Agreed on leaving the width > INT_MAX branch alone; it is not practically constructible through the op API and a test for it would cost more than it protects.
Approving.
Fixes #5623
Summary
se_afour-value descriptor stride and these_rone-value stride before output allocationnet_deriv,in_deriv,nlist,rij, and descriptor/neighbor stride mismatchesWhy existing tests missed this
The existing tests use placeholders whose second dimensions are fixed to the correct
nloc * ndescrpt,nloc * ndescrpt * 3, andnloc * nneiwidths. Feeding a differently sized array is therefore rejected by TensorFlow before the custom op executes. The tests also cover only valid descriptor layouts, so the release-build paths whereassertis compiled out were never exercised.The new tests construct malformed tensors directly at the op boundary. They verify
InvalidArgumentis returned by the custom op before output allocation or raw CPU/GPU pointer dispatch.Validation
cmake --build source/build --target deepmd_oplibdeepmd_opandlibop_gradspytest source/tests/tf/test_multi_device_shape_validation.py -v(6 validation cases plus TensorFlowtest_session, all passed)TestProdForce::test_prod_force,TestProdForceGrad::test_prod_force_grad, andTestProdVirialGrad::test_prod_virial_grad(3 passed)ruff format .ruff check .Coding agent: Codex
Codex version: codex-cli 0.144.4
Model: gpt-5.6-sol
Reasoning effort: xhigh
Summary by CodeRabbit
Bug Fixes
Tests