@@ -521,8 +521,12 @@ impl_region_model_context::on_state_leak (const state_machine &sm,
}
}
- sm.on_leak (&sm_ctxt, m_enode_for_diag->get_supernode (), m_stmt,
- leaked_tree, state);
+ pending_diagnostic *pd = sm.on_leak (leaked_tree);
+ if (pd)
+ m_eg->get_diagnostic_manager ().add_diagnostic
+ (&sm, m_enode_for_diag, m_enode_for_diag->get_supernode (),
+ m_stmt, &stmt_finder,
+ leaked_tree, state, pd);
}
/* Implementation of region_model_context::on_inherited_svalue vfunc
@@ -52,12 +52,8 @@ public:
enum tree_code op,
tree rhs) const FINAL OVERRIDE;
- void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
+ pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
/* Start state. */
state_t m_start;
@@ -299,24 +295,6 @@ fileptr_state_machine::on_condition (sm_context *sm_ctxt,
}
}
-/* Implementation of state_machine::on_leak vfunc for
- fileptr_state_machine.
- Complain about leaks of FILE * in state 'unchecked' and 'nonnull'. */
-
-void
-fileptr_state_machine::on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state ATTRIBUTE_UNUSED)
- const
-{
- sm_ctxt->warn_for_state (node, stmt, var, m_unchecked,
- new file_leak (*this, var));
- sm_ctxt->warn_for_state (node, stmt, var, m_nonnull,
- new file_leak (*this, var));
-}
-
/* Implementation of state_machine::can_purge_p vfunc for fileptr_state_machine.
Don't allow purging of pointers in state 'unchecked' or 'nonnull'
(to avoid false leak reports). */
@@ -327,6 +305,16 @@ fileptr_state_machine::can_purge_p (state_t s) const
return s != m_unchecked && s != m_nonnull;
}
+/* Implementation of state_machine::on_leak vfunc for
+ fileptr_state_machine, for complaining about leaks of FILE * in
+ state 'unchecked' and 'nonnull'. */
+
+pending_diagnostic *
+fileptr_state_machine::on_leak (tree var) const
+{
+ return new file_leak (*this, var);
+}
+
} // anonymous namespace
/* Internal interface to this file. */
@@ -54,12 +54,8 @@ public:
enum tree_code op,
tree rhs) const FINAL OVERRIDE;
- void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
+ pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
/* Start state. */
state_t m_start;
@@ -761,23 +757,6 @@ malloc_state_machine::on_condition (sm_context *sm_ctxt,
}
}
-/* Implementation of state_machine::on_leak vfunc for malloc_state_machine.
- Complain about leaks of pointers in state 'unchecked' and 'nonnull'. */
-
-void
-malloc_state_machine::on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state ATTRIBUTE_UNUSED)
- const
-{
- sm_ctxt->warn_for_state (node, stmt, var, m_unchecked,
- new malloc_leak (*this, var));
- sm_ctxt->warn_for_state (node, stmt, var, m_nonnull,
- new malloc_leak (*this, var));
-}
-
/* Implementation of state_machine::can_purge_p vfunc for malloc_state_machine.
Don't allow purging of pointers in state 'unchecked' or 'nonnull'
(to avoid false leak reports). */
@@ -788,6 +767,16 @@ malloc_state_machine::can_purge_p (state_t s) const
return s != m_unchecked && s != m_nonnull;
}
+/* Implementation of state_machine::on_leak vfunc for malloc_state_machine
+ (for complaining about leaks of pointers in state 'unchecked' and
+ 'nonnull'). */
+
+pending_diagnostic *
+malloc_state_machine::on_leak (tree var) const
+{
+ return new malloc_leak (*this, var);
+}
+
} // anonymous namespace
/* Internal interface to this file. */
@@ -56,11 +56,6 @@ public:
enum tree_code op,
tree rhs) const FINAL OVERRIDE;
- void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
private:
@@ -136,18 +131,6 @@ pattern_test_state_machine::on_condition (sm_context *sm_ctxt,
sm_ctxt->warn_for_state (node, stmt, lhs, m_start, diag);
}
-void
-pattern_test_state_machine::on_leak (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
- const supernode *node ATTRIBUTE_UNUSED,
- const gimple *stmt ATTRIBUTE_UNUSED,
- tree var ATTRIBUTE_UNUSED,
- state_machine::state_t state
- ATTRIBUTE_UNUSED)
- const
-{
- /* Empty. */
-}
-
bool
pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
{
@@ -54,11 +54,6 @@ public:
enum tree_code op,
tree rhs) const FINAL OVERRIDE;
- void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
private:
@@ -181,17 +176,6 @@ sensitive_state_machine::on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
/* Empty. */
}
-void
-sensitive_state_machine::on_leak (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
- const supernode *node ATTRIBUTE_UNUSED,
- const gimple *stmt ATTRIBUTE_UNUSED,
- tree var ATTRIBUTE_UNUSED,
- state_machine::state_t state ATTRIBUTE_UNUSED)
- const
-{
- /* Empty. */
-}
-
bool
sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
{
@@ -55,11 +55,6 @@ public:
enum tree_code op,
tree rhs) const FINAL OVERRIDE;
- void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
/* Start state. */
@@ -310,17 +305,6 @@ taint_state_machine::on_condition (sm_context *sm_ctxt,
}
}
-void
-taint_state_machine::on_leak (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
- const supernode *node ATTRIBUTE_UNUSED,
- const gimple *stmt ATTRIBUTE_UNUSED,
- tree var ATTRIBUTE_UNUSED,
- state_machine::state_t state ATTRIBUTE_UNUSED)
- const
-{
- /* Empty. */
-}
-
bool
taint_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
{
@@ -73,17 +73,17 @@ public:
const gimple *stmt,
tree lhs, enum tree_code op, tree rhs) const = 0;
- virtual void on_leak (sm_context *sm_ctxt,
- const supernode *node,
- const gimple *stmt,
- tree var,
- state_machine::state_t state) const = 0;
-
/* Return true if it safe to discard the given state (to help
when simplifying state objects).
States that need leak detection should return false. */
virtual bool can_purge_p (state_t s) const = 0;
+ /* Called when VAR leaks (and !can_purge_p). */
+ virtual pending_diagnostic *on_leak (tree var ATTRIBUTE_UNUSED) const
+ {
+ return NULL;
+ }
+
void validate (state_t s) const;
protected:
@@ -8,12 +8,12 @@ static jmp_buf env;
static void inner (void)
{
- longjmp (env, 1); /* { dg-warning "leak of 'ptr'" "" { xfail *-*-* } } */
+ longjmp (env, 1); /* { dg-warning "leak of 'ptr'" } */
}
static void middle (void)
{
- void *ptr = malloc (1024); /* { dg-message "allocated here" "" { xfail *-*-* } } */
+ void *ptr = malloc (1024); /* { dg-message "allocated here" } */
inner ();
free (ptr);
}
new file mode 100644
@@ -0,0 +1,101 @@
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-nn-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+#include <setjmp.h>
+#include <stdlib.h>
+
+extern void foo (int);
+
+static jmp_buf env;
+
+static void inner (void)
+{
+ longjmp (env, 1); /* { dg-warning "leak of 'ptr'" } */
+}
+
+static void middle (void)
+{
+ void *ptr = malloc (1024);
+ inner ();
+ free (ptr);
+}
+
+void outer (void)
+{
+ int i;
+
+ foo (0);
+
+ i = setjmp(env);
+
+ if (i == 0)
+ {
+ foo (1);
+ middle ();
+ }
+
+ foo (3);
+}
+
+/* { dg-begin-multiline-output "" }
+ NN | longjmp (env, 1);
+ | ^~~~~~~~~~~~~~~~
+ 'outer': event 1
+ |
+ | NN | void outer (void)
+ | | ^~~~~
+ | | |
+ | | (1) entry to 'outer'
+ |
+ 'outer': event 2
+ |
+ | NN | i = setjmp(env);
+ | | ^~~~~~
+ | | |
+ | | (2) 'setjmp' called here
+ |
+ 'outer': events 3-5
+ |
+ | NN | if (i == 0)
+ | | ^
+ | | |
+ | | (3) following 'true' branch (when 'i == 0')...
+ | NN | {
+ | NN | foo (1);
+ | | ~~~~~~~
+ | | |
+ | | (4) ...to here
+ | NN | middle ();
+ | | ~~~~~~~~~
+ | | |
+ | | (5) calling 'middle' from 'outer'
+ |
+ +--> 'middle': events 6-8
+ |
+ | NN | static void middle (void)
+ | | ^~~~~~
+ | | |
+ | | (6) entry to 'middle'
+ | NN | {
+ | NN | void *ptr = malloc (1024);
+ | | ~~~~~~~~~~~~~
+ | | |
+ | | (7) allocated here
+ | NN | inner ();
+ | | ~~~~~~~~
+ | | |
+ | | (8) calling 'inner' from 'middle'
+ |
+ +--> 'inner': events 9-10
+ |
+ | NN | static void inner (void)
+ | | ^~~~~
+ | | |
+ | | (9) entry to 'inner'
+ | NN | {
+ | NN | longjmp (env, 1);
+ | | ~~~~~~~~~~~~~~~~
+ | | |
+ | | (10) 'ptr' leaks here; was allocated at (7)
+ |
+ { dg-end-multiline-output "" } */
+// TODO: show the rewind to the setjmp