@@ -227,8 +227,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;
@@ -642,7 +642,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;
@@ -297,6 +297,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
"__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,
@@ -1457,6 +1457,7 @@ common_handle_option (struct gcc_options
{ "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 }
};
@@ -212,8 +212,9 @@ enum sanitize_code {
SANITIZE_UNREACHABLE = 1 << 4,
SANITIZE_VLA = 1 << 5,
SANITIZE_NULL = 1 << 6,
+ SANITIZE_RETURN = 1 << 8,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
- | SANITIZE_VLA | SANITIZE_NULL
+ | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
};
/* flag_vtable_verify initialization levels. */
@@ -24,5 +24,6 @@ along with GCC; see the file COPYING3.
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 */
@@ -179,3 +179,14 @@ ubsan_instrument_vla (location_t loc, tr
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));
+}
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.
#include "pointer-set.h"
#include "flags.h"
#include "splay-tree.h"
+#include "target.h"
+#include "c-family/c-ubsan.h"
/* Forward declarations. */
@@ -1235,6 +1237,54 @@ cp_genericize (tree fndecl)
walk_tree's hash functionality. */
cp_genericize_tree (&DECL_SAVED_TREE (fndecl));
+ if ((flag_sanitize & SANITIZE_RETURN)
+ && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))
+ && !DECL_CONSTRUCTOR_P (fndecl)
+ && !DECL_DESTRUCTOR_P (fndecl)
+ && targetm.warn_func_return (fndecl))
+ {
+ 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:
+ t = NULL_TREE;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ if (t)
+ {
+ 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);
+ }
+ }
+ }
+
/* Do everything else. */
c_genericize (fndecl);
@@ -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" }
@@ -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);
+}