Patchwork Add no_sanitize_undefined attribute (PR sanitizer/58411)

login
register
mail settings
Submitter Marek Polacek
Date Sept. 17, 2013, 4:45 p.m.
Message ID <20130917164525.GD15960@redhat.com>
Download mbox | patch
Permalink /patch/275504/
State New
Headers show

Comments

Marek Polacek - Sept. 17, 2013, 4:45 p.m.
On Tue, Sep 17, 2013 at 06:34:38PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 17, 2013 at 06:26:52PM +0200, Marek Polacek wrote:
> > Well I wonder too ;)  I thought it can't be NULL, and tried this
> > 
> > struct C {
> >   C() { __builtin_unreachable (); }
> > };
> 
> I was more wondering about stuff like:
> int a = (__builtin_unreachable (), 1);
> or similar.

Oh yeah, that would segfault, so I added the check that c_f_d is
non-NULL.  Ok now?

2013-09-17  Marek Polacek  <polacek@redhat.com>

	PR sanitizer/58411
	* doc/extend.texi: Document no_sanitize_undefined attribute.
	* builtins.c (fold_builtin_0): Don't sanitize function if it has the
	no_sanitize_undefined attribute.

c-family/
	* c-common.c (handle_no_sanitize_undefined_attribute): New function.
	Declare it.
	(struct attribute_spec c_common_att): Add no_sanitize_undefined.
cp/
	* typeck.c (cp_build_binary_op): Don't sanitize function if it has the
	no_sanitize_undefined attribute.
c/
	* c-typeck.c (build_binary_op): Don't sanitize function if it has the
	no_sanitize_undefined attribute.

testsuite/
	* c-c++-common/ubsan/attrib-1.c: New test.

	Marek
Jakub Jelinek - Sept. 17, 2013, 4:51 p.m.
On Tue, Sep 17, 2013 at 06:45:25PM +0200, Marek Polacek wrote:
> --- gcc/builtins.c.mp2	2013-09-17 16:13:26.623161281 +0200
> +++ gcc/builtins.c	2013-09-17 18:42:11.338273135 +0200
> @@ -10313,7 +10313,10 @@ fold_builtin_0 (location_t loc, tree fnd
>        return fold_builtin_classify_type (NULL_TREE);
>  
>      case BUILT_IN_UNREACHABLE:
> -      if (flag_sanitize & SANITIZE_UNREACHABLE)
> +      if (flag_sanitize & SANITIZE_UNREACHABLE
> +	  && current_function_decl != 0
> +	  && !lookup_attribute ("no_sanitize_undefined",
> +				DECL_ATTRIBUTES (current_function_decl)))
>  	return ubsan_instrument_unreachable (loc);
>        break;
>  

I'd say you should instead use
&& (current_function_decl == NULL
    || !lookup_attribute (...))
so that you instrument even outside of fn bodies, just with no way to turn
it off in the code (only command line options).

Ok with that change.

	Jakub

Patch

--- gcc/c-family/c-common.c.mp2	2013-09-17 15:55:56.417946667 +0200
+++ gcc/c-family/c-common.c	2013-09-17 15:58:55.905513029 +0200
@@ -311,6 +311,8 @@  static tree handle_no_sanitize_address_a
 						  int, bool *);
 static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree,
 							 int, bool *);
+static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
+						    bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
@@ -722,6 +724,9 @@  const struct attribute_spec c_common_att
   { "no_sanitize_address",    0, 0, true, false, false,
 			      handle_no_sanitize_address_attribute,
 			      false },
+  { "no_sanitize_undefined",  0, 0, true, false, false,
+			      handle_no_sanitize_undefined_attribute,
+			      false },
   { "warning",		      1, 1, true,  false, false,
 			      handle_error_attribute, false },
   { "error",		      1, 1, true,  false, false,
@@ -6575,6 +6580,22 @@  handle_no_address_safety_analysis_attrib
   return NULL_TREE;
 }
 
+/* Handle a "no_sanitize_undefined" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int,
+				      bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "noinline" attribute; arguments as in
    struct attribute_spec.handler.  */
 
--- gcc/doc/extend.texi.mp2	2013-09-17 15:55:44.250907707 +0200
+++ gcc/doc/extend.texi	2013-09-17 16:06:21.439974916 +0200
@@ -2136,6 +2136,7 @@  attributes are currently defined for fun
 @code{warn_unused_result}, @code{nonnull}, @code{gnu_inline},
 @code{externally_visible}, @code{hot}, @code{cold}, @code{artificial},
 @code{no_sanitize_address}, @code{no_address_safety_analysis},
+@code{no_sanitize_undefined},
 @code{error} and @code{warning}.
 Several other attributes are defined for functions on particular
 target systems.  Other attributes, including @code{section} are
@@ -3500,6 +3501,12 @@  The @code{no_address_safety_analysis} is
 @code{no_sanitize_address} attribute, new code should use
 @code{no_sanitize_address}.
 
+@item no_sanitize_undefined
+@cindex @code{no_sanitize_undefined} function attribute
+The @code{no_sanitize_undefined} attribute on functions is used
+to inform the compiler that it should not check for undefined behavior
+in the function when compiling with the @option{-fsanitize=undefined} option.
+
 @item regparm (@var{number})
 @cindex @code{regparm} attribute
 @cindex functions that are passed arguments in registers on the 386
--- gcc/cp/typeck.c.mp2	2013-09-17 16:10:49.935644344 +0200
+++ gcc/cp/typeck.c	2013-09-17 16:11:20.601743694 +0200
@@ -4887,6 +4887,8 @@  cp_build_binary_op (location_t location,
   if ((flag_sanitize & SANITIZE_UNDEFINED)
       && !processing_template_decl
       && current_function_decl != 0
+      && !lookup_attribute ("no_sanitize_undefined",
+			    DECL_ATTRIBUTES (current_function_decl))
       && (doing_div_or_mod || doing_shift))
     {
       /* OP0 and/or OP1 might have side-effects.  */
--- gcc/c/c-typeck.c.mp2	2013-09-17 16:09:31.423381687 +0200
+++ gcc/c/c-typeck.c	2013-09-17 16:10:00.626476422 +0200
@@ -10498,6 +10498,8 @@  build_binary_op (location_t location, en
 
   if (flag_sanitize & SANITIZE_UNDEFINED
       && current_function_decl != 0
+      && !lookup_attribute ("no_sanitize_undefined",
+			    DECL_ATTRIBUTES (current_function_decl))
       && (doing_div_or_mod || doing_shift))
     {
       /* OP0 and/or OP1 might have side-effects.  */
--- gcc/testsuite/c-c++-common/ubsan/attrib-1.c.mp2	2013-09-17 16:33:46.729660165 +0200
+++ gcc/testsuite/c-c++-common/ubsan/attrib-1.c	2013-09-17 16:43:22.308566840 +0200
@@ -0,0 +1,33 @@ 
+/* PR sanitizer/58411 */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined -w" } */
+
+__attribute__((no_sanitize_undefined)) int
+f1 (int i)
+{
+  return 16 << i;
+}
+
+int f2 (int i);
+int f2 (int i) __attribute__((no_sanitize_undefined));
+int f2 (int i) __attribute__((no_sanitize_undefined));
+int f2 (int i);
+
+int
+f2 (int i)
+{
+  return 1 / i;
+}
+
+void f3 (void);
+__typeof (f3) f3  __attribute__((__no_sanitize_undefined__));
+
+void
+f3 (void)
+{
+  __builtin_unreachable ();
+}
+
+/* { dg-final { scan-assembler-not "__ubsan_handle_shift_out_of_bounds" } } */
+/* { dg-final { scan-assembler-not "__ubsan_handle_divrem_overflow" } } */
+/* { dg-final { scan-assembler-not "__ubsan_handle_builtin_unreachable" } } */
--- gcc/builtins.c.mp2	2013-09-17 16:13:26.623161281 +0200
+++ gcc/builtins.c	2013-09-17 18:42:11.338273135 +0200
@@ -10313,7 +10313,10 @@  fold_builtin_0 (location_t loc, tree fnd
       return fold_builtin_classify_type (NULL_TREE);
 
     case BUILT_IN_UNREACHABLE:
-      if (flag_sanitize & SANITIZE_UNREACHABLE)
+      if (flag_sanitize & SANITIZE_UNREACHABLE
+	  && current_function_decl != 0
+	  && !lookup_attribute ("no_sanitize_undefined",
+				DECL_ATTRIBUTES (current_function_decl)))
 	return ubsan_instrument_unreachable (loc);
       break;