invoke.texi: Document the options.
authorMartin Liska <mliska@suse.cz>
Tue, 5 Dec 2017 09:23:25 +0000 (10:23 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 5 Dec 2017 09:23:25 +0000 (10:23 +0100)
gcc/
* doc/invoke.texi: Document the options.
* flag-types.h (enum sanitize_code): Add
SANITIZE_POINTER_COMPARE and SANITIZE_POINTER_SUBTRACT.
* ipa-inline.c (sanitize_attrs_match_for_inline_p): Add handling
of SANITIZE_POINTER_COMPARE and SANITIZE_POINTER_SUBTRACT.
* opts.c: Define new sanitizer options.
* sanitizer.def (BUILT_IN_ASAN_POINTER_COMPARE): Likewise.
(BUILT_IN_ASAN_POINTER_SUBTRACT): Likewise.
gcc/c/
* c-typeck.c (pointer_diff): Add new argument and instrument
pointer subtraction.
(build_binary_op): Similar for pointer comparison.
gcc/cp/
* typeck.c (pointer_diff): Add new argument and instrument
pointer subtraction.
(cp_build_binary_op): Create compound expression if doing an
instrumentation.
gcc/testsuite/
* c-c++-common/asan/pointer-compare-1.c: New test.
* c-c++-common/asan/pointer-compare-2.c: New test.
* c-c++-common/asan/pointer-subtract-1.c: New test.
* c-c++-common/asan/pointer-subtract-2.c: New test.
* c-c++-common/asan/pointer-subtract-3.c: New test.
* c-c++-common/asan/pointer-subtract-4.c: New test.
libsanitizer/
* asan/asan_descriptions.cc: Cherry-pick upstream r319668.
* asan/asan_descriptions.h: Likewise.
* asan/asan_report.cc: Likewise.
* asan/asan_thread.cc: Likewise.
* asan/asan_thread.h: Likewise.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
From-SVN: r255404

23 files changed:
gcc/ChangeLog
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/doc/invoke.texi
gcc/flag-types.h
gcc/ipa-inline.c
gcc/opts.c
gcc/sanitizer.def
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/asan/pointer-compare-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/pointer-compare-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/pointer-subtract-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/pointer-subtract-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/pointer-subtract-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/pointer-subtract-4.c [new file with mode: 0644]
libsanitizer/ChangeLog
libsanitizer/asan/asan_descriptions.cc
libsanitizer/asan/asan_descriptions.h
libsanitizer/asan/asan_report.cc
libsanitizer/asan/asan_thread.cc
libsanitizer/asan/asan_thread.h

index 879fb99b313b6c6dfe644c8fadfb98788d1f0de8..3959ec6f54eeaf421b997edd3640f2be6313c3b5 100644 (file)
@@ -1,3 +1,15 @@
+2017-12-05  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * doc/invoke.texi: Document the options.
+       * flag-types.h (enum sanitize_code): Add
+       SANITIZE_POINTER_COMPARE and SANITIZE_POINTER_SUBTRACT.
+       * ipa-inline.c (sanitize_attrs_match_for_inline_p): Add handling
+       of SANITIZE_POINTER_COMPARE and SANITIZE_POINTER_SUBTRACT.
+       * opts.c: Define new sanitizer options.
+       * sanitizer.def (BUILT_IN_ASAN_POINTER_COMPARE): Likewise.
+       (BUILT_IN_ASAN_POINTER_SUBTRACT): Likewise.
+
 2017-12-05  Julia Koval  <julia.koval@intel.com>
 
        * common/config/i386/i386-common.c (OPTION_MASK_ISA_AVX512VNNI_SET,
index 1fb0c3d0b7ff96baecfbc303604b895c4f8a02eb..8fea42622b233e40b497e197178acb4d1c2cd45c 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-05  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * c-typeck.c (pointer_diff): Add new argument and instrument
+       pointer subtraction.
+       (build_binary_op): Similar for pointer comparison.
+
 2017-12-01  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/79153
index 922266038afb6d3d410ef97b5d61837146631a5d..676dbbd2e2ff81157d6d910d62a7cf3c874deefb 100644 (file)
@@ -95,7 +95,7 @@ static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec<location_t>, tree,
                              vec<tree, va_gc> *, vec<tree, va_gc> *, tree,
                              tree);
-static tree pointer_diff (location_t, tree, tree);
+static tree pointer_diff (location_t, tree, tree, tree *);
 static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
                                    enum impl_conv, bool, tree, tree, int);
 static tree valid_compound_expr_initializer (tree, tree);
@@ -3768,10 +3768,11 @@ parser_build_binary_op (location_t location, enum tree_code code,
 }
 \f
 /* Return a tree for the difference of pointers OP0 and OP1.
-   The resulting tree has type ptrdiff_t.  */
+   The resulting tree has type ptrdiff_t.  If POINTER_SUBTRACT sanitization is
+   enabled, assign to INSTRUMENT_EXPR call to libsanitizer.  */
 
 static tree
-pointer_diff (location_t loc, tree op0, tree op1)
+pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr)
 {
   tree restype = ptrdiff_type_node;
   tree result, inttype;
@@ -3815,6 +3816,17 @@ pointer_diff (location_t loc, tree op0, tree op1)
     pedwarn (loc, OPT_Wpointer_arith,
             "pointer to a function used in subtraction");
 
+  if (sanitize_flags_p (SANITIZE_POINTER_SUBTRACT))
+    {
+      gcc_assert (current_function_decl != NULL_TREE);
+
+      op0 = save_expr (op0);
+      op1 = save_expr (op1);
+
+      tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_SUBTRACT);
+      *instrument_expr = build_call_expr_loc (loc, tt, 2, op0, op1);
+    }
+
   /* First do the subtraction, then build the divide operator
      and only convert at the very end.
      Do not do default conversions in case restype is a short type.  */
@@ -3825,8 +3837,8 @@ pointer_diff (location_t loc, tree op0, tree op1)
      space, cast the pointers to some larger integer type and do the
      computations in that type.  */
   if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0)))
-       op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0),
-                             convert (inttype, op1), false);
+    op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0),
+                          convert (inttype, op1), false);
   else
     op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1);
 
@@ -11113,7 +11125,7 @@ build_binary_op (location_t location, enum tree_code code,
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
          && comp_target_types (location, type0, type1))
        {
-         ret = pointer_diff (location, op0, op1);
+         ret = pointer_diff (location, op0, op1, &instrument_expr);
          goto return_build_binary_op;
        }
       /* Handle pointer minus int.  Just like pointer plus int.  */
@@ -11663,6 +11675,17 @@ build_binary_op (location_t location, enum tree_code code,
          result_type = type1;
          pedwarn (location, 0, "comparison between pointer and integer");
        }
+
+      if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE)
+         && sanitize_flags_p (SANITIZE_POINTER_COMPARE))
+       {
+         op0 = save_expr (op0);
+         op1 = save_expr (op1);
+
+         tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_COMPARE);
+         instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1);
+       }
+
       if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE
           || truth_value_p (TREE_CODE (orig_op0)))
          ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE
index 5f7a574e7a59d5e585e745c3abee7756c675022a..a5ab703d1d3ffdcd002801e3e6e116f6cb0f9f27 100644 (file)
@@ -1,3 +1,11 @@
+2017-12-05  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * typeck.c (pointer_diff): Add new argument and instrument
+       pointer subtraction.
+       (cp_build_binary_op): Create compound expression if doing an
+       instrumentation.
+
 2017-12-05  Jakub Jelinek  <jakub@redhat.com>
 
        * cp-gimplify.c (cp_maybe_instrument_return): Don't add
index 8454719118efdccf7b579fde84645df645dcf591..7210f99fb083bdbbc1da97699293ad0825002fd2 100644 (file)
@@ -54,7 +54,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
-static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t);
+static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t, tree *);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
 static bool casts_away_constness (tree, tree, tsubst_flags_t);
@@ -4329,8 +4329,16 @@ cp_build_binary_op (location_t location,
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
          && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
                                                        TREE_TYPE (type1)))
-       return pointer_diff (location, op0, op1,
-                            common_pointer_type (type0, type1), complain);
+       {
+         result = pointer_diff (location, op0, op1,
+                                common_pointer_type (type0, type1), complain,
+                                &instrument_expr);
+         if (instrument_expr != NULL)
+           result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+                            instrument_expr, result);
+
+         return result;
+       }
       /* In all other cases except pointer - int, the usual arithmetic
         rules apply.  */
       else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE))
@@ -5019,6 +5027,17 @@ cp_build_binary_op (location_t location,
           else
             return error_mark_node;
        }
+
+      if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE)
+         && sanitize_flags_p (SANITIZE_POINTER_COMPARE))
+       {
+         op0 = save_expr (op0);
+         op1 = save_expr (op1);
+
+         tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_COMPARE);
+         instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1);
+       }
+
       break;
 
     case UNORDERED_EXPR:
@@ -5374,11 +5393,12 @@ cp_pointer_int_sum (location_t loc, enum tree_code resultcode, tree ptrop,
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
-   The resulting tree has type int.  */
+   The resulting tree has type int.  If POINTER_SUBTRACT sanitization is
+   enabled, assign to INSTRUMENT_EXPR call to libsanitizer.  */
 
 static tree
 pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
-             tsubst_flags_t complain)
+             tsubst_flags_t complain, tree *instrument_expr)
 {
   tree result, inttype;
   tree restype = ptrdiff_type_node;
@@ -5420,6 +5440,15 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
   else
     inttype = restype;
 
+  if (sanitize_flags_p (SANITIZE_POINTER_SUBTRACT))
+    {
+      op0 = save_expr (op0);
+      op1 = save_expr (op1);
+
+      tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_SUBTRACT);
+      *instrument_expr = build_call_expr_loc (loc, tt, 2, op0, op1);
+    }
+
   /* First do the subtraction, then build the divide operator
      and only convert at the very end.
      Do not do default conversions in case restype is a short type.  */
index b4e0231602c67512d05a56a2b1f351112d2f1448..b8c8083daa7209bd7ea27159a4c718f02c63b1fd 100644 (file)
@@ -11034,6 +11034,28 @@ Enable AddressSanitizer for Linux kernel.
 See @uref{https://github.com/google/kasan/wiki} for more details.
 The option cannot be combined with @option{-fcheck-pointer-bounds}.
 
+@item -fsanitize=pointer-compare
+@opindex fsanitize=pointer-compare
+Instrument comparison operation (<, <=, >, >=) with pointer operands.
+The option must be combined with either @option{-fsanitize=kernel-address} or
+@option{-fsanitize=address}
+The option cannot be combined with @option{-fsanitize=thread}
+and/or @option{-fcheck-pointer-bounds}.
+Note: By default the check is disabled at run time.  To enable it,
+add @code{detect_invalid_pointer_pairs=1} to the environment variable
+@env{ASAN_OPTIONS}.
+
+@item -fsanitize=pointer-subtract
+@opindex fsanitize=pointer-subtract
+Instrument subtraction with pointer operands.
+The option must be combined with either @option{-fsanitize=kernel-address} or
+@option{-fsanitize=address}
+The option cannot be combined with @option{-fsanitize=thread}
+and/or @option{-fcheck-pointer-bounds}.
+Note: By default the check is disabled at run time.  To enable it,
+add @code{detect_invalid_pointer_pairs=1} to the environment variable
+@env{ASAN_OPTIONS}.
+
 @item -fsanitize=thread
 @opindex fsanitize=thread
 Enable ThreadSanitizer, a fast data race detector.
index 591b74457cdd24e942c5901d7db380da4fe54a49..3073c66187243453372451ecfe2bdc535aacd88d 100644 (file)
@@ -246,6 +246,8 @@ enum sanitize_code {
   SANITIZE_BOUNDS_STRICT = 1UL << 23,
   SANITIZE_POINTER_OVERFLOW = 1UL << 24,
   SANITIZE_BUILTIN = 1UL << 25,
+  SANITIZE_POINTER_COMPARE = 1UL << 26,
+  SANITIZE_POINTER_SUBTRACT = 1UL << 27,
   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
                       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
index 8f12aa16687656a70f6b45e70cd7f9b6a633e698..7846e93d119992dbdd66e4a9368437c402c21775 100644 (file)
@@ -260,8 +260,12 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee)
   if (!caller || !callee)
     return true;
 
-  return sanitize_flags_p (SANITIZE_ADDRESS, caller)
-    == sanitize_flags_p (SANITIZE_ADDRESS, callee);
+  return ((sanitize_flags_p (SANITIZE_ADDRESS, caller)
+          == sanitize_flags_p (SANITIZE_ADDRESS, callee))
+         && (sanitize_flags_p (SANITIZE_POINTER_COMPARE, caller)
+             == sanitize_flags_p (SANITIZE_POINTER_COMPARE, callee))
+         && (sanitize_flags_p (SANITIZE_POINTER_SUBTRACT, caller)
+             == sanitize_flags_p (SANITIZE_POINTER_SUBTRACT, callee)));
 }
 
 /* Used for flags where it is safe to inline when caller's value is
index ab3f4aefed32c0a265221678c87549958bb50ccb..17579e72373ee831a55d5efde4fbbe305b4fcf6c 100644 (file)
@@ -953,6 +953,19 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_dwarf_split_debug_info)
     opts->x_debug_generate_pub_sections = 2;
 
+  if ((opts->x_flag_sanitize
+       & (SANITIZE_USER_ADDRESS | SANITIZE_KERNEL_ADDRESS)) == 0)
+    {
+      if (opts->x_flag_sanitize & SANITIZE_POINTER_COMPARE)
+       error_at (loc,
+                 "%<-fsanitize=pointer-compare%> must be combined with "
+                 "%<-fsanitize=address%> or %<-fsanitize=kernel-address%>");
+      if (opts->x_flag_sanitize & SANITIZE_POINTER_SUBTRACT)
+       error_at (loc,
+                 "%<-fsanitize=pointer-subtract%> must be combined with "
+                 "%<-fsanitize=address%> or %<-fsanitize=kernel-address%>");
+    }
+
   /* Userspace and kernel ASan conflict with each other.  */
   if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
       && (opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS))
@@ -1497,6 +1510,8 @@ const struct sanitizer_opts_s sanitizer_opts[] =
   SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true),
   SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
                 true),
+  SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true),
+  SANITIZER_OPT (pointer-subtract, SANITIZE_POINTER_SUBTRACT, true),
   SANITIZER_OPT (thread, SANITIZE_THREAD, false),
   SANITIZER_OPT (leak, SANITIZE_LEAK, false),
   SANITIZER_OPT (shift, SANITIZE_SHIFT, true),
index 00e7ae031e677cc3eac176d4a35c92e353f7eb9f..7d224fa081ea09423b3a5088462502b5fdf136ad 100644 (file)
@@ -175,6 +175,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCA_POISON, "__asan_alloca_poison",
                      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCAS_UNPOISON, "__asan_allocas_unpoison",
                      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_COMPARE, "__sanitizer_ptr_cmp",
+                     BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
+                     BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
index aeacec422cc5041d938298701663ad17ba41d37b..d040a7799553ff9b36889e5c8dcf7c0ec976923e 100644 (file)
@@ -1,3 +1,13 @@
+2017-12-05  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * c-c++-common/asan/pointer-compare-1.c: New test.
+       * c-c++-common/asan/pointer-compare-2.c: New test.
+       * c-c++-common/asan/pointer-subtract-1.c: New test.
+       * c-c++-common/asan/pointer-subtract-2.c: New test.
+       * c-c++-common/asan/pointer-subtract-3.c: New test.
+       * c-c++-common/asan/pointer-subtract-4.c: New test.
+
 2017-12-05  Jakub Jelinek  <jakub@redhat.com>
 
        * g++.dg/missing-return.C: Add -O to dg-options.
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-compare-1.c b/gcc/testsuite/c-c++-common/asan/pointer-compare-1.c
new file mode 100644 (file)
index 0000000..2cc7395
--- /dev/null
@@ -0,0 +1,95 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1:halt_on_error=0" } */
+/* { dg-options "-fsanitize=address,pointer-compare" } */
+
+volatile int v;
+
+__attribute__((noipa)) void
+foo (char *p, char *q)
+{
+  v = p > q;
+}
+
+char global1[100] = {}, global2[100] = {};
+char __attribute__((used)) smallest_global[5] = {};
+char small_global[7] = {};
+char __attribute__((used)) little_global[10] = {};
+char __attribute__((used)) medium_global[4000] = {};
+char large_global[5000] = {};
+char __attribute__((used)) largest_global[6000] = {};
+
+int
+main ()
+{
+  /* Heap allocated memory.  */
+  char *heap1 = (char *)__builtin_malloc (42);
+  char *heap2 = (char *)__builtin_malloc (42);
+
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, heap2);
+  __builtin_free (heap1);
+  __builtin_free (heap2);
+
+  heap1 = (char *)__builtin_malloc (1024);
+  __asm ("" : "+g" (heap1));
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, heap1 + 1025);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1 + 1024, heap1 + 1025);
+  __builtin_free (heap1);
+
+  heap1 = (char *)__builtin_malloc (4096);
+  __asm ("" : "+g" (heap1));
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, heap1 + 4097);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, 0);
+
+  /* Global variables.  */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (&global1[0], &global2[10]);
+
+  char *p = &small_global[0];
+  __asm ("" : "+g" (p));
+  foo (p, p); /* OK */
+  foo (p, p + 7); /* OK */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, p + 8);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p - 1, p);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, p - 1);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p - 1, p + 8);
+
+  p = &large_global[0];
+  __asm ("" : "+g" (p));
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p - 1, p);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, p - 1);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, &global1[0]);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, &small_global[0]);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (p, 0);
+
+  /* Stack variables.  */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  char stack1, stack2;
+  foo (&stack1, &stack2);
+
+  /* Mixtures.  */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, &stack1);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, &global1[0]);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (&stack1, &global1[0]);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair" } */
+  foo (&stack1, 0);
+  __builtin_free (heap1);
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-compare-2.c b/gcc/testsuite/c-c++-common/asan/pointer-compare-2.c
new file mode 100644 (file)
index 0000000..5539087
--- /dev/null
@@ -0,0 +1,82 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1 halt_on_error=1" } */
+/* { dg-options "-fsanitize=address,pointer-compare" } */
+
+volatile int v;
+
+int
+foo (char *p)
+{
+  char *p2 = p + 20;
+  v = p > p2;
+  return v;
+}
+
+void
+bar (char *p, char *q)
+{
+  v = p <= q;
+}
+
+void
+baz (char *p, char *q)
+{
+  v = (p != 0 && p < q);
+}
+
+char global[8192] = {};
+char small_global[7] = {};
+
+int
+main ()
+{
+  /* Heap allocated memory.  */
+  char *p = (char *)__builtin_malloc (42);
+  int r = foo (p);
+  __builtin_free (p);
+
+  p = (char *)__builtin_malloc (1024);
+  bar (p, p + 1024);
+  bar (p + 1024, p + 1023);
+  bar (p + 1, p + 1023);
+  __builtin_free (p);
+
+  p = (char *)__builtin_malloc (4096);
+  bar (p, p + 4096);
+  bar (p + 10, p + 100);
+  bar (p + 1024, p + 4096);
+  bar (p + 4095, p + 4096);
+  bar (p + 4095, p + 4094);
+  bar (p + 100, p + 4096);
+  bar (p + 100, p + 4094);
+  __builtin_free (p);
+
+  /* Global variable.  */
+  bar (&global[0], &global[1]);
+  bar (&global[1], &global[2]);
+  bar (&global[2], &global[1]);
+  bar (&global[0], &global[100]);
+  bar (&global[1000], &global[7000]);
+  bar (&global[500], &global[10]);
+  p = &global[0];
+  bar (p, p + 8192);
+  p = &global[8000];
+  bar (p, p + 192);
+
+  p = &small_global[0];
+  bar (p, p + 1);
+  bar (p, p + 7);
+  bar (p + 7, p + 1);
+  bar (p + 6, p + 7);
+  bar (p + 7, p + 7);
+
+  /* Stack variable.  */
+  char stack[10000];
+  bar (&stack[0], &stack[100]);
+  bar (&stack[1000], &stack[9000]);
+  bar (&stack[500], &stack[10]);
+
+  baz (0, &stack[10]);
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-subtract-1.c b/gcc/testsuite/c-c++-common/asan/pointer-subtract-1.c
new file mode 100644 (file)
index 0000000..7cbef81
--- /dev/null
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1 halt_on_error=0" } */
+/* { dg-options "-fsanitize=address,pointer-subtract" } */
+
+volatile __PTRDIFF_TYPE__ v;
+
+__attribute__((noipa)) void
+foo (char *p, char *q)
+{
+  v = p - q;
+}
+
+char global1[100] = {}, global2[100] = {};
+
+int
+main ()
+{
+  /* Heap allocated memory.  */
+  char *heap1 = (char *)__builtin_malloc (42);
+  char *heap2 = (char *)__builtin_malloc (42);
+
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, heap2);
+
+  /* Global variables.  */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (&global1[0], &global2[10]);
+
+  /* Stack variables.  */
+  char stack1, stack2;
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (&stack1, &stack2);
+
+  /* Mixtures.  */
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, &stack1);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair.*" } */
+  foo (heap1, &global1[0]);
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair" } */
+  foo (&stack1, &global1[0]);
+
+  __builtin_free (heap1);
+  __builtin_free (heap2);  
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-subtract-2.c b/gcc/testsuite/c-c++-common/asan/pointer-subtract-2.c
new file mode 100644 (file)
index 0000000..6b65a16
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1 halt_on_error=1" } */
+/* { dg-options "-fsanitize=address,pointer-subtract" } */
+
+volatile __PTRDIFF_TYPE__ v;
+
+void
+bar (char *p, char *q)
+{
+  v = q - p;
+  v = p - q;
+}
+
+char global[10000] = {};
+
+int
+main ()
+{
+  /* Heap allocated memory.  */
+  char *p = (char *)__builtin_malloc (42);
+  bar (p, p + 20);
+  __builtin_free (p);
+
+  /* Global variable.  */
+  bar (&global[0], &global[100]);
+  bar (&global[1000], &global[9000]);
+  bar (&global[500], &global[10]);
+  bar (&global[0], &global[10000]);
+
+  /* Stack variable.  */
+  char stack[10000];
+  bar (&stack[0], &stack[100]);
+  bar (&stack[1000], &stack[9000]);
+  bar (&stack[500], &stack[10]);
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-subtract-3.c b/gcc/testsuite/c-c++-common/asan/pointer-subtract-3.c
new file mode 100644 (file)
index 0000000..5cbcda9
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do run { target pthread_h } } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1:halt_on_error=1" } */
+/* { dg-options "-fsanitize=address,pointer-subtract" } */
+/* { dg-additional-options "-pthread" { target pthread } } */
+
+#include <unistd.h>
+#include <pthread.h>
+
+char *pointers[2];
+pthread_barrier_t bar;
+
+void *
+thread_main (void *n)
+{
+  char local;
+
+  __UINTPTR_TYPE__ id = (__UINTPTR_TYPE__) n;
+  pointers[id] = &local;
+  pthread_barrier_wait (&bar);
+  pthread_barrier_wait (&bar);
+
+  return 0;
+}
+
+int
+main ()
+{
+  pthread_t threads[2];
+  pthread_barrier_init (&bar, NULL, 3);
+  pthread_create (&threads[0], NULL, thread_main, (void *) 0);
+  pthread_create (&threads[1], NULL, thread_main, (void *) 1);
+  pthread_barrier_wait (&bar);
+
+  /* This case is not handled yet.  */
+  volatile __PTRDIFF_TYPE__ r = pointers[0] - pointers[1];
+
+  pthread_barrier_wait (&bar);
+  pthread_join (threads[0], NULL);
+  pthread_join (threads[1], NULL);
+  pthread_barrier_destroy (&bar);
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/asan/pointer-subtract-4.c b/gcc/testsuite/c-c++-common/asan/pointer-subtract-4.c
new file mode 100644 (file)
index 0000000..820f0aa
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do run { target pthread_h } } */
+/* { dg-shouldfail "asan" } */
+/* { dg-set-target-env-var ASAN_OPTIONS "detect_invalid_pointer_pairs=1:halt_on_error=1" } */
+/* { dg-options "-fsanitize=address,pointer-subtract" } */
+/* { dg-additional-options "-pthread" { target pthread } } */
+
+#include <unistd.h>
+#include <pthread.h>
+
+char *pointer;
+pthread_barrier_t bar;
+
+void *
+thread_main (void *n)
+{
+  char local;
+  (void) n;
+  pointer = &local;
+  pthread_barrier_wait (&bar);
+  pthread_barrier_wait (&bar);
+
+  return 0;
+}
+
+int
+main ()
+{
+  pthread_t thread;
+  pthread_barrier_init (&bar, NULL, 2);
+  pthread_create (&thread, NULL, thread_main, NULL);
+  pthread_barrier_wait (&bar);
+
+  char local;
+  char *parent_pointer = &local;
+
+  /* { dg-output "ERROR: AddressSanitizer: invalid-pointer-pair" } */
+  volatile __PTRDIFF_TYPE__ r = parent_pointer - pointer;
+  pthread_barrier_wait (&bar);
+  pthread_join (thread, NULL);
+  pthread_barrier_destroy (&bar);
+
+  return 0;
+}
index 497c4eaed5c0873ccb3c375e5512f429967e2fd6..e5cad19bb5e3da859e162cec9a46ef0a32017bee 100644 (file)
@@ -1,3 +1,12 @@
+2017-12-05  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * asan/asan_descriptions.cc: Cherry-pick upstream r319668.
+       * asan/asan_descriptions.h: Likewise.
+       * asan/asan_report.cc: Likewise.
+       * asan/asan_thread.cc: Likewise.
+       * asan/asan_thread.h: Likewise.
+
 2017-11-17  Igor Tsimbalist  <igor.v.tsimbalist@intel.com>
 
        * acinclude.m4: Add enable.m4 and cet.m4.
index d46962adf2769cbbbc9b29852c9c9e61d975a3ae..c856a6537423ff9e325b0e9e79109faff01d7fc3 100644 (file)
@@ -333,6 +333,26 @@ void GlobalAddressDescription::Print(const char *bug_type) const {
   }
 }
 
+bool GlobalAddressDescription::PointsInsideTheSameVariable(
+    const GlobalAddressDescription &other) const {
+  if (size == 0 || other.size == 0) return false;
+
+  for (uptr i = 0; i < size; i++) {
+    const __asan_global &a = globals[i];
+    for (uptr j = 0; j < other.size; j++) {
+      const __asan_global &b = other.globals[j];
+      if (a.beg == b.beg &&
+          a.beg <= addr &&
+          b.beg <= other.addr &&
+          (addr + access_size) < (a.beg + a.size) &&
+          (other.addr + other.access_size) < (b.beg + b.size))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 void StackAddressDescription::Print() const {
   Decorator d;
   char tname[128];
index 0fbb531492a928093470f442422ee4c15d66a7c9..12d9ac5f70be2f8a3076e7a1260cae94cc12cf1c 100644 (file)
@@ -143,6 +143,10 @@ struct GlobalAddressDescription {
   u8 size;
 
   void Print(const char *bug_type = "") const;
+
+  // Returns true when this descriptions points inside the same global variable
+  // as other. Descriptions can have different address within the variable
+  bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
 };
 
 bool GetGlobalAddressInformation(uptr addr, uptr access_size,
index 51bad6e45e3e1f1c73f78a73d0ac76dac8f24830..261ec1aece5dc544f5ec67f923b1edd126de6bd2 100644 (file)
@@ -295,17 +295,58 @@ static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
   in_report.ReportError(error);
 }
 
+static bool IsInvalidPointerPair(uptr a1, uptr a2) {
+  if (a1 == a2)
+    return false;
+
+  // 256B in shadow memory can be iterated quite fast
+  static const uptr kMaxOffset = 2048;
+
+  uptr left = a1 < a2 ? a1 : a2;
+  uptr right = a1 < a2 ? a2 : a1;
+  uptr offset = right - left;
+  if (offset <= kMaxOffset)
+    return __asan_region_is_poisoned(left, offset);
+
+  AsanThread *t = GetCurrentThread();
+
+  // check whether left is a stack memory pointer
+  if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
+    uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
+    return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
+  }
+
+  // check whether left is a heap memory address
+  HeapAddressDescription hdesc1, hdesc2;
+  if (GetHeapAddressInformation(left, 0, &hdesc1) &&
+      hdesc1.chunk_access.access_type == kAccessTypeInside)
+    return !GetHeapAddressInformation(right, 0, &hdesc2) ||
+        hdesc2.chunk_access.access_type != kAccessTypeInside ||
+        hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
+
+  // check whether left is an address of a global variable
+  GlobalAddressDescription gdesc1, gdesc2;
+  if (GetGlobalAddressInformation(left, 0, &gdesc1))
+    return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
+        !gdesc1.PointsInsideTheSameVariable(gdesc2);
+
+  if (t->GetStackVariableShadowStart(right) ||
+      GetHeapAddressInformation(right, 0, &hdesc2) ||
+      GetGlobalAddressInformation(right - 1, 0, &gdesc2))
+    return true;
+
+  // At this point we know nothing about both a1 and a2 addresses.
+  return false;
+}
+
 static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
   if (!flags()->detect_invalid_pointer_pairs) return;
   uptr a1 = reinterpret_cast<uptr>(p1);
   uptr a2 = reinterpret_cast<uptr>(p2);
-  AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
-  AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
-  bool valid1 = chunk1.IsAllocated();
-  bool valid2 = chunk2.IsAllocated();
-  if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
+
+  if (IsInvalidPointerPair(a1, a2)) {
     GET_CALLER_PC_BP_SP;
-    return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+    ReportInvalidPointerPair(pc, bp, sp, a1, a2);
   }
 }
 // ----------------------- Mac-specific reports ----------------- {{{1
index d0fdf6e984787242a62587fe7b16c3eeb6cf1bd8..f817a10db272e2ea15483a79c7c35a4057f59586 100644 (file)
@@ -315,7 +315,7 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
     access->frame_descr = (const char *)((uptr*)bottom)[1];
     return true;
   }
-  uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
+  uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
   uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
@@ -344,6 +344,29 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
   return true;
 }
 
+uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
+  uptr bottom = 0;
+  if (AddrIsInStack(addr)) {
+    bottom = stack_bottom();
+  } else if (has_fake_stack()) {
+    bottom = fake_stack()->AddrIsInFakeStack(addr);
+    CHECK(bottom);
+  } else
+    return 0;
+
+  uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
+  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
+  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
+
+  while (shadow_ptr >= shadow_bottom &&
+         (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
+          *shadow_ptr != kAsanStackMidRedzoneMagic &&
+          *shadow_ptr != kAsanStackRightRedzoneMagic))
+    shadow_ptr--;
+
+  return (uptr)shadow_ptr + 1;
+}
+
 bool AsanThread::AddrIsInStack(uptr addr) {
   const auto bounds = GetStackBounds();
   return addr >= bounds.bottom && addr < bounds.top;
index f7a91f3e73b0a2413531b45abf1dcb874429aed4..187cb13e85b48ff109e5c8bd4787627d4efe018a 100644 (file)
@@ -88,6 +88,9 @@ class AsanThread {
   };
   bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
 
+  // Returns a pointer to the start of the stack variable's shadow memory.
+  uptr GetStackVariableShadowStart(uptr addr);
+
   bool AddrIsInStack(uptr addr);
 
   void DeleteFakeStack(int tid) {