backward/forward binary compatibility checker

Thiago Macieira thiago at kde.org
Wed Jul 29 18:01:00 BST 2009


Em Quarta-feira 29 Julho 2009, às 17:11:09, Andrey Ponomarenko escreveu:
> We have fixed your problem, but we have tested your library descriptors
> only on Qt4.2.3 and Qt4.3.0 because we have not new Qt versions (4.5.3
> and 4.6) yet and don't know where to find it. You may use beta 4 version
> of tool, it is in the attachment. It must work on your library versions.

Thank you, now it worked.

The versions I am testing with are unreleased versions of Qt. They are 
available from http://qt.gitorious.org/qt/qt.

But you may test with other released versions. As far as we know, there are no 
problems, except one. There is one binary-incompatible change in Qt 4.5.0 when 
compared to 4.4.3 (and it would be interesting to see if the tool can find it).


I'm looking at the report it generated and it says that there are two entries 
removed in Qt 4.6.0:
======
qbytearray.h, libQtGui.so.4.5.3
  QByteArray::replace(char const*, char const*) 
[ mangled name: _ZN10QByteArray7replaceEPKcS1_ ]
 
 qtransform.h, libQtGui.so.4.5.3
  QTransform::isInvertible() const 
[ mangled name: _ZNK10QTransform12isInvertibleEv ]
=====

On the first case, I don't see how it can make such a claim:
$ nm -D qt-4.5/lib/libQtCore.so.4.5.3 | grep _ZN10QByteArray7replaceEPKcS1_
$ nm -D qt-main/lib/libQtCore.so.4.6.0 | grep _ZN10QByteArray7replaceEPKcS1_
00169f20 W _ZN10QByteArray7replaceEPKcS1_

If anything, it should be the opposite. The symbol was added in Qt 4.6.

As for the second case:
$ nm -D qt-4.5/lib/libQtGui.so.4.5.3 | grep _ZNK10QTransform12isInvertibleEv
00821c2a W _ZNK10QTransform12isInvertibleEv
$ nm -D qt-main/lib/libQtGui.so.4.6.0 | grep _ZNK10QTransform12isInvertibleEv

At first glance, it looks like the symbol was removed. But closer inspection, 
by looking at the header qtransform.h:

$ grep -A3 QTransform::isInvertible src/gui/*/qtransform.h
inline bool QTransform::isInvertible() const
{
    return !qFuzzyCompare(determinant() + 1, 1);
}

The function in question is declared inline and is present in the .h file. It 
continues to be declared inline in the new version of the header. Therefore, 
the (weak) symbol disappearing from the library is not a problem per-se.

Arguably, gcc should have generated this symbol with HIDDEN visibility (due to 
-fvisibility-inlines-hidden). So it appears to be a gcc bug too.


The next section of the report is Problems in Data Types (High risk). This 
section is full of false positives. It is listing all the new classes as high 
risk (QAbstractAnimation, QEventTransition, QFinalState, QGesture, etc.) with 
messages like:

====
Virtual method 
QAbstractAnimation::updateDirection(QAbstractAnimation::Direction) has been 
added to this class and therefore the layout of virtual table has been changed
====

Yes, the virtual method was added to that class. But the class didn't exist in 
the previous version, so existing code cannot be calling it. Crashes are 
impossible.

That section also contains three classes that aren't new: QAssistantClient, 
QColumnView and QtConcurrent::ThreadEngineBase.

For QAssistantClient, it says that qt_metacast() and metaObject() virtuals are 
swapped. That's incorrect. If they had, then all QObject-derived classes 
should be reporting the same error.

For QColumnView, it's reporting that QColumnView::currentChanged moved to 
before two other virtuals. That corresponds to this commit: 
http://qt.gitorious.org/qt/qt/commit/e5e2f9fd5c1554337a576374ec6744f953d2404d. 
You can see the createColumn virtual in the diff, though 
QColumnView::scrollContentsBy doesn't appear.

That's also a false positive. Comparing the two virtual tables as generated by 
the compiler shows:

$ diff -u <(objdump -Crj.data.rel.ro._ZTV11QColumnView .obj/debug-
shared/qcolumnview.o | sort) <(objdump -Crj.data.rel.ro._ZTV11QColumnView 
~/obj/troll/qt-main/src/gui/.obj/debug-shared/qcolumnview.o | sort)

--- /proc/self/fd/11    2009-07-29 18:41:56.608117609 +0200
+++ /proc/self/fd/12    2009-07-29 18:41:56.600117739 +0200
@@ -72,7 +72,7 @@
 00000110 R_386_32          QAbstractItemView::doItemsLayout()
 00000114 R_386_32          QColumnView::selectAll()
 00000118 R_386_32          QAbstractItemView::dataChanged(QModelIndex const&, 
QModelIndex const&)
-0000011c R_386_32          QAbstractItemView::rowsInserted(QModelIndex 
const&, int, int)
+0000011c R_386_32          QColumnView::rowsInserted(QModelIndex const&, int, 
int)
 00000120 R_386_32          
QAbstractItemView::rowsAboutToBeRemoved(QModelIndex const&, int, int)
 00000124 R_386_32          QAbstractItemView::selectionChanged(QItemSelection 
const&, QItemSelection const&)
 00000128 R_386_32          QColumnView::currentChanged(QModelIndex const&, 
QModelIndex const&)

As you can see, the only change in the vtable is that rowsInserted got 
reimplemented. Nothing else changed positions. The false positive comes from 
the fact that the order of the declarations in the header did change, but the 
vtable didn't: remember that the order of the entries in the vtable is given 
by the parent classes first. Overriding functions are all listed first, then the 
new bases.

However, I should note that the commit above was a risky change.

The third change in this section is on QtConcurrent::ThreadEngineBase. That's 
something I need to investigate more. The report is correct that the protected 
members changed, in what is a private class, but present in public files for 
implementation reasons.

In the medium risk section, it is pointing to the addition of hasGuards to 
QObjectData. The report is correct (see commit 
http://qt.gitorious.org/qt/qt/commit/1a5e7171b9da383ca5f6be92b7cb6e502fd79fc4#src/corelib/kernel/qobject.h), 
however this change is acceptable since the overall size is still the same and 
just the "unused" field was shrunk. Using bits in bitfields is a known BC 
method.

Finally, in the Low Risk section, it is listing all newly-overridden virtual 
methods. The report is correct, because it's a risky change: the old method 
may still be called.

Note how QColumnView::rowsInserted is listed here, correctly.

However, this section is again listing all new classes. That is incorrect, 
since the new classes cannot be called from old code.

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
  Senior Product Manager - Nokia, Qt Software
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: abi_compat_report.html.bz2
Type: application/x-bzip
Size: 30477 bytes
Desc: not available
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20090729/445d99d4/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20090729/445d99d4/attachment.sig>


More information about the kde-core-devel mailing list