71072c025d
mju_boxQP documents that only the lower triangle of the Hessian H is read, but the gradient and search-direction updates inside mju_boxQPoption still called the dense mju_mulMatVec, which reads the upper triangle as well. This violated the documented contract and prevented callers from safely leaving the upper triangle uninitialized. Add a file-local mulMatVecSym helper that computes res = H*vec while reading only the lower triangle of H (mirroring the convention of the existing mulVecMatVecSym quadratic-form helper), and use it in place of mju_mulMatVec in both call sites. Extend the BoxQP test suite with UpperTrianglePoisoned, which fills the strict upper triangle of H with NaN and verifies that the solver produces the same result as on the clean symmetric input. Reported by @lshdlut. Fixes #3275