https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70760

            Bug ID: 70760
           Summary: [6 regression] wrong generated code for
                    std::make_unique with -fipa-pta
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: david.abdurachmanov at gmail dot com
  Target Milestone: ---

Created attachment 38325
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=38325&action=edit
untouched preprocessed file

Hopefully this is truly the last issues I see with GCC 6 on x86_64 and our
software.

Compiler with GCC 5.3.0, ASan and valgrind shows no issues. Compiled with GCC
6.0.1, ASan and valgrind shows issues, program segfaults. If we disable
-fipa-pta the program compiles and runs successfully. Developers so far
couldn't understand whats happening, at least at C++ level from their point of
view everything is fine. No issues if compiled with latest Clang or ICC.

TL;DR doing .get() on std::unique_ptr in a bizarre 0x100000000 pointer. Of
course accessing later such address causes segfaults.

GIT bisect tracked down the issue to a fix for PR ipa/68331
(https://gcc.gnu.org/viewcvs?rev=231498&root=gcc&view=rev)

In git,
first bad: 7ae97ba6651703d99d9f0e20a4e48eb7743c103c
last good: 6c2acfc4892316b46df0fe4a6769fb6766ab1e0b

The following code is failing on C++ level:

421     std::unique_ptr<ParameterDescriptionNode> node =
std::make_unique<ParameterDescription<T>>(iLabel, value, isTracked);
422     ParameterDescriptionNode* pnode = addNode(std::move(node), isOptional,
writeToCfi);

addNode function segfauls once it tries access through 0x100000000 address
which is from std::unique_ptr.

I looked at addNode assembly and fully expected that it should segfault.
Nothing wrong found with it. I went one frame up to
edmtest::ProducerWithPSetDesc::fillDescriptions(edm::ConfigurationDescriptions&)
symbol, but found no significant differences in generated assembly between
those two commits. All differences were in offsets which looked fine.

I knew that it's 2nd call to addNode inside
edmtest::ProducerWithPSetDesc::fillDescriptions which caused the failure.
Before 2nd addNode call is done it called to
std::_MakeUniq<edm::ParameterDescription<int> >::__single_object
std::make_unique<edm::ParameterDescription<int>, char const (&) [16], int
const&, bool&>(char const (&) [16], int const&, bool&) [clone .isra.142] symbol
and after it the second argument (to be passed to addNode) was damaged with
bizarre 0x100000000 pointer at run-time.

"Good code" annotated by me is below for this std::make_unique function. Due to
-fipa-pta we loose one instruction which is related to return value from
std::make_unique:

  3 @@ -19,7 +19,6 @@
  4         48 89 df                mov    %rbx,%rdi
  5         e8 75 e8 ff ff          callq  17060 <edm
  6         48 8b 05 a6 36 03 00    mov    0x336a6(%rip),%rax        # 4be98
<_DYNAMIC+0x430>


  7 -       49 89 1c 24             mov    %rbx,(%r12)



  8         48 83 c0 10             add    $0x10,%rax
  9         48 89 03                mov    %rax,(%rbx)
 10         41 8b 45 00             mov    0x0(%r13),%eax
 11 @@ -34,9 +33,10 @@
 12         48 89 c5                mov    %rax,%rbp
 13         48 89 df                mov    %rbx,%rdi
 14         be 28 00 00 00          mov    $0x28,%esi
 15 -       e8 50 e4 ff ff          callq  16c70 <operator delete(void*,
unsigned long)@plt>
 16 +       e8 54 e4 ff ff          callq  16c70 <operator delete(void*,
unsigned long)@plt>
 17         48 89 ef                mov    %rbp,%rdi
 18 -       e8 48 ef ff ff          callq  17770 <_Unwind_Resume@plt>
 19 -       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
 20 -       00
 21 +       e8 4c ef ff ff          callq  17770 <_Unwind_Resume@plt>
 22 +       66 90                   xchg   %ax,%ax
 23 +       66 2e 0f 1f 84 00 00    nopw   %cs
 24 +       00 00 00

In a "good code" it used to return a pointer to a pointer to internally
allocated object. That missing instruction was storing address of allocation on
heap to some memory location. Later we used to return R12. Without that
instruction R12 contains RDI. Thus we are basically returning the first
argument of std::make_unique.

I have rushed a bit, thus hopefully didn't make too many mistakes. That's the
only meaningful difference I can in see in assembly code in 3 related symbols.

Attaching the preprocessed file (untouched).

We compile it with:

c++ -c -O2 -std=c++1z -ftree-vectorize -fvisibility-inlines-hidden
-fno-math-errno --param vect-max-version-for-alias-checks=50 -fipa-pta -msse3
-felide-constructors -fPIC ProducerWithPSetDesc.ii

Again, removing -fipa-pta seems to solve the issue (bring back the missing
instruction).

##### GOOD ASM #####

00000000000187b0 <std::_MakeUniq<edm::ParameterDescription<int>
>::__single_object std::make_unique<edm::ParameterDescription<int>, char const
(&) [16], int const&, bool&>(char const (&) [16], int const&, bool&) [clone
.isra.142]>:
   187b0:       41 56                   push   %r14
   187b2:       41 55                   push   %r13
   187b4:       49 89 f6                mov    %rsi,%r14
   187b7:       41 54                   push   %r12
   187b9:       55                      push   %rbp
   187ba:       49 89 fc                mov    %rdi,%r12
   187bd:       53                      push   %rbx

// Allocate 40 bytes on the heap

   187be:       bf 28 00 00 00          mov    $0x28,%edi
   187c3:       49 89 d5                mov    %rdx,%r13
   187c6:       0f b6 e9                movzbl %cl,%ebp
   187c9:       e8 62 e5 ff ff          callq  16d30 <operator new(unsigned
long)@plt>

// Store returned pointer in RBX

   187ce:       48 89 c3                mov    %rax,%rbx
   187d1:       e8 da f8 ff ff          callq  180b0 <edm::ParameterTypes
edm::ParameterTypeToEnum::toEnum<int>()@plt>
   187d6:       41 b8 01 00 00 00       mov    $0x1,%r8d
   187dc:       89 e9                   mov    %ebp,%ecx
   187de:       89 c2                   mov    %eax,%edx
   187e0:       4c 89 f6                mov    %r14,%rsi

// Call the ctor, pass pointer (this) from RBX

   187e3:       48 89 df                mov    %rbx,%rdi
   187e6:       e8 75 e8 ff ff          callq  17060
<edm::ParameterDescriptionBase::ParameterDescriptionBase(char const*,
edm::ParameterTypes, bool, bool)@plt>
   187eb:       48 8b 05 a6 36 03 00    mov    0x336a6(%rip),%rax        #
4be98 <_DYNAMIC+0x430>

// Store RBX to memory pointed by R12

   187f2:       49 89 1c 24             mov    %rbx,(%r12)
   187f6:       48 83 c0 10             add    $0x10,%rax
   187fa:       48 89 03                mov    %rax,(%rbx)
   187fd:       41 8b 45 00             mov    0x0(%r13),%eax
   18801:       89 43 20                mov    %eax,0x20(%rbx)

// Put address in R12 into return register

   18804:       4c 89 e0                mov    %r12,%rax
   18807:       5b                      pop    %rbx
   18808:       5d                      pop    %rbp
   18809:       41 5c                   pop    %r12
   1880b:       41 5d                   pop    %r13
   1880d:       41 5e                   pop    %r14
   1880f:       c3                      retq
   18810:       48 89 c5                mov    %rax,%rbp
   18813:       48 89 df                mov    %rbx,%rdi
   18816:       be 28 00 00 00          mov    $0x28,%esi
   1881b:       e8 50 e4 ff ff          callq  16c70 <operator delete(void*,
unsigned long)@plt>
   18820:       48 89 ef                mov    %rbp,%rdi
   18823:       e8 48 ef ff ff          callq  17770 <_Unwind_Resume@plt>
   18828:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
   1882f:       00

##### ASAN REPORT #####

ASAN:DEADLYSIGNAL
=================================================================
==11345==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc
0x2abffdb95e22 bp 0x7ffd8abe14b0 sp 0x7ffd8abe12c0 T0)
    #0 0x2abffdb95e21 in
edm::ParameterDescriptionNode::checkAndGetLabelsAndTypes(std::set<std::string,
std::less<std::string>, std::allocator<std::string> >&,
std::set<edm::ParameterTypes, std::less<edm::ParameterTypes>,
std::allocator<edm::ParameterTypes> >&, std::set<e
dm::ParameterTypes, std::less<edm::ParameterTypes>,
std::allocator<edm::ParameterTypes> >&) const
/mnt/build/davidlt/CMSSW_8_1_X_2016-04-18-1100/src/FWCore/ParameterSet/interface/ParameterDescriptionNode.h:213
    #1 0x2abffdb95e21 in
edm::ParameterSetDescription::addNode(std::unique_ptr<edm::ParameterDescriptionNode,
std::default_delete<edm::ParameterDescriptionNode> >, bool, bool)
/mnt/build/davidlt/CMSSW_8_1_X_2016-04-18-1100/src/FWCore/ParameterSet/src/ParameterSetDescripti
on.cc:92
    #2 0x2ac0041a3961 in edm::ParameterDescriptionBase*
edm::ParameterSetDescription::add<int, char [16]>(char const (&) [16], int
const&, bool, bool, bool)
/mnt/build/davidlt/CMSSW_8_1_X_2016-04-18-1100/src/FWCore/ParameterSet/interface/ParameterSetDescription.h:422
    #3 0x2ac0041a3961 in edm::ParameterDescriptionBase*
edm::ParameterSetDescription::addUntracked<int, char [16]>(char const (&) [16],
int const&)
/mnt/build/davidlt/CMSSW_8_1_X_2016-04-18-1100/src/FWCore/ParameterSet/interface/ParameterSetDescription.h:95
[..]

##### VALGRIND REPORT #####

These happens already after calling edm::ParameterSetDescription::addNode where
the pointer is already wrong.

==31968== Use of uninitialised value of size 8
==31968==    at 0x40C7674: checkAndGetLabelsAndTypes
(ParameterDescriptionNode.h:213)
==31968==    by 0x40C7674:
edm::ParameterSetDescription::addNode(std::unique_ptr<edm::ParameterDescriptionNode,
std::default_delete<edm::ParameterDescriptionNode> >, bool, bool)
(ParameterSetDescription.cc:92)
==31968==    by 0x8705657: add<int, char [16]> (ParameterSetDescription.h:422)
==31968==    by 0x8705657: addUntracked<int, char [16]>
(ParameterSetDescription.h:95)
==31968==    by 0x8705657:
edmtest::ProducerWithPSetDesc::fillDescriptions(edm::ConfigurationDescriptions&)
(ProducerWithPSetDesc.cc:459)
==31968==    by 0x871ABBB:
edm::ParameterSetDescriptionFiller<edmtest::ProducerWithPSetDesc>::fill(edm::ConfigurationDescriptions&)
const (ParameterSetDescriptionFiller.h:55)
==31968==    by 0x4059BF: operator() (edmWriteConfigs.cpp:90)
==31968==    by 0x4059BF: wrap<(anonymous namespace)::writeCfisForPlugin(const
string&, edm::ParameterSetDescriptionFillerPluginFactory*)::<lambda()> >
(ConvertException.h:20)
==31968==    by 0x4059BF: writeCfisForPlugin (edmWriteConfigs.cpp:91)
==31968==    by 0x4059BF: __call<void, std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, 0ul, 1ul> (functional:943)
==31968==    by 0x4059BF: operator()<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&> (functional:1002)
==31968==    by 0x4059BF:
for_each<__gnu_cxx::__normal_iterator<std::basic_string<char>*,
std::vector<std::basic_string<char> > >, std::_Bind<void
(*(std::_Placeholder<1>,
edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*))(const
std::basic_string<cha
r>&, edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*)> >
(stl_algo.h:3776)
==31968==    by 0x4059BF: for_all<std::vector<std::basic_string<char> >,
std::_Bind<void (*(std::_Placeholder<1>,
edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*))(const
std::basic_string<char>&, edmplugin::PluginFactory<edm::ParameterSetDescription
FillerBase*()>*)> > (Algorithms.h:17)
==31968==    by 0x4059BF: operator() (edmWriteConfigs.cpp:285)
==31968==    by 0x4059BF: wrap<main(int, char**)::<lambda()> >
(ConvertException.h:20)
==31968==    by 0x4059BF: main (edmWriteConfigs.cpp:286)
==31968==  Uninitialised value was created by a stack allocation
==31968==    at 0x8705544:
edmtest::ProducerWithPSetDesc::fillDescriptions(edm::ConfigurationDescriptions&)
(ProducerWithPSetDesc.cc:438)
==31968==
==31968== Invalid read of size 8
==31968==    at 0x40C7674: checkAndGetLabelsAndTypes
(ParameterDescriptionNode.h:213)
==31968==    by 0x40C7674:
edm::ParameterSetDescription::addNode(std::unique_ptr<edm::ParameterDescriptionNode,
std::default_delete<edm::ParameterDescriptionNode> >, bool, bool)
(ParameterSetDescription.cc:92)
==31968==    by 0x8705657: add<int, char [16]> (ParameterSetDescription.h:422)
==31968==    by 0x8705657: addUntracked<int, char [16]>
(ParameterSetDescription.h:95)
==31968==    by 0x8705657:
edmtest::ProducerWithPSetDesc::fillDescriptions(edm::ConfigurationDescriptions&)
(ProducerWithPSetDesc.cc:459)
==31968==    by 0x871ABBB:
edm::ParameterSetDescriptionFiller<edmtest::ProducerWithPSetDesc>::fill(edm::ConfigurationDescriptions&)
const (ParameterSetDescriptionFiller.h:55)
==31968==    by 0x4059BF: operator() (edmWriteConfigs.cpp:90)
==31968==    by 0x4059BF: wrap<(anonymous namespace)::writeCfisForPlugin(const
string&, edm::ParameterSetDescriptionFillerPluginFactory*)::<lambda()> >
(ConvertException.h:20)
==31968==    by 0x4059BF: writeCfisForPlugin (edmWriteConfigs.cpp:91)
==31968==    by 0x4059BF: __call<void, std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, 0ul, 1ul> (functional:943)
==31968==    by 0x4059BF: operator()<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&> (functional:1002)
==31968==    by 0x4059BF:
for_each<__gnu_cxx::__normal_iterator<std::basic_string<char>*,
std::vector<std::basic_string<char> > >, std::_Bind<void
(*(std::_Placeholder<1>,
edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*))(const
std::basic_string<cha
r>&, edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*)> >
(stl_algo.h:3776)
==31968==    by 0x4059BF: for_all<std::vector<std::basic_string<char> >,
std::_Bind<void (*(std::_Placeholder<1>,
edmplugin::PluginFactory<edm::ParameterSetDescriptionFillerBase*()>*))(const
std::basic_string<char>&, edmplugin::PluginFactory<edm::ParameterSetDescription
FillerBase*()>*)> > (Algorithms.h:17)
==31968==    by 0x4059BF: operator() (edmWriteConfigs.cpp:285)
==31968==    by 0x4059BF: wrap<main(int, char**)::<lambda()> >
(ConvertException.h:20)
==31968==    by 0x4059BF: main (edmWriteConfigs.cpp:286)
==31968==  Address 0x1ffdfeb5400000 is not stack'd, malloc'd or (recently)
free'd

Reply via email to