This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] -fsanitize=nonnull-attribute and -fsanitize=returns-nonnull-attribute support
- From: Richard Biener <rguenther at suse dot de>
- To: Jakub Jelinek <jakub at redhat dot com>
- Cc: Jeff Law <law at redhat dot com>, gcc-patches at gcc dot gnu dot org, Marek Polacek <polacek at redhat dot com>, Alexey Samsonov <vonosmas at gmail dot com>, Konstantin Serebryany <konstantin dot s dot serebryany at gmail dot com>
- Date: Wed, 10 Sep 2014 09:49:16 +0200 (CEST)
- Subject: Re: [PATCH] -fsanitize=nonnull-attribute and -fsanitize=returns-nonnull-attribute support
- Authentication-results: sourceware.org; auth=none
- References: <20140627071307 dot GW31640 at tucnak dot redhat dot com> <20140909175319 dot GA17454 at tucnak dot redhat dot com>
On Tue, 9 Sep 2014, Jakub Jelinek wrote:
> On Fri, Jun 27, 2014 at 09:13:07AM +0200, Jakub Jelinek wrote:
> > The patch adds two new (trivial handlers) to libubsan, as it is maintained
> > in llvm's compiler-rt, will talk to them if they are interested in those
> > and what exact wording and form (AFAIK clang also added the gcc
> > {,returns_}nonnull attributes). If they wouldn't be interested, guess
> > we could add them in a separate, gcc owned, source file in ubsan (like we
> > own Makefile*).
>
> And here is the actual new version of the patch, including cherry-picked
> libsanitizer changes.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Ok.
Thanks,
Richard.
> 2014-09-09 Jakub Jelinek <jakub@redhat.com>
>
> gcc/
> * flag-types.h (enum sanitize_code): Add SANITIZE_NONNULL_ATTRIBUTE
> and SANITIZE_RETURNS_NONNULL_ATTRIBUTE, or them into SANITIZE_UNDEFINED.
> * opts.c (common_handle_option): Handle SANITIZE_NONNULL_ATTRIBUTE and
> SANITIZE_RETURNS_NONNULL_ATTRIBUTE and disable
> flag_delete_null_pointer_checks for them.
> * sanitizer.def (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG,
> BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT,
> BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
> BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): New.
> * ubsan.c (instrument_bool_enum_load): Set *gsi back to
> stmt's iterator.
> (instrument_nonnull_arg, instrument_nonnull_return): New functions.
> (pass_ubsan::gate): Return true even for SANITIZE_NONNULL_ATTRIBUTE
> or SANITIZE_RETURNS_NONNULL_ATTRIBUTE.
> (pass_ubsan::execute): Call instrument_nonnull_{arg,return}.
> * doc/invoke.texi (-fsanitize=nonnull-attribute,
> -fsanitize=returns-nonnull-attribute): Document.
> gcc/testsuite/
> * c-c++-common/ubsan/attrib-3.c: New test.
> * c-c++-common/ubsan/nonnull-1.c: New test.
> * c-c++-common/ubsan/nonnull-2.c: New test.
> * c-c++-common/ubsan/nonnull-3.c: New test.
> * c-c++-common/ubsan/nonnull-4.c: New test.
> * c-c++-common/ubsan/nonnull-5.c: New test.
> libsanitizer/
> * ubsan/ubsan_handlers.cc, ubsan/ubsan_handlers.h: Cherry pick
> upstream r215485, r217389, r217391 and r217400.
>
> --- gcc/sanitizer.def.jj 2014-09-08 22:12:27.671740863 +0200
> +++ gcc/sanitizer.def 2014-09-09 11:59:18.694180701 +0200
> @@ -417,3 +417,19 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
> "__ubsan_handle_out_of_bounds_abort",
> BT_FN_VOID_PTR_PTR,
> ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_ARG,
> + "__ubsan_handle_nonnull_arg",
> + BT_FN_VOID_PTR_PTRMODE,
> + ATTR_COLD_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT,
> + "__ubsan_handle_nonnull_arg_abort",
> + BT_FN_VOID_PTR_PTRMODE,
> + ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
> + "__ubsan_handle_nonnull_return",
> + BT_FN_VOID_PTR,
> + ATTR_COLD_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT,
> + "__ubsan_handle_nonnull_return_abort",
> + BT_FN_VOID_PTR,
> + ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
> --- gcc/flag-types.h.jj 2014-09-09 11:59:18.693180712 +0200
> +++ gcc/flag-types.h 2014-09-09 12:00:26.780842334 +0200
> @@ -234,10 +234,14 @@ enum sanitize_code {
> SANITIZE_FLOAT_CAST = 1 << 15,
> SANITIZE_BOUNDS = 1 << 16,
> SANITIZE_ALIGNMENT = 1 << 17,
> + SANITIZE_NONNULL_ATTRIBUTE = 1 << 18,
> + SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1 << 19,
> SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
> | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
> | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
> - | SANITIZE_BOUNDS | SANITIZE_ALIGNMENT,
> + | SANITIZE_BOUNDS | SANITIZE_ALIGNMENT
> + | SANITIZE_NONNULL_ATTRIBUTE
> + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE,
> SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
> };
>
> --- gcc/ubsan.c.jj 2014-09-09 14:08:22.938445806 +0200
> +++ gcc/ubsan.c 2014-09-09 13:58:14.381504541 +0200
> @@ -1090,6 +1090,7 @@ instrument_bool_enum_load (gimple_stmt_i
> }
> gimple_set_location (g, loc);
> gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
> + *gsi = gsi_for_stmt (stmt);
> }
>
> /* Instrument float point-to-integer conversion. TYPE is an integer type of
> @@ -1215,6 +1216,122 @@ ubsan_instrument_float_cast (location_t
> fn, integer_zero_node);
> }
>
> +/* Instrument values passed to function arguments with nonnull attribute. */
> +
> +static void
> +instrument_nonnull_arg (gimple_stmt_iterator *gsi)
> +{
> + gimple stmt = gsi_stmt (*gsi);
> + location_t loc[2];
> + /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
> + while for nonnull sanitization it is clear. */
> + int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
> + flag_delete_null_pointer_checks = 1;
> + loc[0] = gimple_location (stmt);
> + loc[1] = UNKNOWN_LOCATION;
> + for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
> + {
> + tree arg = gimple_call_arg (stmt, i);
> + if (POINTER_TYPE_P (TREE_TYPE (arg))
> + && infer_nonnull_range (stmt, arg, false, true))
> + {
> + gimple g;
> + if (!is_gimple_val (arg))
> + {
> + g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg), NULL),
> + arg);
> + gimple_set_location (g, loc[0]);
> + gsi_insert_before (gsi, g, GSI_SAME_STMT);
> + arg = gimple_assign_lhs (g);
> + }
> +
> + basic_block then_bb, fallthru_bb;
> + *gsi = create_cond_insert_point (gsi, true, false, true,
> + &then_bb, &fallthru_bb);
> + g = gimple_build_cond (EQ_EXPR, arg,
> + build_zero_cst (TREE_TYPE (arg)),
> + NULL_TREE, NULL_TREE);
> + gimple_set_location (g, loc[0]);
> + gsi_insert_after (gsi, g, GSI_NEW_STMT);
> +
> + *gsi = gsi_after_labels (then_bb);
> + if (flag_sanitize_undefined_trap_on_error)
> + g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + else
> + {
> + tree data = ubsan_create_data ("__ubsan_nonnull_arg_data",
> + 2, loc, NULL_TREE,
> + build_int_cst (integer_type_node,
> + i + 1),
> + NULL_TREE);
> + data = build_fold_addr_expr_loc (loc[0], data);
> + enum built_in_function bcode
> + = flag_sanitize_recover
> + ? BUILT_IN_UBSAN_HANDLE_NONNULL_ARG
> + : BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT;
> + tree fn = builtin_decl_explicit (bcode);
> +
> + g = gimple_build_call (fn, 1, data);
> + }
> + gimple_set_location (g, loc[0]);
> + gsi_insert_before (gsi, g, GSI_SAME_STMT);
> + }
> + *gsi = gsi_for_stmt (stmt);
> + }
> + flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
> +}
> +
> +/* Instrument returns in functions with returns_nonnull attribute. */
> +
> +static void
> +instrument_nonnull_return (gimple_stmt_iterator *gsi)
> +{
> + gimple stmt = gsi_stmt (*gsi);
> + location_t loc[2];
> + tree arg = gimple_return_retval (stmt);
> + /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
> + while for nonnull return sanitization it is clear. */
> + int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
> + flag_delete_null_pointer_checks = 1;
> + loc[0] = gimple_location (stmt);
> + loc[1] = UNKNOWN_LOCATION;
> + if (arg
> + && POINTER_TYPE_P (TREE_TYPE (arg))
> + && is_gimple_val (arg)
> + && infer_nonnull_range (stmt, arg, false, true))
> + {
> + basic_block then_bb, fallthru_bb;
> + *gsi = create_cond_insert_point (gsi, true, false, true,
> + &then_bb, &fallthru_bb);
> + gimple g = gimple_build_cond (EQ_EXPR, arg,
> + build_zero_cst (TREE_TYPE (arg)),
> + NULL_TREE, NULL_TREE);
> + gimple_set_location (g, loc[0]);
> + gsi_insert_after (gsi, g, GSI_NEW_STMT);
> +
> + *gsi = gsi_after_labels (then_bb);
> + if (flag_sanitize_undefined_trap_on_error)
> + g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + else
> + {
> + tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
> + 2, loc, NULL_TREE, NULL_TREE);
> + data = build_fold_addr_expr_loc (loc[0], data);
> + enum built_in_function bcode
> + = flag_sanitize_recover
> + ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN
> + : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT;
> + tree fn = builtin_decl_explicit (bcode);
> +
> + g = gimple_build_call (fn, 1, data);
> + }
> + gimple_set_location (g, loc[0]);
> + gsi_insert_before (gsi, g, GSI_SAME_STMT);
> + *gsi = gsi_for_stmt (stmt);
> + }
> + flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
> +}
> +
> namespace {
>
> const pass_data pass_data_ubsan =
> @@ -1242,7 +1359,9 @@ public:
> {
> return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW
> | SANITIZE_BOOL | SANITIZE_ENUM
> - | SANITIZE_ALIGNMENT)
> + | SANITIZE_ALIGNMENT
> + | SANITIZE_NONNULL_ATTRIBUTE
> + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
> && current_function_decl != NULL_TREE
> && !lookup_attribute ("no_sanitize_undefined",
> DECL_ATTRIBUTES (current_function_decl));
> @@ -1285,7 +1404,25 @@ pass_ubsan::execute (function *fun)
>
> if (flag_sanitize & (SANITIZE_BOOL | SANITIZE_ENUM)
> && gimple_assign_load_p (stmt))
> - instrument_bool_enum_load (&gsi);
> + {
> + instrument_bool_enum_load (&gsi);
> + bb = gimple_bb (stmt);
> + }
> +
> + if ((flag_sanitize & SANITIZE_NONNULL_ATTRIBUTE)
> + && is_gimple_call (stmt)
> + && !gimple_call_internal_p (stmt))
> + {
> + instrument_nonnull_arg (&gsi);
> + bb = gimple_bb (stmt);
> + }
> +
> + if ((flag_sanitize & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
> + && gimple_code (stmt) == GIMPLE_RETURN)
> + {
> + instrument_nonnull_return (&gsi);
> + bb = gimple_bb (stmt);
> + }
>
> gsi_next (&gsi);
> }
> --- gcc/doc/invoke.texi.jj 2014-09-08 22:12:42.643667108 +0200
> +++ gcc/doc/invoke.texi 2014-09-09 11:59:18.702180660 +0200
> @@ -5578,6 +5578,20 @@ This option enables floating-point type
> We check that the result of the conversion does not overflow.
> This option does not work well with @code{FE_INVALID} exceptions enabled.
>
> +@item -fsanitize=nonnull-attribute
> +@opindex fsanitize=nonnull-attribute
> +
> +This option enables instrumentation of calls, checking whether null values
> +are not passed to arguments marked as requiring a non-null value by the
> +@code{nonnull} function attribute.
> +
> +@item -fsanitize=returns-nonnull-attribute
> +@opindex fsanitize=returns-nonnull-attribute
> +
> +This option enables instrumentation of return statements in functions
> +marked with @code{returns_nonnull} function attribute, to detect returning
> +of null values from such functions.
> +
> @end table
>
> While @option{-ftrapv} causes traps for signed overflows to be emitted,
> --- gcc/testsuite/c-c++-common/ubsan/nonnull-4.c.jj 2014-09-09 11:59:18.704180650 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/nonnull-4.c 2014-09-09 11:59:18.704180650 +0200
> @@ -0,0 +1,34 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "ubsan" } */
> +/* { dg-options "-fsanitize=undefined -fsanitize-undefined-trap-on-error" } */
> +
> +int q, r;
> +void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
> +
> +__attribute__((returns_nonnull, nonnull (1, 3)))
> +void *
> +foo (void *p, void *q, void *r)
> +{
> + a = p;
> + b = r;
> + return q;
> +}
> +
> +int
> +bar (const void *a, const void *b)
> +{
> + int c = *(const int *) a;
> + int d = *(const int *) b;
> + return c - d;
> +}
> +
> +int
> +main ()
> +{
> + asm volatile ("" : : : "memory");
> + d = foo (c, b, c);
> + e = foo (e, c, f);
> + g = foo (c, f, g);
> + __builtin_memset (d, '\0', q);
> + return 0;
> +}
> --- gcc/testsuite/c-c++-common/ubsan/attrib-3.c.jj 2014-09-09 11:59:18.703180655 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/attrib-3.c 2014-09-09 11:59:18.703180655 +0200
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fsanitize=undefined" } */
> +
> +/* Test that we don't instrument functions marked with
> + no_sanitize_undefined attribute. */
> +
> +__attribute__((no_sanitize_undefined, returns_nonnull))
> +char *
> +foo (char *x)
> +{
> + return x;
> +}
> +
> +__attribute__((nonnull)) void bar (char *, int, char *);
> +
> +__attribute__((no_sanitize_undefined))
> +void
> +baz (char *x, int y, char *z)
> +{
> + bar (x, y, z);
> +}
> +
> +/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
> --- gcc/testsuite/c-c++-common/ubsan/nonnull-5.c.jj 2014-09-09 11:59:18.704180650 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/nonnull-5.c 2014-09-09 11:59:18.704180650 +0200
> @@ -0,0 +1,34 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "ubsan" } */
> +/* { dg-options "-fsanitize=undefined -fsanitize-undefined-trap-on-error" } */
> +
> +int q, r;
> +void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
> +
> +__attribute__((returns_nonnull, nonnull (1, 3)))
> +void *
> +foo (void *p, void *q, void *r)
> +{
> + a = p;
> + b = r;
> + return q;
> +}
> +
> +int
> +bar (const void *a, const void *b)
> +{
> + int c = *(const int *) a;
> + int d = *(const int *) b;
> + return c - d;
> +}
> +
> +int
> +main ()
> +{
> + asm volatile ("" : : : "memory");
> + d = foo (c, (void *) &r, c);
> + e = foo (e, c, f);
> + g = foo (c, f, g);
> + __builtin_memset (d, '\0', q);
> + return 0;
> +}
> --- gcc/testsuite/c-c++-common/ubsan/nonnull-1.c.jj 2014-09-09 11:59:18.703180655 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/nonnull-1.c 2014-09-09 14:55:26.778264963 +0200
> @@ -0,0 +1,38 @@
> +/* { dg-do run } */
> +/* { dg-options "-fsanitize=nonnull-attribute,returns-nonnull-attribute" } */
> +
> +int q, r;
> +void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
> +
> +__attribute__((returns_nonnull, nonnull (1, 3)))
> +void *
> +foo (void *p, void *q, void *r)
> +{
> + a = p;
> + b = r;
> + return q;
> +}
> +
> +int
> +bar (const void *a, const void *b)
> +{
> + int c = *(const int *) a;
> + int d = *(const int *) b;
> + return c - d;
> +}
> +
> +int
> +main ()
> +{
> + asm volatile ("" : : : "memory");
> + d = foo (c, b, c);
> + e = foo (e, c, f);
> + g = foo (c, f, g);
> + __builtin_memset (d, '\0', q);
> + return 0;
> +}
> +
> +/* { dg-output "\.c:13:\[0-9]*:\[^\n\r]*null pointer returned from function declared to never return null\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "\[^\n\r]*\.c:29:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "\[^\n\r]*\.c:30:\[0-9]*:\[^\n\r]*null pointer passed as argument 3, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "\[^\n\r]*\.c:31:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null" } */
> --- gcc/testsuite/c-c++-common/ubsan/nonnull-2.c.jj 2014-09-09 11:59:18.703180655 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/nonnull-2.c 2014-09-09 14:54:11.202642791 +0200
> @@ -0,0 +1,36 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "ubsan" } */
> +/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
> +
> +int q, r;
> +void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
> +
> +__attribute__((returns_nonnull, nonnull (1, 3)))
> +void *
> +foo (void *p, void *q, void *r)
> +{
> + a = p;
> + b = r;
> + return q;
> +}
> +
> +int
> +bar (const void *a, const void *b)
> +{
> + int c = *(const int *) a;
> + int d = *(const int *) b;
> + return c - d;
> +}
> +
> +int
> +main ()
> +{
> + asm volatile ("" : : : "memory");
> + d = foo (c, b, c);
> + e = foo (e, c, f);
> + g = foo (c, f, g);
> + __builtin_memset (d, '\0', q);
> + return 0;
> +}
> +
> +/* { dg-output "\.c:14:\[0-9]*:\[^\n\r]*null pointer returned from function declared to never return null" } */
> --- gcc/testsuite/c-c++-common/ubsan/nonnull-3.c.jj 2014-09-09 11:59:18.704180650 +0200
> +++ gcc/testsuite/c-c++-common/ubsan/nonnull-3.c 2014-09-09 14:55:45.110173336 +0200
> @@ -0,0 +1,36 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "ubsan" } */
> +/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
> +
> +int q, r;
> +void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
> +
> +__attribute__((returns_nonnull, nonnull (1, 3)))
> +void *
> +foo (void *p, void *q, void *r)
> +{
> + a = p;
> + b = r;
> + return q;
> +}
> +
> +int
> +bar (const void *a, const void *b)
> +{
> + int c = *(const int *) a;
> + int d = *(const int *) b;
> + return c - d;
> +}
> +
> +int
> +main ()
> +{
> + asm volatile ("" : : : "memory");
> + d = foo (c, (void *) &r, c);
> + e = foo (e, c, f);
> + g = foo (c, f, g);
> + __builtin_memset (d, '\0', q);
> + return 0;
> +}
> +
> +/* { dg-output "\.c:30:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null" } */
> --- gcc/opts.c.jj 2014-09-08 22:12:52.797617097 +0200
> +++ gcc/opts.c 2014-09-09 13:41:10.725662283 +0200
> @@ -1499,6 +1499,11 @@ common_handle_option (struct gcc_options
> sizeof "float-cast-overflow" - 1 },
> { "bounds", SANITIZE_BOUNDS, sizeof "bounds" - 1 },
> { "alignment", SANITIZE_ALIGNMENT, sizeof "alignment" - 1 },
> + { "nonnull-attribute", SANITIZE_NONNULL_ATTRIBUTE,
> + sizeof "nonnull-attribute" - 1 },
> + { "returns-nonnull-attribute",
> + SANITIZE_RETURNS_NONNULL_ATTRIBUTE,
> + sizeof "returns-nonnull-attribute" - 1 },
> { NULL, 0, 0 }
> };
> const char *comma;
> @@ -1542,7 +1547,8 @@ common_handle_option (struct gcc_options
>
> /* When instrumenting the pointers, we don't want to remove
> the null pointer checks. */
> - if (flag_sanitize & SANITIZE_NULL)
> + if (flag_sanitize & (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE
> + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE))
> opts->x_flag_delete_null_pointer_checks = 0;
>
> /* Kernel ASan implies normal ASan but does not yet support
> --- libsanitizer/ubsan/ubsan_handlers.cc.jj 2014-06-30 16:15:11.139941236 +0200
> +++ libsanitizer/ubsan/ubsan_handlers.cc 2014-09-09 13:18:23.449511672 +0200
> @@ -277,3 +277,43 @@ void __ubsan::__ubsan_handle_function_ty
> __ubsan_handle_function_type_mismatch(Data, Function);
> Die();
> }
> +
> +static void handleNonnullReturn(NonNullReturnData *Data) {
> + SourceLocation Loc = Data->Loc.acquire();
> + if (Loc.isDisabled())
> + return;
> +
> + Diag(Loc, DL_Error, "null pointer returned from function declared to never "
> + "return null");
> + if (!Data->AttrLoc.isInvalid())
> + Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
> +}
> +
> +void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
> + handleNonnullReturn(Data);
> +}
> +
> +void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
> + handleNonnullReturn(Data);
> + Die();
> +}
> +
> +static void handleNonNullArg(NonNullArgData *Data) {
> + SourceLocation Loc = Data->Loc.acquire();
> + if (Loc.isDisabled())
> + return;
> +
> + Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
> + "never be null") << Data->ArgIndex;
> + if (!Data->AttrLoc.isInvalid())
> + Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
> +}
> +
> +void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
> + handleNonNullArg(Data);
> +}
> +
> +void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
> + handleNonNullArg(Data);
> + Die();
> +}
> --- libsanitizer/ubsan/ubsan_handlers.h.jj 2014-06-30 16:15:11.128941292 +0200
> +++ libsanitizer/ubsan/ubsan_handlers.h 2014-09-09 13:48:42.686387487 +0200
> @@ -119,6 +119,23 @@ RECOVERABLE(function_type_mismatch,
> FunctionTypeMismatchData *Data,
> ValueHandle Val)
>
> +struct NonNullReturnData {
> + SourceLocation Loc;
> + SourceLocation AttrLoc;
> +};
> +
> +/// \brief Handle returning null from function with returns_nonnull attribute.
> +RECOVERABLE(nonnull_return, NonNullReturnData *Data)
> +
> +struct NonNullArgData {
> + SourceLocation Loc;
> + SourceLocation AttrLoc;
> + int ArgIndex;
> +};
> +
> +/// \brief Handle passing null pointer to function with nonnull attribute.
> +RECOVERABLE(nonnull_arg, NonNullArgData *Data)
> +
> }
>
> #endif // UBSAN_HANDLERS_H
>
> Jakub
>
>
--
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer