aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2017-12-05 10:23:25 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-12-05 10:23:25 +0100
commit05abad4cca62d3725175ccf628b74638fe43e043 (patch)
treea28c9b3ac2e4db36105499565bc890964b061fbb /gcc
parent81e4859a97804dfe76eb090f8b4d6a68361ce658 (diff)
downloadgcc-05abad4cca62d3725175ccf628b74638fe43e043.zip
gcc-05abad4cca62d3725175ccf628b74638fe43e043.tar.gz
gcc-05abad4cca62d3725175ccf628b74638fe43e043.tar.bz2
invoke.texi: Document the options.
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/c/ChangeLog7
-rw-r--r--gcc/c/c-typeck.c35
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/typeck.c39
-rw-r--r--gcc/doc/invoke.texi22
-rw-r--r--gcc/flag-types.h2
-rw-r--r--gcc/ipa-inline.c8
-rw-r--r--gcc/opts.c15
-rw-r--r--gcc/sanitizer.def4
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-compare-1.c95
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-compare-2.c82
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-subtract-1.c45
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-subtract-2.c37
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-subtract-3.c43
-rw-r--r--gcc/testsuite/c-c++-common/asan/pointer-subtract-4.c43
17 files changed, 494 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 879fb99..3959ec6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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,
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 1fb0c3d..8fea426 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 9222660..676dbbd 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -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,
}
/* 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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5f7a574..a5ab703 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 8454719..7210f99 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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. */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b4e0231..b8c8083 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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.
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 591b744..3073c66 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -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
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 8f12aa1..7846e93 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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
diff --git a/gcc/opts.c b/gcc/opts.c
index ab3f4ae..17579e7 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -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),
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 00e7ae0..7d224fa 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -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",
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index aeacec4..d040a77 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..2cc7395
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-compare-1.c
@@ -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
index 0000000..5539087
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-compare-2.c
@@ -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
index 0000000..7cbef81
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-subtract-1.c
@@ -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
index 0000000..6b65a16
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-subtract-2.c
@@ -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
index 0000000..5cbcda9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-subtract-3.c
@@ -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
index 0000000..820f0aa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pointer-subtract-4.c
@@ -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;
+}