wrong objects addresses using virtual and diamond inheritance
Denis Rivière
denis.riviere at cea.fr
Wed Dec 15 10:35:36 GMT 2021
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 --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20211215/b380433c/attachment.htm>
-------------- 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/20211215/b380433c/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/20211215/b380433c/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/20211215/b380433c/attachment.cpp>
More information about the PyQt
mailing list