This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

EH verifier/dumper


Hi,
this patch adds simple EH verification and dumping facility. Not 100%
complette but good enought to hunt down misscompilation I faced and
another two latent bugs.
With previous patch to fix BB duplication it still fails with one
testcase on mainline (but not tree-profiling)

ext/stdio_sync_filebuf/wchar_t/12077.cc (test for excess errors)

I am going to look into this one now.  At the moment it verifies only
the conservative side (Ie that the EH statements do have proper EH
edges).  I also added check that EH statements can trap and this catch
number of extra positives (and we do have similar code in verify_stmts
just we don't use this verifier very much), so I will address this by
followup patch.
OK?
Honza

2005-04-25  Jan Hubicka  <jh@suse.cz>
	* except.c: Include diagnostic.h
	(dump_eh_tree, verify_eh_tree): New functions.
	* except.h (verify_eh_tree, dump_eh_tree, verify_eh_edges): Declare.
	* tree-cfg.c (tree_verify_flow_info): verify eh edges.
	(dump_function_to_file): dump eh tree.
	* tree-eh.c (mark_eh_edge): New function.
	(mark_eh_edge_found_error): New static variable.
	(verify_eh_edges): New function.

Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.302
diff -c -3 -p -r1.302 except.c
*** except.c	22 Apr 2005 08:16:50 -0000	1.302
--- except.c	24 Apr 2005 15:12:29 -0000
*************** Software Foundation, 59 Temple Place - S
*** 74,79 ****
--- 74,80 ----
  #include "target.h"
  #include "langhooks.h"
  #include "cgraph.h"
+ #include "diagnostic.h"
  
  /* Provide defaults for stuff that may not be defined when using
     sjlj exceptions.  */
*************** output_function_exception_table (void)
*** 3435,3438 ****
--- 3436,3571 ----
    current_function_section (current_function_decl);
  }
  
+ /* Dump EH information to OUT.  */
+ void 
+ dump_eh_tree (FILE *out, struct function *fun)
+ {
+   struct eh_region *i;
+   int depth = 0;
+   static const char * const type_name[] = {"unknown", "cleanup", "try", "catch",
+ 					   "allowed_exceptions", "must_not_throw",
+ 					   "throw", "fixup"};
+ 
+   i = fun->eh->region_tree;
+   if (! i)
+     return;
+ 
+   fprintf (out, "Eh tree:\n");
+   while (1)
+     {
+       fprintf (out, "  %*s %i %s", depth * 2, "",
+ 	       i->region_number, type_name [(int)i->type]);
+       if (i->tree_label)
+ 	{
+           fprintf (out, " tree_label:");
+ 	  print_generic_expr (out, i->tree_label, 0);
+ 	}
+       fprintf (out, "\n");
+       /* If there are sub-regions, process them.  */
+       if (i->inner)
+ 	i = i->inner, depth++;
+       /* If there are peers, process them.  */
+       else if (i->next_peer)
+ 	i = i->next_peer;
+       /* Otherwise, step back up the tree to the next peer.  */
+       else
+ 	{
+ 	  do {
+ 	    i = i->outer;
+ 	    depth--;
+ 	    if (i == NULL)
+ 	      return;
+ 	  } while (i->next_peer == NULL);
+ 	  i = i->next_peer;
+ 	}
+     }
+ }
+ 
+ /* Verify some basic invariants on EH datastructures.  Could be extended to
+    catch more.  */
+ void 
+ verify_eh_tree (struct function *fun)
+ {
+   struct eh_region *i, *outer = NULL;
+   bool err = false;
+   int nvisited = 0;
+   int count = 0;
+   int j;
+   int depth = 0;
+ 
+   i = fun->eh->region_tree;
+   if (! i)
+     return;
+   for (j = fun->eh->last_region_number; j > 0; --j)
+     if (fun->eh->region_array[j])
+       {
+ 	count++;
+ 	if (fun->eh->region_array[j]->region_number != j)
+ 	  {
+ 	    error ("region_array is corrupted for region %i", i->region_number);
+ 	    err = true;
+ 	  }
+       }
+ 
+   while (1)
+     {
+       if (fun->eh->region_array[i->region_number] != i)
+ 	{
+ 	  error ("region_array is corrupted for region %i", i->region_number);
+ 	  err = true;
+ 	}
+       if (i->outer != outer)
+ 	{
+ 	  error ("outer block of region %i is wrong", i->region_number);
+ 	  err = true;
+ 	}
+       if (i->may_contain_throw && outer && !outer->may_contain_throw)
+ 	{
+ 	  error ("region %i may contain throw and is contained in region that may not",
+ 		 i->region_number);
+ 	  err = true;
+ 	}
+       if (depth < 0)
+ 	{
+ 	  error ("negative nesting depth of region %i", i->region_number);
+ 	  err = true;
+ 	}
+       nvisited ++;
+       /* If there are sub-regions, process them.  */
+       if (i->inner)
+ 	outer = i, i = i->inner, depth++;
+       /* If there are peers, process them.  */
+       else if (i->next_peer)
+ 	i = i->next_peer;
+       /* Otherwise, step back up the tree to the next peer.  */
+       else
+ 	{
+ 	  do {
+ 	    i = i->outer;
+ 	    depth--;
+ 	    if (i == NULL)
+ 	      {
+ 		if (depth != -1)
+ 		  {
+ 		    error ("Tree list ends on depth %i", depth + 1);
+ 		    err = true;
+ 		  }
+ 		if (count != nvisited)
+ 		  {
+ 		    error ("array does not match the region tree");
+ 		    err = true;
+ 		  }
+ 		if (err)
+ 		  {
+ 		    dump_eh_tree (stderr, fun);
+ 		    internal_error ("verify_eh_tree failed.");
+ 		  }
+ 	        return;
+ 	      }
+ 	    outer = i->outer;
+ 	  } while (i->next_peer == NULL);
+ 	  i = i->next_peer;
+ 	}
+     }
+ }
  #include "gt-except.h"
Index: except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.82
diff -c -3 -p -r1.82 except.h
*** except.h	14 Mar 2005 13:10:50 -0000	1.82
--- except.h	24 Apr 2005 15:12:29 -0000
*************** extern void foreach_reachable_handler (i
*** 101,109 ****
--- 101,112 ----
  
  extern void collect_eh_region_array (void);
  extern void expand_resx_expr (tree);
+ extern void verify_eh_tree (struct function *);
+ extern void dump_eh_tree (FILE *, struct function *);
  
  /* tree-eh.c */
  extern int lookup_stmt_eh_region (tree);
+ extern bool verify_eh_edges (tree);
  
  /* If non-NULL, this is a function that returns an expression to be
     executed if an unhandled exception is propagated out of a cleanup
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v
retrieving revision 2.179
diff -c -3 -p -r2.179 tree-cfg.c
*** tree-cfg.c	23 Apr 2005 21:27:56 -0000	2.179
--- tree-cfg.c	24 Apr 2005 15:12:29 -0000
*************** tree_verify_flow_info (void)
*** 3761,3766 ****
--- 3761,3768 ----
  
        stmt = bsi_stmt (bsi);
  
+       err |= verify_eh_edges (stmt);
+ 
        if (is_ctrl_stmt (stmt))
  	{
  	  FOR_EACH_EDGE (e, ei, bb->succs)
*************** dump_function_to_file (tree fn, FILE *fi
*** 4947,4952 ****
--- 4953,4960 ----
      }
    fprintf (file, ")\n");
  
+   if (flags & TDF_DETAILS)
+     dump_eh_tree (file, DECL_STRUCT_FUNCTION (fn));
    if (flags & TDF_RAW)
      {
        dump_node (fn, TDF_SLIM | flags, file);
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 2.32
diff -c -3 -p -r2.32 tree-eh.c
*** tree-eh.c	23 Apr 2005 21:26:26 -0000	2.32
--- tree-eh.c	24 Apr 2005 15:12:30 -0000
*************** make_eh_edges (tree stmt)
*** 1746,1751 ****
--- 1746,1842 ----
    foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt);
  }
  
+ static bool mark_eh_edge_found_error;
+ 
+ /* Mark edge make_eh_edge would create for given region by setting it aux
+    field, output error if something goes wrong.  */
+ static void
+ mark_eh_edge (struct eh_region *region, void *data)
+ {
+   tree stmt, lab;
+   basic_block src, dst;
+   edge e;
+ 
+   stmt = data;
+   lab = get_eh_region_tree_label (region);
+ 
+   src = bb_for_stmt (stmt);
+   dst = label_to_block (lab);
+ 
+   e = find_edge (src, dst);
+   if (!e)
+     {
+       error ("EH edge %i->%i is missing %i %i.", src->index, dst->index, src, dst);
+       mark_eh_edge_found_error = true;
+     }
+   else if (!(e->flags & EDGE_EH))
+     {
+       error ("EH edge %i->%i miss EH flag.", src->index, dst->index);
+       mark_eh_edge_found_error = true;
+     }
+   else if (e->aux)
+     {
+       /* ??? might not be mistake.  */
+       error ("EH edge %i->%i has duplicated regions.", src->index, dst->index);
+       mark_eh_edge_found_error = true;
+     }
+   else
+     e->aux = (void *)1;
+ }
+ 
+ /* Verify that BB containing stmt as last stmt has precisely the edges
+    make_eh_edges would create.  */
+ bool
+ verify_eh_edges (tree stmt)
+ {
+   int region_nr;
+   bool is_resx;
+   basic_block bb = bb_for_stmt (stmt);
+   edge_iterator ei;
+   edge e;
+ 
+   FOR_EACH_EDGE (e, ei, bb->succs)
+     gcc_assert (!e->aux);
+   mark_eh_edge_found_error = false;
+   if (TREE_CODE (stmt) == RESX_EXPR)
+     {
+       region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
+       is_resx = true;
+     }
+   else
+     {
+       region_nr = lookup_stmt_eh_region (stmt);
+       if (region_nr < 0)
+ 	{
+ 	  FOR_EACH_EDGE (e, ei, bb->succs)
+ 	    if (e->flags & EDGE_EH)
+ 	      {
+ 		error ("BB %i can not throw but has EH edges", bb->index);
+ 		return true;
+ 	      }
+ 	   return false;
+ 	}
+       if (!tree_could_throw_p (stmt))
+ 	{
+ 	  error ("BB %i last statement has incorrectly set region", bb->index);
+ 	  return true;
+ 	}
+       is_resx = false;
+     }
+ 
+   foreach_reachable_handler (region_nr, is_resx, mark_eh_edge, stmt);
+   FOR_EACH_EDGE (e, ei, bb->succs)
+     {
+       if ((e->flags & EDGE_EH) && !e->aux)
+ 	{
+ 	  error ("Unnecesary EH edge %i->%i", bb->index, e->dest->index);
+ 	  mark_eh_edge_found_error = true;
+ 	  return true;
+ 	}
+       e->aux = NULL;
+     }
+   return mark_eh_edge_found_error;
+ }
  
  
  /* Return true if the expr can trap, as in dereferencing an invalid pointer


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]