Bug 28642 - vtable offset position seems wrong
Summary: vtable offset position seems wrong
Status: NEW
Alias: None
Product: libabigail
Classification: Unclassified
Component: default (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Dodji Seketeli
URL:
Keywords:
Depends on:
Blocks: 27019
  Show dependency treegraph
 
Reported: 2021-12-02 00:21 UTC by Ben Woodard
Modified: 2021-12-09 00:52 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ben Woodard 2021-12-02 00:21:21 UTC
Build libabigail with both gcc and clang then compare the resulting library with abidiff

$ abidiff g5/lib/libabigail.so.0.0.0 l5/lib/libabigail.so.0.0.0 

the gcc object can be found: http://ssh.bencoyote.net/~ben/libabigail.so.0.0.0.gcc.bz2 while the clang object can be found: https://sourceware.org/bugzilla/attachment.cgi?id=13812

There seems to be something wrong with the vtable DWARF parsing or comparison. it kind of looks like it may be a latent bug in gcc's vtable position numbering which may not have been detected because it was encoded the same way and therefore compared as equivalent.

There are many differences reported along like this:

 [C] 'method virtual abigail::ini::config::section::~section(int)' at abg-ini.h:386:1 has some indirect sub-type changes:
    the vtable offset of method virtual abigail::ini::config::section::~section(int) changed from 18446744073709551615 to 0
      note that this is an ABI incompatible change to the vtable of class abigail::ini::config::section
    parameter 1 of type 'int' was removed

  [C] 'method virtual abigail::ini::config::~config(int)' at abg-ini.h:342:1 has some indirect sub-type changes:
    the vtable offset of method virtual abigail::ini::config::~config(int) changed from 18446744073709551615 to 0
      note that this is an ABI incompatible change to the vtable of class abigail::ini::config
    parameter 1 of type 'int' was removed

Note that the vtable offset for GCC is 18446744073709551615 which happens to be: 0xFFFF FFFF FFFF FFFF so it looks like a decoding error.
Comment 1 Ben Woodard 2021-12-02 00:30:20 UTC
The removal of the int parameter to the virtual class destructor is probably a second problem but that could be a bug in clang where it doesn't give virtual destructors a parameter (I would have to look at the assembly) or it may be a problem with the DWARF that clang generates for that function. I would have thought that removing the parameter would have changed the C++ function name mangling thus making the functions linkage name different. If the resulting codegen didn't make a destructor which took the int, it would have serious ABI implications that would break at execution time. This suggests to me that it is more likely a clang DWARF generation bug.

Anyway, I think that the removal of the int parameter is a different problem from the offset in the vtable.
Comment 2 Ben Woodard 2021-12-02 00:36:43 UTC
Some background information on the hidden parameter to a class's virtual destructor and why it takes an int. https://stackoverflow.com/questions/7750280/how-does-virtual-destructor-work-in-c/7750873#7750873
Comment 3 Ben Woodard 2021-12-03 22:42:01 UTC
it appears in the DWARF that clang explicitly provides the vtable offset using the DW_AT_vtable_elem_location for the function but GCC relies on the C++ABI rules to layout the vtable and so the element location in the vtable is inferred rather than being specified.

So it appears like when libabigail doesn't get an explicit vtable_element it sets its position to -1 which is 0xFFFF FFFF FFFF FFFF 18446744073709551615 for a 64b int in twos compliment.

There is some trickiness to inferring the vtable position of a particular function. It is by order of declaration in the class declaration. Quoting the C++ABI section 2.5.2 http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components

"The order of the virtual function pointers in a virtual table is the order of declaration of the corresponding member functions in the class. If an implicitly-declared copy assignment operator, move assignment operator, or destructor is virtual, it is treated as if it were declared at the end of the class, in that order. (Implicitly-declared assignment operators may be virtual if a base class declares a virtual assignment operator taking a reference to a derived class type.)" 

Unless I am missing something, it would seem like this logic would have to be implemented in libabigail to ensure that the vtable order is right.
Comment 4 Ben Woodard 2021-12-03 23:19:38 UTC
This is from the abixml from the gcc version of the library:

                <function-decl name='~section' mangled-name='_ZN7abigail3ini6config7sectionD4Ev' filepath='../../../../Work/libabigail/src/abg-ini.cc' line='856' column='1' visibility='default' binding='global' size-in-bits='64'>
                  <parameter type-id='type-id-20101' is-artificial='yes'/>
                  <parameter type-id='type-id-8712' is-artificial='yes'/>
                  <return type-id='type-id-3'/>
                </function-decl>
              </member-function>
              <member-function access='public' destructor='yes' vtable-offset='-1'>
                <function-decl name='~section' mangled-name='_ZN7abigail3ini6config7sectionD0Ev' filepath='../../../../Work/libabigail/src/abg-ini.cc' line='856' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN7abigail3ini6config7sectionD0Ev'>
                  <parameter type-id='type-id-20101' is-artificial='yes'/>
                  <parameter type-id='type-id-8712' is-artificial='yes'/>
                  <return type-id='type-id-3'/>
                </function-decl>
              </member-function>
              <member-function access='public' destructor='yes' vtable-offset='-1'>
                <function-decl name='~section' mangled-name='_ZN7abigail3ini6config7sectionD2Ev' filepath='../../../../Work/libabigail/src/abg-ini.cc' line='856' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN7abigail3ini6config7sectionD2Ev'>
                  <parameter type-id='type-id-20101' is-artificial='yes'/>
                  <parameter type-id='type-id-8712' is-artificial='yes'/>
                  <return type-id='type-id-3'/>
                </function-decl>
              </member-function>

There are the vtable-offsets being set to -1. 

----

Here is the abixml for the clang version.

              <member-function access='public' destructor='yes' vtable-offset='0'>
                <function-decl name='~section' mangled-name='_ZN7abigail3ini6config7sectionD0Ev' filepath='/home/ben/Shared/test/libabigail-test/l5/../../../Work/libabigail/include/abg-ini.h' line='386' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN7abigail3ini6config7sectionD2Ev'>
                  <parameter type-id='type-id-19664' is-artificial='yes'/>
                  <return type-id='type-id-11'/>
                </function-decl>
              </member-function>

it does appear that the parameter is missing.
Comment 5 Ben Woodard 2021-12-09 00:52:29 UTC
Note that every single virtual destructor in code compiled by gcc has a -1 vtable offset. Other virtual methods seem to have reasonable numbers. 

All the virtual destructors in the same code compiled by LLVM have an offset of 0.