pybind / pybind/pybind11

[BUG]: __getattr__ and multiple inheritance with smart holders

Open
#3,801 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

triage
Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Required prerequisites
Problem description

Hi, I've found an other issue related to #3788
this is in regard to the smart holder branch

The example code below fails with infinite recursive getattr calls.

removing either Base2, Derived2 or the binding of __getattr__ removes the problem.

removing the following lines
https://github.com/pybind/pybind11/blob/9d4b4dffce6677a7c9a9af37a45f4436d353f5e1/include/pybind11/detail/smart_holder_type_casters.h#L295-L297
also removes the issue.

Reproducible example code
// Binding code

#include <pybind11/pybind11.h>

namespace py = pybind11;

struct Base1 {int a1{};};
struct Base2 {int a2{};};

struct Base12 : Base1, Base2 {
    virtual ~Base12() = default;
    int foo() const { return 0; }
};

struct Derived1 : Base12 {
    int bar() const { return 1; }
};

struct Derived2 : Base12 {
    int bar() const { return 2; }
};


PYBIND11_MODULE(foo, m) {
    py::class_<Base1>(m, "Base1");
    py::class_<Base2>(m, "Base2");

    py::class_<Base12, Base1, Base2>(m, "Base12")
        .def(py::init<>())
        .def("foo", &Base12::foo)
       .def("__getattr__", [](Base12&, std::string key) {
            return "Base GetAttr: " + key;
        });

    py::class_<Derived1, Base12>(m, "Derived1")
        .def(py::init<>())
        .def("bar", &Derived1::bar);

    py::class_<Derived2, Base12>(m, "Derived2")
        .def(py::init<>())
        .def("bar", &Derived2::bar);
}


// Test code
import foo

d1 = foo.Derived1()
print(f"d1.foo(): {d1.foo()}")
print(f"d1.bar(): {d1.bar()}")
print(f"d1.prop1: {d1.prop1}")

d2 = foo.Derived2()
print(f"d2.foo(): {d2.foo()}")
print(f"d2.bar(): {d2.bar()}")
print(f"d2.prop1: {d2.prop2}")

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproducer in the issue and inspect include/pybind11/detail/smart_holder_type_casters.h around lines 295-297. Reproduce the infinite recursive getattr calls with multiple inheritance and smart holders; done means the example no longer recurses while preserving the described bindings.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.