{
if (m_is_rethrow)
{
- auto eh_node = model->get_current_caught_exception ();
- gcc_assert (eh_node);
- model->push_thrown_exception (*eh_node);
+ if (auto eh_node = model->get_current_caught_exception ())
+ model->push_thrown_exception (*eh_node);
+ else
+ {
+ /* We have a rethrow of some unknown exception.
+ We don't have a good way of representing this;
+ leave the exception stack empty. */
+ }
}
else
{
if (is_rethrow)
{
const exception_node *eh_node = model->get_current_caught_exception ();
- gcc_assert (eh_node);
- type = eh_node->maybe_get_type ();
+ if (eh_node)
+ type = eh_node->maybe_get_type ();
+ else
+ {
+ /* We have a "throw;" but no exception to rethrow.
+ Presumably the top-level of the analysis is an
+ entrypoint for handling exceptions, so we will
+ simulate fully unwinding. */
+ }
}
else
{
--- /dev/null
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+/* Top-level rethrow (PR analyzer/123880). */
+
+void test_1 ()
+{
+ throw;
+}
+
+/* Intraprocedural leak involving a rethrow. */
+
+void test_2 ()
+{
+ void *p = __builtin_malloc (1024);
+ throw; // { dg-warning "leak of 'p'" }
+ // { dg-message "rethrowing exception here\.\.\." "rethrow event" { target *-*-* } .-1 }
+}
+
+/* Interprocedural leak involving a rethrow. */
+
+static void called_by_test_3 ()
+{
+ throw; // { dg-warning "leak of 'p'" }
+ // { dg-message "rethrowing exception here\.\.\." "rethrow event" { target *-*-* } .-1 }
+}
+
+void test_3 ()
+{
+ void *p = __builtin_malloc (1024); // { dg-message "allocated here" }
+ called_by_test_3 ();
+}
+
+/* Rethrow of a rethrow. */
+
+void test_4 ()
+{
+ try
+ {
+ throw;
+ }
+ catch (...)
+ {
+ __analyzer_dump_path (); // { dg-message "path" "" { xfail *-*-* } }
+ throw;
+ }
+}