Skip to content

Fix #483 (bug half): user-reachable preconditions throw instead of assert - #509

Open
petlenz wants to merge 1 commit into
mainfrom
fix-483-user-reachable-asserts
Open

petlenz wants to merge 1 commit into
mainfrom
fix-483-user-reachable-asserts

Conversation

@petlenz

@petlenz petlenz commented Sep 19, 2026

Copy link
Copy Markdown
Member

Addresses the assert half of #483; the policy/CI-grep half stays open.

Library asserts guarding user-reachable preconditions vanish under NDEBUG, so a release build silently built malformed nodes — the class already fixed for tensors (#360/#438) and t2s invariants (#439/#474). This converts the remaining ones and moves sequence.h into the cas_error hierarchy.

36-assert classification (grep -rn "assert(" include src, static_asserts excluded):

Site Class Action
scalar_std.h:77-78 pow, :313 comparisons, :460-461 max, :487-488 min, :608-610 if_then_else (a) user-reachable: null holder throw invalid_expression_error via new detail::require_valid(op, holders...)
tensor_std.h:141-143, 169-171 if_then_else null holders (a) same
tensor_std.h:145-146, 173-174 if_then_else branch dim/rank (c)→(a): the ctors already throw (#295), but the asserts sat before the constant-condition folds and the ctor check after themif_then_else(zero, X, C4) returned C4 without ever reaching the ctor. Now validate_same_shape runs before the folds throw
tensor_to_scalar_std.h:215-217 if_then_else (a) throw
basic_functions.h:21 is_same_r (a), but noexcept — returns nullopt for a null holder return
expression_holder.h:93,103 get() downcast (b) internal: throw_if_invalid() already throws for null; the assert only checks the T the caller asked for after an id check upstream keep
visitor_base.h:118,124, n_ary_tree.h:159, tensor_scalar_mul.h:48 (b) downcast after an id() tie, unreachable by user input (typeid tiebreak from #442 guards cross-type) keep
scalar_differentiation.h:339 (b) visitor-internal state contract keep
projection_tensor.h:45 (b) invariant enforced by clear_space() no-op override keep
positivity_propagation.h:43 (b) explicitly a debug-only rule guard, #ifndef NDEBUG by design keep
tensor_to_scalar_functions.cpp:47,69,85 trace/norm/det rank (a) already converted in PR #474 (#439)
tensor.h:52-53 commented out

sequence.h: the 7 std::out_of_range / std::invalid_argument throws (ctor 0-index, split, split_many, permute ×2, invert_perm ×2) are now invalid_expression_error with unchanged messages. Nothing in include/, src/ or tests/ catches the std types specifically; the fuzz harness catches std::exception only as its "unexpected" path (#376), which these no longer hit.

Tests (each fails without the fix): ScalarFixture.FactoriesRejectInvalidHolder, TensorShapeValidation.IfThenElseBranchesShareShape, TensorToScalar_IfThenElseRejectsInvalidHolder (dims 1–3), IndexSequenceIdentity.ErrorsDeriveFromCasError.

Negative control in Release (the point of the issue), headers restored from main via git show, rebuilt clean: the tensor branch-shape and null-holder checks "throw nothing"; sequence throws std::out_of_range / std::invalid_argument on all 7 sites; the scalar case terminates the process — the null holder reaches a noexcept path that throws — which is worse than a failed assertion. In Debug the old asserts abort instead. All pass with the fix.

Suites: Debug 2411/2411, Release 2411/2411, parser-enabled 2597/2597 (gcc-14). clang-format clean. Fuzz unchanged (known rank-limit skips only).

…sert

Factory arguments were checked with assert, so a release build accepted a
null holder or mismatched if_then_else branches and built a malformed
node. pow, the comparisons, max, min and if_then_else in all three domains
now throw invalid_expression_error; the tensor branch-shape check runs
before the constant-condition folds, which previously hid the mismatch.

is_same_r returns nullopt for a null holder instead of asserting, since it
is noexcept and cannot report otherwise.

sequence.h raised std::out_of_range and std::invalid_argument, outside the
cas_error hierarchy a caller is told to catch; every throw is now
invalid_expression_error with the same message.

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
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.

1 participant