wrong objects addresses using virtual and diamond inheritance
Phil Thompson
phil at riverbankcomputing.com
Wed Dec 22 13:12:48 GMT 2021
This should be fixed in the next snapshot.
Thanks,
Phil
On 15/12/2021 10:35, Denis Rivière wrote:
> Hi,
>
> I experience a new virtual class address issue using sip
> 4.19.21-4.19.25.
> I have a rather complex C++ inheritance tree, using virtual inheritance
> and
> diamond inheritance, looking like this:
>
> A B
> \\ //
> \\ //
> D C
> \ // \\
> \// \\
> E F
> \\ //
> \\ //
> G
>
> (double lines mean virtual inheritance)
>
> In recent Sip bindings the addresses of the different parts of a G
> object
> appear to be wrong, thus objects are unusable and cause crashes.
>
> Here is a simple C++ implementation code:
>
> // header declarations:
>
> #include <iostream> // not used here but simplifies the sip MethodCodes
> later
>
> class A
> {
> public:
> A();
> virtual ~A();
> int a;
> };
>
>
> class B
> {
> public:
> B();
> virtual ~B();
> int b;
> };
>
> class C : public virtual A, public virtual B
> {
> public:
> C(): c(3) {}
> virtual ~C() {}
>
> int c;
> };
>
> class D
> {
> public:
> D();
> virtual ~D();
> int d;
> };
>
> class E: public D, public virtual C
> {
> public:
> E();
> virtual ~E();
> };
>
> class F : public virtual C
> {
> public:
> F();
> virtual ~F();
> };
>
> class G : public virtual E, public virtual F
> {
> public:
> G();
> virtual ~G();
> int g;
> };
>
>
> // C++ implementation
>
> A::A(): a( 1 ) {}
> A::~A() {}
>
> B::B(): b( 2 ) {}
> B::~B() {}
>
> C::C() : A(), B(), c( 3 ) {}
> C::~C() {}
>
> D::D() : d( 4 ){}
> D::~D() {}
>
> E::E() : D(), C() {}
> E::~E() {}
>
> F::F() : C() {}
> F::~F() {}
>
> G::G() : E(), F(), g( 7 ) {}
> G::~G() {}
>
>
> // SIP bindings file
>
>
> class A
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> A();
> virtual ~A();
> void __a__();
> %MethodCode
> std::cout << "A: " << sipCpp << std::endl;
> %End
>
> int a;
> };
>
>
> class B
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> B();
> virtual ~B();
> void __b__();
> %MethodCode
> std::cout << "B: " << sipCpp << std::endl;
> %End
>
> int b;
> };
>
>
> class C : A, B
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> C();
> virtual ~C();
> void __c__();
> %MethodCode
> std::cout << "C: " << sipCpp << std::endl;
> %End
>
> int c;
> };
>
>
> class D
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> D();
> virtual ~D();
> void __d__();
> %MethodCode
> std::cout << "D: " << sipCpp << std::endl;
> %End
> int d;
> };
>
> class E : D, C
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> E();
> virtual ~E();
> void __e__();
> %MethodCode
> std::cout << "E: " << sipCpp << std::endl;
> %End
> };
>
>
> class F : C
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> F();
> virtual ~F();
> void __f__();
> %MethodCode
> std::cout << "F: " << sipCpp << std::endl;
> %End
> };
>
>
> class G : E, F
> {
> %TypeHeaderCode
> #include "test.h"
> %End
>
> public:
> G();
> virtual ~G();
> void __g__();
> %MethodCode
> std::cout << "G: " << sipCpp << std::endl;
> %End
>
> int g;
> };
>
> // end code
>
> (the source files are also attached to the message)
>
> Thus each class X in python has a __X__() method which prints its C++
> address, and a number of classes have an int data to check the value.
>
> Now if we run this python test:
>
> import test
>
> def print_all(x, methods='abcdefg'):
> for att in methods:
> m = getattr(x, '__%s__' % att, None)
> if m:
> m()
> print()
> for att in methods:
> m = getattr(x, '%s' % att, None)
> if m:
> print('%s:' % att, m)
>
> g = test.G()
>
> print_all(g)
>
>
> This test outputs, using sip 4.19.21 to 4.19.25:
>
> A: 0x36fd720
> B: 0x36fd720
> C: 0x36fd720
> D: 0x36fd738
> E: 0x36fd738
> F: 0x36fd720
> G: 0x36fd720
>
> a: 7
> b: 7
> c: 7
> d: 4
> g: 7
>
> As you see object parts A, B, C, F and G all have the same address in
> the
> bindings, whereas they obviously do not have the same address in C++
> (A, B
> and C are not related). Moreover as the offsets of virtual tables and
> data
> in the object are wrong, the int values are wrong for most of them (a,
> b
> and c all seem to contain 7 whereas they should contain 1, 2 and 3).
>
> Using sip 4.19.15, the output of the same code was:
>
> A: 0x1f72ed8
> B: 0x1f72ee8
> C: 0x1f72ec8
> D: 0x1f72eb8
> E: 0x1f72eb8
> F: 0x1f72ea0
> G: 0x1f72ea0
>
> a: 1
> b: 2
> c: 3
> d: 4
> g: 7
>
> which is totally correct.
>
> In the sip code, if I remove the inheritance from C in F (just in the
> sip
> code, not changing anything in the C++ part), then things become right
> for
> a G object (using sip 4.19.25 again):
>
> A: 0x31b5798
> B: 0x31b57a8
> C: 0x31b5788
> D: 0x31b5778
> E: 0x31b5778
> F: 0x31b5760
> G: 0x31b5760
>
> a: 1
> b: 2
> c: 3
> d: 4
> g: 7
>
> But obviously an instance of F will now be missing its A, B and C
> parts.
>
> After trying all this I remember that we have had possibly similar
> problems
> in the first releases of sip 4.19:
> https://www.riverbankcomputing.com/pipermail/pyqt/2019-February/041313.html
> I haven't tested with the same example yet, so I'm not sure it's the
> same
> problem which has re-appeared.
>
> Thanks for your help,
> Denis
-------------- next part --------------
A non-text attachment was scrubbed...
Name: classes.sip
Type: application/octet-stream
Size: 1243 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20211222/544c3be0/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: classes.h
Type: text/x-chdr
Size: 597 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20211222/544c3be0/attachment.h>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: classes.cpp
Type: text/x-c++src
Size: 256 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20211222/544c3be0/attachment.cpp>
More information about the PyQt
mailing list