[Bug libstdc++/92577] New: Undefined behavior when using std::map with a noexcept allocator

2019-11-19 Thread lucas.bader at sap dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92577

Bug ID: 92577
   Summary: Undefined behavior when using std::map with a noexcept
allocator
   Product: gcc
   Version: 9.2.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: lucas.bader at sap dot com
  Target Milestone: ---

Created attachment 47296
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47296&action=edit
minimal code example

Using std::map with an allocator with a noexcept specifier leads to undefined
behavior when constructing a node in-place.

Compiled with GCC9 this results in the generation of a ud2 instruction that is
encountered when nullptr be retured by the allocation function:

$ g++ -std=c++17 -O3 allocator_ub.cpp
$ ./a.out
[2]114342 illegal hardware instruction (core dumped)  ./a.out

$ objdump -d a.out
00400780
<_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiE10mallocatorIS2_EE17_M_emplace_uniqueIJS0_IiiS0_ISt17_Rb_tree_iteratorIS2_EbEDpOT_>:
...
4008b3:   0f 0b   ud2

The corresponding stack trace in gdb is:

#0  0x004008b3 in std::pair >, bool> std::_Rb_tree,
std::_Select1st >, std::less,
mallocator > >::_M_emplace_unique
>(std::pair&&) ()
#1  0x00400632 in main ()

According to the C++17 working draft (8.3.4 paragraph 16):

"If the allocation function has a non-throwing exception specification, it
returns null to
indicate failure to allocate storage and a non-null pointer otherwise. [...]
If the allocation function is a non-allocating form (21.6.2.3) that returns
null, the behavior is undefined."

This is also supported by cppreference.com
(https://en.cppreference.com/w/cpp/language/new) with:

"If the standard placement allocation function returns a null pointer, which is
possible if the user passes a null pointer as the argument, the behavior is
undefined. (since C++17)"

The std::map implementation should handle this appropriately or prohibit using
it with an allocator that is defined noexcept.
When using an allocation function with the noexcept specifier (and thus
returning nullptr on failure), nullptr is passed to placement new (in
stl_tree.h) via the following code:

  2406 _M_emplace_unique(_Args&&... __args)
  2407 {
  2408  _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);


   628 _M_create_node(_Args&&... __args)
   629 {
   630  _Link_type __tmp = _M_get_node();
   631  _M_construct_node(__tmp, std::forward<_Args>(__args)...);


   579 _M_get_node()
   580 { return _Alloc_traits::allocate(_M_get_Node_allocator(), 1); }


   609 _M_construct_node(_Link_type __node, _Args&&... __args)
   610 {
   611  __try
   612{
   613 ::new(__node) _Rb_tree_node<_Val>;
   614 _Alloc_traits::construct(_M_get_Node_allocator(),
   615  __node->_M_valptr(),
   616  std::forward<_Args>(__args)...);
   617}
   618  __catch(...)
   619{
   620 __node->~_Rb_tree_node<_Val>();
   621 _M_put_node(__node);
   622 __throw_exception_again;
   623}
   624 }

[Bug libstdc++/92577] Undefined behavior when using std::map with a noexcept allocator

2019-11-19 Thread lucas.bader at sap dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92577

--- Comment #3 from Lucas Bader  ---
Thanks for the clarification. I know that the standard quotes refer to new and
I added them under the impression that an allocator is allowed to return
nullptr from its allocate function. This would make the call to new in
_M_construct_node undefined.

In the allocator requirements defined in the standard (20.5.3.5) it only says
that "allocate may throw an appropriate exception.". This sounds optional to
me, that's why I thought allocate could legally return nullptr.

[Bug preprocessor/79106] wrong source line printed in diagnostics for a translation unit

2019-12-09 Thread lucas.bader at sap dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79106

Lucas Bader  changed:

   What|Removed |Added

 CC||lucas.bader at sap dot com

--- Comment #7 from Lucas Bader  ---
Created attachment 47443
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47443&action=edit
Proposed patch

This behavior (opening the original source file for diagnostics) also causes
issues when compiling within a compile cluster because only preprocessed files
are distributed. This results in wrong or no source lines being printed.

The attached patch attempts to alter the behavior by implementing a
location_get_source_line_preprocessed function that can be used in
diagnostic-show-locus.c in case a preprocessed file is compiled.