Bug 114935 - [14/15 regression] Miscompilation of initializer_list<std::string> in presence of exceptions since r14-1705-g2764335bd336f2
Summary: [14/15 regression] Miscompilation of initializer_list<std::string> in presenc...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 14.0
: P1 normal
Target Milestone: 14.0
Assignee: Jason Merrill
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2024-05-03 12:18 UTC by Martin Jambor
Modified: 2024-05-14 21:44 UTC (History)
5 users (show)

See Also:
Host: x86_64-linux-gnu
Target: x86_64-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-05-03 00:00:00


Attachments
attempt to reduce redundancy (1.55 KB, patch)
2024-05-14 21:44 UTC, Jason Merrill
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Jambor 2024-05-03 12:18:33 UTC
The following testcase:

#include <string>
#include <initializer_list>

void __attribute__((noipa))
tata(std::initializer_list<std::string> init)
{
  throw 1;
}

int
main()
{
  try
    {
      tata({ "0123456789012346" }); // using shorter string or "..."s works
    }
  catch (...)
    {
    }
}

aborts when compiled with GCC 14 even when not optimizing.

I have bisected the failure to r14-1705-g2764335bd336f2 (Jason
Merrill: c++: build initializer_list<string> in a loop [PR105838])

This has been extracted from libstorage-ng testsuite and originally
filed as https://bugzilla.opensuse.org/show_bug.cgi?id=1223820
Comment 1 Jason Merrill 2024-05-03 16:23:01 UTC
Without <string>:

#include <initializer_list>

int as;
struct A {
  A(const char *) { ++as; }
  A(const A&) { ++as; }
  ~A() { --as; }
};

void __attribute__((noipa))
tata(std::initializer_list<A> init)
{
  throw 1;
}

int
main()
{
  try { tata({ "foo","bar" }); }
  catch (...) { }

  if (as != 0) __builtin_abort ();
}



The problem is with the array EH cleanup handling: when we initialize an array of a type with a non-trivial destructor, such as the backing array for the initializer_list, we have a cleanup to destroy any constructed elements if a later constructor throws.  But in this case the call to tata is still in that region.  Without the r14-1705 change, we deal with that by disabling the array cleanup in split_nonconstant_init, but with the change we don't go through split_nonconstant_init and so we miss disabling the cleanup.
Comment 2 GCC Commits 2024-05-03 20:01:06 UTC
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:8f3afb83c879f1bfa722a963a07c06aaf174ef72

commit r15-138-g8f3afb83c879f1bfa722a963a07c06aaf174ef72
Author: Jason Merrill <jason@redhat.com>
Date:   Fri May 3 09:52:46 2024 -0400

    c++: initializer_list<string> and EH [PR114935]
    
    When we initialize an array of a type with a non-trivial destructor, such as
    the backing array for the initializer_list, we have a cleanup to destroy any
    constructed elements if a later constructor throws.  When the array being
    created is a variable, the end of that EH region naturally coincides with
    the beginning of the EH region for the cleanup for the variable as a whole.
    
    But if the array is a temporary, or a subobject of one, the array cleanup
    region lasts for the rest of the full-expression, along with the normal
    cleanup for the TARGET_EXPR.  As a result, when tata throws we clean it up
    twice.  Before r14-1705 we avoided this by disabling the array cleanup in
    split_nonconstant_init, but after that we don't go through
    split_nonconstant_init, so let's handle it in cp_genericize_target_expr.
    
            PR c++/114935
    
    gcc/cp/ChangeLog:
    
            * cp-gimplify.cc (cp_genericize_init): Add flags parm.
            (cp_genericize_init_expr): Pass nullptr.
            (cp_genericize_target_expr): Handle cleanup flags.
            * typeck2.cc (build_disable_temp_cleanup): Factor out of...
            (split_nonconstant_init): ...here.
            * cp-tree.h (build_disable_temp_cleanup): Declare.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/initlist-eh1.C: New test.
Comment 3 GCC Commits 2024-05-03 20:01:43 UTC
The releases/gcc-14 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:3b4d6b6ecd79df790bf0938dab1f51094f94d777

commit r14-10165-g3b4d6b6ecd79df790bf0938dab1f51094f94d777
Author: Jason Merrill <jason@redhat.com>
Date:   Fri May 3 09:52:46 2024 -0400

    c++: initializer_list<string> and EH [PR114935]
    
    When we initialize an array of a type with a non-trivial destructor, such as
    the backing array for the initializer_list, we have a cleanup to destroy any
    constructed elements if a later constructor throws.  When the array being
    created is a variable, the end of that EH region naturally coincides with
    the beginning of the EH region for the cleanup for the variable as a whole.
    
    But if the array is a temporary, or a subobject of one, the array cleanup
    region lasts for the rest of the full-expression, along with the normal
    cleanup for the TARGET_EXPR.  As a result, when tata throws we clean it up
    twice.  Before r14-1705 we avoided this by disabling the array cleanup in
    split_nonconstant_init, but after that we don't go through
    split_nonconstant_init, so let's handle it in cp_genericize_target_expr.
    
            PR c++/114935
    
    gcc/cp/ChangeLog:
    
            * cp-gimplify.cc (cp_genericize_init): Add flags parm.
            (cp_genericize_init_expr): Pass nullptr.
            (cp_genericize_target_expr): Handle cleanup flags.
            * typeck2.cc (build_disable_temp_cleanup): Factor out of...
            (split_nonconstant_init): ...here.
            * cp-tree.h (build_disable_temp_cleanup): Declare.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/initlist-eh1.C: New test.
    
    (cherry picked from commit 8f3afb83c879f1bfa722a963a07c06aaf174ef72)
Comment 4 Jason Merrill 2024-05-03 20:02:32 UTC
Fixed.
Comment 5 Jason Merrill 2024-05-14 21:44:26 UTC
Created attachment 58210 [details]
attempt to reduce redundancy

A failed attempt to avoid duplicate array cleanups in this case.