libbacktrace integration for _GLIBCXX_DEBUG mode

François Dumont frs.dumont@gmail.com
Fri Jun 7 16:21:00 GMT 2019


I forgot to comment on the chosen behavior of _GLIBCXX_DEBUG_BACKTRACE.

So, if the user define it, it means that he has install libbacktrace on 
its system. However we silently ignore it if libbacktrace is eventually 
not supported. I think it is the simplest thing to do. I am not 
convinced by the #warning. Personnaly I always try to build without any 
warnings and most of the time I consider warnings as errors.

Regarding the post-treatment I introduced here is an example of 
transformation.

BEFORE:
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:606:
In function:
     std::__debug::vector<_Tp, _Allocator>::iterator
     std::__debug::vector<_Tp, 
_Allocator>::insert(std::__debug::vector<_Tp,
     _Allocator>::const_iterator, _InputIterator, _InputIterator) [with
     _InputIterator =
std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int>*, 

     std::__cxx1998::vector<std::unique_ptr<int>,
     std::allocator<std::unique_ptr<int> > > >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag> >; <template-parameter-2-2> = 
void; _Tp
     = std::unique_ptr<int>; _Allocator = 
std::allocator<std::unique_ptr<int>
     >; std::__debug::vector<_Tp, _Allocator>::iterator =
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int>*, 

     std::__cxx1998::vector<std::unique_ptr<int>,
     std::allocator<std::unique_ptr<int> > > >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag>; typename 
std::iterator_traits<typename
     std::__cxx1998::vector<_Tp, _Alloc>::iterator>::iterator_category =
     std::random_access_iterator_tag; typename std::__cxx1998::vector<_Tp,
     _Alloc>::iterator = 
__gnu_cxx::__normal_iterator<std::unique_ptr<int>*,
     std::__cxx1998::vector<std::unique_ptr<int>,
     std::allocator<std::unique_ptr<int> > > >; std::__debug::vector<_Tp,
     _Allocator>::const_iterator =
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const
     std::unique_ptr<int>*, std::__cxx1998::vector<std::unique_ptr<int>,
     std::allocator<std::unique_ptr<int> > > >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag>; typename 
std::iterator_traits<typename
     std::__cxx1998::vector<_Tp, 
_Alloc>::const_iterator>::iterator_category
     = std::random_access_iterator_tag; typename 
std::__cxx1998::vector<_Tp,
     _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const
     std::unique_ptr<int>*, std::__cxx1998::vector<std::unique_ptr<int>,
     std::allocator<std::unique_ptr<int> > > >]

Backtrace:
     0x4029ff 
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, 
std::default_delete<int> >, std::allocator<std::unique_ptr<int, 
std::default_delete<int> > > > >, 
std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, 
std::allocator<std::unique_ptr<int, std::default_delete<int> > > >, 
std::random_access_iterator_tag> 
std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, 
std::allocator<std::unique_ptr<int, std::default_delete<int> > > 
 >::insert<std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >, std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >, std::random_access_iterator_tag> >, void>(__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> > const*, std::__cxx1998::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >, std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >, std::random_access_iterator_tag>, std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >, std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >, std::random_access_iterator_tag> >, std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >, std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >, std::random_access_iterator_tag> >)
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:606
     0x4030cc test01()
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/insert7_neg.cc:34
     0x401458 main
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/insert7_neg.cc:42

Error: attempt to insert with an iterator range [__first, __last) from this
container.

Objects involved in the operation:
     iterator "__first" @ 0x0x7ffd719fc0f0 {
       type = 
std::move_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, 
std::default_delete<int> >, std::allocator<std::unique_ptr<int, 
std::default_delete<int> > > > > > (mutable iterator);
       state = dereferenceable (start-of-sequence);
       references sequence with type 
'std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, 
std::allocator<std::unique_ptr<int, std::default_delete<int> > > >' @ 
0x0x7ffd719fc4d0
     }
     iterator "__last" @ 0x0x7ffd719fc0f0 {
       type = 
std::move_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::__cxx1998::vector<std::unique_ptr<int, 
std::default_delete<int> >, std::allocator<std::unique_ptr<int, 
std::default_delete<int> > > > > > (mutable iterator);
       state = past-the-end;
       references sequence with type 
'std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >, 
std::allocator<std::unique_ptr<int, std::default_delete<int> > > >' @ 
0x0x7ffd719fc4d0
     }
     sequence "this" @ 0x0x7ffd719fc4d0 {
       type = std::__debug::vector<std::unique_ptr<int, 
std::default_delete<int> >, std::allocator<std::unique_ptr<int, 
std::default_delete<int> > > >;
     }
XFAIL: 23_containers/vector/debug/insert7_neg.cc execution test

AFTER:
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:606:
In function:
     std::__debug::vector<_Tp, _Allocator>::iterator
     std::__debug::vector<_Tp, 
_Allocator>::insert(std::__debug::vector<_Tp,
     _Allocator>::const_iterator, _InputIterator, _InputIterator) [with
     _InputIterator =
std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int>*, 

     std::vector<std::unique_ptr<int>> >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag> >; <template-parameter-2-2> = 
void; _Tp
     = std::unique_ptr<int>; _Allocator = 
std::allocator<std::unique_ptr<int>
     >; std::__debug::vector<_Tp, _Allocator>::iterator =
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int>*, 

     std::vector<std::unique_ptr<int>> >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag>; typename 
std::iterator_traits<typename
     std::vector<_Tp, _Alloc>::iterator>::iterator_category =
     std::random_access_iterator_tag; typename std::vector<_Tp,
     _Alloc>::iterator = 
__gnu_cxx::__normal_iterator<std::unique_ptr<int>*,
     std::vector<std::unique_ptr<int>> >; std::__debug::vector<_Tp,
     _Allocator>::const_iterator =
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const
     std::unique_ptr<int>*, std::vector<std::unique_ptr<int>> >,
     std::__debug::vector<std::unique_ptr<int> >,
     std::random_access_iterator_tag>; typename 
std::iterator_traits<typename
     std::vector<_Tp, _Alloc>::const_iterator>::iterator_category =
     std::random_access_iterator_tag; typename std::vector<_Tp,
     _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const
     std::unique_ptr<int>*, std::vector<std::unique_ptr<int>> >]

Backtrace:
     0x4029ff 
__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::vector<std::unique_ptr<int, 
std::default_delete<int> >> >> std::__debug::vector<std::unique_ptr<int, 
std::default_delete<int> 
 >>::insert<std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::vector<std::unique_ptr<int, std::default_delete<int> >> >> >, void>(__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> > const*, std::vector<std::unique_ptr<int, std::default_delete<int> >> >>, std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::vector<std::unique_ptr<int, std::default_delete<int> >> >> >, std::move_iterator<__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, std::default_delete<int> >*, std::vector<std::unique_ptr<int, std::default_delete<int> >> >> >)
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:606
     0x4030cc test01()
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/insert7_neg.cc:34
     0x401458 main
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/insert7_neg.cc:42

Error: attempt to insert with an iterator range [__first, __last) from this
container.

Objects involved in the operation:
     iterator "__first" @ 0x0x7fffdbf5ea10 {
       type = 
std::move_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::vector<std::unique_ptr<int, 
std::default_delete<int> >> > > (mutable iterator);
       state = dereferenceable (start-of-sequence);
       references sequence with type 
'std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >>' 
@ 0x0x7fffdbf5edf0
     }
     iterator "__last" @ 0x0x7fffdbf5ea10 {
       type = 
std::move_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<int, 
std::default_delete<int> >*, std::vector<std::unique_ptr<int, 
std::default_delete<int> >> > > (mutable iterator);
       state = past-the-end;
       references sequence with type 
'std::__debug::vector<std::unique_ptr<int, std::default_delete<int> >>' 
@ 0x0x7fffdbf5edf0
     }
     sequence "this" @ 0x0x7fffdbf5edf0 {
       type = std::__debug::vector<std::unique_ptr<int, 
std::default_delete<int> >>;
     }
XFAIL: 23_containers/vector/debug/insert7_neg.cc execution test

It is just better, not ideal of course. And you are right, current code 
can fail to do the proper thing.

I am clearly not the first one to try such a thing and to struggle to do 
so. So just tell me if you prefer I keep the original labels and I'll do so.

François


On 6/6/19 11:43 PM, Jonathan Wakely wrote:
> On 06/06/19 22:33 +0200, François Dumont wrote:
>> Here is what I come up with.
>>
>>
>> Regarding allocation in print_function I would also prefer to avoid 
>> it. But this patch also aim at creating a backtrace_state object in 
>> case of UB so the alloc is perhaps not so important. I can't use 
>> string_view as I need to modify it to display only a part of it 
>
> I was only referring to these strings, which allocated memory on every
> call to print_function, but you don't modify:
>
> +    const string cxx1998 = "__cxx1998::";
> +    const string allocator = ", std::allocator<";
> +    const string safe_iterator = "__gnu_debug::_Safe_iterator<";
>
> I see you've changed them now though.
>
>> through fsprintf. I could try to use "%.*s" however. I haven't also 
>> consider your remark about template parameters containing '<' yet.
>>
>>
>>>> +#if defined(_GLIBCXX_DEBUG_BACKTRACE)
>>>> +# if !defined(BACKTRACE_SUPPORTED)
>>>> +#  if defined(__has_include) && 
>>>> !__has_include(<backtrace-supported.h>)
>>>> +#   error No libbacktrace backtrace-supported.h file found.
>>>> +#  endif
>>>> +#  include <backtrace-supported.h>
>>>> +# endif
>>>> +# if !BACKTRACE_SUPPORTED
>>>> +#  error libbacktrace not supported.
>>>> +# endif
>>>> +# include <backtrace.h>
>>>> +#else
>>>> +# include <stdint.h> // For uintptr_t.
>>>
>>> Please use <cstdint> and std::uintptr_t.
>>
>> I did so but then realized that to do so I had to be in C++11 mode. I 
>> used tr1/cstdint in pre-C++11 mode.
>
> Ugh, right, of course, sorry.
>
> Then I guess <stdint.h> is better than relying on TR1 (even though
> <stdint.h> isn't technically part of C++98 either).
>
>




More information about the Libstdc++ mailing list