Изменился ли макет libstdc ++ для make_shared между gcc 4.x и gcc 6.x? - PullRequest
0 голосов
/ 22 мая 2018

Рассмотрим следующий минимальный пример, состоящий из трех файлов:

foo.h:

#pragma once
#include <memory>

struct X {
    uint64_t i = 0xdeadbeefdeadbeefULL;
};

void foo();

foo.cxx:

#include "foo.h"

void foo() {
    std::make_shared<X>();
}

main.cxx:

#include <memory>
#include "foo.h"

template std::shared_ptr<X> std::make_shared();

int main() {
    foo();
}

А затем скомпилируйте два модуля перевода с разными версиями gcc:

$ g++-4.8.2 -g -std=c++11 -O0 -c foo.cxx -o foo.o
$ g++-6.2.0 -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -O0 -g main.cxx foo.o -fsanitize=address -fno-omit-frame-pointer

Обратите внимание, что я специально компилирую со старым ABI.

Выполняетсяполученный исполняемый файл умирает (это не произойдет, если оба TU будут скомпилированы с одной и той же версией gcc):

==33535==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff8 at pc 0x000000401dcf bp 0x7fffffffd7f0 sp 0x7fffffffd7e8
WRITE of size 8 at 0x60300000eff8 thread T0
    #0 0x401dce in X::X() (.../a.out+0x401dce)
    #1 0x402758 in _ZN9__gnu_cxx13new_allocatorI1XE9constructIS1_IEEEvPT_DpOT0_ /.../gcc-4.8.2/include/c++/4.8.2/ext/new_allocator.h:120
    #2 0x402721 in _ZNSt16allocator_traitsISaI1XEE12_S_constructIS0_IEEENSt9enable_ifIXsrNS2_18__construct_helperIT_IDpT0_EEE5valueEvE4typeERS1_PS6_DpOS7_ /.../gcc-4.8.2/include/c++/4.8.2/bits/alloc_traits.h:254
    #3 0x4026fc in _ZNSt16allocator_traitsISaI1XEE9constructIS0_IEEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS1_PT_DpOS4_ /.../gcc-4.8.2/include/c++/4.8.2/bits/alloc_traits.h:393
    #4 0x4026a6 in std::_Sp_counted_ptr_inplace<X, std::allocator<X>, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_ptr_inplace<>(std::allocator<X>) /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr_base.h:399
    #5 0x4025d4 in _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI1XSaIS2_ELNS_12_Lock_policyE2EEE9constructIS5_IKS3_EEEvPT_DpOT0_ /.../gcc-4.8.2/include/c++/4.8.2/ext/new_allocator.h:120
    #6 0x402572 in _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI1XSaIS1_ELN9__gnu_cxx12_Lock_policyE2EEEE12_S_constructIS5_IKS2_EEENSt9enable_ifIXsrNS7_18__construct_helperIT_IDpT0_EEE5valueEvE4typeERS6_PSC_DpOSD_ /.../gcc-4.8.2/include/c++/4.8.2/bits/alloc_traits.h:254
    #7 0x40253a in _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI1XSaIS1_ELN9__gnu_cxx12_Lock_policyE2EEEE9constructIS5_IKS2_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS6_PT_DpOSA_ /.../gcc-4.8.2/include/c++/4.8.2/bits/alloc_traits.h:393
    #8 0x40249b in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<X, std::allocator<X>>(std::_Sp_make_shared_tag, X*, std::allocator<X> const&) /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr_base.h:502
    #9 0x4023b1 in std::__shared_ptr<X, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<X>>(std::_Sp_make_shared_tag, std::allocator<X> const&) /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr_base.h:957
    #10 0x402375 in std::shared_ptr<X>::shared_ptr<std::allocator<X>>(std::_Sp_make_shared_tag, std::allocator<X> const&) /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr.h:316
    #11 0x4022c4 in std::shared_ptr<X> std::allocate_shared<X, std::allocator<X>>(std::allocator<X> const&) /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr.h:598
    #12 0x402241 in _ZSt11make_sharedI1XIEESt10shared_ptrIT_EDpOT0_ /.../gcc-4.8.2/include/c++/4.8.2/bits/shared_ptr.h:614
    #13 0x4021cf in foo() /.../foo.cxx:4
    #14 0x400fd0 in main /.../main.cxx:7
    #15 0x7ffff6208b34 in __libc_start_main (/lib64/libc.so.6+0x21b34)
    #16 0x400ef8  (/.../a.out+0x400ef8)

Это также верно для gcc 7 и gcc 8, но не верно для gcc 5.4.Это специфично для std::make_shared.Что здесь происходит?Я не могу найти информацию о разрыве ABI, и при этом я не понимаю, какие изменения могут сломать этот пример.

1 Ответ

0 голосов
/ 27 мая 2018
Поддержка

C ++ 11 в GCC 4.8 все еще была экспериментальной, поэтому два объекта, скомпилированных с помощью -std=c++11, можно связать вместе, только если они оба скомпилированы с помощью GCC 4.8.x

См. https://stackoverflow.com/a/49119902/981959 для более полного объяснения.

...