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.
+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.
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));
+}
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 */
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
#include "hashtab.h"
#include "flags.h"
#include "splay-tree.h"
+#include "target.h"
+#include "c-family/c-ubsan.h"
/* Forward declarations. */
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)
{
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);
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. */
{ "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 }
};
"__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,
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.
--- /dev/null
+// { 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" }
--- /dev/null
+// { 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);
+}
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;
{
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;