aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-ubsan.c11
-rw-r--r--gcc/c-family/c-ubsan.h1
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/cp-gimplify.c58
-rw-r--r--gcc/flag-types.h3
-rw-r--r--gcc/opts.c1
-rw-r--r--gcc/sanitizer.def4
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-1.C27
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-2.C25
-rw-r--r--gcc/ubsan.c6
13 files changed, 153 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 334d082..f380e44 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
2013-11-22 Jakub Jelinek <jakub@redhat.com>
+ * ubsan.c (ubsan_source_location): Don't crash on
+ unknown locations.
+ (ubsan_pass): Ignore clobber stmts.
+
+ * sanitizer.def (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN): New built-in.
+ * opts.c (common_handle_option): Add -fsanitize=return.
+ * flag-types.h (enum sanitize_code): Add SANITIZE_RETURN and
+ or it into SANITIZE_UNDEFINED.
+
* sanitizer.def (BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT,
BUILT_IN_ASAN_AFTER_DYNAMIC_INIT): New.
* asan.c (instrument_derefs): Handle also VAR_DECL loads/stores.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 358ab47..43c4dad 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,8 @@
+2013-11-22 Jakub Jelinek <jakub@redhat.com>
+
+ * c-ubsan.h (ubsan_instrument_return): New prototype.
+ * c-ubsan.c (ubsan_instrument_return): New function.
+
2013-11-22 Andrew MacLeod <amacleod@redhat.com>
* c-common.c: Add required include files from gimple.h.
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 7a09e7b..a276935 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -179,3 +179,14 @@ ubsan_instrument_vla (location_t loc, tree size)
return t;
}
+
+/* Instrument missing return in C++ functions returning non-void. */
+
+tree
+ubsan_instrument_return (location_t loc)
+{
+ tree data = ubsan_create_data ("__ubsan_missing_return_data", loc,
+ NULL, NULL_TREE);
+ tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN);
+ return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
+}
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index fdf27d9..9b91bad 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -24,5 +24,6 @@ along with GCC; see the file COPYING3. If not see
extern tree ubsan_instrument_division (location_t, tree, tree);
extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
extern tree ubsan_instrument_vla (location_t, tree);
+extern tree ubsan_instrument_return (location_t);
#endif /* GCC_C_UBSAN_H */
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 479d919..ee0674c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
2013-11-22 Jakub Jelinek <jakub@redhat.com>
+ * cp-gimplify.c: Include target.h and c-family/c-ubsan.h.
+ (cp_ubsan_maybe_instrument_return): New function.
+ (cp_genericize): Call it if -fsanitize=return.
+
* decl2.c: Include asan.h.
(one_static_initialization_or_destruction): If -fsanitize=address,
init is non-NULL and guard is NULL, set
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 176dbc3..b1270a1 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3. If not see
#include "hashtab.h"
#include "flags.h"
#include "splay-tree.h"
+#include "target.h"
+#include "c-family/c-ubsan.h"
/* Forward declarations. */
@@ -1178,6 +1180,59 @@ cp_genericize_tree (tree* t_p)
wtd.bind_expr_stack.release ();
}
+/* If a function that should end with a return in non-void
+ function doesn't obviously end with return, add ubsan
+ instrmentation code to verify it at runtime. */
+
+static void
+cp_ubsan_maybe_instrument_return (tree fndecl)
+{
+ if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))
+ || DECL_CONSTRUCTOR_P (fndecl)
+ || DECL_DESTRUCTOR_P (fndecl)
+ || !targetm.warn_func_return (fndecl))
+ return;
+
+ tree t = DECL_SAVED_TREE (fndecl);
+ while (t)
+ {
+ switch (TREE_CODE (t))
+ {
+ case BIND_EXPR:
+ t = BIND_EXPR_BODY (t);
+ continue;
+ case TRY_FINALLY_EXPR:
+ t = TREE_OPERAND (t, 0);
+ continue;
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator i = tsi_last (t);
+ if (!tsi_end_p (i))
+ {
+ t = tsi_stmt (i);
+ continue;
+ }
+ }
+ break;
+ case RETURN_EXPR:
+ return;
+ default:
+ break;
+ }
+ break;
+ }
+ if (t == NULL_TREE)
+ return;
+ t = DECL_SAVED_TREE (fndecl);
+ if (TREE_CODE (t) == BIND_EXPR
+ && TREE_CODE (BIND_EXPR_BODY (t)) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i = tsi_last (BIND_EXPR_BODY (t));
+ t = ubsan_instrument_return (DECL_SOURCE_LOCATION (fndecl));
+ tsi_link_after (&i, t, TSI_NEW_STMT);
+ }
+}
+
void
cp_genericize (tree fndecl)
{
@@ -1240,6 +1295,9 @@ cp_genericize (tree fndecl)
walk_tree's hash functionality. */
cp_genericize_tree (&DECL_SAVED_TREE (fndecl));
+ if (flag_sanitize & SANITIZE_RETURN)
+ cp_ubsan_maybe_instrument_return (fndecl);
+
/* Do everything else. */
c_genericize (fndecl);
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 528c88a..1d85a9a 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -212,8 +212,9 @@ enum sanitize_code {
SANITIZE_UNREACHABLE = 1 << 4,
SANITIZE_VLA = 1 << 5,
SANITIZE_NULL = 1 << 6,
+ SANITIZE_RETURN = 1 << 7,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
- | SANITIZE_VLA | SANITIZE_NULL
+ | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
};
/* flag_vtable_verify initialization levels. */
diff --git a/gcc/opts.c b/gcc/opts.c
index 5a9d7c8..21ca9dc 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1457,6 +1457,7 @@ common_handle_option (struct gcc_options *opts,
{ "unreachable", SANITIZE_UNREACHABLE,
sizeof "unreachable" - 1 },
{ "vla-bound", SANITIZE_VLA, sizeof "vla-bound" - 1 },
+ { "return", SANITIZE_RETURN, sizeof "return" - 1 },
{ "null", SANITIZE_NULL, sizeof "null" - 1 },
{ NULL, 0, 0 }
};
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index ad1248d..5bf1e3c 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -303,6 +303,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE,
"__ubsan_handle_builtin_unreachable",
BT_FN_VOID_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_MISSING_RETURN,
+ "__ubsan_handle_missing_return",
+ BT_FN_VOID_PTR,
+ ATTR_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE,
"__ubsan_handle_vla_bound_not_positive",
BT_FN_VOID_PTR_PTR,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a98a7b97..091cc52 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
2013-11-22 Jakub Jelinek <jakub@redhat.com>
+ * g++.dg/ubsan/return-1.C: New test.
+ * g++.dg/ubsan/return-2.C: New test.
+
* c-c++-common/asan/no-redundant-instrumentation-1.c: Tweak to avoid
optimizing away some __asan_report* calls.
diff --git a/gcc/testsuite/g++.dg/ubsan/return-1.C b/gcc/testsuite/g++.dg/ubsan/return-1.C
new file mode 100644
index 0000000..43791b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-1.C
@@ -0,0 +1,27 @@
+// { dg-do run }
+// { dg-options "-fsanitize=return" }
+// { dg-shouldfail "ubsan" }
+
+struct S { S (); ~S (); };
+
+S::S () {}
+S::~S () {}
+
+int
+foo (int x)
+{
+ S a;
+ {
+ S b;
+ if (x)
+ return 1;
+ }
+}
+
+int
+main ()
+{
+ foo (0);
+}
+
+// { dg-output "execution reached the end of a value-returning function without returning a value" }
diff --git a/gcc/testsuite/g++.dg/ubsan/return-2.C b/gcc/testsuite/g++.dg/ubsan/return-2.C
new file mode 100644
index 0000000..c7380f03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-2.C
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-options "-fsanitize=return" }
+
+struct S { S (); ~S (); };
+
+S::S () {}
+S::~S () {}
+
+int
+foo (int x)
+{
+ S a;
+ {
+ S b;
+ if (x)
+ return 1;
+ }
+}
+
+int
+main ()
+{
+ foo (1);
+ foo (14);
+}
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 5effd55..f2b66bf 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -229,8 +229,8 @@ ubsan_source_location (location_t loc)
xloc = expand_location (loc);
/* Fill in the values from LOC. */
- size_t len = strlen (xloc.file);
- tree str = build_string (len + 1, xloc.file);
+ size_t len = xloc.file ? strlen (xloc.file) : 0;
+ tree str = build_string (len + 1, xloc.file ? xloc.file : "");
TREE_TYPE (str) = build_array_type (char_type_node,
build_index_type (size_int (len)));
TREE_READONLY (str) = 1;
@@ -644,7 +644,7 @@ ubsan_pass (void)
{
struct walk_stmt_info wi;
gimple stmt = gsi_stmt (gsi);
- if (is_gimple_debug (stmt))
+ if (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
{
gsi_next (&gsi);
continue;