-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Title: pybind wrapper needs safe handling for inherited methods on multiply inherited C++ classes
Summary
We found a pybind wrapper bug affecting inherited non-virtual base methods when the wrapped C++ class has multiple inheritance but the generated binding only lists one base and does not use py::multiple_inheritance().
Concrete case from GTSAM legged estimators:
gtsam::LeggedEstimatordeclares non-virtual methods:void turnHeightPriorOn(double terrainHeight);void turnHeightPriorOff();
gtsam::LeggedInvariantEKFinherits from:LeftLinearEKF<ExtendedPose3d>LeggedEstimator
Observed behavior
When turnHeightPriorOn/Off() were exposed only on the abstract base LeggedEstimator in the .i file, Python calls on concrete LeggedInvariantEKF instances had no behavioral effect.
Workaround that fixed it immediately:
- redeclare the same methods on each concrete wrapped class in the
.ifile
That strongly suggests the issue is wrapper inheritance / base-pointer adjustment, not estimator logic.
pybind11 docs say this is undefined behavior unless:
- all C++ bases are listed, or
py::multiple_inheritance()is supplied
Minimal reproduction pattern
- abstract base class with non-virtual method
- derived class with multiple C++ bases
- wrapper lists only one base
- base method is only bound on the base class
- calling that method from Python on a concrete object does not affect behavior correctly
- rebinding the same method directly on the concrete class works around the problem
The smallest fix that appears correct is:
- emit
py::multiple_inheritance()for classes with a base class in generated pybind bindings
Possible better long-term fixes:
- model multiple bases explicitly in the interface language
- validate
.iinheritance against the real C++ inheritance - emit
py::multiple_inheritance()only when truly needed, if that can be detected reliably
Regression test suggestion
Add a small pybind integration test with:
- base class method
- multiply inherited derived class
- binding lists one base
- verify that inherited method on derived object behaves correctly only when
py::multiple_inheritance()is present
Why this matters
Without this fix, downstream projects have to duplicate inherited methods on concrete classes in .i files as a workaround, which is brittle and obscures the real wrapper problem.