Skip to content

fix(api_c): preserve exact bytes in DP_ReadFileToChar2#5763

Merged
wanghan-iapcm merged 3 commits into
deepmodeling:masterfrom
njzjz-bot:fix/readfile-exact-bytes
Jul 12, 2026
Merged

fix(api_c): preserve exact bytes in DP_ReadFileToChar2#5763
wanghan-iapcm merged 3 commits into
deepmodeling:masterfrom
njzjz-bot:fix/readfile-exact-bytes

Conversation

@njzjz-bot

@njzjz-bot njzjz-bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Fix #5620

Problem

DP_ReadFileToChar气Char2 reported the original file size but returned a buffer from string_to_char, which trims trailing whitespace before allocating/copying. The C++ wrapper (read_file_to_string in deepmd.hpp) then reconstructed a std::string with the reported (larger) size, causing an over-read of the shorter allocation.

Fix

Added string_to_char_exact, a new helper that preserves every byte without trimming, and use it in DP_ReadFileToChar2 and DP_ReadFileToChar. Error-message paths still use the trimming string_to_char since whitespace trimming is desirable there.

Test

Added both a C++ test (test_read_file_to_string.cc) and a Python test (test_c_api_readfile.py) that verify trailing whitespace is preserved. The Python test uses ctypes to call DP_ReadFileToChar2 directly and the C API.

Verified: the test fails against the buggy code (over-reads garbage bytes) and passes with the fix.

Attribution

Generated with opencode using model glm-5.2.

Recommended reviewers

@njzjz (maintainer of the C API)

Summary by CodeRabbit

  • New Features
    • Added per-frame charge_spin support to DeepPot and model-deviation C API computations.
    • Introduced “version 3” compute entry points that accept charge_spin (including neighbor-list variants).
    • Added APIs to query the required charge-spin dimension.
  • Bug Fixes
    • File-reading C APIs now preserve exact bytes, including trailing whitespace/newlines, and add safer size handling.
  • Tests
    • Added regression tests (C++ and Python) validating byte-for-byte file content preservation.

Comment thread source/tests/test_c_api_readfile.py Fixed
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The C API adds charge-spin-aware DeepPot and model-deviation compute functions, exposes charge-spin dimensions, and preserves exact file bytes in file-reading APIs with C++ and Python regression coverage.

Changes

Charge-spin C API

Layer / File(s) Summary
DeepPot charge-spin compute flow
source/api_c/include/c_api.h, source/api_c/src/c_api.cc
DeepPot standard and neighbor-list helpers convert and forward charge-spin data, while version 3 entry points and a dimension getter expose the new API.
Model-deviation charge-spin compute flow
source/api_c/include/c_api.h, source/api_c/src/c_api.cc
Model-deviation standard and neighbor-list helpers forward charge-spin data through new version 3 entry points and expose its dimension.
Exact file-byte preservation
source/api_c/src/c_api.cc, source/api_cc/tests/test_read_file_to_string.cc, source/tests/test_c_api_readfile.py
File-reading APIs preserve trailing bytes and report exact sizes, with C++ and Python tests validating byte-for-byte results.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant C_API
  participant ComputeHelper
  participant DeepPotBackend
  participant Outputs
  C_API->>ComputeHelper: submit coordinates and charge_spin
  ComputeHelper->>DeepPotBackend: convert and forward charge-spin vector
  DeepPotBackend-->>Outputs: return energy, force, virial, and atomic outputs
Loading

Possibly related PRs

Suggested reviewers: iProzd, njzjz, wanghan-iapcm

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: preserving exact bytes in DP_ReadFileToChar2.
Linked Issues check ✅ Passed The PR fixes #5620 by using an exact byte-copy path, preserving trailing whitespace and adding regression tests.
Out of Scope Changes check ✅ Passed No unrelated code changes stand out beyond the linked fix and its supporting API/test updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/readfile-exact-bytes

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
source/tests/test_c_api_readfile.py (1)

37-102: 📐 Maintainability & Code Quality | 🔵 Trivial

Extract shared library loading and function signature setup into a fixture.

Both tests duplicate _load_c_lib() calls and the argtypes/restype configuration. A session-scoped fixture would load the library once and centralize the setup.

♻️ Proposed refactor
+@pytest.fixture(scope="module")
+def c_lib():
+    lib = _load_c_lib()
+    lib.DP_ReadFileToChar2.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)]
+    lib.DP_ReadFileToChar2.restype = ctypes.c_void_p
+    lib.DP_DeleteChar.argtypes = [ctypes.c_void_p]
+    lib.DP_DeleteChar.restype = None
+    return lib
+
+
-def test_readfiletochar2_preserves_trailing_whitespace(tmp_path):
+def test_readfiletochar2_preserves_trailing_whitespace(tmp_path, c_lib):
     """Files ending in whitespace must return exact size and bytes."""
-    lib = _load_c_lib()
-
-    # Set up function signatures -------------------------------------------
-    # Use c_void_p for the return type so ctypes does not truncate the
-    # buffer at the first null byte (c_char_p would do that).
-    lib.DP_ReadFileToChar2.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)]
-    lib.DP_ReadFileToChar2.restype = ctypes.c_void_p
-    lib.DP_DeleteChar.argtypes = [ctypes.c_void_p]
-    lib.DP_DeleteChar.restype = None
+    # c_void_p return type avoids truncation at the first null byte.
     ...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/test_c_api_readfile.py` around lines 37 - 102, Extract the
duplicated library loading and ctypes signature setup from
test_readfiletochar2_preserves_trailing_whitespace and
test_readfiletochar2_preserves_no_trailing_whitespace into a session-scoped
pytest fixture. Configure DP_ReadFileToChar2 and DP_DeleteChar once in the
fixture, then inject the prepared library into both tests while preserving their
existing assertions and cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@source/api_c/src/c_api.cc`:
- Line 2686: Guard the assignment in the file-reading function containing *size
= file_content.size() by checking whether file_content.size() exceeds INT_MAX
before converting it to int. For oversized content, return the existing error
sentinel and surface a clear error through the function’s established
error-reporting mechanism; otherwise assign the safely bounded size.
- Around line 1774-1854: Add declarations to source/api_c/include/c_api.h for
the new DP_DeepPotCompute3, DP_DeepPotComputef3, DP_DeepPotComputeNList3,
DP_DeepPotComputeNListf3, all DP_DeepPotModelDevi*3 entry points, and the new
GetDimChgSpin accessors, matching the definitions’ signatures and existing API
declaration style.

---

Nitpick comments:
In `@source/tests/test_c_api_readfile.py`:
- Around line 37-102: Extract the duplicated library loading and ctypes
signature setup from test_readfiletochar2_preserves_trailing_whitespace and
test_readfiletochar2_preserves_no_trailing_whitespace into a session-scoped
pytest fixture. Configure DP_ReadFileToChar2 and DP_DeleteChar once in the
fixture, then inject the prepared library into both tests while preserving their
existing assertions and cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 547099a2-1f8a-44da-86da-dc88fb1ea9fb

📥 Commits

Reviewing files that changed from the base of the PR and between 7c362d7 and 6c79957.

📒 Files selected for processing (3)
  • source/api_c/src/c_api.cc
  • source/api_cc/tests/test_read_file_to_string.cc
  • source/tests/test_c_api_readfile.py

Comment thread source/api_c/src/c_api.cc
Comment thread source/api_c/src/c_api.cc Outdated
@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.57%. Comparing base (7c362d7) to head (223f88f).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
source/api_c/src/c_api.cc 78.57% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5763      +/-   ##
==========================================
- Coverage   79.65%   79.57%   -0.09%     
==========================================
  Files        1015     1020       +5     
  Lines      115781   116383     +602     
  Branches     4272     4303      +31     
==========================================
+ Hits        92229    92613     +384     
- Misses      22008    22223     +215     
- Partials     1544     1547       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@njzjz-bot njzjz-bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I found one test-coverage issue in the C++ regression test. The effective merge result otherwise looks correct.

Coding agent: Codex
Codex version: codex-cli 0.144.0-alpha.4
Model: gpt-5.6-sol
Reasoning effort: xhigh

Comment thread source/api_cc/tests/test_read_file_to_string.cc Outdated
njzjz pushed a commit to njzjz-bot/deepmd-kit that referenced this pull request Jul 11, 2026
- Add INT_MAX overflow guard in DP_ReadFileToChar2
- Add missing version-3 charge-spin C API declarations to header
- Refactor test_c_api_readfile.py to use a module-scoped pytest fixture
- Fix implicit return in _load_c_lib (CodeQL/Ruff)

Coding-Agent: opencode
opencode-Version: 1.17.18
Model: ustc/deepseek-v4-pro
Reasoning-Effort: max

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@source/api_c/include/c_api.h`:
- Around line 687-701: Update the Doxygen buffer-size documentation for all
affected C API declarations, including the symbols around the documented
input/output parameters and their corresponding variants, to include nframes
consistently: cell as nframes x 9, energy as nframes, force as nframes x natoms
x 3, virial as nframes x 9, atomic_energy as nframes x natoms, and atomic_virial
as nframes x natoms x 9. Apply the same corrections at every referenced
declaration, including the additional ranges noted in the review.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3620e9b2-a23a-455a-ac1f-ab70bf8b4a65

📥 Commits

Reviewing files that changed from the base of the PR and between 6c79957 and d3c85ce.

📒 Files selected for processing (3)
  • source/api_c/include/c_api.h
  • source/api_c/src/c_api.cc
  • source/tests/test_c_api_readfile.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/tests/test_c_api_readfile.py
  • source/api_c/src/c_api.cc

Comment thread source/api_c/include/c_api.h Outdated
njzjz-bot and others added 2 commits July 11, 2026 14:15
DP_ReadFileToChar2 reported the original file size but returned a buffer
from string_to_char, which trims trailing whitespace before allocating.
The C++ wrapper then reconstructed a std::string with the reported
(larger) size, causing an over-read of the shorter allocation.

Fix by adding string_to_char_exact, a helper that preserves every byte
without trimming, and use it in DP_ReadFileToChar2 and
DP_ReadFileToChar.  Error-message paths still use the trimming
string_to_char since whitespace trimming is desirable there.

Added both a C++ test (test_read_file_to_string.cc) and a Python test
(test_c_api_readfile.py) that verify trailing whitespace is preserved.

Fixes deepmodeling#5620.

Generated with opencode using model glm-5.2.
- Add INT_MAX overflow guard in DP_ReadFileToChar2
- Correct multi-frame buffer documentation for charge-spin DeepPot APIs
- Refactor test_c_api_readfile.py to use a module-scoped pytest fixture
- Fix implicit return in _load_c_lib (CodeQL/Ruff)

Coding-Agent: opencode
opencode-Version: 1.17.18
Model: ustc/deepseek-v4-pro
Reasoning-Effort: max

Coding-Agent: Codex
Codex-Version: codex-cli 0.144.1
Model: gpt-5.6-sol
Reasoning-Effort: xhigh
@njzjz njzjz force-pushed the fix/readfile-exact-bytes branch from d3c85ce to f7cd760 Compare July 11, 2026 07:10
Test exact byte preservation through the native C API suite instead of ctypes in the Python tests. Use std::numeric_limits for the file-size guard so GCC and Clang builds compile portably.

Coding-Agent: Codex
Codex-Version: codex-cli 0.144.1
Model: gpt-5.6-sol
Reasoning-Effort: xhigh
@njzjz njzjz force-pushed the fix/readfile-exact-bytes branch from ece5230 to 223f88f Compare July 12, 2026 09:46
@njzjz njzjz requested a review from wanghan-iapcm July 12, 2026 12:12

@wanghan-iapcm wanghan-iapcm left a comment

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.

Verified the fix: DP_ReadFileToChar2 now reports the exact byte count and returns a matching untrimmed buffer via string_to_char_exact, resolving the over-read in read_file_to_string (#5620). The INT_MAX guard correctly precedes the int cast, and the doc-comment nframes corrections match the Compute3/ComputeNList3 implementations. Regression tests (c_api_preserves_exact_bytes, legacy_c_api_preserves_trailing_whitespace) fail on the buggy code and pass with the fix.

Minor, non-blocking: the file-too-large branch (size > INT_MAX) is unexercised by tests, but a 2GB fixture is impractical and the branch mirrors the existing error path.

@wanghan-iapcm wanghan-iapcm added this pull request to the merge queue Jul 12, 2026
Merged via the queue into deepmodeling:master with commit 0601c79 Jul 12, 2026
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Code scan] Preserve exact bytes in DP_ReadFileToChar2

3 participants