Sibling of #348, confirmed while reviewing PR #442. #348 covers a scalar and a tensor sharing a name (crash / UB, fixed by type discrimination). This one is two tensor symbols sharing a name with different shapes — no crash, silently wrong numbers.
tensor (include/numsim_cas/tensor/tensor.h:10) overrides neither the hash nor equality, so it inherits name-only identity from symbol_base. dim and rank are carried on the node but never take part in identity.
Reproduced:
| Probe |
Result |
A(3,2) == A(2,2) |
true |
map holding A(3,2), A(2,2), A(3,4) |
size 1 |
bind A(3,2) → 1.0 and A(2,2) → 7.0 in one tensor_evaluator, then apply(A(3,2)) |
7.0 |
trace(A(3,2)) with only the 2×2 binding |
14 (the 2×2 trace) |
No throw, no crash, no out-of-bounds read — the evaluator dispatches on the bound data's own shape, so the wrong tensor is simply used. A natural way to hit it: reusing the name A for a 3D rank-2 stress and a rank-4 tangent in one script.
The type discriminator added by #442 cannot help here: both are tensor.
Fix (mirrors what #442 did for names): add dim and rank as tiebreaks in symbol_base::operator== / operator< for tensor symbols — or override both in tensor. Leave the hash alone: it only needs to be a fast reject, and changing it churns hash-driven print order (measured in #442: several print-pinned tests flip).
Tests: the four probes above, plus an evaluator end-to-end asserting both bindings survive and each returns its own data.
Signed-off-by: petlenz peterlenz89.pl@gmail.com
Sibling of #348, confirmed while reviewing PR #442. #348 covers a scalar and a tensor sharing a name (crash / UB, fixed by type discrimination). This one is two tensor symbols sharing a name with different shapes — no crash, silently wrong numbers.
tensor(include/numsim_cas/tensor/tensor.h:10) overrides neither the hash nor equality, so it inherits name-only identity fromsymbol_base.dimandrankare carried on the node but never take part in identity.Reproduced:
A(3,2) == A(2,2)A(3,2),A(2,2),A(3,4)A(3,2)→ 1.0 andA(2,2)→ 7.0 in onetensor_evaluator, thenapply(A(3,2))trace(A(3,2))with only the 2×2 bindingNo throw, no crash, no out-of-bounds read — the evaluator dispatches on the bound data's own shape, so the wrong tensor is simply used. A natural way to hit it: reusing the name
Afor a 3D rank-2 stress and a rank-4 tangent in one script.The type discriminator added by #442 cannot help here: both are
tensor.Fix (mirrors what #442 did for names): add
dimandrankas tiebreaks insymbol_base::operator==/operator<for tensor symbols — or override both intensor. Leave the hash alone: it only needs to be a fast reject, and changing it churns hash-driven print order (measured in #442: several print-pinned tests flip).Tests: the four probes above, plus an evaluator end-to-end asserting both bindings survive and each returns its own data.
Signed-off-by: petlenz peterlenz89.pl@gmail.com