Serious design flaw in mangling sheme.

Carlo Wood carlo@alinoe.com
Fri Mar 2 19:48:00 GMT 2001


Hiya,

I am analyzing the mangler of the new ABI and found a serious
design flaw.  The details are explained below.

Firstly, I am not subbed to gcc-patches, so I do not know if
the bug in the mangler that I reported two days ago is already
fixed - and I can't prove this flaw until it is.  Nevertheless
I decided to mail gcc-bugs because I think a discussion might
be needed, and to urge for a quick fix.

To recall, the bug that I reported two days ago is that the
mangler omnits the 'const' qualifier of member function pointers;
thus,

  int (A::*) func(void) const

is mangled as

  int (A::*) func(void)

This seems to be a small problem, and I thought it was, until
I tried using c++filt to find out how the mangled name SHOULD
look like.

What I found is this, it works correctly without const:

mangled name: M<scopetype>F<return_type><p1><p2>...<pN>E
demangled   : <return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>)

And the only way to get a 'const' behind this, using c++filt is
by prepending a 'K':

mangled name: KM<scopetype>F<return_type><p1><p2>...<pN>E
demangled   : <return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>) const

*THIS IS INCORRECT*

If we want to use the same method as was used in the old ABI, then
it SHOULD be:

mangled name: KM<scopetype>F<return_type><p1><p2>...<pN>E
demangled   : <return_type> (<scopetype>::* const)(<p1>, <p2>, ..., <pN>)

and an extention to the mangler/demangler needs to be added to get
the 'const' behind the function, I propose:

mangled name: M<scopetype>KF<return_type><p1><p2>...<pN>E
demangled   : <return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>) const

Allow me to explain why:

a function type exists of two parts: a <prefix> and <postfix>:

With <return_type> (*)(<p1>, <p2>, ..., <pN>) the prefix is:
"<return_type> (*" and the postfix is ")(<p1>, <p2>, ..., <pN>)".

With the old ABI, the mangling worked as follows:

C<type>		-->	<prefix> const <postfix>

While with the new ABI, the (de)mangling does this:

K<type>		-->	<type> const

in other words, it does this:

K<type>		-->	<prefix><postfix> const

That means that with the NEW ABI it is *impossible* to mangle
"<return_type> (<scopetype>::* const)(<p1>, <p2>, ..., <pN>)"

and that IS a problem.  After all, the following four types
are *different*:

<return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>)
<return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>) const
<return_type> (<scopetype>::* const)(<p1>, <p2>, ..., <pN>)
<return_type> (<scopetype>::* const)(<p1>, <p2>, ..., <pN>) const

The current CVS version (unless my last bug report was already fixed)
mangles "<return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>) const"
     as "<return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>)"
and
        "<return_type> (<scopetype>::* const)(<p1>, <p2>, ..., <pN>)"
     as "<return_type> (<scopetype>::*)(<p1>, <p2>, ..., <pN>) const".

Its inability to put a const inbetween the prefix and postfix
will make it impossible for the new ABI mangling sheme to compile
the attached code (20010302.cc) correctly.

When I use g++ version 2.96, it works:

~/c++/libcw/src/gcc.bugs>g++ -v 20010302.cc
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.0)
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/cpp0 -lang-c++ -D__GNUG__=2 -v -D__GNUC__=2 -D__GNUC_MINOR__=96 -D__GNUC_PATCHLEVEL__=0 -D__ELF__ -Dunix -Dlinux -D__ELF__ -D__unix__ -D__linux__ -D__unix -D__linux -Asystem(posix) -Acpu(i386) -Amachine(i386) -Di386 -D__i386 -D__i386__ -D__tune_i386__ 20010302.cc /tmp/cc4oj7k5.ii
GNU CPP version 2.96 20000731 (Red Hat Linux 7.0) (cpplib)
 (i386 Linux/ELF)
ignoring nonexistent directory "/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/g++-3
 /usr/local/include
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/include
 /usr/include
End of search list.
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/cc1plus /tmp/cc4oj7k5.ii -quiet -dumpbase 20010302.cc -version -o /tmp/cc2N8NV2.s
GNU C++ version 2.96 20000731 (Red Hat Linux 7.0) (i386-redhat-linux) compiled by GNU C version 2.96 20000731 (Red Hat Linux 7.0).
 as -V -Qy -o /tmp/ccjFUzua.o /tmp/cc2N8NV2.s
GNU assembler version 2.10.90 (i386-redhat-linux) using BFD version 2.10.0.18
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/collect2 -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crti.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/2.96 -L/usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../../i386-redhat-linux/lib -L/usr/lib/gcc-lib/i386-redhat-linux/2.96/../../.. /tmp/ccjFUzua.o -lstdc++ -lm -lgcc -lc -lgcc /usr/lib/gcc-lib/i386-redhat-linux/2.96/crtend.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crtn.o

~/c++/libcw/src/gcc.bugs>a.out
Calling void overloaded_function(func1_t&)
Calling void overloaded_function(func1_t const&)
Calling void overloaded_function(func2_t&)
Calling void overloaded_function(func2_t const&)

While version 3.0 (as per previously reported bug) can not compile it:

~/c++/libcw/src/gcc.bugs>g++-3.0 -v 20010302.cc
Reading specs from /usr/local/gcc-3.0/lib/gcc-lib/i686-pc-linux-gnu/3.0/specs
Configured with: /usr/src/gcc/gcc-cvs-3.0/configure --prefix=/usr/local/gcc-3.0 --enable-shared --with-gnu-as --with-gnu-ld --enable-languages=c++
gcc version 3.0 20010226 (prerelease)
 /usr/local/gcc-3.0/lib/gcc-lib/i686-pc-linux-gnu/3.0/cc1plus -v -D__GNUC__=3 -D__GNUC_MINOR__=0 -D__GNUC_PATCHLEVEL__=0 -D__ELF__ -Dunix -Dlinux -D__ELF__ -D__unix__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__STDC_HOSTED__=1 -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i686__ -D__tune_pentiumpro__ 20010302.cc -D__GNUG__=3 -D_GNU_SOURCE -D__EXCEPTIONS -D__GXX_ABI_VERSION=100 -quiet -dumpbase 20010302.cc -version -o /tmp/ccUxdEed.s
GNU CPP version 3.0 20010226 (prerelease) (cpplib) (i386 Linux/ELF)
GNU CPP version 3.0 20010226 (prerelease) (cpplib) (i386 Linux/ELF)
GNU C++ version 3.0 20010226 (prerelease) (i686-pc-linux-gnu)
        compiled by GNU C version 3.0 20010226 (prerelease).
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/gcc-3.0/include/g++-v3
 /usr/local/gcc-3.0/include/g++-v3/i686-pc-linux-gnu
 /usr/local/include
 /usr/local/gcc-3.0/lib/gcc-lib/i686-pc-linux-gnu/3.0/include
 /usr/local/gcc-3.0/i686-pc-linux-gnu/include
 /usr/include
End of search list.
20010302.cc: In function `void overloaded_function(int (A::*&)(char) const)':
20010302.cc:22: Internal error #378.
20010302.cc:22: Internal compiler error in pushdecl, at cp/decl.c:4051
Please submit a full bug report, with preprocessed source if appropriate.
See <URL: http://www.gnu.org/software/gcc/bugs.html > for instructions.

-----------------------------------------------------------------------------------------

On a seperate note, version 2.95.x can ALSO not compile it:

~/c++/libcw/src/gcc.bugs>g++-2.95.3 20010302.cc
20010302.cc: In function `void overloaded_function(int (A::* &)(char))':
20010302.cc:17: redefinition of `void overloaded_function(int (A::* &)(char))'
20010302.cc:12: `void overloaded_function(int (A::* &)(char))' previously defined here
20010302.cc: In function `void overloaded_function(int (A::* &)(char) const)':
20010302.cc:27: redefinition of `void overloaded_function(int (A::* &)(char) const)'
20010302.cc:22: `void overloaded_function(int (A::* &)(char) const)' previously defined here

I find this very interesting because that is exactly the problem I see with the
new ABI (so perhaps I am wrong after all).

Apparently, 2.95.x thinks that

void overloaded_function(func1_t&)

and

void overloaded_function(func1_t const&)

are the same function (neglecting the 'const').

I think that is wrong - because that disregards a const qualifier
and would allow me to change a "func1_t const" constant!  Or wouldn't it?
No it doesn't - 2.95.x contradicts itself.  When we remove the apparently
duplicated function declarations we get:

~/c++/libcw/src/gcc.bugs>g++-2.95.3 -DBUG2953 20010302.cc
20010302.cc: In function `int main()':
20010302.cc:45: conversion from `int (A::*)(char)' to `int (A::* &)(char)' discards qualifiers
20010302.cc:12: in passing argument 1 of `overloaded_function(int (A::* &)(char))'
20010302.cc:47: conversion from `int (A::*)(char) const' to `int (A::* &)(char) const' discards qualifiers
20010302.cc:24: in passing argument 1 of `overloaded_function(int (A::* &)(char) const)'

-----------------------------------------------------------------------------------------

Finally, note that the problem with g++-3.0 seems to be purely in the mangling sheme.
Internally the compiler knows the right types (and is even able to produce the right
demangled types in compiler errors!), as is evident from:

~/c++/libcw/src/gcc.bugs>g++-3.0 -DFINALNOTE 20010302.cc
20010302.cc: In function `int main()':
20010302.cc:48: no matching function for call to `overloaded_function(int
   (A::*&)(char) const)'
20010302.cc:12: candidates are: void overloaded_function(int (A::*&)(char))
20010302.cc:18:                 void overloaded_function(int
   (A::*const&)(char))
20010302.cc:49: no matching function for call to `overloaded_function(int
   (A::*const&)(char) const)'
20010302.cc:12: candidates are: void overloaded_function(int (A::*&)(char))
20010302.cc:18:                 void overloaded_function(int
   (A::*const&)(char))
    ^^^^^^^^^^____________ so it DOES know that this type exist.


What is the opinion of the gurus about this?  I think the mangling should be changed
as soon as possible - before people start to release libraries with it ;).

-- 
Carlo Wood <carlo@alinoe.com>



More information about the Gcc-bugs mailing list