Bug 23257 - Incorrect exception-handling behavior with references
Summary: Incorrect exception-handling behavior with references
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: EH, wrong-code
Depends on:
Blocks:
 
Reported: 2005-08-06 00:25 UTC by Mark Mitchell
Modified: 2023-11-19 19:13 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-08-25 13:58:06


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Mitchell 2005-08-06 00:25:29 UTC
This program

===
struct Base {};
struct Derived : virtual Base {};

Derived derived;
Base base;

int main() {
  Base *b = &derived;

  try {
    try {
      throw b;
    } catch (Base*& br) {
      br = &base;
      throw;
    }
  } catch (Base*& br) {
    if (br != &base)
      return 1;
  }
}
===

should exit with code zero, but does not.
Comment 1 Andrew Pinski 2005-08-06 06:09:30 UTC
Hmm, ICC 8.0 produces the same result as GCC.
Comment 2 Andrew Pinski 2005-10-17 15:05:00 UTC
Hmm, this looks related to DR 388.
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
Comment 3 Chris Rimmer 2008-01-16 12:08:07 UTC
I've just encountered the same issue.  My reading of the standard says that it is a bug.

  15.3 [except.handle] paragraph 3
  A handler is a match for an exception object of type E if
  - The handler is of type cv T or cv T& and [...]
  - the handler is of type cv T or cv T& and [...]
  - the handler is of type cv1 T* cv2 and E is a pointer type that can be converted to the type of the handler by [...]
  [...]

Note the lack of "or cv1 T* cv2 &" in the third list item.

Interestingly, the document "The Exception Handling ABI for the ARM Architecture" (http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf) defines (in 8.4.2 - Personality routine helper functions) a function __cxa_type_match which takes an argument 'bool is_reference_type'.
Comment 4 Chris Rimmer 2008-01-17 09:52:35 UTC
Sorry - my earlier comment was addressing the behaviour of GCC with respect to the DR, not the program in this bug report.

The situation in the DR is where the static type of the thrown object is 'Derived*', which the standard says should not be handled by a handler for 'Base*&'.  GCC incorrectly catches the exception in this case.

The situation in the original bug report is where the static type of the thrown object is 'Base*', so the handler should handle the exception, since 15.3 [except.handle]/3, first list item, says that a handler of type T& is a match for an exception of type E if E and T are the same type.  (E and T are 'Base*' in this case).

The GCC behaviour is a bug because 15.3 [except.handle]/19 says:

"When the handler declares a reference to a non-constant object, any changes to the referenced object are changes to the temporary object initialised when the throw-expression was executed and will have effect should that object be rethrown."

GCC binds the reference to a different object in each handler.  We can see this by adding:

  std::cout << "&br = " << (void *) &br << '\n';

to each handler.  When I ran this, the output was:

  &br = 0xbfb923e8
  &br = 0xbfb923ec

(gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21))
Comment 5 Mark Mitchell 2008-01-20 20:13:42 UTC
This is a known bug in the Itanium C++ ABI.  ARM noticed this; there variant of the C++ ABI has the additional is_reference parameter precisely to correctly handle this case.

I looked at this in some detail at one point and concluded that the only ways we could fix it would require a binary-compatibility break with previous releases.  Perhaps the next major libstdc++ upgrade would be a good opportunity for that.
Comment 6 Wolfgang Bangerth 2009-08-25 13:58:06 UTC
Confirmed.

Nathan, is this the bug you had worked on? If so, it may be of interest to
add a link to your patch to this PR for reference.

W.
Comment 7 Andrew Pinski 2021-08-09 18:09:00 UTC
Hmm, ICC and clang have the same behavior as GCC but they might be using the same libstdc++ here and such.
Comment 8 Jonathan Wakely 2021-08-09 23:14:46 UTC
LLVM's libc++abi.so gives the same result, because it's a property of the Itanium ABI not GCC's implementation of it.