Skip to content

Commit 262a609

Browse files
committed
ChatGPT-generated diamond virtual-inheritance test case.
1 parent d4d555d commit 262a609

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

tests/test_class_sh_mi_thunks.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,54 @@ struct Derived : Base1, Base0 {
3030
Derived(const Derived &) = delete;
3131
};
3232

33+
// ChatGPT-generated Diamond
34+
35+
struct VBase {
36+
virtual ~VBase() = default;
37+
virtual int ping() const { return 1; }
38+
int vbase_tag = 42; // ensure it's not empty
39+
};
40+
41+
// Left/right add some weight to steer layout differences across compilers
42+
struct Left : virtual VBase {
43+
char pad_l[7];
44+
virtual ~Left() = default;
45+
};
46+
struct Right : virtual VBase {
47+
long long pad_r;
48+
virtual ~Right() = default;
49+
};
50+
51+
struct Diamond : Left, Right {
52+
Diamond() = default;
53+
Diamond(const Diamond &) = default;
54+
~Diamond() override = default;
55+
int ping() const override { return 7; }
56+
int self_tag = 99;
57+
};
58+
59+
// Factory that returns the *virtual base* type; this is the seam
60+
std::shared_ptr<VBase> make_diamond_as_vbase() {
61+
auto sp = std::make_shared<Diamond>();
62+
return sp; // upcast to VBase shared_ptr (virtual base)
63+
}
64+
65+
// For diagnostics / skip decisions in test
66+
struct DiamondAddrs {
67+
uintptr_t as_self;
68+
uintptr_t as_vbase;
69+
uintptr_t as_left;
70+
uintptr_t as_right;
71+
};
72+
73+
DiamondAddrs diamond_addrs() {
74+
auto sp = std::make_shared<Diamond>();
75+
return DiamondAddrs{reinterpret_cast<uintptr_t>(sp.get()),
76+
reinterpret_cast<uintptr_t>(static_cast<VBase *>(sp.get())),
77+
reinterpret_cast<uintptr_t>(static_cast<Left *>(sp.get())),
78+
reinterpret_cast<uintptr_t>(static_cast<Right *>(sp.get()))};
79+
}
80+
3381
} // namespace test_class_sh_mi_thunks
3482

3583
TEST_SUBMODULE(class_sh_mi_thunks, m) {
@@ -90,4 +138,23 @@ TEST_SUBMODULE(class_sh_mi_thunks, m) {
90138
}
91139
return obj_der->vec.size();
92140
});
141+
142+
py::class_<VBase, py::smart_holder>(m, "VBase").def("ping", &VBase::ping);
143+
144+
py::class_<Left, VBase, py::smart_holder>(m, "Left");
145+
py::class_<Right, VBase, py::smart_holder>(m, "Right");
146+
147+
py::class_<Diamond, Left, Right, py::smart_holder>(m, "Diamond", py::multiple_inheritance())
148+
.def(py::init<>())
149+
.def("ping", &Diamond::ping);
150+
151+
m.def("make_diamond_as_vbase", &make_diamond_as_vbase);
152+
153+
py::class_<DiamondAddrs, py::smart_holder>(m, "DiamondAddrs")
154+
.def_readonly("as_self", &DiamondAddrs::as_self)
155+
.def_readonly("as_vbase", &DiamondAddrs::as_vbase)
156+
.def_readonly("as_left", &DiamondAddrs::as_left)
157+
.def_readonly("as_right", &DiamondAddrs::as_right);
158+
159+
m.def("diamond_addrs", &diamond_addrs);
93160
}

tests/test_class_sh_mi_thunks.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,19 @@ def test_get_shared_vec_size_unique():
5151
assert (
5252
str(exc_info.value) == "Cannot disown external shared_ptr (load_as_unique_ptr)."
5353
)
54+
55+
56+
def _delta_nonzero():
57+
a = m.diamond_addrs()
58+
return (a.as_vbase - a.as_self) != 0
59+
60+
61+
@pytest.mark.skipif(
62+
not _delta_nonzero(), reason="virtual base at offset 0 on this compiler/layout"
63+
)
64+
def test_shared_ptr_return_to_virtual_base_triggers_vi_path():
65+
# This exercised the broken seam pre-fix.
66+
vb = m.make_diamond_as_vbase()
67+
# If registration used the wrong subobject, this would crash pre-fix on MSVC
68+
# and often on Linux with diamond MI (or under ASan/UBSan).
69+
assert vb.ping() == 7

0 commit comments

Comments
 (0)