From 0a508bb66b6056dd7a7cd7a689daa1b1dfff6863 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 22 Nov 2013 21:07:31 +0100 Subject: ubsan.c (ubsan_source_location): Don't crash on unknown locations. * 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. c-family/ * c-ubsan.h (ubsan_instrument_return): New prototype. * c-ubsan.c (ubsan_instrument_return): New function. cp/ * 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. testsuite/ * g++.dg/ubsan/return-1.C: New test. * g++.dg/ubsan/return-2.C: New test. From-SVN: r205283 --- gcc/ChangeLog | 9 ++++++ gcc/c-family/ChangeLog | 5 +++ gcc/c-family/c-ubsan.c | 11 +++++++ gcc/c-family/c-ubsan.h | 1 + gcc/cp/ChangeLog | 4 +++ gcc/cp/cp-gimplify.c | 58 +++++++++++++++++++++++++++++++++++ gcc/flag-types.h | 3 +- gcc/opts.c | 1 + gcc/sanitizer.def | 4 +++ gcc/testsuite/ChangeLog | 3 ++ gcc/testsuite/g++.dg/ubsan/return-1.C | 27 ++++++++++++++++ gcc/testsuite/g++.dg/ubsan/return-2.C | 25 +++++++++++++++ gcc/ubsan.c | 6 ++-- 13 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ubsan/return-1.C create mode 100644 gcc/testsuite/g++.dg/ubsan/return-2.C (limited to 'gcc') 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 + * 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 + + * c-ubsan.h (ubsan_instrument_return): New prototype. + * c-ubsan.c (ubsan_instrument_return): New function. + 2013-11-22 Andrew MacLeod * 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 + * 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 + * 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; -- cgit v1.1