|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0225 |
| Class | BUG |
| Severity | 2 |
| Status | blocked |
Models: —
Found: 2026-11-03, feature base-asan (local ASan/UBSan build of fhsim_base 0bcb39f against fhsim 56c64d9e)
Decision needed: how the Kalman plugin interface stays safe when fhsim and a plugin are built with different Eigen allocator settings: (a) state it as part of the plugin ABI (same Eigen version and the same EIGEN_MAX_ALIGN_BYTES/SIMD flags in every package, D14 AVX2), and for sanitizer runs build every package with ASan or define EIGEN_MALLOC_ALREADY_ALIGNED=1 everywhere; or (b) change KalmanObject to fill buffers that fhsim owns (API change: fhsim_base src/kalman and fhsim's test objects must follow). Agent default: (a), no code or flag change until ruled.
include/fhsim/simobject/KalmanObject.h:32-56: five pure virtuals return estimator::Matrix / estimator::Vector (dynamic Eigen types) by value. The plugin allocates the heap buffer; fhsim frees it.src/engine/integrator/kalman/KalmanFilter.cpp:75, :84, :100 (KalmanFilterData) and src/engine/integrator/kalman/KalmanIntegrator.cpp:235, :259 take the results and destroy them in fhsim.eigen/5.0.1) Eigen/src/Core/util/Memory.h:22-54: EIGEN_MALLOC_ALREADY_ALIGNED is 1 only on glibc 64-bit, with EIGEN_DEFAULT_ALIGN_BYTES == 16 and !defined(__SANITIZE_ADDRESS__). Otherwise Eigen uses handmade_aligned_malloc (over-allocates and returns an offset pointer) and frees with handmade_aligned_free. The macro is decided per translation unit, so two packages can disagree.-fsanitize=address,undefined, fhsim (local_main) without. fhsim_base fast tier, SimObject.KalmanPendulum, KalmanHydroBall, KalmanHydroCable, ZeroDynamics, Jacobian.KalmanPendulum_atNonZeroStateOffset abort: AddressSanitizer: attempting free on address which was not malloc()-ed, "16 bytes inside of 48-byte region", allocated in KalmanPendulum::GetInitialEstimationErrorCovariance() (libfhsim_base.so), freed in estimator::KalmanFilterData::KalmanFilterData (fhsim). The 16-byte offset is the handmade header.-DEIGEN_MALLOC_ALREADY_ALIGNED=1 added to base's flags passes the whole fast tier in one process (380 gtest cases), with no ASan, LSan or UBSan report from src/kalman. The Kalman "leaks" seen before were a consequence of the abort.In a normal Linux build both sides use plain malloc/free, so nothing fails today. It fails as soon as the two sides choose a different allocator: a sanitizer build of one package only, a plugin built with AVX (32-byte alignment, handmade allocator) against an fhsim built without (or the reverse), or a different Eigen version across the boundary. The result is a crash or heap corruption at the first Kalman setup (KalmanFilterData), not a wrong number. On MSVC both sides normally use _aligned_malloc only when alignment > 16; the same flag mismatch applies there.
EIGEN_MALLOC_ALREADY_ALIGNED=1 in all of them. No code change.void GetProcessNoiseCovariance(Eigen::Ref<estimator::Matrix>) or raw double* buffers sized by fhsim, so memory never crosses the boundary. Changes fhsim_base src/kalman (KalmanHydroBall, KalmanHydroCable, KalmanPendulum, ZeroDynamics) and tests/testobjects/DecayingStateEstimator.The reproduction above (fhsim_base fast tier with ASan in base only) is red today; under (b) it turns green without the macro. Under (a) a CI ASan job that instruments every package is the guard.
(b) is an API break for every KalmanObject implementation (only fhsim_base and fhsim's own tests in the workspace; outside code unknown). (a) leaves a crash for anyone who mixes flags.