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
This commit is contained in:
Jakub Jelinek 2013-11-22 21:07:31 +01:00 committed by Jakub Jelinek
parent 59b36ecf23
commit 0a508bb66b
13 changed files with 153 additions and 4 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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));
}

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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 }
};

View File

@ -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,

View File

@ -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.

View File

@ -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" }

View File

@ -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);
}

View File

@ -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;