You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Closed High-severity issue #199 — fix(capi): buffer overflow in multiple functions writing to caller buffers was closed as "Addressed in PR #218", but item 2 of that issue — spir_uhat_get_default_matsus lacking a companion output-size query function and output-buffer validation — was never fixed. The function still writes points_vec.len() elements into the caller-owned points buffer with no capacity check and no way for the caller to learn the required size in advance.
PR #218 (diff) did not touch spir_uhat_get_default_matsus. Its only sparse-ir-capi/src/funcs.rs change was the spir_funcs_is_assigned null-check hardening (issue #200). The maintainer's closure comment confirms the narrow scope:
"Addressed in PR #218: documented that segments_x/y callers must allocate n_segments+1 elements for boundary points."
That documents only the item-3 segments_x/y off-by-one; item 2 (the uhat getter) is not covered.
Current evidence
spir_uhat_get_default_matsus (sparse-ir-capi/src/funcs.rs:737-808, commit 0579962) still takes no output-length/capacity parameter, has no companion size-query function, and performs an unchecked copy:
No spir_uhat_get_n_default_matsus (or any size-query variant) exists anywhere in sparse-ir-capi, fortran, python, cxx_tests, or julia (verified by grep and the checked-in header).
The generated header declares the same signature and only warns, with no size-query companion:
Doc: "The size of the array must be sufficient for the returned points (may exceed L if mitigate is true)" (sparseir.h:954) — it does not state an exact bound, and there is no API to learn the count before allocating.
The overflow path is real: spir_uhat_get_default_matsus calls FiniteTempBasis::default_matsubara_sampling_points_impl(..., fence=mitigate, ...) (sparse-ir/src/basis.rs:502-562). With mitigate=true, fence_matsubara_sampling (sparse-ir/src/basis.rs:434-500) appends up to two extra frequencies per outer frequency once the base vector reaches size 20 (resp. 42), so the returned count can exceed the requested l. The function then writes all of those elements with no check against the caller's buffer.
Contrast with the same issue's item 1, which was remediated: spir_basis_get_default_matsus_ext now truncates to the caller capacity (n_to_return = matsu_points.len().min(n_points as usize), sparse-ir-capi/src/basis.rs:1211) and gained the companion spir_basis_get_n_default_matsus_ext (basis.rs:1126-1155).
Expected behavior
Per the C ABI Safety rules, spir_uhat_get_default_matsus must give the caller a way to determine the output size before allocating and must validate capacity before writing to caller-owned buffers — the same pattern applied to the basis getter and, for the sibling residual, to the SVE hint getters in PR #218.
spir_uhat_get_default_matsus writes points_vec.len()i64 elements with no capacity validation. With mitigate=true and a full Matsubara grid (l around 20+), the fence can produce more points than l; a caller allocating l elements (the natural reading of the l "Number of requested sampling points" argument) triggers an out-of-bounds write. Because there is no companion size-query, the two-pass "call to learn size, then allocate" protocol cannot even be started safely (the first call already writes the full vector).
Potential heap buffer overflow (out-of-bounds write) in a public C ABI entry point reachable with valid parameters (mitigate=true, non-positive-only grid, l >= ~20). C/C++/Fortran/Python callers that allocate l elements and pass mitigate=true are affected. The write is silent: the function returns SPIR_COMPUTATION_SUCCESS.
Violated repository-local rule
REPOSITORY_RULES.md:126-128 — "Validate output capacity, shape, and element type before writing. Unless an API explicitly documents partial output on failure, validation must complete before mutating caller-owned output buffers."
REPOSITORY_RULES.md:121-123 — "Before constructing a slice or tensor view from raw parts, validate pointer requirements and use checked arithmetic for dimension products, element counts, byte lengths, strides, and offsets."
REPOSITORY_RULES.md:116-118 (C ABI Safety) — Rust must check every verifiable precondition before dereferencing, including lengths and arithmetic bounds.
These repository-local rules override the shared tensor4all-agent-rulesrules/common/repository.md when they conflict.
Verification limitations
Verified at source level against commit 0579962 (origin/main): the unchecked copy_nonoverlapping of points_vec.len() elements and the absence of any companion size-query function are directly confirmed in the code and checked-in header.
The overflow mechanism (fence appends frequencies when the base vector reaches size 20/42) is confirmed by inspection of fence_matsubara_sampling; the identical mechanism was empirically reproduced in the sibling issue #239 (spir_basis_get_default_matsus_ext returning 32 points for a requested 30 with mitigate=true). The full C ABI call for this specific function was not compiled/linked here to avoid a broad workspace build; the uhat getter shares the exact same sampling path (default_matsubara_sampling_points_impl with fence=mitigate).
No maintainer confirmation obtained; finding is based on source inspection plus the shared, previously reproduced fence behavior.
Summary
Closed High-severity issue #199 — fix(capi): buffer overflow in multiple functions writing to caller buffers was closed as "Addressed in PR #218", but item 2 of that issue —
spir_uhat_get_default_matsuslacking a companion output-size query function and output-buffer validation — was never fixed. The function still writespoints_vec.len()elements into the caller-ownedpointsbuffer with no capacity check and no way for the caller to learn the required size in advance.Audited commit:
057996207ed633a3786588539f869e689235983c(origin/main, 2026-08-18).Referenced closed issue
Original claim (issue #199, item 2)
The proposed fix in #199 was: "Add
out_lenparameters and validate before writing, or at minimum document exact buffer size requirements."What PR #218 actually did
PR #218 (diff) did not touch
spir_uhat_get_default_matsus. Its onlysparse-ir-capi/src/funcs.rschange was thespir_funcs_is_assignednull-check hardening (issue #200). The maintainer's closure comment confirms the narrow scope:That documents only the item-3
segments_x/yoff-by-one; item 2 (the uhat getter) is not covered.Current evidence
spir_uhat_get_default_matsus(sparse-ir-capi/src/funcs.rs:737-808, commit0579962) still takes no output-length/capacity parameter, has no companion size-query function, and performs an unchecked copy:spir_uhat_get_n_default_matsus(or any size-query variant) exists anywhere insparse-ir-capi,fortran,python,cxx_tests, orjulia(verified by grep and the checked-in header).sparse-ir-capi/include/sparseir/sparseir.h:969-974.sparseir.h:954) — it does not state an exact bound, and there is no API to learn the count before allocating.The overflow path is real:
spir_uhat_get_default_matsuscallsFiniteTempBasis::default_matsubara_sampling_points_impl(..., fence=mitigate, ...)(sparse-ir/src/basis.rs:502-562). Withmitigate=true,fence_matsubara_sampling(sparse-ir/src/basis.rs:434-500) appends up to two extra frequencies per outer frequency once the base vector reaches size 20 (resp. 42), so the returned count can exceed the requestedl. The function then writes all of those elements with no check against the caller's buffer.Contrast with the same issue's item 1, which was remediated:
spir_basis_get_default_matsus_extnow truncates to the caller capacity (n_to_return = matsu_points.len().min(n_points as usize),sparse-ir-capi/src/basis.rs:1211) and gained the companionspir_basis_get_n_default_matsus_ext(basis.rs:1126-1155).Expected behavior
Per the C ABI Safety rules,
spir_uhat_get_default_matsusmust give the caller a way to determine the output size before allocating and must validate capacity before writing to caller-owned buffers — the same pattern applied to the basis getter and, for the sibling residual, to the SVE hint getters in PR #218.Observed gap
spir_uhat_get_default_matsus) was never applied; the issue was closed as "Addressed" without covering this function.spir_uhat_get_default_matsuswritespoints_vec.len()i64elements with no capacity validation. Withmitigate=trueand a full Matsubara grid (laround 20+), the fence can produce more points thanl; a caller allocatinglelements (the natural reading of thel"Number of requested sampling points" argument) triggers an out-of-bounds write. Because there is no companion size-query, the two-pass "call to learn size, then allocate" protocol cannot even be started safely (the first call already writes the full vector).Impact
Potential heap buffer overflow (out-of-bounds write) in a public C ABI entry point reachable with valid parameters (
mitigate=true, non-positive-only grid,l >= ~20). C/C++/Fortran/Python callers that allocatelelements and passmitigate=trueare affected. The write is silent: the function returnsSPIR_COMPUTATION_SUCCESS.Violated repository-local rule
REPOSITORY_RULES.md:126-128— "Validate output capacity, shape, and element type before writing. Unless an API explicitly documents partial output on failure, validation must complete before mutating caller-owned output buffers."REPOSITORY_RULES.md:121-123— "Before constructing a slice or tensor view from raw parts, validate pointer requirements and use checked arithmetic for dimension products, element counts, byte lengths, strides, and offsets."REPOSITORY_RULES.md:116-118(C ABI Safety) — Rust must check every verifiable precondition before dereferencing, including lengths and arithmetic bounds.These repository-local rules override the shared
tensor4all-agent-rulesrules/common/repository.mdwhen they conflict.Verification limitations
0579962(origin/main): the uncheckedcopy_nonoverlappingofpoints_vec.len()elements and the absence of any companion size-query function are directly confirmed in the code and checked-in header.fence_matsubara_sampling; the identical mechanism was empirically reproduced in the sibling issue #239 (spir_basis_get_default_matsus_extreturning 32 points for a requested 30 withmitigate=true). The full C ABI call for this specific function was not compiled/linked here to avoid a broad workspace build; the uhat getter shares the exact same sampling path (default_matsubara_sampling_points_implwithfence=mitigate).Duplicate check
spir_basis_get_default_matsus_ext(item 1 of fix(capi): buffer overflow in multiple functions writing to caller buffers #199), which has since been remediated (truncation atbasis.rs:1211, via PR fix: address spm-lab-repository-audit-bot issues #237-#243 #244); it does not coverspir_uhat_get_default_matsus.spir_uhat_get_default_matsus.