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]

[patch] null dereference warning


 Hi,

  This patch fixes pr 16351.  I got the idea to check for null pointer 
dereferences from a talk by Bill Pugh where he said his program[1] could
warn developers about these problems.  To catch all the null pointer
dereferences, in the test case, we do need dom all three dom runs, so that is
why this pass runs so late.  It's possible to put this warning into the 
dominator pass, like I did with the patch attached to the bug, but I think a 
separate pass is cleaner.  The code is mostly adapted from the uninitialized 
variables pass.  I've also split out the warn uninitialized variables pass into
its own file so that tree-ssa.c isn't quite so big.

 Bootstrapped and regtested on i686-linux-gnu with c,c++,f95,objc.
The differences were:
-XPASS: 26_numerics/cmath/c99_classification_macros_c.cc (test for excess errors
)
+FAIL: ext/enc_filebuf/char/13189.cc (test for excess errors)
+WARNING: ext/enc_filebuf/char/13189.cc compilation failed to produce executable
+FAIL: ext/enc_filebuf/wchar_t/13189.cc (test for excess errors)
+WARNING: ext/enc_filebuf/wchar_t/13189.cc compilation failed to produce executable

 However, I don't think these have anything todo with my patch as these
failures have shown up elsewhere.

Jim
[1] http://findbugs.sf.net

2004-07-04  James Morrison  <phython@gcc.gnu.org>

	PR c/16351
	* common.opt: Add Wnull-dereference
	* doc/invoke.texi (Warning Options): Likewise.
	* opts.c (common_handle_option): Likewise.
	(decode_options): Warn if -Wnull-dereference is specified without 
	optimizations.
	* flags.h (flag_warn_null_dereference): New Variable.
	* c-opts.c (c_common_handle_option): Add -Wnull-dereference to -Wall
	* Makefile.in (tree-ssa-warn-null.o): Add target.
	(tree-ssa-warn-uninit.o): Likewise.
	* tree-ssa.c: Move warn uninitialized passes to...
	* tree-ssa-warn-uninit.c: ... Here.
	* tree-ssa-warn-null.c: New File.
	* tree-optimize.c (init_tree_optimization_passes): Add
	pass_warn_null_dereference
	* tree-pass.h: Likewise.
	
testsuite:
	* null-dereference-1.c: New test.

Index: Makefile.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1316
diff -u -u -p -r1.1316 Makefile.in
--- Makefile.in	1 Jul 2004 04:08:57 -0000	1.1316
+++ Makefile.in	5 Jul 2004 05:58:27 -0000
@@ -894,6 +894,7 @@ OBJS-common = \
  tree-ssa-phiopt.o tree-ssa-forwprop.o tree-nested.o tree-ssa-dse.o	   \
  tree-ssa-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o	   \
  tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o tree-ssa-loop.o \
+ tree-ssa-warn-uninit.o tree-ssa-warn-null.o                               \
  alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o	  	   \
  cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o		   \
  cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o	   \
@@ -1645,6 +1646,13 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_F
    $(SYSTEM_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \
    $(GGC_H) output.h diagnostic.h errors.h toplev.h $(TIMEVAR_H) \
    $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H)
+tree-ssa-warn-null.o : tree-ssa-warn-null.c $(TREE_FLOW_H) $(CONFIG_H) \
+   $(SYSTEM_H) $(TREE_H) $(TM_H) coretypes.h diagnostic.h tree-pass.h \
+   $(FLAGS_H) basic-block.h toplev.h
+tree-ssa-warn-uninit.o : tree-ssa-warn-uninit.c $(TREE_FLOW_H) $(CONFIG_H) \
+   $(SYSTEM_H) $(TREE_H) $(TM_H) coretypes.h diagnostic.h tree-pass.h \
+   $(FLAGS_H) basic-block.h toplev.h
+tree-ssa-warn-uninit.o : tree-ssa-warn-uninit.c coretypes.h diagnostic.h
 tree-vn.o : tree-vn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \
    $(TREE_H) $(TREE_FLOW_H) $(HASHTAB_H) langhooks.h tree-pass.h \
    $(TREE_DUMP_H) diagnostic.h
Index: c-opts.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.119
diff -u -u -p -r1.119 c-opts.c
--- c-opts.c	30 Jun 2004 18:05:04 -0000	1.119
+++ c-opts.c	5 Jul 2004 05:58:27 -0000
@@ -383,6 +383,9 @@ c_common_handle_option (size_t scode, co
       if (warn_uninitialized != 1)
 	warn_uninitialized = (value ? 2 : 0);
 
+      if (flag_warn_null_dereference != 1)
+        flag_warn_null_dereference = (value ? 2 : 0);
+
       if (!c_dialect_cxx ())
 	/* We set this to 2 here, but 1 in -Wmain, so -ffreestanding
 	   can turn it off only if it's not explicit.  */
Index: common.opt
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/common.opt,v
retrieving revision 1.39
diff -u -u -p -r1.39 common.opt
--- common.opt	30 Jun 2004 21:28:59 -0000	1.39
+++ common.opt	5 Jul 2004 05:58:27 -0000
@@ -93,6 +93,10 @@ Wmissing-noreturn
 Common Var(warn_missing_noreturn)
 Warn about functions which might be candidates for __attribute__((noreturn))
 
+Wnull-dereference
+Common Var(flag_warn_null_dereference)
+Warn about null dereferences
+
 Wpacked
 Common Var(warn_packed)
 Warn when the packed attribute has no effect on struct layout
Index: flags.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/flags.h,v
retrieving revision 1.144
diff -u -u -p -r1.144 flags.h
--- flags.h	29 Jun 2004 01:53:02 -0000	1.144
+++ flags.h	5 Jul 2004 05:58:27 -0000
@@ -91,6 +91,9 @@ extern bool extra_warnings;
 
 extern void set_Wunused (int setting);
 
+/* Nonzero to warn about null dereferences.  */
+extern int flags_warn_null_dereference;
+
 /* Nonzero to warn about variables used before they are initialized.  */
 
 extern int warn_uninitialized;
Index: opts.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/opts.c,v
retrieving revision 1.71
diff -u -u -p -r1.71 opts.c
--- opts.c	29 Jun 2004 01:53:02 -0000	1.71
+++ opts.c	5 Jul 2004 05:58:27 -0000
@@ -618,6 +618,8 @@ decode_options (unsigned int argc, const
 	 lots of errors for people who don't realize what -Wall does.  */
       if (warn_uninitialized == 1)
 	warning ("-Wuninitialized is not supported without -O");
+      if (flag_warn_null_dereference == 1)
+        warning ("-Wnull-dereference is not supported without -O");
     }
 
   if (flag_really_no_inline == 2)
@@ -630,8 +632,7 @@ decode_options (unsigned int argc, const
 
   if (flag_exceptions && flag_reorder_blocks_and_partition)
     {
-      warning 
-	    ("-freorder-blocks-and-partition does not work with exceptions");
+      warning ("-freorder-blocks-and-partition does not work with exceptions");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -701,6 +702,10 @@ common_handle_option (size_t scode, cons
       set_Wunused (value);
       break;
 
+    case OPT_Wnull_dereference:
+      flag_warn_null_dereference = value;
+      break;
+
     case OPT_aux_info:
     case OPT_aux_info_:
       aux_info_file_name = arg;
Index: tree-optimize.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 2.25
diff -u -u -p -r2.25 tree-optimize.c
--- tree-optimize.c	1 Jul 2004 01:12:17 -0000	2.25
+++ tree-optimize.c	5 Jul 2004 05:58:27 -0000
@@ -329,6 +330,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_tail_calls);
   NEXT_PASS (pass_late_warn_uninitialized);
   NEXT_PASS (pass_warn_function_return);
+  NEXT_PASS (pass_warn_null_dereference);
   NEXT_PASS (pass_del_ssa);
   NEXT_PASS (pass_nrv);
   NEXT_PASS (pass_remove_useless_vars);
Index: tree-pass.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 2.4
diff -u -u -p -r2.4 tree-pass.h
--- tree-pass.h	30 Jun 2004 21:28:59 -0000	2.4
+++ tree-pass.h	5 Jul 2004 05:58:27 -0000
@@ -123,6 +123,7 @@ extern struct tree_opt_pass pass_lower_c
 extern struct tree_opt_pass pass_fold_builtins;
 extern struct tree_opt_pass pass_early_warn_uninitialized;
 extern struct tree_opt_pass pass_late_warn_uninitialized;
+extern struct tree_opt_pass pass_warn_null_dereference;
 extern struct tree_opt_pass pass_warn_function_return;
 extern struct tree_opt_pass pass_phiopt;
 extern struct tree_opt_pass pass_forwprop;
Index: tree-ssa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/tree-ssa.c,v
retrieving revision 2.18
diff -u -u -p -r2.18 tree-ssa.c
--- tree-ssa.c	3 Jul 2004 13:45:28 -0000	2.18
+++ tree-ssa.c	5 Jul 2004 05:58:27 -0000
@@ -1007,159 +1007,3 @@ struct tree_opt_pass pass_redundant_phi 
   TODO_dump_func | TODO_rename_vars 
     | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
 };
-
-/* Emit warnings for uninitialized variables.  This is done in two passes.
-
-   The first pass notices real uses of SSA names with default definitions.
-   Such uses are unconditionally uninitialized, and we can be certain that
-   such a use is a mistake.  This pass is run before most optimizations,
-   so that we catch as many as we can.
-
-   The second pass follows PHI nodes to find uses that are potentially
-   uninitialized.  In this case we can't necessarily prove that the use
-   is really uninitialized.  This pass is run after most optimizations,
-   so that we thread as many jumps and possible, and delete as much dead
-   code as possible, in order to reduce false positives.  We also look
-   again for plain uninitialized variables, since optimization may have
-   changed conditionally uninitialized to unconditionally uninitialized.  */
-
-/* Emit a warning for T, an SSA_NAME, being uninitialized.  The exact
-   warning text is in MSGID and LOCUS may contain a location or be null.  */
-
-static void
-warn_uninit (tree t, const char *msgid, location_t *locus)
-{
-  tree var = SSA_NAME_VAR (t);
-  tree def = SSA_NAME_DEF_STMT (t);
-
-  /* Default uses (indicated by an empty definition statement),
-     are uninitialized.  */
-  if (!IS_EMPTY_STMT (def))
-    return;
-
-  /* Except for PARMs of course, which are always initialized.  */
-  if (TREE_CODE (var) == PARM_DECL)
-    return;
-
-  /* Hard register variables get their initial value from the ether.  */
-  if (DECL_HARD_REGISTER (var))
-    return;
-
-  /* TREE_NO_WARNING either means we already warned, or the front end
-     wishes to suppress the warning.  */
-  if (TREE_NO_WARNING (var))
-    return;
-
-  if (!locus)
-    locus = &DECL_SOURCE_LOCATION (var);
-  warning (msgid, locus, var);
-  TREE_NO_WARNING (var) = 1;
-}
-   
-/* Called via walk_tree, look for SSA_NAMEs that have empty definitions
-   and warn about them.  */
-
-static tree
-warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data)
-{
-  location_t *locus = data;
-  tree t = *tp;
-
-  /* We only do data flow with SSA_NAMEs, so that's all we can warn about.  */
-  if (TREE_CODE (t) == SSA_NAME)
-    {
-      warn_uninit (t, "%H'%D' is used uninitialized in this function", locus);
-      *walk_subtrees = 0;
-    }
-  else if (DECL_P (t) || TYPE_P (t))
-    *walk_subtrees = 0;
-
-  return NULL_TREE;
-}
-
-/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions
-   and warn about them.  */
-
-static void
-warn_uninitialized_phi (tree phi)
-{
-  int i, n = PHI_NUM_ARGS (phi);
-
-  /* Don't look at memory tags.  */
-  if (!is_gimple_reg (PHI_RESULT (phi)))
-    return;
-
-  for (i = 0; i < n; ++i)
-    {
-      tree op = PHI_ARG_DEF (phi, i);
-      if (TREE_CODE (op) == SSA_NAME)
-	warn_uninit (op, "%H'%D' may be used uninitialized in this function",
-		     NULL);
-    }
-}
-
-static void
-execute_early_warn_uninitialized (void)
-{
-  block_stmt_iterator bsi;
-  basic_block bb;
-
-  FOR_EACH_BB (bb)
-    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-      walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var,
-		 EXPR_LOCUS (bsi_stmt (bsi)), NULL);
-}
-
-static void
-execute_late_warn_uninitialized (void)
-{
-  basic_block bb;
-  tree phi;
-
-  /* Re-do the plain uninitialized variable check, as optimization may have
-     straightened control flow.  Do this first so that we don't accidentally
-     get a "may be" warning when we'd have seen an "is" warning later.  */
-  execute_early_warn_uninitialized ();
-
-  FOR_EACH_BB (bb)
-    for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-      warn_uninitialized_phi (phi);
-}
-
-static bool
-gate_warn_uninitialized (void)
-{
-  return warn_uninitialized != 0;
-}
-
-struct tree_opt_pass pass_early_warn_uninitialized =
-{
-  NULL,					/* name */
-  gate_warn_uninitialized,		/* gate */
-  execute_early_warn_uninitialized,	/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  0,					/* tv_id */
-  PROP_ssa,				/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  0					/* todo_flags_finish */
-};
-
-struct tree_opt_pass pass_late_warn_uninitialized =
-{
-  NULL,					/* name */
-  gate_warn_uninitialized,		/* gate */
-  execute_late_warn_uninitialized,	/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  0,					/* tv_id */
-  PROP_ssa,				/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  0					/* todo_flags_finish */
-};
Index: doc/invoke.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.478
diff -u -u -p -r1.478 invoke.texi
--- doc/invoke.texi	4 Jul 2004 08:07:14 -0000	1.478
+++ doc/invoke.texi	5 Jul 2004 05:58:30 -0000
@@ -224,7 +224,7 @@ in the following sections.
 -Wmain  -Wmissing-braces @gol
 -Wmissing-format-attribute  -Wmissing-include-dirs @gol
 -Wmissing-noreturn @gol
--Wno-multichar  -Wnonnull  -Wpacked  -Wpadded @gol
+-Wno-multichar  -Wnonnull  Wnull-dereference  -Wpacked  -Wpadded @gol
 -Wparentheses  -Wpointer-arith  -Wredundant-decls @gol
 -Wreturn-type  -Wsequence-point  -Wshadow @gol
 -Wsign-compare  -Wstrict-aliasing -Wstrict-aliasing=2 @gol
@@ -2243,6 +2243,10 @@ int b[2][2] = @{ @{ 0, 1 @}, @{ 2, 3 @} 
 @opindex Wmissing-include-dirs
 Warn if a user-supplied include directory does not exist.
 
+@item -Wnull-dereference
+@opindex Wnull-dereference
+Warn if a null pointer is dereferenced.
+
 @item -Wparentheses
 @opindex Wparentheses
 Warn if parentheses are omitted in certain contexts, such
--- /dev/null	2003-01-30 02:24:37.000000000 -0800
+++ tree-ssa-warn-uninit.c	2004-07-04 18:01:15.000000000 -0700
@@ -0,0 +1,187 @@
+/* SSA uninitialized variables warning passes.
+   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "flags.h"
+#include "tree-pass.h"
+#include "basic-block.h"
+#include "toplev.h"
+#include "tree-flow.h"
+
+/* Emit warnings for uninitialized variables.  This is done in two passes.
+
+   The first pass notices real uses of SSA names with default definitions.
+   Such uses are unconditionally uninitialized, and we can be certain that
+   such a use is a mistake.  This pass is run before most optimizations,
+   so that we catch as many as we can.
+
+   The second pass follows PHI nodes to find uses that are potentially
+   uninitialized.  In this case we can't necessarily prove that the use
+   is really uninitialized.  This pass is run after most optimizations,
+   so that we thread as many jumps and possible, and delete as much dead
+   code as possible, in order to reduce false positives.  We also look
+   again for plain uninitialized variables, since optimization may have
+   changed conditionally uninitialized to unconditionally uninitialized.  */
+
+/* Emit a warning for T, an SSA_NAME, being uninitialized.  The exact
+   warning text is in MSGID and LOCUS may contain a location or be null.  */
+
+static void
+warn_uninit (tree t, const char *msgid, location_t *locus)
+{
+  tree var = SSA_NAME_VAR (t);
+  tree def = SSA_NAME_DEF_STMT (t);
+
+  /* Default uses (indicated by an empty definition statement),
+     are uninitialized.  */
+  if (!IS_EMPTY_STMT (def))
+    return;
+
+  /* Except for PARMs of course, which are always initialized.  */
+  if (TREE_CODE (var) == PARM_DECL)
+    return;
+
+  /* Hard register variables get their initial value from the ether.  */
+  if (DECL_HARD_REGISTER (var))
+    return;
+
+  /* TREE_NO_WARNING either means we already warned, or the front end
+     wishes to suppress the warning.  */
+  if (TREE_NO_WARNING (var))
+    return;
+
+  if (!locus)
+    locus = &DECL_SOURCE_LOCATION (var);
+  warning (msgid, locus, var);
+  TREE_NO_WARNING (var) = 1;
+}
+   
+/* Called via walk_tree, look for SSA_NAMEs that have empty definitions
+   and warn about them.  */
+
+static tree
+warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data)
+{
+  location_t *locus = data;
+  tree t = *tp;
+
+  /* We only do data flow with SSA_NAMEs, so that's all we can warn about.  */
+  if (TREE_CODE (t) == SSA_NAME)
+    {
+      warn_uninit (t, "%H'%D' is used uninitialized in this function", locus);
+      *walk_subtrees = 0;
+    }
+  else if (DECL_P (t) || TYPE_P (t))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions
+   and warn about them.  */
+
+static void
+warn_uninitialized_phi (tree phi)
+{
+  int i, n = PHI_NUM_ARGS (phi);
+
+  /* Don't look at memory tags.  */
+  if (!is_gimple_reg (PHI_RESULT (phi)))
+    return;
+
+  for (i = 0; i < n; ++i)
+    {
+      tree op = PHI_ARG_DEF (phi, i);
+      if (TREE_CODE (op) == SSA_NAME)
+	warn_uninit (op, "%H'%D' may be used uninitialized in this function",
+		     NULL);
+    }
+}
+
+static void
+execute_early_warn_uninitialized (void)
+{
+  block_stmt_iterator bsi;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var,
+		 EXPR_LOCUS (bsi_stmt (bsi)), NULL);
+}
+
+static void
+execute_late_warn_uninitialized (void)
+{
+  basic_block bb;
+  tree phi;
+
+  /* Re-do the plain uninitialized variable check, as optimization may have
+     straightened control flow.  Do this first so that we don't accidentally
+     get a "may be" warning when we'd have seen an "is" warning later.  */
+  execute_early_warn_uninitialized ();
+
+  FOR_EACH_BB (bb)
+    for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+      warn_uninitialized_phi (phi);
+}
+
+static bool
+gate_warn_uninitialized (void)
+{
+  return warn_uninitialized != 0;
+}
+
+struct tree_opt_pass pass_early_warn_uninitialized =
+{
+  NULL,					/* name */
+  gate_warn_uninitialized,		/* gate */
+  execute_early_warn_uninitialized,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  0,					/* tv_id */
+  PROP_ssa,				/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0					/* todo_flags_finish */
+};
+
+struct tree_opt_pass pass_late_warn_uninitialized =
+{
+  NULL,					/* name */
+  gate_warn_uninitialized,		/* gate */
+  execute_late_warn_uninitialized,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  0,					/* tv_id */
+  PROP_ssa,				/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0					/* todo_flags_finish */
+};
--- /dev/null	2003-01-30 02:24:37.000000000 -0800
+++ tree-ssa-warn-null.c	2004-07-04 19:40:09.000000000 -0700
@@ -0,0 +1,122 @@
+/* SSA null dereference warning pass.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "flags.h"
+#include "tree-pass.h"
+#include "basic-block.h"
+#include "toplev.h"
+#include "tree-flow.h"
+
+/* Emit warnings for dereferenced NULL pointers.  This is done after the
+   dominator optimizations so we can catch most of the dereferences.
+
+   This pass could be done in tree-ssa-dom.c.  However, the dominator pass
+   already does enough, so this is a new pass that can be run on it's own,
+   after the dominator pass.
+
+   This pass catches mistakes such as:
+   
+   foo == NULL && foo->bar
+   or
+   foo != NULL || foo->bar
+*/
+
+/* Look into MODIFY_EXPRs for INDIRECT_REFs that could dereference a null
+   pointer.  */
+
+static tree
+warn_null_dereference (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+
+  if (TREE_CODE (t) == MODIFY_EXPR)
+    {
+      location_t *locus = data;
+      int i = 0;
+
+      for (; i < 2; i++)
+        {
+          t = TREE_OPERAND (*tp, i);
+
+          /* Strip away any COMPONENT_REFs.  */
+          while (TREE_CODE (t) == COMPONENT_REF)
+            t = TREE_OPERAND (t, 0);
+
+          if (TREE_CODE (t) == INDIRECT_REF)
+            {
+              tree op = TREE_OPERAND (t, 0);
+              if (integer_zerop (op) && ! TREE_NO_WARNING(op))
+                { 
+                  if (TREE_CODE (op) == SSA_NAME)
+                    warning("%Hdereferenced null pointer %D", locus,
+                            SSA_NAME_VAR (op));
+                  else
+                    warning("%Hdereferenced null pointer", locus);
+
+                  TREE_NO_WARNING (op) = 1;
+                }
+            }
+        }
+    }
+
+  *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+static void
+execute_warn_null_dereference (void)
+{
+  block_stmt_iterator bsi;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      walk_tree (bsi_stmt_ptr (bsi), warn_null_dereference,
+		 EXPR_LOCUS (bsi_stmt (bsi)), NULL);
+}
+
+
+static bool
+gate_warn_null_dereference (void)
+{
+  return flag_warn_null_dereference != 0;
+}
+
+struct tree_opt_pass pass_warn_null_dereference =
+{
+  NULL,
+  gate_warn_null_dereference,
+  execute_warn_null_dereference,
+  NULL,
+  NULL,
+  0,
+  0,
+  PROP_ssa,
+  0,
+  0,
+  0,
+  0
+};
--- /dev/null	2003-01-30 02:24:37.000000000 -0800
+++ testsuite/gcc.dg/null-dereference-1.c	2004-07-04 20:44:20.000000000 -0700
@@ -0,0 +1,75 @@
+/* PR c/16351 */
+/* Origin: James A. Morrison <phython@gcc.gnu.org>  */
+
+/* Verify that the user is warned about null dereferences.  */
+
+/* { dg-do compile } */
+/* { dg-options "-Wnull-dereference -O" } */
+
+struct t
+{
+  int bar;
+};
+
+struct t2
+{
+  struct t *s;
+};
+
+void test1 ()
+{
+  struct t *s = 0;
+  s->bar = 1;  /* { dg-warning "null" } */
+}
+
+void test2 (struct t *s)
+{
+  if (s == 0 && s->bar > 2)  /* { dg-warning "null" } */
+    return;
+
+  s->bar = 3;
+}
+
+void test3 (struct t *s)
+{
+  if (s != 0 || s->bar > 2)  /* { dg-warning "null" } */
+    return;
+
+  s->bar = 3;  /* { dg-warning "null" } */
+}
+
+void test4 (struct t *s)
+{
+  if (s != 0 && s->bar > 2)  /* { dg-bogus "null" } */
+    return;
+}
+
+void test5 (struct t *s)
+{
+  if (s == 0 || s->bar > 2)  /* { dg-bogus "null" } */
+    return;
+}
+
+void test6 (struct t2 *s)
+{
+  if (s->s == 0 && s->s->bar == 0)  /* { dg-warning "null" } */
+    return;
+}
+
+int test7 (struct t *s)
+{
+  s = 0;
+  return s->bar;  /* { dg-warning "null" } */
+}
+
+int test8 ()
+{
+  return ((struct t *)0)->bar;  /* { dg-warning "null" } */
+}
+
+void test9 (struct t **s)
+{
+  if (s == 0)
+    *s = 0;  /* { dg-warning "null" } */
+}
+


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