@@ -1,3 +1,17 @@
+2014-01-27 Jeff Law <law@redhat.com>
+
+ * common.opt (Wnull-dereference): New option.
+ (Wnull-attribute): Likewise.
+ * doc/invoke.texi: Document new warnings.
+ * gimple-ssa-isolate-paths.c: (find_implicit_erroneous_behaviour): Warn
+ for NULL dereferences and NULL values flowing into arguments or
+ return values where an attribute indicates that should never happen.
+ Do not optimize unless the optimization is enabled.
+ (find_explicit_erroneous_behaviour): Similarly.
+ (gate_isolate_erroneous_paths): Run if we want the optimization
+ or the warning.
+
+
2014-01-27 Jakub Jelinek <jakub@redhat.com>
PR bootstrap/59934
@@ -576,6 +576,17 @@ Wlarger-than=
Common RejectNegative Joined UInteger Warning
-Wlarger-than=<number> Warn if an object is larger than <number> bytes
+Wnull-dereference
+Common Var(warn_null_dereference) Warning
+Warn if the compiler detects paths which trigger erroneous or undefined
+behaviour due to dereferencing a NULL pointer.
+
+Wnull-attribute
+Common Var(warn_null_attribute) Warning
+Warn if the compiler detects paths which trigger erroneous or undefined
+behaviour due to passing a NULL value for an argument which must be non-NULL or
+if a function returns NULL when it has been declared as must not return NULL.
+
Wunsafe-loop-optimizations
Common Var(warn_unsafe_loop_optimizations) Warning
Warn if the loop cannot be optimized due to nontrivial assumptions.
@@ -252,6 +252,7 @@ Objective-C and Objective-C++ Dialects}.
-Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol
-Winit-self -Winline -Wmaybe-uninitialized @gol
-Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
+-Wnull-dereference -Wnull-attribute @gol
-Winvalid-pch -Wlarger-than=@var{len} -Wunsafe-loop-optimizations @gol
-Wlogical-op -Wlong-long @gol
-Wmain -Wmaybe-uninitialized -Wmissing-braces -Wmissing-field-initializers @gol
@@ -3946,6 +3947,18 @@ In order to get a warning about an unused function parameter, you must
either specify @option{-Wextra -Wunused} (note that @option{-Wall} implies
@option{-Wunused}), or separately specify @option{-Wunused-parameter}.
+@item -Wnull-dereference
+@opindex Wnull-dereference
+@opindex Wno-null-dereference
+Warn if the compiler detects paths which trigger erroneous or undefined
+behaviour due to dereferencing a NULL pointer.
+
+@item -Wnull-attribute
+@opindex Wnull-attribute
+@opindex Wno-null-attribute
+Warn if the compiler detects paths which trigger erroneous or undefined
+behaviour due to passing a NULL value for an argument which must be non-NULL or if a function returns NULL when it has been declared as must not return NULL.
+
@item -Wuninitialized
@opindex Wuninitialized
@opindex Wno-uninitialized
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-pass.h"
#include "tree-cfg.h"
+#include "diagnostic.h"
static bool cfg_altered;
@@ -275,11 +276,34 @@ find_implicit_erroneous_behaviour (void)
if (gimple_bb (use_stmt) != bb)
continue;
- if (infer_nonnull_range (use_stmt, lhs,
- flag_isolate_erroneous_paths_dereference,
- flag_isolate_erroneous_paths_attribute))
+ if (infer_nonnull_range (use_stmt, lhs, true, true))
{
+ /* By calling infer_nonnull_range again, we can determine
+ if it was a dereference or attribute which gave us the
+ NULL range and appropriately customize the warning. */
+ bool dereference = infer_nonnull_range (use_stmt, lhs,
+ true, false);
+
+ if (dereference)
+ warning_at ((gimple_location (use_stmt)
+ ? gimple_location (use_stmt)
+ : gimple_phi_arg_location (phi, i)),
+ OPT_Wnull_dereference,
+ "Potential NULL pointer dereference");
+ else
+ warning_at ((gimple_location (use_stmt)
+ ? gimple_location (use_stmt)
+ : gimple_phi_arg_location (phi, i)),
+ OPT_Wnull_attribute,
+ "Potential invalid NULL argument or return value");
+
+ if ((!flag_isolate_erroneous_paths_dereference
+ && dereference)
+ || (!flag_isolate_erroneous_paths_attribute
+ && !dereference))
+ continue;
+
duplicate = isolate_path (bb, duplicate,
e, use_stmt, lhs);
@@ -328,10 +352,27 @@ find_explicit_erroneous_behaviour (void)
/* By passing null_pointer_node, we can use infer_nonnull_range
to detect explicit NULL pointer dereferences and other uses
where a non-NULL value is required. */
- if (infer_nonnull_range (stmt, null_pointer_node,
- flag_isolate_erroneous_paths_dereference,
- flag_isolate_erroneous_paths_attribute))
+ if (infer_nonnull_range (stmt, null_pointer_node, true, true))
{
+ /* By calling infer_nonnull_range again, we can determine
+ if it was a dereference or attribute which gave us the
+ NULL range. */
+ bool dereference = infer_nonnull_range (stmt, null_pointer_node,
+ true, false);
+
+ if (dereference)
+ warning_at (gimple_location (stmt),
+ OPT_Wnull_dereference,
+ "NULL pointer dereference");
+ else
+ warning_at (gimple_location (stmt),
+ OPT_Wnull_attribute,
+ "Invalid NULL argument or return value");
+
+ if ((!flag_isolate_erroneous_paths_dereference && dereference)
+ || (!flag_isolate_erroneous_paths_attribute && !dereference))
+ continue;
+
insert_trap_and_remove_trailing_statements (&si,
null_pointer_node);
@@ -417,10 +458,10 @@ gimple_ssa_isolate_erroneous_paths (void)
static bool
gate_isolate_erroneous_paths (void)
{
- /* If we do not have a suitable builtin function for the trap statement,
- then do not perform the optimization. */
return (flag_isolate_erroneous_paths_dereference != 0
- || flag_isolate_erroneous_paths_attribute != 0);
+ || flag_isolate_erroneous_paths_attribute != 0
+ || warn_null_dereference
+ || warn_null_attribute);
}
namespace {
@@ -1,3 +1,16 @@
+2014-01-27 Jeff Law <law@redhat.com>
+
+ * gcc.dg/nullwarn.c: New test.
+ * gcc.dg/tree-ssa/isolate-1.c: Split into two tests.
+ isolate-1.c, and isolate-1a.c. Add appropriate warning
+ markers for the former. Disable the optimization, but
+ enable the warnings for the former test. The latter
+ test just checks the optimization.
+ * gcc.dg/tree-ssa-isolate-2.c: Similarly.
+ * gcc.dg/tree-ssa-isolate-3.c: Similarly.
+ * gcc.dg/tree-ssa-isolate-4.c: Similarly.
+ * gcc.dg/tree-ssa-isolate-5.c: Similarly.
+
2014-01-27 Christian Bruel <christian.bruel@st.com>
* gcc.target/sh/torture/strncmp.c: New tests.
new file mode 100644
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wnull-dereference" } */
+
+#include <stdio.h>
+
+struct t
+{
+ int bar;
+};
+
+void test1 ()
+{
+ struct t *s = NULL;
+ s->bar = 1; /* { dg-warning "NULL pointer dereference" } */
+}
+
+void test2 (struct t *s)
+{
+ if (s == NULL && s->bar > 2) /* { dg-warning "NULL pointer dereference" } */
+ return;
+
+ s->bar = 3;
+}
+
+void test3 (struct t *s)
+{
+ if (s != NULL || s->bar > 2) /* { dg-warning "NULL pointer dereference" } */
+ return;
+
+ s->bar = 3; /* { dg-warning "NULL pointer dereference" } */
+}
+
+void test4 (struct t *s)
+{
+ if (s != NULL && s->bar > 2) /* { dg-bogus "NULL pointer dereference" } */
+ return;
+}
+
+void test5 (struct t *s)
+{
+ if (s == NULL || s->bar > 2) /* { dg-bogus "NULL pointer dereference" } */
+ return;
+
+}
+
@@ -1,6 +1,6 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+/* { dg-options "-O2 -fno-isolate-erroneous-paths-dereference -Wnull-dereference" } */
struct demangle_component
@@ -38,23 +38,7 @@ d_type (struct d_info *di)
{
struct demangle_component *ret;
ret = d_make_empty (di);
- ret->type = 42;
- ret->zzz = -1;
+ ret->type = 42; /* { dg-warning "NULL pointer dereference" } */
+ ret->zzz = -1; /* { dg-warning "NULL pointer dereference" } */
return ret;
}
-
-/* We're testing three aspects of isolation here. First that isolation
- occurs, second that if we have two null dereferences in a block that
- that we delete everything from the first dereferece to the end of the
- block, regardless of which comes first in the immediate use iterator
- and finally that we set the RHS of the store to zero. */
-/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->type = 42" 1 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->type ={v} 0" 1 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
-/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
-
-
-
-
-
new file mode 100644
@@ -0,0 +1,21 @@
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+
+#include "isolate-1.c"
+
+/* We're testing three aspects of isolation here. First that isolation
+ occurs, second that if we have two null dereferences in a block that
+ that we delete everything from the first dereferece to the end of the
+ block, regardless of which comes first in the immediate use iterator
+ and finally that we set the RHS of the store to zero. */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type = 42" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type ={v} 0" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+
+
+
+
+
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+/* { dg-options "-O2 -fno-isolate-erroneous-paths-attribute -Wnull-attribute" } */
int z;
@@ -17,7 +17,7 @@ foo(int a)
case 0:
return &z;
default:
- return (int *)0;
+ return (int *)0; /* { dg-warning "NULL argument or return value" } */
}
}
@@ -25,19 +25,5 @@ foo(int a)
int *
bar (void)
{
- return 0;
+ return 0; /* { dg-warning "NULL argument or return value" } */
}
-
-/* We testing that the path isolation code can take advantage of the
- returns non-null attribute to isolate a path where NULL flows into
- a return statement. We test this twice, once where the NULL flows
- from a PHI, the second with an explicit return 0 in the IL.
-
- We also verify that after isolation phi-cprop simplifies the
- return statement so that it returns &z directly.
-/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "return &z;" 1 "phicprop1"} } */
-/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
-/* { dg-final { cleanup-tree-dump "phicprop1" } } */
-
-
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+
+#include "isolate-2.c"
+
+/* We testing that the path isolation code can take advantage of the
+ returns non-null attribute to isolate a path where NULL flows into
+ a return statement. We test this twice, once where the NULL flows
+ from a PHI, the second with an explicit return 0 in the IL.
+
+ We also verify that after isolation phi-cprop simplifies the
+ return statement so that it returns &z directly.
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "return &z;" 1 "phicprop1"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+/* { dg-final { cleanup-tree-dump "phicprop1" } } */
+
+
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+/* { dg-options "-O2 -fno-isolate-erroneous-paths-dereference -Wnull-dereference" } */
typedef long unsigned int size_t;
@@ -28,7 +28,7 @@ static __inline__ void
VEC_rtx_gc_safe_grow (VEC_rtx_gc ** vec_, int size_, const char *file_,
unsigned line_, const char *function_)
{
- ((*vec_) ? &(*vec_)->base : 0)->num = size_;
+ ((*vec_) ? &(*vec_)->base : 0)->num = size_; /* { dg-warning "NULL pointer dereference" } */
}
static __inline__ void
@@ -50,16 +50,3 @@ init_alias_analysis (void)
(&(reg_base_value), maxreg, "../../../gcc-4.6.0/gcc/alias.c", 2755,
__FUNCTION__, arf ()));
}
-
-
-
-/* This is an example of how a NULL pointer dereference can show up
- without a PHI. Note VEC_rtx_gcc_safe_grow. If an earlier pass
- (such as VRP) isolates the NULL path for some reason or another
- we end up with an explicit NULL dereference in the IL. Yes, it
- started with a PHI, but by the time the path isolation code runs
- its explicit in the IL. */
-/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
-/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
-
-
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+
+#include "isolate-3.c"
+
+/* This is an example of how a NULL pointer dereference can show up
+ without a PHI. Note VEC_rtx_gcc_safe_grow. If an earlier pass
+ (such as VRP) isolates the NULL path for some reason or another
+ we end up with an explicit NULL dereference in the IL. Yes, it
+ started with a PHI, but by the time the path isolation code runs
+ its explicit in the IL. */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+
+
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+/* { dg-options "-O2 -fno-isolate-erroneous-paths-attribute -Wnull-attribute" } */
extern void foo(void *) __attribute__ ((__nonnull__ (1)));
@@ -9,24 +9,11 @@ int z;
void
com (int a)
{
- foo (a == 42 ? &z : (void *) 0);
+ foo (a == 42 ? &z : (void *) 0); /* { dg-warning "NULL argument or return value" } */
}
void
bar (void)
{
- foo ((void *)0);
+ foo ((void *)0); /* { dg-warning "NULL argument or return value" } */
}
-
-/* We testing that the path isolation code can take advantage of the
- returns non-null attribute to isolate a path where NULL flows into
- a return statement.
-
- We also verify that after isolation phi-cprop simplifies the
- return statement so that it returns &z directly.
-/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "foo .&z.;" 1 "phicprop1"} } */
-/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
-/* { dg-final { cleanup-tree-dump "phicprop1" } } */
-
-
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */
+
+#include "isolate-4.c"
+
+/* We testing that the path isolation code can take advantage of the
+ returns non-null attribute to isolate a path where NULL flows into
+ a return statement.
+
+ We also verify that after isolation phi-cprop simplifies the
+ return statement so that it returns &z directly.
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "foo .&z.;" 1 "phicprop1"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+/* { dg-final { cleanup-tree-dump "phicprop1" } } */
+
+
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-isolate-paths -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fno-isolate-erroneous-paths-dereference -Wnull-dereference" } */
struct demangle_component
{
@@ -32,21 +32,7 @@ d_type (struct d_info *di)
{
struct demangle_component *ret;
ret = d_make_empty (di);
- foo (ret->type);
- bar (ret->zzz);
+ foo (ret->type); /* { dg-warning "NULL pointer dereference" } */
+ bar (ret->zzz); /* { dg-warning "NULL pointer dereference" } */
return ret;
}
-
-/* We're testing two aspects of isolation here. First that isolation
- occurs, second that if we have two null dereferences in a block that
- that we delete everything from the first dereferece to the end of the
- block, regardless of which comes first in the immediate use iterator.
-
- We leave the 0->type in the IL, so expect to see ->type twice. */
-/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->type" 2 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->type" 1 "optimized"} } */
-/* { dg-final { scan-tree-dump-times "\\.type" 1 "optimized"} } */
-/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
-/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
-/* { dg-final { cleanup-tree-dump "optimized" } } */
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-isolate-paths -fdump-tree-optimized" } */
+
+#include "isolate-5.c"
+
+/* We're testing two aspects of isolation here. First that isolation
+ occurs, second that if we have two null dereferences in a block that
+ that we delete everything from the first dereferece to the end of the
+ block, regardless of which comes first in the immediate use iterator.
+
+ We leave the 0->type in the IL, so expect to see ->type twice. */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "\\.type" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */