Skip to content

Commit 83b0fca

Browse files
authored
[cpyrt] Use GetActualClass in cast_actual (#90)
cast_actual kept the static class, so comparing two proxies of the same object through different base subobjects compared unequal addresses. Reachable when a proxy is not downcast on creation, e.g. for a pinned type. Also drops a stray '&' from the ostream operand name used for the operator<< lookup, and fixes two comment typos.
1 parent 65c3564 commit 83b0fca

3 files changed

Lines changed: 33 additions & 5 deletions

File tree

‎src/cpyrt/CPPInstance.cxx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ static PyObject* op_destruct(CPPInstance* self) {
281281

282282
//= cpyrt object dispatch support =========================================
283283
static PyObject* op_dispatch(PyObject* self, PyObject* args,
284-
PyObject* /* kdws */) {
284+
PyObject* /* kwds */) {
285285
// User-side __dispatch__ method to allow selection of a specific overloaded
286286
// method. The actual selection is in the __overload__() method of
287287
// CPPOverload.
@@ -554,8 +554,7 @@ static inline void* cast_actual(void* obj) {
554554
return address;
555555

556556
interop::TCppScope_t klass = ((CPPClass*)Py_TYPE((PyObject*)obj))->fCppType;
557-
interop::TCppScope_t clActual =
558-
klass /* XXX: interop::GetActualClass(klass, address) */;
557+
interop::TCppScope_t clActual = interop::GetActualClass(klass, address);
559558
if (clActual && clActual != klass) {
560559
intptr_t offset = interop::GetBaseOffset(
561560
clActual, klass, address, -1 /* down-cast */, true /* report errors */);
@@ -827,7 +826,7 @@ static PyObject* op_str(CPPInstance* self) {
827826
interop::TCppScope_t rnsID =
828827
interop::GetScope(TypeManip::extract_namespace(rcname));
829828
PyCallable* pyfunc =
830-
Utility::FindBinaryOperator("std::ostream&", rcname, "<<", rnsID);
829+
Utility::FindBinaryOperator("std::ostream", rcname, "<<", rnsID);
831830
if (!pyfunc)
832831
continue;
833832

‎src/cpyrt/CPPMethod.cxx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ void cpyrt::CPPMethod::SetPyError_(PyObject* msg) {
297297
// C++ method to give some context.
298298
// 2. A C++ exception has occured:
299299
// Augment the exception message with the docstring of this method
300-
// 3. A Python exception has occured with a traceback:
300+
// 3. A Python exception has occurred with a traceback:
301301
// Do nothing, Python exceptions are already informative enough
302302
// 4. If the Python exception has no traceback hinting to an internally set
303303
// error stack,

‎test/test_pythonify.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,3 +617,32 @@ def test03_write_access_to_globals(self):
617617
assert proxy.__get__(proxy, None) == 3
618618

619619
cppjit.gbl.ns_example01.gMyGlobalInt = oldval
620+
621+
622+
class TestPINNEDCOMPARISON:
623+
def test01_pinned_base_compares_equal(self):
624+
"""Comparison downcasts to the actual class before comparing addresses"""
625+
626+
import cppjit
627+
from cppjit._pythonization import pin_type
628+
629+
cppjit.cppdef("""\
630+
namespace PinnedCmp {
631+
struct B1 { virtual ~B1() {} int a = 1; };
632+
struct B2 { virtual ~B2() {} int b = 2; };
633+
struct D : B1, B2 {};
634+
D g_d;
635+
D* get_d() { return &g_d; }
636+
B2* get_b2() { return static_cast<B2*>(&g_d); }
637+
}""")
638+
639+
ns = cppjit.gbl.PinnedCmp
640+
641+
# pinning keeps the B2 proxy from being downcast on creation, so the
642+
# B2 subobject address is what reaches the comparison
643+
pin_type(ns.B2)
644+
d, b2 = ns.get_d(), ns.get_b2()
645+
assert type(b2).__cpp_name__ == "PinnedCmp::B2"
646+
647+
assert d == b2
648+
assert not (d != b2)

0 commit comments

Comments
 (0)