On Thu, Apr 23, 2020 at 5:43 PM Marco Elver <el...@google.com> wrote:
>
> Add support to optionally emit different instrumentation for accesses to
> volatile variables. While the default TSAN runtime likely will never
> require this feature, other runtimes for different environments that
> have subtly different memory models or assumptions may require
> distinguishing volatiles.
>
> One such environment are OS kernels, where volatile is still used in
> various places for various reasons, and often declare volatile to be
> "safe enough" even in multi-threaded contexts. One such example is the
> Linux kernel, which implements various synchronization primitives using
> volatile (READ_ONCE(), WRITE_ONCE()). Here the Kernel Concurrency
> Sanitizer (KCSAN) [1], is a runtime that uses TSAN instrumentation but
> otherwise implements a very different approach to race detection from
> TSAN.
>
> While in the Linux kernel it is generally discouraged to use volatiles
> explicitly, the topic will likely come up again, and we will eventually
> need to distinguish volatile accesses [2]. The other use-case is
> ignoring data races on specially marked variables in the kernel, for
> example bit-flags (here we may hide 'volatile' behind a different name
> such as 'no_data_race').
>
> [1] https://github.com/google/ktsan/wiki/KCSAN
> [2] 
> https://lkml.kernel.org/r/CANpmjNOfXNE-Zh3MNP=-gmnhvKbsfUfTtWkyg_=vqtxs4nn...@mail.gmail.com


Hi Jakub,

FWIW this is:

Acked-by: Dmitry Vyukov <dvuy...@google.com>

We just landed a similar change to llvm:
https://github.com/llvm/llvm-project/commit/5a2c31116f412c3b6888be361137efd705e05814

Do you have any objections?
Yes, I know volatile is not related to threading :) But 5 years we
have a similar patch for gcc for another race detector prototype:
https://gist.github.com/xairy/862ba3260348efe23a37decb93aa79e9
So this is not the first time this comes up.

Thanks




> 2020-04-23  Marco Elver  <el...@google.com>
>
> gcc/
>         * params.opt: Define --param=tsan-distinguish-volatile=[0,1].
>         * sanitizer.def (BUILT_IN_TSAN_VOLATILE_READ1): Define new
>         builtin for volatile instrumentation of reads/writes.
>         (BUILT_IN_TSAN_VOLATILE_READ2): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_READ4): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_READ8): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_READ16): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_WRITE1): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_WRITE2): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_WRITE4): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_WRITE8): Likewise.
>         (BUILT_IN_TSAN_VOLATILE_WRITE16): Likewise.
>         * tsan.c (get_memory_access_decl): Argument if access is
>         volatile. If param tsan-distinguish-volatile is non-zero, and
>         access if volatile, return volatile instrumentation decl.
>         (instrument_expr): Check if access is volatile.
>
> gcc/testsuite/
>         * c-c++-common/tsan/volatile.c: New test.
> ---
>  gcc/ChangeLog                              | 19 +++++++
>  gcc/params.opt                             |  4 ++
>  gcc/sanitizer.def                          | 21 ++++++++
>  gcc/testsuite/ChangeLog                    |  4 ++
>  gcc/testsuite/c-c++-common/tsan/volatile.c | 62 ++++++++++++++++++++++
>  gcc/tsan.c                                 | 53 ++++++++++++------
>  6 files changed, 146 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/tsan/volatile.c
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 5f299e463db..aa2bb98ae05 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,22 @@
> +2020-04-23  Marco Elver  <el...@google.com>
> +
> +       * params.opt: Define --param=tsan-distinguish-volatile=[0,1].
> +       * sanitizer.def (BUILT_IN_TSAN_VOLATILE_READ1): Define new
> +       builtin for volatile instrumentation of reads/writes.
> +       (BUILT_IN_TSAN_VOLATILE_READ2): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_READ4): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_READ8): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_READ16): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_WRITE1): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_WRITE2): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_WRITE4): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_WRITE8): Likewise.
> +       (BUILT_IN_TSAN_VOLATILE_WRITE16): Likewise.
> +       * tsan.c (get_memory_access_decl): Argument if access is
> +       volatile. If param tsan-distinguish-volatile is non-zero, and
> +       access if volatile, return volatile instrumentation decl.
> +       (instrument_expr): Check if access is volatile.
> +
>  2020-04-23  Srinath Parvathaneni  <srinath.parvathan...@arm.com>
>
>         * config/arm/arm_mve.h (__arm_vbicq_n_u16): Modify function 
> parameter's
> diff --git a/gcc/params.opt b/gcc/params.opt
> index 4aec480798b..9b564bb046c 100644
> --- a/gcc/params.opt
> +++ b/gcc/params.opt
> @@ -908,6 +908,10 @@ Stop reverse growth if the reverse probability of best 
> edge is less than this th
>  Common Joined UInteger Var(param_tree_reassoc_width) Param Optimization
>  Set the maximum number of instructions executed in parallel in reassociated 
> tree.  If 0, use the target dependent heuristic.
>
> +-param=tsan-distinguish-volatile=
> +Common Joined UInteger Var(param_tsan_distinguish_volatile) IntegerRange(0, 
> 1) Param
> +Emit special instrumentation for accesses to volatiles.
> +
>  -param=uninit-control-dep-attempts=
>  Common Joined UInteger Var(param_uninit_control_dep_attempts) Init(1000) 
> IntegerRange(1, 65536) Param Optimization
>  Maximum number of nested calls to search for control dependencies during 
> uninitialized variable analysis.
> diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
> index 11eb6467eba..a32715ddb92 100644
> --- a/gcc/sanitizer.def
> +++ b/gcc/sanitizer.def
> @@ -214,6 +214,27 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_RANGE, 
> "__tsan_read_range",
>  DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_RANGE, "__tsan_write_range",
>                       BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
>
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_READ1, "__tsan_volatile_read1",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_READ2, "__tsan_volatile_read2",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_READ4, "__tsan_volatile_read4",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_READ8, "__tsan_volatile_read8",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_READ16, 
> "__tsan_volatile_read16",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_WRITE1, 
> "__tsan_volatile_write1",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_WRITE2, 
> "__tsan_volatile_write2",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_WRITE4, 
> "__tsan_volatile_write4",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_WRITE8, 
> "__tsan_volatile_write8",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VOLATILE_WRITE16, 
> "__tsan_volatile_write16",
> +                     BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
> +
>  DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC8_LOAD,
>                       "__tsan_atomic8_load",
>                       BT_FN_I1_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST)
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index 245c1512c76..f1d3e236b86 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,7 @@
> +2020-04-23  Marco Elver  <el...@google.com>
> +
> +       * c-c++-common/tsan/volatile.c: New test.
> +
>  2020-04-23  Jakub Jelinek  <ja...@redhat.com>
>
>         PR target/94707
> diff --git a/gcc/testsuite/c-c++-common/tsan/volatile.c 
> b/gcc/testsuite/c-c++-common/tsan/volatile.c
> new file mode 100644
> index 00000000000..d51d1e3ce8d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/tsan/volatile.c
> @@ -0,0 +1,62 @@
> +/* { dg-additional-options "--param=tsan-distinguish-volatile=1" } */
> +
> +#include <assert.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +int32_t Global4;
> +volatile int32_t VolatileGlobal4;
> +volatile int64_t VolatileGlobal8;
> +
> +static int nvolatile_reads;
> +static int nvolatile_writes;
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +__attribute__((no_sanitize_thread))
> +void __tsan_volatile_read4(void *addr) {
> +  assert(addr == &VolatileGlobal4);
> +  nvolatile_reads++;
> +}
> +__attribute__((no_sanitize_thread))
> +void __tsan_volatile_write4(void *addr) {
> +  assert(addr == &VolatileGlobal4);
> +  nvolatile_writes++;
> +}
> +__attribute__((no_sanitize_thread))
> +void __tsan_volatile_read8(void *addr) {
> +  assert(addr == &VolatileGlobal8);
> +  nvolatile_reads++;
> +}
> +__attribute__((no_sanitize_thread))
> +void __tsan_volatile_write8(void *addr) {
> +  assert(addr == &VolatileGlobal8);
> +  nvolatile_writes++;
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +__attribute__((no_sanitize_thread))
> +static void check() {
> +  assert(nvolatile_reads == 4);
> +  assert(nvolatile_writes == 4);
> +}
> +
> +int main() {
> +  Global4 = 1;
> +
> +  VolatileGlobal4 = 1;
> +  Global4 = VolatileGlobal4;
> +  VolatileGlobal4 = 1 + VolatileGlobal4;
> +
> +  VolatileGlobal8 = 1;
> +  Global4 = (int32_t)VolatileGlobal8;
> +  VolatileGlobal8 = 1 + VolatileGlobal8;
> +
> +  check();
> +  return 0;
> +}
> diff --git a/gcc/tsan.c b/gcc/tsan.c
> index 8d22a776377..04e92559584 100644
> --- a/gcc/tsan.c
> +++ b/gcc/tsan.c
> @@ -52,25 +52,41 @@ along with GCC; see the file COPYING3.  If not see
>     void __tsan_read/writeX (void *addr);  */
>
>  static tree
> -get_memory_access_decl (bool is_write, unsigned size)
> +get_memory_access_decl (bool is_write, unsigned size, bool volatilep)
>  {
>    enum built_in_function fcode;
>
> -  if (size <= 1)
> -    fcode = is_write ? BUILT_IN_TSAN_WRITE1
> -                    : BUILT_IN_TSAN_READ1;
> -  else if (size <= 3)
> -    fcode = is_write ? BUILT_IN_TSAN_WRITE2
> -                    : BUILT_IN_TSAN_READ2;
> -  else if (size <= 7)
> -    fcode = is_write ? BUILT_IN_TSAN_WRITE4
> -                    : BUILT_IN_TSAN_READ4;
> -  else if (size <= 15)
> -    fcode = is_write ? BUILT_IN_TSAN_WRITE8
> -                    : BUILT_IN_TSAN_READ8;
> +  if (param_tsan_distinguish_volatile && volatilep)
> +    {
> +      if (size <= 1)
> +        fcode = is_write ? BUILT_IN_TSAN_VOLATILE_WRITE1
> +            : BUILT_IN_TSAN_VOLATILE_READ1;
> +      else if (size <= 3)
> +        fcode = is_write ? BUILT_IN_TSAN_VOLATILE_WRITE2
> +            : BUILT_IN_TSAN_VOLATILE_READ2;
> +      else if (size <= 7)
> +        fcode = is_write ? BUILT_IN_TSAN_VOLATILE_WRITE4
> +            : BUILT_IN_TSAN_VOLATILE_READ4;
> +      else if (size <= 15)
> +        fcode = is_write ? BUILT_IN_TSAN_VOLATILE_WRITE8
> +            : BUILT_IN_TSAN_VOLATILE_READ8;
> +      else
> +        fcode = is_write ? BUILT_IN_TSAN_VOLATILE_WRITE16
> +            : BUILT_IN_TSAN_VOLATILE_READ16;
> +    }
>    else
> -    fcode = is_write ? BUILT_IN_TSAN_WRITE16
> -                    : BUILT_IN_TSAN_READ16;
> +    {
> +      if (size <= 1)
> +        fcode = is_write ? BUILT_IN_TSAN_WRITE1 : BUILT_IN_TSAN_READ1;
> +      else if (size <= 3)
> +        fcode = is_write ? BUILT_IN_TSAN_WRITE2 : BUILT_IN_TSAN_READ2;
> +      else if (size <= 7)
> +        fcode = is_write ? BUILT_IN_TSAN_WRITE4 : BUILT_IN_TSAN_READ4;
> +      else if (size <= 15)
> +        fcode = is_write ? BUILT_IN_TSAN_WRITE8 : BUILT_IN_TSAN_READ8;
> +      else
> +        fcode = is_write ? BUILT_IN_TSAN_WRITE16 : BUILT_IN_TSAN_READ16;
> +    }
>
>    return builtin_decl_implicit (fcode);
>  }
> @@ -204,8 +220,11 @@ instrument_expr (gimple_stmt_iterator gsi, tree expr, 
> bool is_write)
>        g = gimple_build_call (builtin_decl, 2, expr_ptr, size_int (size));
>      }
>    else if (rhs == NULL)
> -    g = gimple_build_call (get_memory_access_decl (is_write, size),
> -                          1, expr_ptr);
> +    {
> +      builtin_decl = get_memory_access_decl (is_write, size,
> +                                             TREE_THIS_VOLATILE(expr));
> +      g = gimple_build_call (builtin_decl, 1, expr_ptr);
> +    }
>    else
>      {
>        builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE);
> --
> 2.26.1.301.g55bc3eb7cb9-goog
>

Reply via email to