Re: [PATCH v3 3/3] Aarch64: Fix segfault when casting dummy calls

Pedro Alves
2018-10-30T16:31:55Z

On 10/30/2018 11:13 AM, Alan Hayward wrote:

>> On 29 Oct 2018, at 18:13, Pedro Alves <palves@redhat.com> wrote:
>>
>> On 10/29/2018 02:56 PM, Alan Hayward wrote:
>>
>>> A-ha! Now I understand why I get two calls into _push_dummy_call.
>>>
>>> So to answer your question, the TYPE_CODE_PTR->TYPE_CODE_INT is the malloc call.
>>>
>>> Then the next call to _push_dummy_call has a return type of 0, as expected.
>>> This doesn’t segfault because it goes into language_pass_by_reference which
>>> routes to default_pass_by_reference. The same as the C shared library version.
>>>
>>>
>>> I’ve updated the test so it does {c,c++}*{debug nodebug}.
>>> I can also update it to do both shared lib and non shared lib too. That should
>>> cover everything.
>> But still, why do you see a difference between shared library and non-shared
>> library?
>
> In all cases the function type is the same.
>
> The difference is because with c++ && shared library, the code ends up in
> gnuv3_pass_by_reference(), which means it’s using the GNU G++ Version 3 ABI,
> whereas with any other options (non shared or c) it ends up in
> default_pass_by_reference().

The function is the same, and should have been compiled using the calling
convention irrespective of whether it is linked into the main program,
or linked into the separate library. Right?

So, either I'm missing something, or in one of the cases (shared
vs non-shared), we're calling the function incorrectly (along
with anything else that depends on call ABI), no?

What am I missing?

What does:

(gdb) show cp-abi
The currently selected C++ ABI is "auto" (currently "gnu-v3").

show for you, in the shared and non-shared cases?

/me pokes a bit.

OK, I see what it is.

You've compiled the _main_ .cc without debug info as well:

g++ -c condbreak-solib-main.cc -o condbreak-solib-main.o -fno-inline
g++ -c condbreak-solib-lib.cc -o condbreak-solib-lib.o -fno-inline
g++ condbreak-solib-main.o condbreak-solib-lib.o

And if you do that, the program ends up with no debug info at
all, and so GDB has no clue that this is a C++ program:

(gdb) start
Temporary breakpoint 1 at 0x4004c1
Starting program: /tmp/a.out

Temporary breakpoint 1, 0x00000000004004c1 in main ()
(gdb) show language
The current source language is "auto; currently c".
(gdb)

If you compile (only) the main.cc with debug info, like this:

- g++ -c condbreak-solib-main.cc -o condbreak-solib-main.o -fno-inline
+ g++ -c condbreak-solib-main.cc -o condbreak-solib-main.o -fno-inline -g

then GDB will know that the program is a C++ program. And you'd
still be calling a cmp3 function that has no debug info,
and should thus trigger the bug.

So when we call cmp3 with GDB's language set to C, we land
in default_pass_by_reference:

(gdb) show language
The current source language is "auto; currently c".
(gdb) p (int) cmp3(word)

Thread 1 "gdb" hit Breakpoint 3, default_pass_by_reference (type=0x1b5a230) at src/gdb/language.c:669
669 return 0;
(top-gdb) c
Continuing.

When the language is set to C++, we end up in gnuv3_pass_by_reference:

(gdb) set language c++
(gdb) p (int) cmp3(word)

Thread 1 "gdb" hit Breakpoint 4, gnuv3_pass_by_reference (type=0x1b33290) at src/gdb/gnu-v3-abi.c:1255
1255 type = check_typedef (type);
(top-gdb)

And this is because language_pass_by_reference uses the
current language, instead of the symbol's language (arguably a bug):

(top-gdb) bt
#0 0x000000000065be91 in gnuv3_pass_by_reference(type*) (type=0x1b33290)
at src/gdb/gnu-v3-abi.c:1255
#1 0x0000000000543e2a in cp_pass_by_reference(type*) (type=0x1b33290) at src/gdb/cp-abi.c:229
#2 0x00000000006cc09b in language_pass_by_reference(type*) (type=0x1b33290)
at src/gdb/language.c:660
#3 0x000000000045a27a in default_return_in_first_hidden_param_p(gdbarch*, type*) (gdbarch=0x1b316b0, type=0x1b33290)
at src/gdb/arch-utils.c:861
#4 0x0000000000640a86 in gdbarch_return_in_first_hidden_param_p(gdbarch*, type*) (gdbarch=0x1b316b0, type=0x1b33290)
at src/gdb/gdbarch.c:2739
#5 0x00000000006a1011 in call_function_by_hand_dummy(value*, type*, int, value**, void (*)(void*, int), void*) (function=0x1b44730, default_return_type=0x1b33290, nargs=1, args=0x7fffffffc128, dummy_dtor=0x0, dummy_dtor_data=0x0)
at src/gdb/infcall.c:881

So that's the real difference. Shared vs non-shared is just
a kind of a red herring. If you don't have debug info for
libstdc++, for example, then probably GDB won't know that the
no-debug-info program is a C++ program either.

So please adjust your test to eliminate use of the shared
library, and build just the cmp3 source file without
debug info.

> Looking at the doc for GNU G++ Version 3 ABI:
> https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
> The library needs to be linked against libstdc++.so to use it.
>
> A quick ldd shows only the c++ .so is linked against it.

That wouldn't make much sense. The whole program is using the
same compiler/call/mangling ABI, certainly, which is what
matters here.

Thanks,
Pedro Alves