Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions tests/test_opaque_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "pybind11_tests.h"

#include <array>
#include <vector>

// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
Expand All @@ -20,8 +21,18 @@
// bit is just the default `std::vector` allocator).
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)

// Test for GitHub issue #5988: PYBIND11_MAKE_OPAQUE with std::array types.
// These types are not used as converted types in other test files, so they
// can safely be made opaque here without ODR violations.
PYBIND11_MAKE_OPAQUE(std::array<double, 3>)
PYBIND11_MAKE_OPAQUE(std::vector<std::array<double, 3>>)

using StringList = std::vector<std::string, std::allocator<std::string>>;

// Type aliases for issue #5988 test
using Array3d = std::array<double, 3>;
using VecArray3d = std::vector<Array3d>;

TEST_SUBMODULE(opaque_types, m) {
// test_string_list
py::class_<StringList>(m, "StringList")
Expand Down Expand Up @@ -74,4 +85,38 @@ TEST_SUBMODULE(opaque_types, m) {
.def(py::init<>())
.def_readwrite("i", &IntFloat::i)
.def_readwrite("f", &IntFloat::f);

// test_issue_5988: PYBIND11_MAKE_OPAQUE with std::array and nested containers
// (Regression test for crash when importing modules with opaque std::array types)
py::class_<Array3d>(m, "Array3d")
.def(py::init<>())
.def("__getitem__",
[](const Array3d &a, std::size_t i) -> double {
if (i >= a.size()) {
throw py::index_error();
}
return a[i];
})
.def("__setitem__",
[](Array3d &a, std::size_t i, double v) {
if (i >= a.size()) {
throw py::index_error();
}
a[i] = v;
})
.def("__len__", [](const Array3d &a) { return a.size(); });

py::class_<VecArray3d>(m, "VecArray3d")
.def(py::init<>())
.def("push_back", [](VecArray3d &v, const Array3d &a) { v.push_back(a); })
.def(
"__getitem__",
[](const VecArray3d &v, std::size_t i) -> const Array3d & {
if (i >= v.size()) {
throw py::index_error();
}
return v[i];
},
py::return_value_policy::reference_internal)
.def("__len__", [](const VecArray3d &v) { return v.size(); });
}
28 changes: 28 additions & 0 deletions tests/test_opaque_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,31 @@ def test_unions():
assert int_float_union.i == 42
int_float_union.f = 3.0
assert int_float_union.f == 3.0


def test_issue_5988_opaque_std_array():
"""Regression test for GitHub issue #5988: crash when binding with opaque std::array types."""
# Test basic Array3d (opaque std::array<double, 3>) functionality
a = m.Array3d()
a[0] = 1.0
a[1] = 2.5
a[2] = 3.0
assert a[0] == 1.0
assert a[1] == 2.5
assert a[2] == 3.0
assert len(a) == 3

with pytest.raises(IndexError):
_ = a[3]

# Test VecArray3d (opaque std::vector<std::array<double, 3>>) functionality
v = m.VecArray3d()
assert len(v) == 0
v.push_back(a)
assert len(v) == 1
assert v[0][0] == 1.0
assert v[0][1] == 2.5
assert v[0][2] == 3.0

with pytest.raises(IndexError):
_ = v[1]