Skip to content

Commit

Permalink
Demonstration of Undefined Behavior in handling of shared_ptr holder.
Browse files Browse the repository at this point in the history
Based on https://godbolt.org/z/4fdjaW by jorgbrown@ (thanks Jorg!).
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Dec 20, 2020
1 parent 3b34392 commit e0207d6
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
47 changes: 47 additions & 0 deletions tests/test_smart_ptr_private_first_base.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Demonstration of Undefined Behavior in handling of shared_ptr holder,
// specifically:
// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L235
// `return reinterpret_cast<H &>(vh[1]);`
// indirectly casts a `shared_ptr<drvd>` reference to a `shared_ptr<base>`.
// `test_smart_ptr_private_first_base.py` fails with an AssertionError and
// a subsequent Segmentation Fault (Linux, clang++ -std=c++17).

#include <memory>

#include "pybind11_tests.h"

namespace pybind11_tests {
namespace smart_ptr_private_first_base {

struct base {
base() : base_id(100) {}
virtual ~base() = default;
virtual int id() const { return base_id; }
int base_id;
};

struct private_first_base { // Any class with a virtual function will do.
virtual void some_other_virtual_function() const {}
virtual ~private_first_base() = default;
};

struct drvd : private private_first_base, public base {
int id() const override { return 2 * base_id; }
};

inline std::shared_ptr<drvd> make_shared_drvd() {
return std::shared_ptr<drvd>(new drvd);
}

inline int pass_shared_base(std::shared_ptr<base> b) { return b->id(); }

TEST_SUBMODULE(smart_ptr_private_first_base, m) {
py::class_<base, std::shared_ptr<base>>(m, "base");
py::class_<drvd, base, std::shared_ptr<drvd>>(m, "drvd");

m.def("make_shared_drvd", make_shared_drvd);
m.def("pass_shared_base", pass_shared_base);
}

} // namespace smart_ptr_private_first_base
} // namespace pybind11_tests
9 changes: 9 additions & 0 deletions tests/test_smart_ptr_private_first_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
import pytest

from pybind11_tests import smart_ptr_private_first_base as m

def test_make_pass():
d = m.make_shared_drvd()
i = m.pass_shared_base(d)
assert i == 200

0 comments on commit e0207d6

Please sign in to comment.