Skip to content

fix(Storage): check dtype in at<T> unconditionally (#965)#978

Merged
yingjerkao merged 2 commits into
masterfrom
fix/storage-at-unconditional-dtype-check
Jul 6, 2026
Merged

fix(Storage): check dtype in at<T> unconditionally (#965)#978
yingjerkao merged 2 commits into
masterfrom
fix/storage-at-unconditional-dtype-check

Conversation

@yingjerkao

Copy link
Copy Markdown
Collaborator

Summary

Fixes #965.

  • Unconditional dtype check in Storage_base::at<T>. Every at<T> specialization wrapped its dtype-mismatch check in if (cytnx::User_debug) (default false), so e.g. Tensor({1}, Type.Float).item<double>() reinterpreted a float buffer as double and returned garbage in normal builds. The checks now run unconditionally, matching data<T>() and back<T>(), which already checked unconditionally. Mismatched at<T>/item<T> calls now throw std::logic_error instead of silently type-punning.
  • Review follow-up: the out-of-bound error in the same at<T> specializations formatted cytnx_uint64 index and unsigned long long size through %d (garbage for values ≥ 2³¹, UB in the formatter) — now %llu with explicit casts.

Test fallout fixed (call sites relying on the old silent behavior)

  • tests/linalg_test/Arnoldi_Ut_test.cpp: linalg::Max(block).item<double>() on linalg::Eig output (ComplexDouble) — now reads .item().real().
  • tests/DenseUniTensor_test.cpp (at test): the const cut tensor was constructed once with default dtype but read as every dtype in the loop — now cloned per-dtype.

Tests

  • Storage.AtDtypeMismatchThrows, Tensor.ItemDtypeMismatchThrows — written red-first against the silent-garbage behavior.
  • StorageTest.AtDtypeMismatchThrowsForAllDtypes — exhaustive 11×11 dtype/T matrix, iterating the shared TestTools::dtype_list.
  • StorageTest.AtOutOfBoundMessageReportsIndexAndSize — pins the bounds-error message content.

Full suite on macOS/AppleClang: 1067 passed; the only failures are the 4 pre-existing linalg_Test.*_return_err_* SVD-truncate failures tracked in #975 (verified identical without this change).

A follow-up branch (in progress) consolidates the 11 copy-pasted at<T>/back<T>/data<T> specializations into one template body via cy_typeid_v<T> so no future specialization can drop the check again.

🤖 Generated with Claude Code

yingjerkao and others added 2 commits July 5, 2026 21:16
The dtype-mismatch check was guarded by cytnx::User_debug (off by
default), so Tensor::item<T>() and Storage::at<T>() silently
reinterpreted storage as the wrong type in normal builds. data<T>()
and back<T>() already checked unconditionally; at<T> now matches.

Enabling the check unconditionally exposed two tests that were
relying on the previously-silent type punning:
- DenseUniTensorTest.at compared a const UniTensor against complex
  types without ever casting it to that dtype (it stayed Double).
- Arnoldi_Gnd.Arnoldi_BK_test read the ComplexDouble output of
  linalg::Eig() with item<double>(); switched to item().real().

Co-Authored-By: Claude <noreply@anthropic.com>
…s; reuse shared dtype list in test

The out-of-bound error in every at<T> specialization formatted
cytnx_uint64 idx and unsigned long long size() through %d, printing
garbage for values >= 2^31 (and formally UB in the printf-family
formatter). Use %llu with explicit casts, and pin the error-path
message with a test.

AtDtypeMismatchThrowsForAllDtypes now iterates TestTools::dtype_list
instead of re-declaring the same 11-dtype list, so the exhaustive test
stays exhaustive if a dtype is ever added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request removes the cytnx::User_debug guard around type mismatch checks in Storage_base::at<T> specializations, ensuring that type checks are always performed. It also updates out-of-bounds error messages to use %llu with explicit casts to unsigned long long. Corresponding unit tests have been added to verify that type mismatches throw std::logic_error and that out-of-bounds messages report the correct indices. Additionally, a test in Arnoldi_Ut_test.cpp was updated to use .item().real() to avoid type mismatch exceptions. There are no review comments, and we have no further feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.27273% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 30.91%. Comparing base (32079a4) to head (32ad1e8).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/backend/Storage_base.cpp 52.27% 10 Missing and 11 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #978      +/-   ##
==========================================
+ Coverage   30.87%   30.91%   +0.04%     
==========================================
  Files         229      229              
  Lines       34757    34759       +2     
  Branches    14409    14398      -11     
==========================================
+ Hits        10730    10745      +15     
+ Misses      16720    16708      -12     
+ Partials     7307     7306       -1     
Flag Coverage Δ
cpp 30.42% <52.27%> (+0.04%) ⬆️
python 59.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
C++ backend 32.24% <52.27%> (+0.04%) ⬆️
Python bindings 17.28% <ø> (ø)
Python package 59.41% <ø> (ø)
Files with missing lines Coverage Δ
src/backend/Storage_base.cpp 25.23% <52.27%> (+3.46%) ⬆️

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 32079a4...32ad1e8. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Heads-up: #979 is stacked on this branch — it refactors the 11 copy-pasted at<T>/back<T>/data<T> specializations in Storage_base.cpp into single template bodies keyed on cy_typeid_v<T>, so the dtype check this PR fixes can't drift per-type again. It should be retargeted to master and merged after this one.

@yingjerkao
yingjerkao merged commit b5db6b8 into master Jul 6, 2026
19 checks passed
@yingjerkao
yingjerkao deleted the fix/storage-at-unconditional-dtype-check branch July 6, 2026 12:16
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.

Storage::at<T>() and Tensor::item<T>() silently reinterpret mismatched dtype in normal builds

2 participants