On Fri, Oct 06, 2017 at 02:46:05PM +0200, Martin Liška wrote:
> +       if (sanitize_comparison_p)
> +         {
> +           if (is_gimple_assign (s)
> +               && gimple_assign_rhs_class (s) == GIMPLE_BINARY_RHS
> +               && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (s)))
> +               && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs2 (s)))
> +               && is_pointer_compare_opcode (gimple_assign_rhs_code (s)))

Isn't it better to test is_pointer_compare_opcode right after
is_gimple_assign and leave the gimple_assign_rhs_class test out?

> +             {
> +               ptr1 = gimple_assign_rhs1 (s);
> +               ptr2 = gimple_assign_rhs2 (s);
> +               fn = BUILT_IN_ASAN_POINTER_COMPARE;
> +             }
> +           else if (gimple_code (s) == GIMPLE_COND
> +                    && POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (s)))
> +                    && POINTER_TYPE_P (TREE_TYPE (gimple_cond_rhs (s)))
> +                    && is_pointer_compare_opcode (gimple_cond_code (s)))
> +             {
> +               ptr1 = gimple_cond_lhs (s);
> +               ptr2 = gimple_cond_rhs (s);
> +               fn = BUILT_IN_ASAN_POINTER_COMPARE;
> +             }

You don't handle the case when there is a COND_EXPR with pointer comparison
in the condition.

> +         }
> +
> +       if (sanitize_subtraction_p
> +           && is_gimple_assign (s)
> +           && gimple_assign_rhs_class (s) == GIMPLE_BINARY_RHS

The above isn't really needed.

> +           && gimple_assign_rhs_code (s) == MINUS_EXPR)
> +         {
> +           tree rhs1 = gimple_assign_rhs1 (s);
> +           tree rhs2 = gimple_assign_rhs2 (s);
> +
> +           if (TREE_CODE (rhs1) == SSA_NAME
> +               || TREE_CODE (rhs2) == SSA_NAME)
> +             {
> +               gassign *def1
> +                 = dyn_cast<gassign *>(SSA_NAME_DEF_STMT (rhs1));
> +               gassign *def2
> +                 = dyn_cast<gassign *>(SSA_NAME_DEF_STMT (rhs2));
> +
> +               if (def1 && def2
> +                   && gimple_assign_rhs_class (def1) == GIMPLE_UNARY_RHS
> +                   && gimple_assign_rhs_class (def2) == GIMPLE_UNARY_RHS)
> +                 {
> +                   if (POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (def1)))
> +                       && POINTER_TYPE_P
> +                       (TREE_TYPE (gimple_assign_rhs1 (def2))))

Better add temporaries for rhs1/2 of def1, then you don't have issues with
too long lines.

> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -10935,6 +10935,26 @@ 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.

Poiinter-compare doesn't instrument -, so ", -" should be left out.

> +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}.  The checking currently works only for pointers allocated
> +on heap.
> +
> +@item -fsanitize=subtract

-fsanitize=pointer-subtract

> +@opindex fsanitize=pointer-compare

s/compare/subtract/

> +Instrument subtraction with pointer operands.
> +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}.  The checking currently works only for pointers allocated
> +on heap.
> +
>  @item -fsanitize=thread
>  @opindex fsanitize=thread
>  Enable ThreadSanitizer, a fast data race detector.

Conceptually, these two instrumentations rely on address sanitization,
not really sure if we should supporting them for kernel sanitization (but I
bet it is just going to be too costly for kernel).
So, we also need to make sure at least parts of SANITIZE_ADDRESS is enabled
when these options are on.
That can be done by erroring out if -fsanitize=pointer-compare is requested
without -fsanitize=address, or by implicitly enabling -fsanitize=address for
these, or by adding yet another SANITIZE_* bit which would cover
sanitization of memory accesses for asan, that bit would be set by
-fsanitize={address,kernel-address} in addition to the current 2 bits, but
pointer-{subtract,compare} would set its own bit and SANITIZE_ADDRESS and
SANITIZE_USER_ADDRESS only.  Without the new bit we'd emit red zones,
function prologue/epilogue asan changes, registraction of global variables,
but not actual instrumentation of memory accesses (and probably not
instrumentation of C++ ctor ordering).

> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -971,7 +971,9 @@ proper position among the other output files.  */
>  /* Linker command line options for -fsanitize= early on the command line.  */
>  #ifndef SANITIZER_EARLY_SPEC
>  #define SANITIZER_EARLY_SPEC "\
> -%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
> +%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address)\
> +    |%:sanitize(pointer-compare)\
> +    |%:sanitize(pointer-subtract):" LIBASAN_EARLY_SPEC "} \
>      %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
>      %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}"
>  #endif

Depending on the above, I wonder if sanitize(address) shouldn't be implied
by the new -fsanitize=pointer-{subtract,compare}, rather than polluting
specs for it everywhere.


> -      if (flag_sanitize & SANITIZE_ADDRESS)
> +      if (flag_sanitize & SANITIZE_ADDRESS
> +       || flag_sanitize & SANITIZE_POINTER_COMPARE
> +       || flag_sanitize & SANITIZE_POINTER_SUBTRACT)

Style nit, that would be better written as flag_sanitize & (A | B | C).
But depending on the above it might be simpler.

In any case, I'm not sure if we want this patch in GCC until the library
side isn't in so sorry state, because as we've discussed in the past, it
isn't really usable.  At least my reading of it is that whenever you
do one of these pointer comparisons or pointer subtractions and one or both
of the pointers aren't heap allocated, you'll get a runtime error.

        Jakub

Reply via email to