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