[Bug c++/107555] New: Never constructed object destroyed during exception handling

boris at kolpackov dot net gcc-bugzilla@gcc.gnu.org
Mon Nov 7 13:34:49 GMT 2022


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107555

            Bug ID: 107555
           Summary: Never constructed object destroyed during exception
                    handling
           Product: gcc
           Version: 12.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: boris at kolpackov dot net
  Target Milestone: ---

I have a fairly complex function (nested loops, try-catch blocks, etc) that on
throwing an exceptions tries to destroy a stack object (suspected to be the
return value) that was never constructed. This feels like a mis-compilation
introduced in GCC 12 because:

1. The issue disappears if optimization is enabled.

2. The issue disappears if I get rid of the return value with otherwise minimal
changes.

3. Does not reproduce with GCC 11 or 10 in otherwise the same build.

I am not sure what's the best way to debug this. Coming up with a minimal
reproduce feels hopeless. But I can easily provide the instructions on how to
reproduce this on the actual source code. In the meantime, I will capture some
background below:

The relevant fragment of the stack trace looks like this:

#18 0x00007f7472e5d270 in std::pair<build2::file_cache::entry, bool>::~pair
(this=0x7ffdbe099e30, __in_chrg=<optimized out>) at
/usr/include/c++/12/bits/stl_pair.h:185
#19 0x00007f7472e4ab19 in build2::cc::compile_rule::extract_headers (....) at
.../compile-rule.cxx:4768

The pair object being destroyed at frame #18 was never constructed and
eventually leads to "free(): invalid pointer" and abort. The extract_headers()
function has the following overall structure (only what I believe are the
relevant parts are shown):

pair<file_cache::entry, bool> compile_rule::
extract_headers (....)
{

  ...

  if (something)
   return make_pair (file_cache::entry (), false);  // <-- one of early returns

  ...


  try
  {
    ...

    if (something)
      throw failed ();             // <-- the exception that is thrown

  }                                // <-- line 4768
  catch (const process_error& e)
  {
    ...

    throw failed ();
  }

  ...

  return make_pair (move (psrc), puse); 
}

As can be seen, the function has a bunch of early returns. Other than the
returns, it does not construct any pair<file_cache::entry, bool> instances.

The call site look like this:

pair<file_cache::entry, bool> psrc (file_cache::entry (), false);

if (something)
{
  ...
  psrc = extract_headers (....); 
}

Note that I checked and the `this` pointer from frame #18 does not point to
psrc form the call site.

I was able to work around this issue by getting rid of the return type and
instead passing the result object by reference:

void compile_rule::
extract_headers (...., pair<file_cache::entry, bool>& result)
{
    ...

  if (something)
   return;

  ...

  result.first = move (psrc);
  result.second = puse;
}

And the call site:

pair<file_cache::entry, bool> psrc (file_cache::entry (), false);
if (something)
{
  ...
  extract_headers (...., psrc);  
}


More information about the Gcc-bugs mailing list