Bug 70517 - c++filt crashes when demangling a symbol
Summary: c++filt crashes when demangling a symbol
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: demangler (show other bugs)
Version: 5.3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on: 78252
Blocks:
  Show dependency treegraph
 
Reported: 2016-04-02 15:44 UTC by blastrock
Modified: 2019-12-14 19:04 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
preprocessed file by clang 3.8 (295.38 KB, application/x-bzip)
2016-04-02 15:45 UTC, blastrock
Details
preprocessed file by gcc 5.3.1 (308.30 KB, application/x-bzip)
2016-04-02 15:47 UTC, blastrock
Details
Very small test case (172 bytes, text/plain)
2016-05-05 10:51 UTC, blastrock
Details

Note You need to log in before you can comment on or make changes to this bug.
Description blastrock 2016-04-02 15:44:19 UTC
The following command always crashes:

    c++filt _ZSt4moveIRZN11tconcurrent6futureIvE4thenIZ5awaitIS2_EDaOT_EUlRKS6_E_EENS1_INSt5decayIDTclfp_defpTEEE4typeEEES7_EUlvE_EONSt16remove_referenceIS6_E4typeES7_

I have been told to report the bug here.

This may be a duplicate of #67375.

I am attaching the preprocessed file (by clang) that generates the symbol which triggers the bug. Compile it with:

    clang++ test_coroutine2.ii -c  -std=c++14

with clang 3.8 (I haven't tested other versions). You can then trigger the bug with:

    objdump -C -t test_coroutine2.o

The bug does not appear when the file is compiled with GCC. I am attaching the .ii generated by GCC too in case you need it. I am not sure, but shouldn't clang and gcc generate the same symbol names? Does this hide another bug in one of these compilers?
Comment 1 blastrock 2016-04-02 15:45:54 UTC
Created attachment 38165 [details]
preprocessed file by clang 3.8
Comment 2 blastrock 2016-04-02 15:47:30 UTC
Created attachment 38166 [details]
preprocessed file by gcc 5.3.1
Comment 3 blastrock 2016-05-05 10:51:39 UTC
Created attachment 38418 [details]
Very small test case

I investigated this bug a little more and managed to produce a very small test case.

Compile this file with g++ 5.3.1 and clang 3.8 and you will get these two symbols:

_Z4moveIRZ5awaitIRiEDaOT_EUlRKS3_E_ES4_S4_ from clang
_Z4moveIRZ5awaitIRiEDaOT_EUlRKS2_E_ES3_S3_ from gcc

When trying c++filt on the one got from gcc, it will just fail demangling it and print it raw. But when we do it with the one produced by clang, we get a crash. The only difference I see there is the substitutions which are shifted by one on the clang version (I have no idea which compiler is right though).

I enabled the debug stuff from the demangle binary in libiberty and got this (I added the addresses of the nodes for debugging):

0x7fffffffd620: typed name
  0x7fffffffd5d8: template
    0x7fffffffd410: name 'move'
    0x7fffffffd5c0: template argument list
      0x7fffffffd5a8: reference
        0x7fffffffd590: local name
          0x7fffffffd518: typed name
            0x7fffffffd488: template
              0x7fffffffd428: name 'await'
              0x7fffffffd470: template argument list
                0x7fffffffd458: reference
                  0x7fffffffd440: builtin type int
            0x7fffffffd500: function type
              0x7fffffffd4a0: name 'auto'
              0x7fffffffd4e8: argument list
                0x7fffffffd4d0: rvalue reference
                  0x7fffffffd4b8: template parameter 0
          0x7fffffffd578: lambda 0
            0x7fffffffd560: argument list
              0x7fffffffd548: reference
                0x7fffffffd530: const
                  0x7fffffffd4d0: rvalue reference
                    0x7fffffffd4b8: template parameter 0
  0x7fffffffd608: function type
    0x7fffffffd530: const
      0x7fffffffd4d0: rvalue reference
        0x7fffffffd4b8: template parameter 0
    0x7fffffffd5f0: argument list
      0x7fffffffd530: const
        0x7fffffffd4d0: rvalue reference
          0x7fffffffd4b8: template parameter 0

What I understand is that when libiberty goes down the first branch, the "template parameter 0" references this same branch and so we get infinite recursion. I guess we can at least prevent the crash if we keep in the state a variable saying which template parameter we are referencing so that we don't go down the same path infinitely.

My (de)mangling skills are still very low and I don't think I can solve this one alone. Any help is appreciated.
Comment 4 Mark Wielaard 2016-12-04 17:53:09 UTC
This related to Bug 78252 - C++ demangler crashes with infinite recursion with lambda (auto)

With the patch proposed for that bug there is no crash anymore and the symbols demangle.

_ZSt4moveIRZN11tconcurrent6futureIvE4thenIZ5awaitIS2_EDaOT_EUlRKS6_E_EENS1_INSt5decayIDTclfp_defpTEEE4typeEEES7_EUlvE_EONSt16remove_referenceIS6_E4typeES7_

demangles to:

std::remove_reference<tconcurrent::future<std::decay<decltype ({parm#1}(*this))>::type> tconcurrent::future<void>::then<auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}>(auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}&& const)::{lambda()#1}&>::type&& std::move<tconcurrent::future<std::decay<decltype ({parm#1}(*this))>::type> tconcurrent::future<void>::then<auto await<tconcurrent::future<void> >(tconcurrent::future<std::decay<decltype ({parm#1}(*this))>::type> tconcurrent::future<void>::then<auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}>(auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}&& const)::{lambda()#1}&)::{lambda(auto&& const&)#1}>(tconcurrent::future<std::decay<decltype ({parm#1}(*this))>::type> tconcurrent::future<void>::then<auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}>(auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}&& const)::{lambda()#1}& const)::{lambda()#1}&>(tconcurrent::future<std::decay<decltype ({parm#1}(*this))>::type> tconcurrent::future<void>::then<auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}>(auto await<tconcurrent::future<void> >(tconcurrent::future<void>&&)::{lambda(auto&& const&)#1}&& const)::{lambda()#1}& const)

_Z4moveIRZ5awaitIRiEDaOT_EUlRKS3_E_ES4_S4_

demangles to:

auto await<int&>(int&)::{lambda(auto&& const&)#1}& const move<auto await<int&>(auto await<int&>(int&)::{lambda(auto&& const&)#1}&)::{lambda(auto&& const&)#1}&>(auto await<int&>(int&)::{lambda(auto&& const&)#1}& const)

_Z4moveIRZ5awaitIRiEDaOT_EUlRKS2_E_ES3_S3_

demangles to:

auto await<int&>(int&)::{lambda(auto const&)#1}& move<auto await<int&>(auto await<int&>(int&)::{lambda(auto const&)#1}&)::{lambda(auto const&)#1}&>(auto await<int&>(int&)::{lambda(auto const&)#1}&)
Comment 5 Christian Biesinger 2019-12-04 22:48:37 UTC
Using binutils from a month ago or so, this does not crash but also does not demangle...
Comment 6 Mark Wielaard 2019-12-14 19:04:27 UTC
(In reply to Christian Biesinger from comment #5)
> Using binutils from a month ago or so, this does not crash but also does not
> demangle...

Could you be slightly more specific?
Which symbol produced by which compiler doesn't (correctly) demangle?
And, if known, is it a valid mangled symbol?