public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Recursive SIGSEGV question
@ 2019-03-19 22:05 Jonny Grant
  2019-03-20  4:02 ` Florian Weimer
  0 siblings, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-19 22:05 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 3816 bytes --]

Hello

Wanted to ask opinion about the following.

Compiling with g++ 8.2.0 and saw the following. The program was in a 
recursive function call (bug). My test case is attached, although could 
not reproduce exactly same backtrace.

I had a look at https://github.com/lattera/glibc/blob/master/malloc/malloc.c

Is there an issue in _int_malloc? or was it most likely just out of 
memory? Do out of memory issues normally show up as SIGSEGV? I had 
expected some sort of "out of memory"

This is the log from own software (not attached) :-

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
     bytes=bytes@entry=45) at malloc.c:3557
3557	malloc.c: No such file or directory.
[Current thread is 1 (Thread 0x7fa997860700 (LWP 20571))]
(gdb) bt
#0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
     bytes=bytes@entry=45) at malloc.c:3557
#1  0x00007faa0e37e2ed in __GI___libc_malloc (bytes=45) at malloc.c:3065
#2  0x00007faa0eba21a8 in operator new(unsigned long) ()
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6



I tried to create a test case, but got slightly different messages, they 
actually vary. Is there a gdb bug if the same program has different 
backtraces?
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git

Core was generated by `./loop'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> 
 >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> 
 >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00005592fbb669d7 in func (f="a", g=0) at loop.cpp:7
#2  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
#3  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7



The backtrace seems to vary, is this possibly a GDB bug?


Core was generated by `./loop'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00005615cc3549ae in func (
     f=<error reading variable: Cannot access memory at address 
0x7ffe87dfefd8>,
     g=<error reading variable: Cannot access memory at address 
0x7ffe87dfefd4>) at loop.cpp:6
6	{
(gdb) bt
#0  0x00005615cc3549ae in func (
     f=<error reading variable: Cannot access memory at address 
0x7ffe87dfefd8>,
     g=<error reading variable: Cannot access memory at address 
0x7ffe87dfefd4>) at loop.cpp:6
#1  0x00005615cc354a03 in func (f="a", g=0) at loop.cpp:7
#2  0x00005615cc354a03 in func (f="a", g=0) at loop.cpp:7
#3  0x00005615cc354a03 in func (f="a", g=0) at loop.cpp:7
#4  0x00005615cc354a03 in func (f="a", g=0) at loop.cpp:7



Core was generated by `./loop'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000559924c939ae in func (
     f=<error reading variable: Cannot access memory at address 
0x7ffe76f8bfe8>,
     g=<error reading variable: Cannot access memory at address 
0x7ffe76f8bfe4>) at loop.cpp:6
6	{
(gdb) bt
#0  0x0000559924c939ae in func (
     f=<error reading variable: Cannot access memory at address 
0x7ffe76f8bfe8>,
     g=<error reading variable: Cannot access memory at address 
0x7ffe76f8bfe4>) at loop.cpp:6
#1  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#2  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#3  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#4  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#5  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#6  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7
#7  0x0000559924c93a03 in func (f="a", g=0) at loop.cpp:7

Jonny

[-- Attachment #2: loop.cpp --]
[-- Type: text/x-c++src, Size: 189 bytes --]

// g++-8 -g -ggdb -O0 -Wall -Wextra -o loop loop.cpp

#include <string>

static void func(std::string f, int g)
{
    func(f.c_str(), g);
}

int main()
{
    func("a", 0);

    return 0;
}

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-19 22:05 Recursive SIGSEGV question Jonny Grant
@ 2019-03-20  4:02 ` Florian Weimer
  2019-03-20  8:11   ` Jonny Grant
  2019-03-25 13:23   ` Jonny Grant
  0 siblings, 2 replies; 31+ messages in thread
From: Florian Weimer @ 2019-03-20  4:02 UTC (permalink / raw)
  To: Jonny Grant; +Cc: gcc-help

* Jonny Grant:

> Wanted to ask opinion about the following.
>
> Compiling with g++ 8.2.0 and saw the following. The program was in a 
> recursive function call (bug). My test case is attached, although could 
> not reproduce exactly same backtrace.
>
> I had a look at https://github.com/lattera/glibc/blob/master/malloc/malloc.c
>
> Is there an issue in _int_malloc? or was it most likely just out of 
> memory? Do out of memory issues normally show up as SIGSEGV? I had 
> expected some sort of "out of memory"

This isn't really a GCC question, _int_malloc looks like something
that would be part of glibc.

> This is the log from own software (not attached) :-
>
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>      bytes=bytes@entry=45) at malloc.c:3557
> 3557	malloc.c: No such file or directory.
> [Current thread is 1 (Thread 0x7fa997860700 (LWP 20571))]
> (gdb) bt
> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>      bytes=bytes@entry=45) at malloc.c:3557
> #1  0x00007faa0e37e2ed in __GI___libc_malloc (bytes=45) at malloc.c:3065
> #2  0x00007faa0eba21a8 in operator new(unsigned long) ()
>     from /usr/lib/x86_64-linux-gnu/libstdc++.so.6

How does hit go on after that?  Where does the fault actually happen?

See:

(gdb) print $_siginfo._sifields._sigfault

Usually that's heap corruption.  For example, the application might
have overrun a buffer overwritten some internal malloc data
structures.

If you can reproduce it at will, valgrind is a great diagnostic tool
for such issues.

> I tried to create a test case, but got slightly different messages, they 
> actually vary. Is there a gdb bug if the same program has different 
> backtraces?
> GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
>
> Core was generated by `./loop'.
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> 
>  >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>     from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
> (gdb) bt
> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> 
>  >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>     from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
> #1  0x00005592fbb669d7 in func (f="a", g=0) at loop.cpp:7
> #2  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
> #3  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7

This looks like a very different thing.  Due to the deep recursion,
the code faults when accessing the guard page below the stack.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-20  4:02 ` Florian Weimer
@ 2019-03-20  8:11   ` Jonny Grant
  2019-03-25 13:23   ` Jonny Grant
  1 sibling, 0 replies; 31+ messages in thread
From: Jonny Grant @ 2019-03-20  8:11 UTC (permalink / raw)
  To: Florian Weimer; +Cc: gcc-help



On 19/03/2019 22:05, Florian Weimer wrote:
> * Jonny Grant:
> 
>> Wanted to ask opinion about the following.
>>
>> Compiling with g++ 8.2.0 and saw the following. The program was in a
>> recursive function call (bug). My test case is attached, although could
>> not reproduce exactly same backtrace.
>>
>> I had a look at https://github.com/lattera/glibc/blob/master/malloc/malloc.c
>>
>> Is there an issue in _int_malloc? or was it most likely just out of
>> memory? Do out of memory issues normally show up as SIGSEGV? I had
>> expected some sort of "out of memory"
> 
> This isn't really a GCC question, _int_malloc looks like something
> that would be part of glibc.
> 
>> This is the log from own software (not attached) :-
>>
>> Program terminated with signal SIGSEGV, Segmentation fault.
>> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>>       bytes=bytes@entry=45) at malloc.c:3557
>> 3557	malloc.c: No such file or directory.
>> [Current thread is 1 (Thread 0x7fa997860700 (LWP 20571))]
>> (gdb) bt
>> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>>       bytes=bytes@entry=45) at malloc.c:3557
>> #1  0x00007faa0e37e2ed in __GI___libc_malloc (bytes=45) at malloc.c:3065
>> #2  0x00007faa0eba21a8 in operator new(unsigned long) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
> 
> How does hit go on after that?  Where does the fault actually happen?
> 
> See:
> 
> (gdb) print $_siginfo._sifields._sigfault
> 
> Usually that's heap corruption.  For example, the application might
> have overrun a buffer overwritten some internal malloc data
> structures.
> 
> If you can reproduce it at will, valgrind is a great diagnostic tool
> for such issues.
> 
>> I tried to create a test case, but got slightly different messages, they
>> actually vary. Is there a gdb bug if the same program has different
>> backtraces?
>> GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
>>
>> Core was generated by `./loop'.
>> Program terminated with signal SIGSEGV, Segmentation fault.
>> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char>
>>   >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> (gdb) bt
>> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char>
>>   >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> #1  0x00005592fbb669d7 in func (f="a", g=0) at loop.cpp:7
>> #2  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
>> #3  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
> 
> This looks like a very different thing.  Due to the deep recursion,
> the code faults when accessing the guard page below the stack.
> 

Thanks for your reply Florian.

I guess I was just expecting GCC to generate code that avoided 
overrunning the stack (or heap) and exiting gracefully. I don't know if 
that is gcc, glibc, or kernel. Or if it's just down the program!

I'll look into this a bit more.

Jonny

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-20  4:02 ` Florian Weimer
  2019-03-20  8:11   ` Jonny Grant
@ 2019-03-25 13:23   ` Jonny Grant
  2019-03-25 13:27     ` Jonathan Wakely
                       ` (2 more replies)
  1 sibling, 3 replies; 31+ messages in thread
From: Jonny Grant @ 2019-03-25 13:23 UTC (permalink / raw)
  To: Florian Weimer; +Cc: gcc-help

Hi Florian!

On 19/03/2019 22:05, Florian Weimer wrote:
> * Jonny Grant:
> 
>> Wanted to ask opinion about the following.
>>
>> Compiling with g++ 8.2.0 and saw the following. The program was in a
>> recursive function call (bug). My test case is attached, although could
>> not reproduce exactly same backtrace.
>>
>> I had a look at https://github.com/lattera/glibc/blob/master/malloc/malloc.c
>>
>> Is there an issue in _int_malloc? or was it most likely just out of
>> memory? Do out of memory issues normally show up as SIGSEGV? I had
>> expected some sort of "out of memory"
> 
> This isn't really a GCC question, _int_malloc looks like something
> that would be part of glibc.
> 
>> This is the log from own software (not attached) :-
>>
>> Program terminated with signal SIGSEGV, Segmentation fault.
>> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>>       bytes=bytes@entry=45) at malloc.c:3557
>> 3557	malloc.c: No such file or directory.
>> [Current thread is 1 (Thread 0x7fa997860700 (LWP 20571))]
>> (gdb) bt
>> #0  0x00007faa0e37b30e in _int_malloc (av=av@entry=0x7fa980000020,
>>       bytes=bytes@entry=45) at malloc.c:3557
>> #1  0x00007faa0e37e2ed in __GI___libc_malloc (bytes=45) at malloc.c:3065
>> #2  0x00007faa0eba21a8 in operator new(unsigned long) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
> 
> How does hit go on after that?  Where does the fault actually happen?
> 
> See:
> 
> (gdb) print $_siginfo._sifields._sigfault
> 
> Usually that's heap corruption.  For example, the application might
> have overrun a buffer overwritten some internal malloc data
> structures.
> 
> If you can reproduce it at will, valgrind is a great diagnostic tool
> for such issues.

I built & ran with the Sanitizer, it seems it's also stack overflow 
within the operator new()

I had thoughts GCC would generate code that monitored the stack size and 
aborted with a clear message when the stack size was exceeded. Looked 
online, and it doesn't seem to be the case.


AddressSanitizer:DEADLYSIGNAL
=================================================================
==16598==ERROR: AddressSanitizer: stack-overflow on address 
0x7ffe4b0e7fc0 (pc 0x7f85c609293a bp 0x7ffe4b0e88d0 sp 0x7ffe4b0e7fb0 T0)
     #0 0x7f85c6092939  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x28939)
     #1 0x7f85c6091217  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x27217)
     #2 0x7f85c615974e in operator new(unsigned long) 
(/usr/lib/x86_64-linux-gnu/libasan.so.5+0xef74e)
     #3 0x563e23701a4a in void std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >::_M_construct<char 
const*>(char const*, char const*, std::forward_iterator_tag) 
/usr/include/c++/8/bits/basic_string.tcc:219
     #4 0x563e23947131 in void std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char 
const*>(char const*, char const*, std::__false_type) 
/usr/include/c++/8/bits/basic_string.h:236
     #5 0x563e23947131 in void std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >::_M_construct<char 
const*>(char const*, char const*) /usr/include/c++/8/bits/basic_string.h:255
     #6 0x563e23947131 in std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >::basic_string(char 
const*, std::allocator<char> const&) 
/usr/include/c++/8/bits/basic_string.h:516




> 
>> I tried to create a test case, but got slightly different messages, they
>> actually vary. Is there a gdb bug if the same program has different
>> backtraces?
>> GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
>>
>> Core was generated by `./loop'.
>> Program terminated with signal SIGSEGV, Segmentation fault.
>> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char>
>>   >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> (gdb) bt
>> #0  0x00007fc10dee51e7 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char>
>>   >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) ()
>>      from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> #1  0x00005592fbb669d7 in func (f="a", g=0) at loop.cpp:7
>> #2  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
>> #3  0x00005592fbb669e8 in func (f="a", g=0) at loop.cpp:7
> 
> This looks like a very different thing.  Due to the deep recursion,
> the code faults when accessing the guard page below the stack.

Sanitizer says the same. There isn't really anything that can be done 
when stack is exceeded! There isn't a StackOverflowException




$ ./loop
AddressSanitizer:DEADLYSIGNAL
=================================================================
==13496==ERROR: AddressSanitizer: stack-overflow on address 
0x7ffd8f0f1f18 (pc 0x7f705dcf59b6 bp 0x7ffd8f0f27a0 sp 0x7ffd8f0f1f20 T0)
     #0 0x7f705dcf59b5  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x989b5)
     #1 0x7f705d9fb536 in std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >::basic_string(char 
const*, std::allocator<char> const&) 
(/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x127536)
     #2 0x562e51e7ceed in func /home/jonny/code/loop.cpp:7
     #3 0x562e51e7cf01 in func /home/jonny/code/loop.cpp:7


Cheers, Jonny

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 13:23   ` Jonny Grant
@ 2019-03-25 13:27     ` Jonathan Wakely
  2019-03-25 13:56     ` Florian Weimer
  2019-03-25 14:01     ` Xi Ruoyao
  2 siblings, 0 replies; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-25 13:27 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Florian Weimer, gcc-help

On Mon, 25 Mar 2019 at 13:06, Jonny Grant wrote:
> I had thoughts GCC would generate code that monitored the stack size and
> aborted with a clear message when the stack size was exceeded. Looked
> online, and it doesn't seem to be the case.

That would add overhead that most people don't want.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 13:23   ` Jonny Grant
  2019-03-25 13:27     ` Jonathan Wakely
@ 2019-03-25 13:56     ` Florian Weimer
  2019-03-25 14:01     ` Xi Ruoyao
  2 siblings, 0 replies; 31+ messages in thread
From: Florian Weimer @ 2019-03-25 13:56 UTC (permalink / raw)
  To: Jonny Grant; +Cc: gcc-help

* Jonny Grant:

> I had thoughts GCC would generate code that monitored the stack size and 
> aborted with a clear message when the stack size was exceeded. Looked 
> online, and it doesn't seem to be the case.

A lot of programs switch stack, and there's no universal convention
about expressing the stack boundary.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 13:23   ` Jonny Grant
  2019-03-25 13:27     ` Jonathan Wakely
  2019-03-25 13:56     ` Florian Weimer
@ 2019-03-25 14:01     ` Xi Ruoyao
  2019-03-25 15:47       ` Florian Weimer
                         ` (2 more replies)
  2 siblings, 3 replies; 31+ messages in thread
From: Xi Ruoyao @ 2019-03-25 14:01 UTC (permalink / raw)
  To: Jonny Grant, Florian Weimer; +Cc: gcc-help

On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> 
> I built & ran with the Sanitizer, it seems it's also stack overflow 
> within the operator new()
> 
> I had thoughts GCC would generate code that monitored the stack size and 
> aborted with a clear message when the stack size was exceeded. Looked 
> online, and it doesn't seem to be the case.

Impossible.  We can't distinguish "stack overflow" with other segmentation
faults.  For example

int foo() {volatile char p[10000000]; p[0] = 1;}

and

int foo() {
 volatile char a;
 (&a)[-9999999] = 1;
}

may be compiled to exactly same machine code.  Now which one is a stack
overflow?

> AddressSanitizer:DEADLYSIGNAL
> =================================================================
> ==16598==ERROR: AddressSanitizer: stack-overflow on address 
> 0x7ffe4b0e7fc0 (pc 0x7f85c609293a bp 0x7ffe4b0e88d0 sp 0x7ffe4b0e7fb0 T0)
>      #0 0x7f85c6092939  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x28939)
>      #1 0x7f85c6091217  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x27217)
>      #2 0x7f85c615974e in operator new(unsigned long) 
> (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xef74e)
>      #3 0x563e23701a4a in void std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> >::_M_construct<char 
> const*>(char const*, char const*, std::forward_iterator_tag) 
> /usr/include/c++/8/bits/basic_string.tcc:219
>      #4 0x563e23947131 in void std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char 
> const*>(char const*, char const*, std::__false_type) 
> /usr/include/c++/8/bits/basic_string.h:236
>      #5 0x563e23947131 in void std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> >::_M_construct<char 
> const*>(char const*, char const*) /usr/include/c++/8/bits/basic_string.h:255
>      #6 0x563e23947131 in std::__cxx11::basic_string<char, 
> std::char_traits<char>, std::allocator<char> >::basic_string(char 
> const*, std::allocator<char> const&) 
> /usr/include/c++/8/bits/basic_string.h:516

If you consume too much stack, stack overflow may happens in any functions.  For
example:

int x()
{
	int a[100];
	malloc(1);
	return x();
}

int main()
{
	return x();
}

> Sanitizer says the same. There isn't really anything that can be done 
> when stack is exceeded! There isn't a StackOverflowException

This is gcc-help, not java-help or python-help.  But actually you can do
something here:

0.  Do not consume so much stack.  Throw large things into the heap.
1.  Set a signal handler for SIGSEGV.  And you will need sigaltstack so the
signal handler can run in an alternative stack.
2.  Use ulimit -s or setrlimit to increase stack limit, if you really need more
stack.
3.  Use -fsplit-stack to automatically "increase" stack size when it overflows,
if you really need this feature.

If you don't like all of these suggestions, go to use Java.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 14:01     ` Xi Ruoyao
@ 2019-03-25 15:47       ` Florian Weimer
  2019-03-25 16:10         ` Andrew Haley
  2019-03-25 20:28         ` Segher Boessenkool
  2019-03-25 18:56       ` Segher Boessenkool
  2019-03-25 22:05       ` Jonny Grant
  2 siblings, 2 replies; 31+ messages in thread
From: Florian Weimer @ 2019-03-25 15:47 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonny Grant, gcc-help

* Xi Ruoyao:

> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>> 
>> I built & ran with the Sanitizer, it seems it's also stack overflow 
>> within the operator new()
>> 
>> I had thoughts GCC would generate code that monitored the stack size and 
>> aborted with a clear message when the stack size was exceeded. Looked 
>> online, and it doesn't seem to be the case.
>
> Impossible.  We can't distinguish "stack overflow" with other segmentation
> faults.

I think “impossible” is too strong.

It would be possible to annotate implicit probes and explicit probes
generated by -fstack-clash-protection in DWARF, and use that
information to generate a more precise error message.

Or we could set a bit on the guard page that instructs the kernel to
report an additional fault flag somewhere in siginfo_t.  In fact, with
protection keys, we could do this today, without any kernel changes
whatsoever (but protection flags are not widely supported,
unfortunately).

The second approach will have false positives, but as buffer overflows
tend to proceed towards higher addresses and stacks grow downward,
only really bogus pointers would be misreported (and once you have
those, all bets are off anyway).

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 15:47       ` Florian Weimer
@ 2019-03-25 16:10         ` Andrew Haley
  2019-03-25 16:13           ` Jonny Grant
  2019-03-25 18:51           ` Florian Weimer
  2019-03-25 20:28         ` Segher Boessenkool
  1 sibling, 2 replies; 31+ messages in thread
From: Andrew Haley @ 2019-03-25 16:10 UTC (permalink / raw)
  To: Florian Weimer, Xi Ruoyao; +Cc: Jonny Grant, gcc-help

On 3/25/19 2:01 PM, Florian Weimer wrote:
> * Xi Ruoyao:
> 
>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>>
>>> I built & ran with the Sanitizer, it seems it's also stack overflow 
>>> within the operator new()
>>>
>>> I had thoughts GCC would generate code that monitored the stack size and 
>>> aborted with a clear message when the stack size was exceeded. Looked 
>>> online, and it doesn't seem to be the case.
>>
>> Impossible.  We can't distinguish "stack overflow" with other segmentation
>> faults.
> 
> I think “impossible” is too strong.

It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
The problem is that recovering well enough to throw an exception requires
some quite hairy non-portable code.

-- 
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 16:10         ` Andrew Haley
@ 2019-03-25 16:13           ` Jonny Grant
  2019-03-25 16:23             ` Jonathan Wakely
  2019-03-25 18:51           ` Florian Weimer
  1 sibling, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-25 16:13 UTC (permalink / raw)
  To: Andrew Haley, Florian Weimer, Xi Ruoyao; +Cc: gcc-help



On 25/03/2019 15:47, Andrew Haley wrote:
> On 3/25/19 2:01 PM, Florian Weimer wrote:
>> * Xi Ruoyao:
>>
>>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>>>
>>>> I built & ran with the Sanitizer, it seems it's also stack overflow
>>>> within the operator new()
>>>>
>>>> I had thoughts GCC would generate code that monitored the stack size and
>>>> aborted with a clear message when the stack size was exceeded. Looked
>>>> online, and it doesn't seem to be the case.
>>>
>>> Impossible.  We can't distinguish "stack overflow" with other segmentation
>>> faults.
>>
>> I think “impossible” is too strong.
> 
> It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
> The problem is that recovering well enough to throw an exception requires
> some quite hairy non-portable code.

Sounds good!

I had expected that GCC (eg on x86) generated code just kept track of 
the base and max SP register, and so would easily be able to call 
abort() and printf "Stack %zu limit reached - Abort\n".

I can see it would be an overhead, and difficult to recover well enough 
to abort() after a message.
Jonny


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 16:13           ` Jonny Grant
@ 2019-03-25 16:23             ` Jonathan Wakely
  0 siblings, 0 replies; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-25 16:23 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Andrew Haley, Florian Weimer, Xi Ruoyao, gcc-help

On Mon, 25 Mar 2019 at 16:10, Jonny Grant <jg@jguk.org> wrote:
>
>
>
> On 25/03/2019 15:47, Andrew Haley wrote:
> > On 3/25/19 2:01 PM, Florian Weimer wrote:
> >> * Xi Ruoyao:
> >>
> >>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> >>>>
> >>>> I built & ran with the Sanitizer, it seems it's also stack overflow
> >>>> within the operator new()
> >>>>
> >>>> I had thoughts GCC would generate code that monitored the stack size and
> >>>> aborted with a clear message when the stack size was exceeded. Looked
> >>>> online, and it doesn't seem to be the case.
> >>>
> >>> Impossible.  We can't distinguish "stack overflow" with other segmentation
> >>> faults.
> >>
> >> I think “impossible” is too strong.
> >
> > It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
> > The problem is that recovering well enough to throw an exception requires
> > some quite hairy non-portable code.
>
> Sounds good!
>
> I had expected that GCC (eg on x86) generated code just kept track of
> the base and max SP register, and so would easily be able to call
> abort() and printf "Stack %zu limit reached - Abort\n".

To do that it would also need to keep track of the per-thread stack limit.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 16:10         ` Andrew Haley
  2019-03-25 16:13           ` Jonny Grant
@ 2019-03-25 18:51           ` Florian Weimer
  2019-03-25 20:39             ` Jonny Grant
  2019-03-27 21:34             ` Jonny Grant
  1 sibling, 2 replies; 31+ messages in thread
From: Florian Weimer @ 2019-03-25 18:51 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Xi Ruoyao, Jonny Grant, gcc-help

* Andrew Haley:

> On 3/25/19 2:01 PM, Florian Weimer wrote:
>> * Xi Ruoyao:
>> 
>>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>>>
>>>> I built & ran with the Sanitizer, it seems it's also stack overflow 
>>>> within the operator new()
>>>>
>>>> I had thoughts GCC would generate code that monitored the stack size and 
>>>> aborted with a clear message when the stack size was exceeded. Looked 
>>>> online, and it doesn't seem to be the case.
>>>
>>> Impossible.  We can't distinguish "stack overflow" with other segmentation
>>> faults.
>> 
>> I think “impossible” is too strong.
>
> It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
> The problem is that recovering well enough to throw an exception requires
> some quite hairy non-portable code.

Of course it's going to be non-portable.  Ideally, this would be
handled out-of-process: the shell registers itself with the system
coredump handler, and the handler analyzes the crash and provides
information back to the shell for display.

It's quite difficult to get there, but it's certainly not impossible.
We really should have lightweight tracebacks for aborts and the like
in C/C++ code.  Right now, every moderately large piece of software
tries to write their robust in-process crash handler, with varying
results.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 14:01     ` Xi Ruoyao
  2019-03-25 15:47       ` Florian Weimer
@ 2019-03-25 18:56       ` Segher Boessenkool
  2019-03-25 22:05       ` Jonny Grant
  2 siblings, 0 replies; 31+ messages in thread
From: Segher Boessenkool @ 2019-03-25 18:56 UTC (permalink / raw)
  To: gcc-help; +Cc: Jonny Grant, Florian Weimer

On Mon, Mar 25, 2019 at 09:55:56PM +0800, Xi Ruoyao wrote:
> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> > I built & ran with the Sanitizer, it seems it's also stack overflow 
> > within the operator new()
> > 
> > I had thoughts GCC would generate code that monitored the stack size and 
> > aborted with a clear message when the stack size was exceeded. Looked 
> > online, and it doesn't seem to be the case.
> 
> Impossible.  We can't distinguish "stack overflow" with other segmentation
> faults.  For example
> 
> int foo() {volatile char p[10000000]; p[0] = 1;}
> 
> and
> 
> int foo() {
>  volatile char a;
>  (&a)[-9999999] = 1;
> }
> 
> may be compiled to exactly same machine code.  Now which one is a stack
> overflow?

The second one is undefined behaviour so it can do whatever you want.
That includes reporting it as a stack overflow.  There in general is no
way to fix this, it has nothing to do with the problem at hand.


Segher

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 15:47       ` Florian Weimer
  2019-03-25 16:10         ` Andrew Haley
@ 2019-03-25 20:28         ` Segher Boessenkool
  1 sibling, 0 replies; 31+ messages in thread
From: Segher Boessenkool @ 2019-03-25 20:28 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Xi Ruoyao, Jonny Grant, gcc-help

On Mon, Mar 25, 2019 at 03:01:25PM +0100, Florian Weimer wrote:
> * Xi Ruoyao:
> 
> > On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> >> 
> >> I built & ran with the Sanitizer, it seems it's also stack overflow 
> >> within the operator new()
> >> 
> >> I had thoughts GCC would generate code that monitored the stack size and 
> >> aborted with a clear message when the stack size was exceeded. Looked 
> >> online, and it doesn't seem to be the case.
> >
> > Impossible.  We can't distinguish "stack overflow" with other segmentation
> > faults.
> 
> I think “impossible” is too strong.
> 
> It would be possible to annotate implicit probes and explicit probes
> generated by -fstack-clash-protection in DWARF, and use that
> information to generate a more precise error message.
> 
> Or we could set a bit on the guard page that instructs the kernel to
> report an additional fault flag somewhere in siginfo_t.  In fact, with
> protection keys, we could do this today, without any kernel changes
> whatsoever (but protection flags are not widely supported,
> unfortunately).
> 
> The second approach will have false positives, but as buffer overflows
> tend to proceed towards higher addresses and stacks grow downward,
> only really bogus pointers would be misreported (and once you have
> those, all bets are off anyway).

Another thing that could be done is looking if the instruction that
faulted uses the (ABI or arch mandated) stack pointer.  This will catch
most common cases, for example most unbounded recursions.  It isn't
perfect of course but would be quite helpful normally, esp. if it said
something like "this look like a stack overflow".


Segher

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 18:51           ` Florian Weimer
@ 2019-03-25 20:39             ` Jonny Grant
  2019-03-26  6:50               ` Xi Ruoyao
  2019-03-27 21:34             ` Jonny Grant
  1 sibling, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-25 20:39 UTC (permalink / raw)
  To: Florian Weimer, Andrew Haley; +Cc: Xi Ruoyao, gcc-help

Hi!

On 25/03/2019 17:14, Florian Weimer wrote:
> * Andrew Haley:
> 
>> On 3/25/19 2:01 PM, Florian Weimer wrote:
>>> * Xi Ruoyao:
>>>
>>>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>>>>
>>>>> I built & ran with the Sanitizer, it seems it's also stack overflow
>>>>> within the operator new()
>>>>>
>>>>> I had thoughts GCC would generate code that monitored the stack size and
>>>>> aborted with a clear message when the stack size was exceeded. Looked
>>>>> online, and it doesn't seem to be the case.
>>>>
>>>> Impossible.  We can't distinguish "stack overflow" with other segmentation
>>>> faults.
>>>
>>> I think “impossible” is too strong.
>>
>> It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
>> The problem is that recovering well enough to throw an exception requires
>> some quite hairy non-portable code.
> 
> Of course it's going to be non-portable.  Ideally, this would be
> handled out-of-process: the shell registers itself with the system
> coredump handler, and the handler analyzes the crash and provides
> information back to the shell for display.
> 
> It's quite difficult to get there, but it's certainly not impossible.
> We really should have lightweight tracebacks for aborts and the like
> in C/C++ code.  Right now, every moderately large piece of software
> tries to write their robust in-process crash handler, with varying
> results.
> .

Could GCC add a simple crash handler? maybe  -fcrash-handler

C++ exceptions show a few clues when there is a crash, which is helpful, eg:

// g++-8 -Wall -o cpp cpp.cpp
#include <vector>
int main()
{
     std::vector<int> v;
     return v.at(0);
}


$ ./cpp
terminate called after throwing an instance of 'std::out_of_range'
   what():  vector::_M_range_check: __n (which is 0) >= this->size() 
(which is 0)
Aborted


Jonny

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 14:01     ` Xi Ruoyao
  2019-03-25 15:47       ` Florian Weimer
  2019-03-25 18:56       ` Segher Boessenkool
@ 2019-03-25 22:05       ` Jonny Grant
  2019-03-26 10:20         ` Xi Ruoyao
  2 siblings, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-25 22:05 UTC (permalink / raw)
  To: gcc-help; +Cc: Florian Weimer, Xi Ruoyao

Hi!

On 25/03/2019 13:55, Xi Ruoyao wrote:
> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>
>> I built & ran with the Sanitizer, it seems it's also stack overflow
>> within the operator new()
>>
>> I had thoughts GCC would generate code that monitored the stack size and
>> aborted with a clear message when the stack size was exceeded. Looked
>> online, and it doesn't seem to be the case.
> 
> Impossible.  We can't distinguish "stack overflow" with other segmentation
> faults.  For example
> 
> int foo() {volatile char p[10000000]; p[0] = 1;}
> 
> and
> 
> int foo() {
>   volatile char a;
>   (&a)[-9999999] = 1;
> }
> 
> may be compiled to exactly same machine code.  Now which one is a stack
> overflow?
> 
>> AddressSanitizer:DEADLYSIGNAL
>> =================================================================
>> ==16598==ERROR: AddressSanitizer: stack-overflow on address
>> 0x7ffe4b0e7fc0 (pc 0x7f85c609293a bp 0x7ffe4b0e88d0 sp 0x7ffe4b0e7fb0 T0)
>>       #0 0x7f85c6092939  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x28939)
>>       #1 0x7f85c6091217  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x27217)
>>       #2 0x7f85c615974e in operator new(unsigned long)
>> (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xef74e)
>>       #3 0x563e23701a4a in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char> >::_M_construct<char
>> const*>(char const*, char const*, std::forward_iterator_tag)
>> /usr/include/c++/8/bits/basic_string.tcc:219
>>       #4 0x563e23947131 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char
>> const*>(char const*, char const*, std::__false_type)
>> /usr/include/c++/8/bits/basic_string.h:236
>>       #5 0x563e23947131 in void std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char> >::_M_construct<char
>> const*>(char const*, char const*) /usr/include/c++/8/bits/basic_string.h:255
>>       #6 0x563e23947131 in std::__cxx11::basic_string<char,
>> std::char_traits<char>, std::allocator<char> >::basic_string(char
>> const*, std::allocator<char> const&)
>> /usr/include/c++/8/bits/basic_string.h:516
> 
> If you consume too much stack, stack overflow may happens in any functions.  For
> example:
> 
> int x()
> {
> 	int a[100];
> 	malloc(1);
> 	return x();
> }
> 
> int main()
> {
> 	return x();
> }
> 
>> Sanitizer says the same. There isn't really anything that can be done
>> when stack is exceeded! There isn't a StackOverflowException
> 
> This is gcc-help, not java-help or python-help.  But actually you can do
> something here:
> 
> 0.  Do not consume so much stack.  Throw large things into the heap.
> 1.  Set a signal handler for SIGSEGV.  And you will need sigaltstack so the
> signal handler can run in an alternative stack.
> 2.  Use ulimit -s or setrlimit to increase stack limit, if you really need more
> stack.
> 3.  Use -fsplit-stack to automatically "increase" stack size when it overflows,
> if you really need this feature.
> 
> If you don't like all of these suggestions, go to use Java.
> 

Sorry, it looks like there was a misunderstanding. I don't need more 
stack. Testcase was created to recurse and reproduce crash! It 
replicated a typo in an application change, which called itself !

The compiler toolchain is ideally placed to provide a clearer abort, 
exit, backtrace when such issues occur. Feels like this mailing list is 
the ideal place to discuss.

Jonny

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 20:39             ` Jonny Grant
@ 2019-03-26  6:50               ` Xi Ruoyao
  2019-03-27  0:29                 ` Jonathan Wakely
  0 siblings, 1 reply; 31+ messages in thread
From: Xi Ruoyao @ 2019-03-26  6:50 UTC (permalink / raw)
  To: Jonny Grant, Florian Weimer, Andrew Haley; +Cc: gcc-help

On 2019-03-25 20:28 +0000, Jonny Grant wrote:
> Hi!
> 
> On 25/03/2019 17:14, Florian Weimer wrote:
> > * Andrew Haley:
> > 
> > > On 3/25/19 2:01 PM, Florian Weimer wrote:
> > > > * Xi Ruoyao:
> > > > 
> > > > > On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> > > > > > I built & ran with the Sanitizer, it seems it's also stack overflow
> > > > > > within the operator new()
> > > > > > 
> > > > > > I had thoughts GCC would generate code that monitored the stack size
> > > > > > and
> > > > > > aborted with a clear message when the stack size was exceeded.
> > > > > > Looked
> > > > > > online, and it doesn't seem to be the case.
> > > > > 
> > > > > Impossible.  We can't distinguish "stack overflow" with other
> > > > > segmentation
> > > > > faults.
> > > > 
> > > > I think “impossible” is too strong.
> > > 
> > > It is. We do it with stack banging and a few guard pages in the HotSpot
> > > JVM.
> > > The problem is that recovering well enough to throw an exception requires
> > > some quite hairy non-portable code.
> > 
> > Of course it's going to be non-portable.  Ideally, this would be
> > handled out-of-process: the shell registers itself with the system
> > coredump handler, and the handler analyzes the crash and provides
> > information back to the shell for display.
> > 
> > It's quite difficult to get there, but it's certainly not impossible.
> > We really should have lightweight tracebacks for aborts and the like
> > in C/C++ code.  Right now, every moderately large piece of software
> > tries to write their robust in-process crash handler, with varying
> > results.
> > .
> 
> Could GCC add a simple crash handler? maybe  -fcrash-handler

I suggest -lcrash-handler.  We can implement a crash handler, register it in
library initialization in libcrash-handler.so.  Then we don't need to hack GCC
code.

We can borrow most of code from glibc libSegFault.so.  Perhaps I'll do this work
if I can overcome my laziness.

> C++ exceptions show a few clues when there is a crash, which is helpful, eg:
> 
> // g++-8 -Wall -o cpp cpp.cpp
> #include <vector>
> int main()
> {
>      std::vector<int> v;
>      return v.at(0);
> }
> 
> 
> $ ./cpp
> terminate called after throwing an instance of 'std::out_of_range'
>    what():  vector::_M_range_check: __n (which is 0) >= this->size() 
> (which is 0)
> Aborted

I'm not familiar with C++ exception.  Maybe we can convert some instances of
unhandled signals to something like __gnu_cxx::unhandled_signal_exception, but I
believe that would require ABI changes.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 22:05       ` Jonny Grant
@ 2019-03-26 10:20         ` Xi Ruoyao
  0 siblings, 0 replies; 31+ messages in thread
From: Xi Ruoyao @ 2019-03-26 10:20 UTC (permalink / raw)
  To: Jonny Grant; +Cc: gcc-help

On 2019-03-25 20:39 +0000, Jonny Grant wrote:
> Hi!
> 
> On 25/03/2019 13:55, Xi Ruoyao wrote:
> > On 2019-03-25 13:06 +0000, Jonny Grant wrote:
> > > I built & ran with the Sanitizer, it seems it's also stack overflow
> > > within the operator new()
> > > 
> > > I had thoughts GCC would generate code that monitored the stack size and
> > > aborted with a clear message when the stack size was exceeded. Looked
> > > online, and it doesn't seem to be the case.
> > 
> > Impossible.  We can't distinguish "stack overflow" with other segmentation
> > faults.  For example
> > 
> > int foo() {volatile char p[10000000]; p[0] = 1;}
> > 
> > and
> > 
> > int foo() {
> >   volatile char a;
> >   (&a)[-9999999] = 1;
> > }
> > 
> > may be compiled to exactly same machine code.  Now which one is a stack
> > overflow?
> > 
> > > AddressSanitizer:DEADLYSIGNAL
> > > =================================================================
> > > ==16598==ERROR: AddressSanitizer: stack-overflow on address
> > > 0x7ffe4b0e7fc0 (pc 0x7f85c609293a bp 0x7ffe4b0e88d0 sp 0x7ffe4b0e7fb0 T0)
> > >       #0 0x7f85c6092939  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x28939)
> > >       #1 0x7f85c6091217  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x27217)
> > >       #2 0x7f85c615974e in operator new(unsigned long)
> > > (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xef74e)
> > >       #3 0x563e23701a4a in void std::__cxx11::basic_string<char,
> > > std::char_traits<char>, std::allocator<char> >::_M_construct<char
> > > const*>(char const*, char const*, std::forward_iterator_tag)
> > > /usr/include/c++/8/bits/basic_string.tcc:219
> > >       #4 0x563e23947131 in void std::__cxx11::basic_string<char,
> > > std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char
> > > const*>(char const*, char const*, std::__false_type)
> > > /usr/include/c++/8/bits/basic_string.h:236
> > >       #5 0x563e23947131 in void std::__cxx11::basic_string<char,
> > > std::char_traits<char>, std::allocator<char> >::_M_construct<char
> > > const*>(char const*, char const*)
> > > /usr/include/c++/8/bits/basic_string.h:255
> > >       #6 0x563e23947131 in std::__cxx11::basic_string<char,
> > > std::char_traits<char>, std::allocator<char> >::basic_string(char
> > > const*, std::allocator<char> const&)
> > > /usr/include/c++/8/bits/basic_string.h:516
> > 
> > If you consume too much stack, stack overflow may happens in any
> > functions.  For
> > example:
> > 
> > int x()
> > {
> > 	int a[100];
> > 	malloc(1);
> > 	return x();
> > }
> > 
> > int main()
> > {
> > 	return x();
> > }
> > 
> > > Sanitizer says the same. There isn't really anything that can be done
> > > when stack is exceeded! There isn't a StackOverflowException
> > 
> > This is gcc-help, not java-help or python-help.  But actually you can do
> > something here:
> > 
> > 0.  Do not consume so much stack.  Throw large things into the heap.
> > 1.  Set a signal handler for SIGSEGV.  And you will need sigaltstack so the
> > signal handler can run in an alternative stack.
> > 2.  Use ulimit -s or setrlimit to increase stack limit, if you really need
> > more
> > stack.
> > 3.  Use -fsplit-stack to automatically "increase" stack size when it
> > overflows,
> > if you really need this feature.
> > 
> > If you don't like all of these suggestions, go to use Java.
> > 
> 
> Sorry, it looks like there was a misunderstanding. I don't need more 
> stack. Testcase was created to recurse and reproduce crash! It 
> replicated a typo in an application change, which called itself !
> 
> The compiler toolchain is ideally placed to provide a clearer abort, 
> exit, backtrace when such issues occur. Feels like this mailing list is 
> the ideal place to discuss.

I understand this.  But I disagree that we should add these support into a
compiler.  That's what a _debugger_ should do and does perfectly well.

When my program crashes on my machine, I just invoke gdb.  When it crashes on a
server or something, I download the coredump file and invoke gdb.  Then I can
not only get the backtrace, but also interactively gather more information.

For the sanitizers things are different.  The sanitizers are meant to catch
undefined behaviors, address violations and etc. which might _not_ lead to
crash.  For example:

int32_t x = 888888888;
x *= 233;

If it doesn't crash, without a sanitizer we won't know there is a bug.  That's
why GCC and clang introduced sanitizers.  But if the program just crashed,
everyone immediately knows there is at least one bug so a debugger should be
used.

OTOH, if you want to salvage your program when it receives SIGSEGV (instead of
crashing of aborting), there is:  https://www.gnu.org/software/libsigsegv/ .
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-26  6:50               ` Xi Ruoyao
@ 2019-03-27  0:29                 ` Jonathan Wakely
  0 siblings, 0 replies; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-27  0:29 UTC (permalink / raw)
  To: gcc-help; +Cc: Jonny Grant, Florian Weimer, Andrew Haley

On Tue, 26 Mar 2019 at 06:13, Xi Ruoyao wrote:
> > C++ exceptions show a few clues when there is a crash, which is helpful, eg:
> >
> > // g++-8 -Wall -o cpp cpp.cpp
> > #include <vector>
> > int main()
> > {
> >      std::vector<int> v;
> >      return v.at(0);
> > }
> >
> >
> > $ ./cpp
> > terminate called after throwing an instance of 'std::out_of_range'
> >    what():  vector::_M_range_check: __n (which is 0) >= this->size()
> > (which is 0)
> > Aborted
>
> I'm not familiar with C++ exception.  Maybe we can convert some instances of
> unhandled signals to something like __gnu_cxx::unhandled_signal_exception, but I
> believe that would require ABI changes.

I don't think that's a good idea. Signals are not exceptions, and vice versa.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-25 18:51           ` Florian Weimer
  2019-03-25 20:39             ` Jonny Grant
@ 2019-03-27 21:34             ` Jonny Grant
  2019-03-27 23:43               ` Jonathan Wakely
  1 sibling, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-27 21:34 UTC (permalink / raw)
  To: Florian Weimer, Andrew Haley; +Cc: Xi Ruoyao, gcc-help


On 25/03/2019 17:14, Florian Weimer wrote:
> * Andrew Haley:
> 
>> On 3/25/19 2:01 PM, Florian Weimer wrote:
>>> * Xi Ruoyao:
>>>
>>>> On 2019-03-25 13:06 +0000, Jonny Grant wrote:
>>>>>
>>>>> I built & ran with the Sanitizer, it seems it's also stack overflow
>>>>> within the operator new()
>>>>>
>>>>> I had thoughts GCC would generate code that monitored the stack size and
>>>>> aborted with a clear message when the stack size was exceeded. Looked
>>>>> online, and it doesn't seem to be the case.
>>>>
>>>> Impossible.  We can't distinguish "stack overflow" with other segmentation
>>>> faults.
>>>
>>> I think “impossible” is too strong.
>>
>> It is. We do it with stack banging and a few guard pages in the HotSpot JVM.
>> The problem is that recovering well enough to throw an exception requires
>> some quite hairy non-portable code.
> 
> Of course it's going to be non-portable.  Ideally, this would be
> handled out-of-process: the shell registers itself with the system
> coredump handler, and the handler analyzes the crash and provides
> information back to the shell for display.
> 
> It's quite difficult to get there, but it's certainly not impossible.
> We really should have lightweight tracebacks for aborts and the like
> in C/C++ code.  Right now, every moderately large piece of software
> tries to write their robust in-process crash handler, with varying
> results.
> .

Hi!

Thank you for your reply and input.

Maybe GCC's "libbacktrace" module could be used?

I was wondering if -fsanitize=address would output a backtrace for the 
C++ exception, but it doesn't seem to. Also it actually prevents the 
core being dumped - that's probably not intended?

Compile without Sanitizer, and it does dump the core to a file at least!

$ export UBSAN_OPTIONS=print_stacktrace=1

// g++-8 -fsanitize=address -Wall -o exception exception.cpp
#include <vector>
int main()
{
     std::vector<int> v;
     return v.at(0);
}


$ ./exception
terminate called after throwing an instance of 'std::out_of_range'
   what():  vector::_M_range_check: __n (which is 0) >= this->size() 
(which is 0)
Aborted




What would be very useful is simple -fcrash-handler it would link in 
automatically, and probably register before main() any stack-overflow, 
segv or bus handlers etc

Maybe it could simply integrate with 
https://www.gnu.org/software/libsigsegv/
(suggested by Xi) in this thread?

Or GCC has the "libbacktrace" in the GCC tree, maybe use that?

Cheers
Jonny


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-27 21:34             ` Jonny Grant
@ 2019-03-27 23:43               ` Jonathan Wakely
  2019-03-27 23:51                 ` Jonny Grant
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-27 23:43 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Florian Weimer, Andrew Haley, Xi Ruoyao, gcc-help

On Wed, 27 Mar 2019 at 21:27, Jonny Grant wrote:
> Hi!
>
> Thank you for your reply and input.
>
> Maybe GCC's "libbacktrace" module could be used?
>
> I was wondering if -fsanitize=address would output a backtrace for the
> C++ exception, but it doesn't seem to. Also it actually prevents the
> core being dumped - that's probably not intended?
>
> Compile without Sanitizer, and it does dump the core to a file at least!
>
> $ export UBSAN_OPTIONS=print_stacktrace=1

This is a UBsan option.

> // g++-8 -fsanitize=address -Wall -o exception exception.cpp

But you're not using UBsan.

> #include <vector>
> int main()
> {
>      std::vector<int> v;
>      return v.at(0);
> }
>
>
> $ ./exception
> terminate called after throwing an instance of 'std::out_of_range'
>    what():  vector::_M_range_check: __n (which is 0) >= this->size()
> (which is 0)
> Aborted

There's no undefined behaviour or memory corruption here, so it's not
surprising that UBsan and Asan don't print anything.

If you want a stack trace for exceptions that terminate the process
then you could install a custom terminate handler which does that.
Libstdc++'s default terminate handler just prints the message above,
which includes the type of the exception and if it's a type derived
from std::exception, the what() string stored in it.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-27 23:43               ` Jonathan Wakely
@ 2019-03-27 23:51                 ` Jonny Grant
  2019-03-28  8:26                   ` Xi Ruoyao
  2019-03-28 13:55                   ` Jonathan Wakely
  0 siblings, 2 replies; 31+ messages in thread
From: Jonny Grant @ 2019-03-27 23:51 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Florian Weimer, Andrew Haley, Xi Ruoyao, gcc-help

[-- Attachment #1: Type: text/plain, Size: 2747 bytes --]



On 27/03/2019 21:34, Jonathan Wakely wrote:
> On Wed, 27 Mar 2019 at 21:27, Jonny Grant wrote:
>> Hi!
>>
>> Thank you for your reply and input.
>>
>> Maybe GCC's "libbacktrace" module could be used?
>>
>> I was wondering if -fsanitize=address would output a backtrace for the
>> C++ exception, but it doesn't seem to. Also it actually prevents the
>> core being dumped - that's probably not intended?
>>
>> Compile without Sanitizer, and it does dump the core to a file at least!
>>
>> $ export UBSAN_OPTIONS=print_stacktrace=1
> 
> This is a UBsan option.
> 
>> // g++-8 -fsanitize=address -Wall -o exception exception.cpp
> 
> But you're not using UBsan.
> 
>> #include <vector>
>> int main()
>> {
>>       std::vector<int> v;
>>       return v.at(0);
>> }
>>
>>
>> $ ./exception
>> terminate called after throwing an instance of 'std::out_of_range'
>>     what():  vector::_M_range_check: __n (which is 0) >= this->size()
>> (which is 0)
>> Aborted
> 
> There's no undefined behaviour or memory corruption here, so it's not
> surprising that UBsan and Asan don't print anything.

Ok I see, thank you for pointing this out.

I did wonder, as -fsanitize=address seems to inhibit the core dump that 
is otherwise created by the abort() that appears to be called - is that 
a known issue?

$ g++-8 -Wall -o exception exception.cpp
jonny@asus:~/code/crash$ ./exception
terminate called after throwing an instance of 'std::out_of_range'
   what():  vector::_M_range_check: __n (which is 0) >= this->size() 
(which is 0)
Aborted (core dumped)
$

Usually I just load the core dump into GDB to take a look at it.


> If you want a stack trace for exceptions that terminate the process
> then you could install a custom terminate handler which does that.
> Libstdc++'s default terminate handler just prints the message above,
> which includes the type of the exception and if it's a type derived
> from std::exception, the what() string stored in it.

Yes, I'd love to have a stack trace for exceptions that terminate the 
process. Do you know a simple example you can refer me to?  I've looked 
and there are people using boost::stacktrace::stacktrace() but I'd 
rather not link to boost as a dependency.

It would be great if there was a glibc option to do this, or GCC could 
insert it.

Otherwise we each need to insert our own stack tracers...

Found this:
https://www.gnu.org/software/libc/manual/html_node/Backtraces.html

I added this (attached) to a C++ exception handler, but there's no file 
and line numbers. Other examples resort to calling addr2line! Seems a 
bit over the top for us each to code our own stack tracer... Or reading 
symbols etc. Am I asking too much for a general print_backtrace() in 
libc or elsewhere ?

Cheers, Jonny

[-- Attachment #2: exception.cpp --]
[-- Type: text/x-c++src, Size: 897 bytes --]

// g++-8 -Wall -g -o exception exception.cpp
#include <vector>
#include <iostream>
int main2();

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

/* Obtain a backtrace and print it to stdout.
 https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
 */
void
print_trace (void)
{
  void *array[10];
  size_t size;
  char **strings;
  size_t i;

  size = backtrace (array, 10);
  strings = backtrace_symbols (array, size);

  printf ("Obtained %zd stack frames.\n", size);

  for (i = 0; i < size; i++)
     printf ("symbols %s\n", strings[i]);

  free (strings);
}

int main()
{
    try
    {
        main2();
    }
    catch( const std::exception &e)
    {
        const std::string what(e.what());
        std::cout << "Unhandled exception: [" << what << "]\n";
        print_trace();
        exit(0);
    }
}

int main2()
{
    std::vector<int> v;
    return v.at(0);
}


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-27 23:51                 ` Jonny Grant
@ 2019-03-28  8:26                   ` Xi Ruoyao
  2019-03-28 11:52                     ` Jonathan Wakely
  2019-03-29  2:24                     ` Jonny Grant
  2019-03-28 13:55                   ` Jonathan Wakely
  1 sibling, 2 replies; 31+ messages in thread
From: Xi Ruoyao @ 2019-03-28  8:26 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Jonathan Wakely, Florian Weimer, Andrew Haley, gcc-help

On 2019-03-27 23:47 +0000, Jonny Grant wrote:
> 
> On 27/03/2019 21:34, Jonathan Wakely wrote:
> > On Wed, 27 Mar 2019 at 21:27, Jonny Grant wrote:
> > > Hi!
> > > 
> > > Thank you for your reply and input.
> > > 
> > > Maybe GCC's "libbacktrace" module could be used?
> > > 
> > > I was wondering if -fsanitize=address would output a backtrace for the
> > > C++ exception, but it doesn't seem to. Also it actually prevents the
> > > core being dumped - that's probably not intended?
> > > 
> > > Compile without Sanitizer, and it does dump the core to a file at least!
> > > 
> > > $ export UBSAN_OPTIONS=print_stacktrace=1
> > 
> > This is a UBsan option.
> > 
> > > // g++-8 -fsanitize=address -Wall -o exception exception.cpp
> > 
> > But you're not using UBsan.
> > 
> > > #include <vector>
> > > int main()
> > > {
> > >       std::vector<int> v;
> > >       return v.at(0);
> > > }
> > > 
> > > 
> > > $ ./exception
> > > terminate called after throwing an instance of 'std::out_of_range'
> > >     what():  vector::_M_range_check: __n (which is 0) >= this->size()
> > > (which is 0)
> > > Aborted
> > 
> > There's no undefined behaviour or memory corruption here, so it's not
> > surprising that UBsan and Asan don't print anything.

C++ exception is a well-defined language feature.  There are even guys
(mis)using it in cases we normally use "if (...) {...}"

> Ok I see, thank you for pointing this out.
> 
> I did wonder, as -fsanitize=address seems to inhibit the core dump that 
> is otherwise created by the abort() that appears to be called - is that 
> a known issue?
> 
> $ g++-8 -Wall -o exception exception.cpp
> jonny@asus:~/code/crash$ ./exception
> terminate called after throwing an instance of 'std::out_of_range'
>    what():  vector::_M_range_check: __n (which is 0) >= this->size() 
> (which is 0)
> Aborted (core dumped)
> $
> 
> Usually I just load the core dump into GDB to take a look at it.

It seems so.  I don't know if this is a intentional feature or an oversight.

> > If you want a stack trace for exceptions that terminate the process
> > then you could install a custom terminate handler which does that.
> > Libstdc++'s default terminate handler just prints the message above,
> > which includes the type of the exception and if it's a type derived
> > from std::exception, the what() string stored in it.
> 
> Yes, I'd love to have a stack trace for exceptions that terminate the 
> process. Do you know a simple example you can refer me to?  I've looked 
> and there are people using boost::stacktrace::stacktrace() but I'd 
> rather not link to boost as a dependency.
> 
> It would be great if there was a glibc option to do this, or GCC could 
> insert it.

> Otherwise we each need to insert our own stack tracers...
> 
> Found this:
> https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
> 
> I added this (attached) to a C++ exception handler, but there's no file 
> and line numbers. Other examples resort to calling addr2line! Seems a 
> bit over the top for us each to code our own stack tracer... Or reading 
> symbols etc. Am I asking too much for a general print_backtrace() in 
> libc or elsewhere ?

Providing backtrace with file:line requires to parse debug info.

glibc libSegFault.so just record a stack bracktrace w/o line numbers.  The shell
wrapper catchsegv convert addresses into line numbers calling addr2line.

If you don't want to call addr2line (or other tools) you'll need DWARF parser in
the executable. Why should we bloat the executable with a lot of code which
should be in (and has been in) a debugger?

For a comparision, Go provides a good stack backtrace at panics.  But how big a
Go executable is?  A "hello world" takes 1997502 bytes!  While a C++ one
compiled by G++ is 22088 bytes (with debug info).

If you need a backtrace in debug, just call a debugger.  If you think you'll
need it in _release_, I believe the right thing to do is catching the exceptions
(or handle the signals) you care and log them into a log file or a syslog
facility.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-28  8:26                   ` Xi Ruoyao
@ 2019-03-28 11:52                     ` Jonathan Wakely
  2019-03-29  2:24                     ` Jonny Grant
  1 sibling, 0 replies; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-28 11:52 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonny Grant, Florian Weimer, Andrew Haley, gcc-help

On Thu, 28 Mar 2019 at 04:59, Xi Ruoyao wrote:
> Providing backtrace with file:line requires to parse debug info.
>
> glibc libSegFault.so just record a stack bracktrace w/o line numbers.  The shell
> wrapper catchsegv convert addresses into line numbers calling addr2line.
>
> If you don't want to call addr2line (or other tools) you'll need DWARF parser in
> the executable. Why should we bloat the executable with a lot of code which
> should be in (and has been in) a debugger?

It's also a security risk to run complex parsers and other code in a
process that has just crashed due to some bug. You don't know what
state the program is in, or why it crashed, or if the stack trace is
reliable.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-27 23:51                 ` Jonny Grant
  2019-03-28  8:26                   ` Xi Ruoyao
@ 2019-03-28 13:55                   ` Jonathan Wakely
  2019-03-28 14:39                     ` Jonny Grant
  1 sibling, 1 reply; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-28 13:55 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Florian Weimer, Andrew Haley, Xi Ruoyao, gcc-help

On Wed, 27 Mar 2019 at 23:47, Jonny Grant wrote:
> I did wonder, as -fsanitize=address seems to inhibit the core dump that
> is otherwise created by the abort() that appears to be called - is that
> a known issue?

Sorry for not thinking of this before you filed the bug report, but as
I said there, the problem is probably not Asan but your settings.
Check what ulimit -a shows for the max core file size, see what
'sysctl -a | grep kernel.core' shows and if appropriate check the
MaxCrashReportsSize in /etc/abrt/abrt.conf

So Asan isn't suppressing the core file, it's just making the address
space larger (for the shadow memory it uses to track heap usage) and
that causes a much larger core file, which your system then doesn't
dump.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-28 13:55                   ` Jonathan Wakely
@ 2019-03-28 14:39                     ` Jonny Grant
  2019-03-28 14:39                       ` Jonathan Wakely
  0 siblings, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2019-03-28 14:39 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Florian Weimer, Andrew Haley, Xi Ruoyao, gcc-help



On 28/03/2019 11:52, Jonathan Wakely wrote:
> On Wed, 27 Mar 2019 at 23:47, Jonny Grant wrote:
>> I did wonder, as -fsanitize=address seems to inhibit the core dump that
>> is otherwise created by the abort() that appears to be called - is that
>> a known issue?
> 
> Sorry for not thinking of this before you filed the bug report, but as
> I said there, the problem is probably not Asan but your settings.
> Check what ulimit -a shows for the max core file size, see what
> 'sysctl -a | grep kernel.core' shows and if appropriate check the
> MaxCrashReportsSize in /etc/abrt/abrt.conf
> 
> So Asan isn't suppressing the core file, it's just making the address
> space larger (for the shadow memory it uses to track heap usage) and
> that causes a much larger core file, which your system then doesn't
> dump.
> 

Hi!
Thank you for your reply

My system is on unlimited core size, so should be okay, 416G free..?

Maybe at least the code that isn't outputting the core, could output the 
reason. I wondered if Asan had overridden the abort() function? Maybe 
Asan putting in an ABRT handler...?

It would b the same as sending ABRT signal I expect:
kill -ABRT <pid>



$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63536
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63536
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited



# sysctl -a | grep kernel.core
kernel.core_pattern = core
kernel.core_pipe_limit = 0
kernel.core_uses_pid = 0
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.enp4s0.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.vmnet1.stable_secret"
sysctl: reading key "net.ipv6.conf.vmnet8.stable_secret"
sysctl: reading key "net.ipv6.conf.wlp3s0.stable_secret"

I don't have /etc/abrt/abrt.conf  on Ubuntu

Jonny

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-28 14:39                     ` Jonny Grant
@ 2019-03-28 14:39                       ` Jonathan Wakely
  0 siblings, 0 replies; 31+ messages in thread
From: Jonathan Wakely @ 2019-03-28 14:39 UTC (permalink / raw)
  To: Jonny Grant; +Cc: Florian Weimer, Andrew Haley, Xi Ruoyao, gcc-help

On Thu, 28 Mar 2019 at 14:26, Jonny Grant <jg@jguk.org> wrote:
>
>
>
> On 28/03/2019 11:52, Jonathan Wakely wrote:
> > On Wed, 27 Mar 2019 at 23:47, Jonny Grant wrote:
> >> I did wonder, as -fsanitize=address seems to inhibit the core dump that
> >> is otherwise created by the abort() that appears to be called - is that
> >> a known issue?
> >
> > Sorry for not thinking of this before you filed the bug report, but as
> > I said there, the problem is probably not Asan but your settings.
> > Check what ulimit -a shows for the max core file size, see what
> > 'sysctl -a | grep kernel.core' shows and if appropriate check the
> > MaxCrashReportsSize in /etc/abrt/abrt.conf
> >
> > So Asan isn't suppressing the core file, it's just making the address
> > space larger (for the shadow memory it uses to track heap usage) and
> > that causes a much larger core file, which your system then doesn't
> > dump.
> >
>
> Hi!
> Thank you for your reply
>
> My system is on unlimited core size, so should be okay, 416G free..?
>
> Maybe at least the code that isn't outputting the core, could output the
> reason.

That's not done by GCC.

> I wondered if Asan had overridden the abort() function? Maybe
> Asan putting in an ABRT handler...?

Nope, because if that was true I wouldn't get "Aborted (core dumped)"
for asan-instrumented binaries, and I do get that, unless I change
settings to disallow larger core files.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-28  8:26                   ` Xi Ruoyao
  2019-03-28 11:52                     ` Jonathan Wakely
@ 2019-03-29  2:24                     ` Jonny Grant
  2019-03-30 17:32                       ` Jonny Grant
  2023-02-19 21:21                       ` Jonny Grant
  1 sibling, 2 replies; 31+ messages in thread
From: Jonny Grant @ 2019-03-29  2:24 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonathan Wakely, Florian Weimer, Andrew Haley, gcc-help

[-- Attachment #1: Type: text/plain, Size: 5064 bytes --]



On 28/03/2019 04:59, Xi Ruoyao wrote:
> On 2019-03-27 23:47 +0000, Jonny Grant wrote:
>>
>> On 27/03/2019 21:34, Jonathan Wakely wrote:
>>> On Wed, 27 Mar 2019 at 21:27, Jonny Grant wrote:
>>>> Hi!
>>>>
>>>> Thank you for your reply and input.
>>>>
>>>> Maybe GCC's "libbacktrace" module could be used?
>>>>
>>>> I was wondering if -fsanitize=address would output a backtrace for the
>>>> C++ exception, but it doesn't seem to. Also it actually prevents the
>>>> core being dumped - that's probably not intended?
>>>>
>>>> Compile without Sanitizer, and it does dump the core to a file at least!
>>>>
>>>> $ export UBSAN_OPTIONS=print_stacktrace=1
>>>
>>> This is a UBsan option.
>>>
>>>> // g++-8 -fsanitize=address -Wall -o exception exception.cpp
>>>
>>> But you're not using UBsan.
>>>
>>>> #include <vector>
>>>> int main()
>>>> {
>>>>        std::vector<int> v;
>>>>        return v.at(0);
>>>> }
>>>>
>>>>
>>>> $ ./exception
>>>> terminate called after throwing an instance of 'std::out_of_range'
>>>>      what():  vector::_M_range_check: __n (which is 0) >= this->size()
>>>> (which is 0)
>>>> Aborted
>>>
>>> There's no undefined behaviour or memory corruption here, so it's not
>>> surprising that UBsan and Asan don't print anything.
> 
> C++ exception is a well-defined language feature.  There are even guys
> (mis)using it in cases we normally use "if (...) {...}"
> 
>> Ok I see, thank you for pointing this out.
>>
>> I did wonder, as -fsanitize=address seems to inhibit the core dump that
>> is otherwise created by the abort() that appears to be called - is that
>> a known issue?
>>
>> $ g++-8 -Wall -o exception exception.cpp
>> jonny@asus:~/code/crash$ ./exception
>> terminate called after throwing an instance of 'std::out_of_range'
>>     what():  vector::_M_range_check: __n (which is 0) >= this->size()
>> (which is 0)
>> Aborted (core dumped)
>> $
>>
>> Usually I just load the core dump into GDB to take a look at it.
> 
> It seems so.  I don't know if this is a intentional feature or an oversight.
> 
>>> If you want a stack trace for exceptions that terminate the process
>>> then you could install a custom terminate handler which does that.
>>> Libstdc++'s default terminate handler just prints the message above,
>>> which includes the type of the exception and if it's a type derived
>>> from std::exception, the what() string stored in it.
>>
>> Yes, I'd love to have a stack trace for exceptions that terminate the
>> process. Do you know a simple example you can refer me to?  I've looked
>> and there are people using boost::stacktrace::stacktrace() but I'd
>> rather not link to boost as a dependency.
>>
>> It would be great if there was a glibc option to do this, or GCC could
>> insert it.
> 
>> Otherwise we each need to insert our own stack tracers...
>>
>> Found this:
>> https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
>>
>> I added this (attached) to a C++ exception handler, but there's no file
>> and line numbers. Other examples resort to calling addr2line! Seems a
>> bit over the top for us each to code our own stack tracer... Or reading
>> symbols etc. Am I asking too much for a general print_backtrace() in
>> libc or elsewhere ?
> 
> Providing backtrace with file:line requires to parse debug info.
> 
> glibc libSegFault.so just record a stack bracktrace w/o line numbers.  The shell
> wrapper catchsegv convert addresses into line numbers calling addr2line.

Hi!

libSegFault.so seems like a big module! If it only records stack frames 
like the backtrace() and backtrace_symbols() functions get in around 10 
lines of code. Maybe libSegFault does a lot more than it seems. I was 
using these functions
https://www.gnu.org/software/libc/manual/html_node/Backtraces.html


catchsegv doesn't show line numbers for me:

backtrace:
./loop(+0x9ae)[0x55ee7f23e9ae]
./loop(+0xa03)[0x55ee7f23ea03]
./loop(+0xa03)[0x55ee7f23ea03]
[repeats]

This is the stack overflow testcase. Please find attached.

The file does have the info:
$ addr2line -e loop 0xa03
/home/jonny/code/crash/loop.cpp:7 (discriminator 4)


> 
> If you don't want to call addr2line (or other tools) you'll need DWARF parser in
> the executable. Why should we bloat the executable with a lot of code which
> should be in (and has been in) a debugger?
> 
> For a comparision, Go provides a good stack backtrace at panics.  But how big a
> Go executable is?  A "hello world" takes 1997502 bytes!  While a C++ one
> compiled by G++ is 22088 bytes (with debug info).

My little test exception file leaps up from 31K to 81K when compiled 
with backtrace() and backtrace_symbols()  A lot of increase... 
Considering they are library functions I am surprised its 50K bigger. 
I've not attached that program, but can share if needed..


> If you need a backtrace in debug, just call a debugger.  If you think you'll
> need it in _release_, I believe the right thing to do is catching the exceptions
> (or handle the signals) you care and log them into a log file or a syslog
> facility.

Sounds good! Yes, that sounds good.

Jonny

[-- Attachment #2: loop.cpp --]
[-- Type: text/x-c++src, Size: 175 bytes --]

// g++-8 -ggdb -g -O0 -o loop loop.cpp

#include <string>

static void func(std::string f, int g)
{
    func(f.c_str(), g);
}

int main()
{
    func("a", 0);

    return 0;
}

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-29  2:24                     ` Jonny Grant
@ 2019-03-30 17:32                       ` Jonny Grant
  2023-02-19 21:21                       ` Jonny Grant
  1 sibling, 0 replies; 31+ messages in thread
From: Jonny Grant @ 2019-03-30 17:32 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonathan Wakely, Florian Weimer, Andrew Haley, gcc-help

[-- Attachment #1: Type: text/plain, Size: 944 bytes --]

Hi!
Just sharing the little backtrace sample I made using addr2line and libc 
backtrace_symbols().

The backtrace doesn't appear to be completely accurate, but it is something.

The file goes from 22KB (as you found Xi!) to 87KB on my 64bit ubuntu 
machine when I add -g.

So I'm pleased with this, better than Go's 1,997,502 byte backtrace then?



$ ./exception4
Unhandled C++ exception: [vector::_M_range_check: __n (which is 0) >= 
this->size() (which is 0)]

Backtrace:
0x00000000000014de: test() at exception4.cpp:75
[1]: ./exception4(+0x14de) [0x563bd5b804de]
0x0000000000001550: main at exception4.cpp:87
[2]: ./exception4(+0x1550) [0x563bd5b80550]
0x0000000000000000: ?? ??:0
[3]: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) 
[0x7f1d0c52bb97]
0x0000000000000fea: _start at ??:?
[4]: ./exception4(+0xfea) [0x563bd5b7ffea]


Could GCC insert something similar using libc backtrace_symbols() with 
an -fcrash-handler ?

Jonny

[-- Attachment #2: exception4.cpp --]
[-- Type: text/x-c++src, Size: 2001 bytes --]

// g++-8 -Wall -g -o exception4 exception4.cpp
#include <vector>
#include <iostream>
#include <string>

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

int main2();

/* Obtain a backtrace and print it to stdout.
 https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
 */
void print_trace(void)
{
    void *array[10];
    const size_t size = backtrace (array, 10);
    char **strings = backtrace_symbols (array, size);

    //printf ("Obtained %zd stack frames.\n", size);
    printf("\nBacktrace:\n");

    // skip first, as it is this handler
    for (size_t i = 1; i < size; i++)
    {
        // extract the exe name
        std::string exe(strings[i]);
        {
            const size_t s = exe.find("(");
            if(std::string::npos != s)
            {
                exe.erase(s, exe.length());
            }
        }

        // extract the address
        std::string addr(strings[i]);
        {
            size_t s = addr.find("(");
            if(std::string::npos != s)
            {
                ++s;
                addr.erase(0, s);

                s = addr.find(")");
                if(std::string::npos != s)
                {
                    addr.erase(s, addr.length());
                }
            }
        }

        //printf("exe '%s' addr '%s'\n", exe.c_str(), addr.c_str());

        char syscom[256];
        sprintf(syscom,"addr2line -s -a -p -f -C -e %s %s", exe.c_str(), addr.c_str());
        //printf("%s\n", syscom);
        system(syscom);

        printf ("[%zu]: %s\n", i, strings[i]);
    }

    free (strings);
}

void test()
{
    try
    {
        main2();
    }
    catch( const std::exception &e)
    {
        const std::string what(e.what());
        std::cout << "Unhandled C++ exception: [" << e.what() << "]\n";
        print_trace();
        //char * p = NULL;
        //*p = 1;
    }
}


int main(int argc, const char * argv[])
{
    test();
}


int main2()
{
    std::vector<int> v;
    return v.at(0);
}


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2019-03-29  2:24                     ` Jonny Grant
  2019-03-30 17:32                       ` Jonny Grant
@ 2023-02-19 21:21                       ` Jonny Grant
  2023-02-19 21:34                         ` Jonny Grant
  1 sibling, 1 reply; 31+ messages in thread
From: Jonny Grant @ 2023-02-19 21:21 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonathan Wakely, Florian Weimer, Andrew Haley, gcc-help



On 29/03/2019 00:05, Jonny Grant wrote:
> 
> 
> On 28/03/2019 04:59, Xi Ruoyao wrote:
>> On 2019-03-27 23:47 +0000, Jonny Grant wrote:
>>>
>>> On 27/03/2019 21:34, Jonathan Wakely wrote:
>>>> On Wed, 27 Mar 2019 at 21:27, Jonny Grant wrote:
>>>>> Hi!
>>>>>
>>>>> Thank you for your reply and input.
>>>>>
>>>>> Maybe GCC's "libbacktrace" module could be used?
>>>>>
>>>>> I was wondering if -fsanitize=address would output a backtrace for the
>>>>> C++ exception, but it doesn't seem to. Also it actually prevents the
>>>>> core being dumped - that's probably not intended?
>>>>>
>>>>> Compile without Sanitizer, and it does dump the core to a file at least!
>>>>>
>>>>> $ export UBSAN_OPTIONS=print_stacktrace=1
>>>>
>>>> This is a UBsan option.
>>>>
>>>>> // g++-8 -fsanitize=address -Wall -o exception exception.cpp
>>>>
>>>> But you're not using UBsan.
>>>>
>>>>> #include <vector>
>>>>> int main()
>>>>> {
>>>>>        std::vector<int> v;
>>>>>        return v.at(0);
>>>>> }
>>>>>
>>>>>
>>>>> $ ./exception
>>>>> terminate called after throwing an instance of 'std::out_of_range'
>>>>>      what():  vector::_M_range_check: __n (which is 0) >= this->size()
>>>>> (which is 0)
>>>>> Aborted
>>>>
>>>> There's no undefined behaviour or memory corruption here, so it's not
>>>> surprising that UBsan and Asan don't print anything.
>>
>> C++ exception is a well-defined language feature.  There are even guys
>> (mis)using it in cases we normally use "if (...) {...}"
>>
>>> Ok I see, thank you for pointing this out.
>>>
>>> I did wonder, as -fsanitize=address seems to inhibit the core dump that
>>> is otherwise created by the abort() that appears to be called - is that
>>> a known issue?
>>>
>>> $ g++-8 -Wall -o exception exception.cpp
>>> jonny@asus:~/code/crash$ ./exception
>>> terminate called after throwing an instance of 'std::out_of_range'
>>>     what():  vector::_M_range_check: __n (which is 0) >= this->size()
>>> (which is 0)
>>> Aborted (core dumped)
>>> $
>>>
>>> Usually I just load the core dump into GDB to take a look at it.
>>
>> It seems so.  I don't know if this is a intentional feature or an oversight.
>>
>>>> If you want a stack trace for exceptions that terminate the process
>>>> then you could install a custom terminate handler which does that.
>>>> Libstdc++'s default terminate handler just prints the message above,
>>>> which includes the type of the exception and if it's a type derived
>>>> from std::exception, the what() string stored in it.
>>>
>>> Yes, I'd love to have a stack trace for exceptions that terminate the
>>> process. Do you know a simple example you can refer me to?  I've looked
>>> and there are people using boost::stacktrace::stacktrace() but I'd
>>> rather not link to boost as a dependency.
>>>
>>> It would be great if there was a glibc option to do this, or GCC could
>>> insert it.
>>
>>> Otherwise we each need to insert our own stack tracers...
>>>
>>> Found this:
>>> https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
>>>
>>> I added this (attached) to a C++ exception handler, but there's no file
>>> and line numbers. Other examples resort to calling addr2line! Seems a
>>> bit over the top for us each to code our own stack tracer... Or reading
>>> symbols etc. Am I asking too much for a general print_backtrace() in
>>> libc or elsewhere ?
>>
>> Providing backtrace with file:line requires to parse debug info.
>>
>> glibc libSegFault.so just record a stack bracktrace w/o line numbers.  The shell
>> wrapper catchsegv convert addresses into line numbers calling addr2line.
> 
> Hi!
> 
> libSegFault.so seems like a big module! If it only records stack frames like the backtrace() and backtrace_symbols() functions get in around 10 lines of code. Maybe libSegFault does a lot more than it seems. I was using these functions
> https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
> 
> 
> catchsegv doesn't show line numbers for me:
> 
> backtrace:
> ./loop(+0x9ae)[0x55ee7f23e9ae]
> ./loop(+0xa03)[0x55ee7f23ea03]
> ./loop(+0xa03)[0x55ee7f23ea03]
> [repeats]
> 
> This is the stack overflow testcase. Please find attached.
> 
> The file does have the info:
> $ addr2line -e loop 0xa03
> /home/jonny/code/crash/loop.cpp:7 (discriminator 4)
> 
> 
>>
>> If you don't want to call addr2line (or other tools) you'll need DWARF parser in
>> the executable. Why should we bloat the executable with a lot of code which
>> should be in (and has been in) a debugger?
>>
>> For a comparision, Go provides a good stack backtrace at panics.  But how big a
>> Go executable is?  A "hello world" takes 1997502 bytes!  While a C++ one
>> compiled by G++ is 22088 bytes (with debug info).
> 
> My little test exception file leaps up from 31K to 81K when compiled with backtrace() and backtrace_symbols()  A lot of increase... Considering they are library functions I am surprised its 50K bigger. I've not attached that program, but can share if needed..
> 
> 
>> If you need a backtrace in debug, just call a debugger.  If you think you'll
>> need it in _release_, I believe the right thing to do is catching the exceptions
>> (or handle the signals) you care and log them into a log file or a syslog
>> facility.
> 
> Sounds good! Yes, that sounds good.
> 
> Jonny


It's not pretty, but this wrapper catches NULL passed at compile time:

std::string make_std_string(const char * const str)
{
    // This line ensures: warning: dereference of NULL '0' [CWE-476] [-Wanalyzer-null-dereference]
    char b = *str; 
    std::string s(str);
    s[0] = b; // copy it back to avoid unused variable warning
    return s;
}

int main()
{
    const char * a = NULL;
    std::string result = make_std_string(a);
    std::cout << result;
}


note, there a PR in latest gcc for an issue, so need to use -Wno-analyzer-use-of-uninitialized-value to avoid std::string having an incorrect warning reported.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Recursive SIGSEGV question
  2023-02-19 21:21                       ` Jonny Grant
@ 2023-02-19 21:34                         ` Jonny Grant
  0 siblings, 0 replies; 31+ messages in thread
From: Jonny Grant @ 2023-02-19 21:34 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: Jonathan Wakely, Florian Weimer, Andrew Haley, gcc-help

I replied in wrong thread. Please ignore the wrapper for NULL static analysis  

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2023-02-20 10:36 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-19 22:05 Recursive SIGSEGV question Jonny Grant
2019-03-20  4:02 ` Florian Weimer
2019-03-20  8:11   ` Jonny Grant
2019-03-25 13:23   ` Jonny Grant
2019-03-25 13:27     ` Jonathan Wakely
2019-03-25 13:56     ` Florian Weimer
2019-03-25 14:01     ` Xi Ruoyao
2019-03-25 15:47       ` Florian Weimer
2019-03-25 16:10         ` Andrew Haley
2019-03-25 16:13           ` Jonny Grant
2019-03-25 16:23             ` Jonathan Wakely
2019-03-25 18:51           ` Florian Weimer
2019-03-25 20:39             ` Jonny Grant
2019-03-26  6:50               ` Xi Ruoyao
2019-03-27  0:29                 ` Jonathan Wakely
2019-03-27 21:34             ` Jonny Grant
2019-03-27 23:43               ` Jonathan Wakely
2019-03-27 23:51                 ` Jonny Grant
2019-03-28  8:26                   ` Xi Ruoyao
2019-03-28 11:52                     ` Jonathan Wakely
2019-03-29  2:24                     ` Jonny Grant
2019-03-30 17:32                       ` Jonny Grant
2023-02-19 21:21                       ` Jonny Grant
2023-02-19 21:34                         ` Jonny Grant
2019-03-28 13:55                   ` Jonathan Wakely
2019-03-28 14:39                     ` Jonny Grant
2019-03-28 14:39                       ` Jonathan Wakely
2019-03-25 20:28         ` Segher Boessenkool
2019-03-25 18:56       ` Segher Boessenkool
2019-03-25 22:05       ` Jonny Grant
2019-03-26 10:20         ` Xi Ruoyao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).