diff mbox

Make some asan builtins tm_pure (PR sanitizer/55508)

Message ID 20121212195033.GE2315@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Dec. 12, 2012, 7:50 p.m. UTC
Hi!

Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
The problem is that asan.c pass adds calls to builtins that weren't there
before and TM is upset about it.  The __asan_report* are all like
abort, in correctly written program they shouldn't have a user visible
effect, in bad program they will terminate the process, but in any case
it doesn't matter how many times they are retried as part of a transaction,
there is no state to roll back on transaction cancellation.
__asan_handle_no_return, while not being noreturn, just marks the stack as
unprotected, so again in correctly written application no effect, in bad app
might result in some issues being undetected, but still, it can be done many
times and isn't irreversible.

The following patch fixes the ICEs by making all of these transaction pure.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

As for TSAN, no idea what to do, TSAN diagnostics could be in a similar
category, there is nothing to reverse, but as the library doesn't understand
transactions, perhaps better would be not to tsan instrument anything inside
of transactions, until the library is made TM aware.

2012-12-12  Jakub Jelinek  <jakub@redhat.com>

	PR sanitizer/55508
	* builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
	* asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
	* sanitizer.def: Make __asan_report_* and __asan_handle_no_return
	builtins tm pure.


	Jakub

Comments

Dodji Seketeli Dec. 12, 2012, 9:22 p.m. UTC | #1
Jakub Jelinek <jakub@redhat.com> writes:

> 	PR sanitizer/55508
> 	* builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
> 	* asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
> 	* sanitizer.def: Make __asan_report_* and __asan_handle_no_return
> 	builtins tm pure.

This looks OK to me, if no one else objects.
Jack Howarth Dec. 12, 2012, 9:45 p.m. UTC | #2
On Wed, Dec 12, 2012 at 08:50:33PM +0100, Jakub Jelinek wrote:
> Hi!
> 
> Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> The problem is that asan.c pass adds calls to builtins that weren't there
> before and TM is upset about it.  The __asan_report* are all like
> abort, in correctly written program they shouldn't have a user visible
> effect, in bad program they will terminate the process, but in any case
> it doesn't matter how many times they are retried as part of a transaction,
> there is no state to roll back on transaction cancellation.
> __asan_handle_no_return, while not being noreturn, just marks the stack as
> unprotected, so again in correctly written application no effect, in bad app
> might result in some issues being undetected, but still, it can be done many
> times and isn't irreversible.
> 
> The following patch fixes the ICEs by making all of these transaction pure.

Jakub,
   Are the tm.exp scan-tree-dump-times failures with...

make -k check RUNTESTFLAGS="tm.exp --target_board=unix'{-fsanitize=address}'"

expected? I see...

FAIL: gcc.dg/tm/memopt-3.c scan-tree-dump-times tmmark "logging: lala.x\\[i_4\\]" 1
FAIL: gcc.dg/tm/memopt-4.c scan-tree-dump-times tmedge "tm_save.[0-9_]+ = lala.x\\[55\\]" 1
FAIL: gcc.dg/tm/memopt-4.c scan-tree-dump-times tmedge "lala.x\\[55\\] = tm_save" 1
FAIL: gcc.dg/tm/memopt-5.c scan-tree-dump-times tmedge "ITM_LU[0-9] \\(&lala.x\\[55\\]" 1
FAIL: gcc.dg/tm/memopt-7.c scan-tree-dump-times tmedge "tm_save.[0-9_]+ = lala" 1
FAIL: gcc.dg/tm/memopt-7.c scan-tree-dump-times tmedge "lala = tm_save" 1
FAIL: g++.dg/tm/noexcept-5.C scan-tree-dump-times tmmark "ITM_RU" 1

on x86_64-apple-darwin12 with your patch applied to current gcc trunk.
           Jack

> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> As for TSAN, no idea what to do, TSAN diagnostics could be in a similar
> category, there is nothing to reverse, but as the library doesn't understand
> transactions, perhaps better would be not to tsan instrument anything inside
> of transactions, until the library is made TM aware.
> 
> 2012-12-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR sanitizer/55508
> 	* builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
> 	* asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
> 	* sanitizer.def: Make __asan_report_* and __asan_handle_no_return
> 	builtins tm pure.
> 
> --- gcc/builtin-attrs.def.jj	2012-10-22 08:42:23.000000000 +0200
> +++ gcc/builtin-attrs.def	2012-12-12 11:56:54.942938879 +0100
> @@ -263,6 +263,11 @@ DEF_ATTR_TREE_LIST (ATTR_TMPURE_MALLOC_N
>  DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LIST,
>  		   ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LIST)
>  
> +DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> +		    ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
> +DEF_ATTR_TREE_LIST (ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST,
> +		    ATTR_TM_TMPURE, ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +
>  /* Construct a tree for a format_arg attribute.  */
>  #define DEF_FORMAT_ARG_ATTRIBUTE(FA)					\
>    DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_##FA, ATTR_FORMAT_ARG,		\
> --- gcc/asan.c.jj	2012-12-11 13:05:36.000000000 +0100
> +++ gcc/asan.c	2012-12-12 11:57:59.626550534 +0100
> @@ -1611,8 +1611,13 @@ initialize_sanitizer_builtins (void)
>  #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
>  #undef ATTR_NOTHROW_LEAF_LIST
>  #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
> +#undef ATTR_TMPURE_NOTHROW_LEAF_LIST
> +#define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
>  #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
>  #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
> +#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
> +#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
> +  ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
>  #undef DEF_SANITIZER_BUILTIN
>  #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
>    decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,		\
> --- gcc/sanitizer.def.jj	2012-12-11 11:28:10.000000000 +0100
> +++ gcc/sanitizer.def	2012-12-12 11:57:12.714833945 +0100
> @@ -32,25 +32,25 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT
>  /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
>     relies on this order.  */
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD2, "__asan_report_load2",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD4, "__asan_report_load4",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD8, "__asan_report_load8",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD16, "__asan_report_load16",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE1, "__asan_report_store1",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE2, "__asan_report_store2",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE4, "__asan_report_store4",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE8, "__asan_report_store8",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
> -		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
>  		      "__asan_register_globals",
>  		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
> @@ -59,7 +59,7 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNRE
>  		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN,
>  		      "__asan_handle_no_return",
> -		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
> +		      BT_FN_VOID, ATTR_TMPURE_NOTHROW_LEAF_LIST)
>  
>  /* Thread Sanitizer */
>  DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
> 
> 	Jakub
Richard Henderson Dec. 12, 2012, 9:58 p.m. UTC | #3
On 12/12/2012 11:50 AM, Jakub Jelinek wrote:
> 2012-12-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR sanitizer/55508
> 	* builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
> 	* asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> 	ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
> 	* sanitizer.def: Make __asan_report_* and __asan_handle_no_return
> 	builtins tm pure.

Ok.

Agreed about we need another solution for tsan + tm.


r~
Dmitry Vyukov Dec. 13, 2012, 6:38 a.m. UTC | #4
On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> The problem is that asan.c pass adds calls to builtins that weren't there
> before and TM is upset about it.  The __asan_report* are all like
> abort, in correctly written program they shouldn't have a user visible
> effect, in bad program they will terminate the process, but in any case
> it doesn't matter how many times they are retried as part of a transaction,
> there is no state to roll back on transaction cancellation.
> __asan_handle_no_return, while not being noreturn, just marks the stack as
> unprotected, so again in correctly written application no effect, in bad app
> might result in some issues being undetected, but still, it can be done many
> times and isn't irreversible.

Hi!

I was only loosely following tm-languages discussions. Does gcc tm
model guarantees strong consistency for all memory accesses? I mean
there are tm implementations that allow transient inconsistencies,
than are detected later and trx is restarted. Can't asan trigger false
positives in this case?
Also, what is the order of instrumentation in tm+asan setting? I mean
that neither tm must instrument asan instrumentation, nor asan must
instrument tm instrumentation. Is it the case? There also can be
conflicts related to ordering of instrumentation in the following
case:
asan_check();
speculative_load();
tm_check();
In this case tm hopes to detect inconsistent speculative load
afterwards, but asan will crash the program before tm has a chance to
abort and retry (it is related to the first point).

Sorry, I don't know how gcc tm works. But I just suspect that it can
be very tricky.


> The following patch fixes the ICEs by making all of these transaction pure.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> As for TSAN, no idea what to do, TSAN diagnostics could be in a similar
> category, there is nothing to reverse, but as the library doesn't understand
> transactions, perhaps better would be not to tsan instrument anything inside
> of transactions, until the library is made TM aware.
>
> 2012-12-12  Jakub Jelinek  <jakub@redhat.com>
>
>         PR sanitizer/55508
>         * builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
>         ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
>         * asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
>         ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
>         * sanitizer.def: Make __asan_report_* and __asan_handle_no_return
>         builtins tm pure.
>
> --- gcc/builtin-attrs.def.jj    2012-10-22 08:42:23.000000000 +0200
> +++ gcc/builtin-attrs.def       2012-12-12 11:56:54.942938879 +0100
> @@ -263,6 +263,11 @@ DEF_ATTR_TREE_LIST (ATTR_TMPURE_MALLOC_N
>  DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LIST,
>                    ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LIST)
>
> +DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> +                   ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
> +DEF_ATTR_TREE_LIST (ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST,
> +                   ATTR_TM_TMPURE, ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +
>  /* Construct a tree for a format_arg attribute.  */
>  #define DEF_FORMAT_ARG_ATTRIBUTE(FA)                                   \
>    DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_##FA, ATTR_FORMAT_ARG,           \
> --- gcc/asan.c.jj       2012-12-11 13:05:36.000000000 +0100
> +++ gcc/asan.c  2012-12-12 11:57:59.626550534 +0100
> @@ -1611,8 +1611,13 @@ initialize_sanitizer_builtins (void)
>  #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
>  #undef ATTR_NOTHROW_LEAF_LIST
>  #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
> +#undef ATTR_TMPURE_NOTHROW_LEAF_LIST
> +#define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
>  #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
>  #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
> +#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
> +#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
> +  ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
>  #undef DEF_SANITIZER_BUILTIN
>  #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
>    decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,          \
> --- gcc/sanitizer.def.jj        2012-12-11 11:28:10.000000000 +0100
> +++ gcc/sanitizer.def   2012-12-12 11:57:12.714833945 +0100
> @@ -32,25 +32,25 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT
>  /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
>     relies on this order.  */
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD2, "__asan_report_load2",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD4, "__asan_report_load4",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD8, "__asan_report_load8",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD16, "__asan_report_load16",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE1, "__asan_report_store1",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE2, "__asan_report_store2",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE4, "__asan_report_store4",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE8, "__asan_report_store8",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
> -                     BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
>                       "__asan_register_globals",
>                       BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
> @@ -59,7 +59,7 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNRE
>                       BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
>  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN,
>                       "__asan_handle_no_return",
> -                     BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
> +                     BT_FN_VOID, ATTR_TMPURE_NOTHROW_LEAF_LIST)
>
>  /* Thread Sanitizer */
>  DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
>
>         Jakub
Dmitry Vyukov Dec. 13, 2012, 6:40 a.m. UTC | #5
On Thu, Dec 13, 2012 at 1:58 AM, Richard Henderson <rth@redhat.com> wrote:
> On 12/12/2012 11:50 AM, Jakub Jelinek wrote:
>> 2012-12-12  Jakub Jelinek  <jakub@redhat.com>
>>
>>       PR sanitizer/55508
>>       * builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
>>       ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
>>       * asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
>>       ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
>>       * sanitizer.def: Make __asan_report_* and __asan_handle_no_return
>>       builtins tm pure.
>
> Ok.
>
> Agreed about we need another solution for tsan + tm.


What type of bugs do you expect tsan catch in transactional setting?
Are we talking about data races between transactional and
non-transactional code?

Does atomic transactions permitted by gcc? I mean can I use mutexes
and atomics inside of transactions to synchronize with
non-transactional code?
Jakub Jelinek Dec. 13, 2012, 9:02 a.m. UTC | #6
On Thu, Dec 13, 2012 at 10:38:13AM +0400, Dmitry Vyukov wrote:
> On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> > The problem is that asan.c pass adds calls to builtins that weren't there
> > before and TM is upset about it.  The __asan_report* are all like
> > abort, in correctly written program they shouldn't have a user visible
> > effect, in bad program they will terminate the process, but in any case
> > it doesn't matter how many times they are retried as part of a transaction,
> > there is no state to roll back on transaction cancellation.
> > __asan_handle_no_return, while not being noreturn, just marks the stack as
> > unprotected, so again in correctly written application no effect, in bad app
> > might result in some issues being undetected, but still, it can be done many
> > times and isn't irreversible.
> 
> I was only loosely following tm-languages discussions. Does gcc tm
> model guarantees strong consistency for all memory accesses? I mean
> there are tm implementations that allow transient inconsistencies,

Will leave this to Torvald.

> than are detected later and trx is restarted. Can't asan trigger false
> positives in this case?

I can't imagine any.

> Also, what is the order of instrumentation in tm+asan setting? I mean
> that neither tm must instrument asan instrumentation, nor asan must
> instrument tm instrumentation. Is it the case? There also can be
> conflicts related to ordering of instrumentation in the following
> case:
> asan_check();
> speculative_load();
> tm_check();

I'm not aware of TM having speculative loads, libgtm certainly doesn't
install a SIGSEGV handler (and testing whether some memory is
readable/writable without actually dereferencing would be terribly slow).
If a memory load or store segfaults, whether in a transaction or outside of
it, it is a program bug and it is right if asan terminates the program.

	Jakub
Dmitry Vyukov Dec. 14, 2012, 9:44 a.m. UTC | #7
On Thu, Dec 13, 2012 at 1:02 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
>> > The problem is that asan.c pass adds calls to builtins that weren't there
>> > before and TM is upset about it.  The __asan_report* are all like
>> > abort, in correctly written program they shouldn't have a user visible
>> > effect, in bad program they will terminate the process, but in any case
>> > it doesn't matter how many times they are retried as part of a transaction,
>> > there is no state to roll back on transaction cancellation.
>> > __asan_handle_no_return, while not being noreturn, just marks the stack as
>> > unprotected, so again in correctly written application no effect, in bad app
>> > might result in some issues being undetected, but still, it can be done many
>> > times and isn't irreversible.
>>
>> I was only loosely following tm-languages discussions. Does gcc tm
>> model guarantees strong consistency for all memory accesses? I mean
>> there are tm implementations that allow transient inconsistencies,
>
> Will leave this to Torvald.
>
>> than are detected later and trx is restarted. Can't asan trigger false
>> positives in this case?
>
> I can't imagine any.
>
>> Also, what is the order of instrumentation in tm+asan setting? I mean
>> that neither tm must instrument asan instrumentation, nor asan must
>> instrument tm instrumentation. Is it the case? There also can be
>> conflicts related to ordering of instrumentation in the following
>> case:
>> asan_check();
>> speculative_load();
>> tm_check();
>
> I'm not aware of TM having speculative loads, libgtm certainly doesn't
> install a SIGSEGV handler (and testing whether some memory is
> readable/writable without actually dereferencing would be terribly slow).
> If a memory load or store segfaults, whether in a transaction or outside of
> it, it is a program bug and it is right if asan terminates the program.


OK, thanks.
AFAIR tl2 installs SIGSEGV and uses non-failing loads.
Torvald Riegel Dec. 14, 2012, 1:43 p.m. UTC | #8
On Thu, 2012-12-13 at 10:02 +0100, Jakub Jelinek wrote:
> On Thu, Dec 13, 2012 at 10:38:13AM +0400, Dmitry Vyukov wrote:
> > On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> > > The problem is that asan.c pass adds calls to builtins that weren't there
> > > before and TM is upset about it.  The __asan_report* are all like
> > > abort, in correctly written program they shouldn't have a user visible
> > > effect, in bad program they will terminate the process, but in any case
> > > it doesn't matter how many times they are retried as part of a transaction,
> > > there is no state to roll back on transaction cancellation.
> > > __asan_handle_no_return, while not being noreturn, just marks the stack as
> > > unprotected, so again in correctly written application no effect, in bad app
> > > might result in some issues being undetected, but still, it can be done many
> > > times and isn't irreversible.
> > 
> > I was only loosely following tm-languages discussions. Does gcc tm
> > model guarantees strong consistency for all memory accesses? I mean
> > there are tm implementations that allow transient inconsistencies,
> 
> Will leave this to Torvald.

This has two parts: (1) how TM fits into the C++11/C11 memory model, and
(2) which guarantees the compiler and the TM runtime library agree on at
the level of the TM ABI that we use in GCC.

Regarding the first part, all transactions provide guarantees similar to
a global lock.  Specifically, there are virtual transaction start/end
events that take part in sequenced-before (similar to acquisition and
release of the global lock), whose are then guaranteed to execute
(without transactions interleaving with each other) in a global total
order (let's call this order TO).  TO then contributes to
happens-before.

On the ABI level, the TM runtime is allowed to execute speculatively as
long as (1) it does not expose any speculative execution to
nontransactional code and (2) speculation doesn't violate the language's
as-if rules (i.e., no visible side effects other than the abstract
machine; no signals due to seg faults etc.).  This means that, for
example, the TM will not access data at a wider granularity than what
nontransactional code that conforms to the C++11 memory model does would
do.
Second, transactions can have a tentative position in TO, but they will
only expose final TO choices to nontxnal code.  So, each transaction
will execute code that would be valid when executed in isolation -- but
it is possible that several transactions noncommitted transactions are
in flight concurrently that may conflict with each other.  The TM
ensures that such speculative execution is safe and not visible to a
race-free program.  So, when a transaction commits at a certain position
in TO, it will make sure that all other active transactions reach
consensus on TO (up to this position) before it returns to the execution
of nontxnal code.  Those active transactions will either see that they
would be still valid at a new TO position (after the committing txn), or
they abort and then signal that they agree to this TO.  That means that
the nontxnal code will not be affected by any speculative execution,
even if the prior txn privatized some data (this is called privatization
safety in TM jargon).
The sort-of counterpart to privatization safety is publication safety
(ie, transactions can safely make some data shared).  While
privatization safety is handled by the TM runtime, publication safety is
ensured by the compiler by not allowing any dangerous load/load
reordering, basicallly.  Publication safety is not yet ensured always,
but Aldy is working on this.

> > than are detected later and trx is restarted. Can't asan trigger false
> > positives in this case?
> 
> I can't imagine any.

I also don't see any, because all loads/stores of all transactions, even
those with a tentative TO position, would be a valid execution.  For
malloc/free in transactions, AFAIR, ASAN hooks into malloc/free
directly, so when libitm handles those including rollback of an
allocation, there shouldn't be false positives.  However, there might be
false negatives in case of free() because deallocations are deferred
until transaction commit (they can't be rolled back).  Could we tell
ASAN about free() directly using a call added by the TM instrumentation
pass?  That would at least help catch the false negatives for all
free()-like functions that the compiler knows about.

All of this is different for TSAN, of course, because there a memory
access does alter the state that TSAN keeps, so if we roll back the
accesses in the TM we would also have to roll back the TSAN state.

> > Also, what is the order of instrumentation in tm+asan setting? I mean
> > that neither tm must instrument asan instrumentation, nor asan must
> > instrument tm instrumentation. Is it the case? There also can be
> > conflicts related to ordering of instrumentation in the following
> > case:
> > asan_check();
> > speculative_load();
> > tm_check();

The ordering of instrumentation is an interesting question, but I think
that putting the ASAN check before the TM load/store is the right thing
to do.  It will catch any illegal access before it's performed.  It
doesn't suffer from false positives because the TM will only allow valid
(even though speculative) executions.  For this ordering to not be valid
(ie, tm_check before asan_check), transactions would need to be able to
prevent access to a certain variable by writing to them (which doesn't
work).  Other cases in which the transaction would perform the access
because of values of other variables that it loaded previously are
covered by privatization safety.

> I'm not aware of TM having speculative loads, libgtm certainly doesn't
> install a SIGSEGV handler (and testing whether some memory is
> readable/writable without actually dereferencing would be terribly slow).
> If a memory load or store segfaults, whether in a transaction or outside of
> it, it is a program bug and it is right if asan terminates the program.

Right, memory accesses performed by the TM are only speculative to the
extent described above.

Torvald
Torvald Riegel Dec. 14, 2012, 1:43 p.m. UTC | #9
On Fri, 2012-12-14 at 13:44 +0400, Dmitry Vyukov wrote:
> On Thu, Dec 13, 2012 at 1:02 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> >> > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> >> > The problem is that asan.c pass adds calls to builtins that weren't there
> >> > before and TM is upset about it.  The __asan_report* are all like
> >> > abort, in correctly written program they shouldn't have a user visible
> >> > effect, in bad program they will terminate the process, but in any case
> >> > it doesn't matter how many times they are retried as part of a transaction,
> >> > there is no state to roll back on transaction cancellation.
> >> > __asan_handle_no_return, while not being noreturn, just marks the stack as
> >> > unprotected, so again in correctly written application no effect, in bad app
> >> > might result in some issues being undetected, but still, it can be done many
> >> > times and isn't irreversible.
> >>
> >> I was only loosely following tm-languages discussions. Does gcc tm
> >> model guarantees strong consistency for all memory accesses? I mean
> >> there are tm implementations that allow transient inconsistencies,
> >
> > Will leave this to Torvald.
> >
> >> than are detected later and trx is restarted. Can't asan trigger false
> >> positives in this case?
> >
> > I can't imagine any.
> >
> >> Also, what is the order of instrumentation in tm+asan setting? I mean
> >> that neither tm must instrument asan instrumentation, nor asan must
> >> instrument tm instrumentation. Is it the case? There also can be
> >> conflicts related to ordering of instrumentation in the following
> >> case:
> >> asan_check();
> >> speculative_load();
> >> tm_check();
> >
> > I'm not aware of TM having speculative loads, libgtm certainly doesn't
> > install a SIGSEGV handler (and testing whether some memory is
> > readable/writable without actually dereferencing would be terribly slow).
> > If a memory load or store segfaults, whether in a transaction or outside of
> > it, it is a program bug and it is right if asan terminates the program.
> 
> 
> OK, thanks.
> AFAIR tl2 installs SIGSEGV and uses non-failing loads.

I think the original implementation didn't, but other TL2
implementations might if they want to avoid providing full privatization
safety without relying on any sandboxing attempts.  Sandboxing is hard
to get right (e.g., if the architecture doesn't provide nonfaulting
loads), and if you try it, you end up with a much more intrusive
solution (e.g., you need to ensure that the program doesn't override
your signal handlers).

Therefore, libitm ensures privatization safety by a quiescence-based
approach (i.e., a privatizing transaction waits until all other active
reading transactions are guaranteed to have observed the privatizer's
updates).

Torvald
Torvald Riegel Dec. 14, 2012, 1:43 p.m. UTC | #10
On Thu, 2012-12-13 at 10:40 +0400, Dmitry Vyukov wrote:
> On Thu, Dec 13, 2012 at 1:58 AM, Richard Henderson <rth@redhat.com> wrote:
> > On 12/12/2012 11:50 AM, Jakub Jelinek wrote:
> >> 2012-12-12  Jakub Jelinek  <jakub@redhat.com>
> >>
> >>       PR sanitizer/55508
> >>       * builtin-attrs.def (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> >>       ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): New.
> >>       * asan.c (ATTR_TMPURE_NOTHROW_LEAF_LIST,
> >>       ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST): Define.
> >>       * sanitizer.def: Make __asan_report_* and __asan_handle_no_return
> >>       builtins tm pure.
> >
> > Ok.
> >
> > Agreed about we need another solution for tsan + tm.
> 
> 
> What type of bugs do you expect tsan catch in transactional setting?
> Are we talking about data races between transactional and
> non-transactional code?

Right.  And it would be good if TSAN can detect these cases.

I don't think we need TSAN to detect races in the TM runtime library
implementation itself, which would probably need a lot of special cases
because of (restricted, see my other post) speculative execution by the
TM.

> Does atomic transactions permitted by gcc? I mean can I use mutexes
> and atomics inside of transactions to synchronize with
> non-transactional code?

Such operations, called "unsafe code", are not allowed in atomic
transactions (currently--that choice is determined by several factors
such as likely runtime overheads and intrusiveness of TM
implementations).  But they are allowed in relaxed transactions.  Before
relaxed transactions execute such unsafe code, they will switch to
serial execution of transactions, which we could make visible to TSAN if
that would help.

Torvald
Dmitry Vyukov Dec. 17, 2012, 9:52 a.m. UTC | #11
resend in plain text

On Mon, Dec 17, 2012 at 1:50 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
>
> On Fri, Dec 14, 2012 at 5:43 PM, Torvald Riegel <triegel@redhat.com> wrote:
> > On Thu, 2012-12-13 at 10:02 +0100, Jakub Jelinek wrote:
> >> On Thu, Dec 13, 2012 at 10:38:13AM +0400, Dmitry Vyukov wrote:
> >> > On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> >> > > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> >> > > The problem is that asan.c pass adds calls to builtins that weren't there
> >> > > before and TM is upset about it.  The __asan_report* are all like
> >> > > abort, in correctly written program they shouldn't have a user visible
> >> > > effect, in bad program they will terminate the process, but in any case
> >> > > it doesn't matter how many times they are retried as part of a transaction,
> >> > > there is no state to roll back on transaction cancellation.
> >> > > __asan_handle_no_return, while not being noreturn, just marks the stack as
> >> > > unprotected, so again in correctly written application no effect, in bad app
> >> > > might result in some issues being undetected, but still, it can be done many
> >> > > times and isn't irreversible.
> >> >
> >> > I was only loosely following tm-languages discussions. Does gcc tm
> >> > model guarantees strong consistency for all memory accesses? I mean
> >> > there are tm implementations that allow transient inconsistencies,
> >>
> >> Will leave this to Torvald.
> >
> > This has two parts: (1) how TM fits into the C++11/C11 memory model, and
> > (2) which guarantees the compiler and the TM runtime library agree on at
> > the level of the TM ABI that we use in GCC.
> >
> > Regarding the first part, all transactions provide guarantees similar to
> > a global lock.  Specifically, there are virtual transaction start/end
> > events that take part in sequenced-before (similar to acquisition and
> > release of the global lock), whose are then guaranteed to execute
> > (without transactions interleaving with each other) in a global total
> > order (let's call this order TO).  TO then contributes to
> > happens-before.
> >
> > On the ABI level, the TM runtime is allowed to execute speculatively as
> > long as (1) it does not expose any speculative execution to
> > nontransactional code and (2) speculation doesn't violate the language's
> > as-if rules (i.e., no visible side effects other than the abstract
> > machine; no signals due to seg faults etc.).  This means that, for
> > example, the TM will not access data at a wider granularity than what
> > nontransactional code that conforms to the C++11 memory model does would
> > do.
> > Second, transactions can have a tentative position in TO, but they will
> > only expose final TO choices to nontxnal code.  So, each transaction
> > will execute code that would be valid when executed in isolation -- but
> > it is possible that several transactions noncommitted transactions are
> > in flight concurrently that may conflict with each other.  The TM
> > ensures that such speculative execution is safe and not visible to a
> > race-free program.  So, when a transaction commits at a certain position
> > in TO, it will make sure that all other active transactions reach
> > consensus on TO (up to this position) before it returns to the execution
> > of nontxnal code.  Those active transactions will either see that they
> > would be still valid at a new TO position (after the committing txn), or
> > they abort and then signal that they agree to this TO.  That means that
> > the nontxnal code will not be affected by any speculative execution,
> > even if the prior txn privatized some data (this is called privatization
> > safety in TM jargon).
> > The sort-of counterpart to privatization safety is publication safety
> > (ie, transactions can safely make some data shared).  While
> > privatization safety is handled by the TM runtime, publication safety is
> > ensured by the compiler by not allowing any dangerous load/load
> > reordering, basicallly.  Publication safety is not yet ensured always,
> > but Aldy is working on this.
> >
> >> > than are detected later and trx is restarted. Can't asan trigger false
> >> > positives in this case?
> >>
> >> I can't imagine any.
> >
> > I also don't see any, because all loads/stores of all transactions, even
> > those with a tentative TO position, would be a valid execution.  For
> > malloc/free in transactions, AFAIR, ASAN hooks into malloc/free
> > directly, so when libitm handles those including rollback of an
> > allocation, there shouldn't be false positives.  However, there might be
> > false negatives in case of free() because deallocations are deferred
> > until transaction commit (they can't be rolled back).  Could we tell
> > ASAN about free() directly using a call added by the TM instrumentation
> > pass?  That would at least help catch the false negatives for all
> > free()-like functions that the compiler knows about.
>
> I do not think that false positive is super important.  We have a similar false negative in case of racy use after free, when the free the just happen to happen after the use.
>
> However, it must be possible to support, because in case of asan we do can "rollback" free.
> But won't it lead to false positives in case of:
>
> __transaction {
>   free(p);
>   p = 0;
> }
>
> __transaction {
>   r = 0;
>   if (p)
>     r = p->x;
>   ...
>
> }
> ?
>
>
> > All of this is different for TSAN, of course, because there a memory
> > access does alter the state that TSAN keeps, so if we roll back the
> > accesses in the TM we would also have to roll back the TSAN state.
>
>
> I think the simplest way to solve it for now, it to use... well, single global lock.
> I.e. replace __txn_start() with global pthread_mutex_t acquisition, __txn_commit() with lock release. And no transactional instrumentation inside of the trx. It should be correct transformation, right. However, I am not sure what to do with __txn_abort()...
>
>
>
>
> >> > Also, what is the order of instrumentation in tm+asan setting? I mean
> >> > that neither tm must instrument asan instrumentation, nor asan must
> >> > instrument tm instrumentation. Is it the case? There also can be
> >> > conflicts related to ordering of instrumentation in the following
> >> > case:
> >> > asan_check();
> >> > speculative_load();
> >> > tm_check();
> >
> > The ordering of instrumentation is an interesting question, but I think
> > that putting the ASAN check before the TM load/store is the right thing
> > to do.  It will catch any illegal access before it's performed.  It
> > doesn't suffer from false positives because the TM will only allow valid
> > (even though speculative) executions.  For this ordering to not be valid
> > (ie, tm_check before asan_check), transactions would need to be able to
> > prevent access to a certain variable by writing to them (which doesn't
> > work).  Other cases in which the transaction would perform the access
> > because of values of other variables that it loaded previously are
> > covered by privatization safety.
> >
> >> I'm not aware of TM having speculative loads, libgtm certainly doesn't
> >> install a SIGSEGV handler (and testing whether some memory is
> >> readable/writable without actually dereferencing would be terribly slow).
> >> If a memory load or store segfaults, whether in a transaction or outside of
> >> it, it is a program bug and it is right if asan terminates the program.
> >
> > Right, memory accesses performed by the TM are only speculative to the
> > extent described above.
>
> There was a project called Transactional Locking II, if you are interested:
>
> https://github.com/daveboutcher/tl2-x86-mp/blob/master/tl2.c
>     /*
>      * Fetch tentative value
>      * Use either SPARC non-fault loads or complicit signal handlers.
>      * If the LD fails we'd like to call TxAbort()
>      * TL2 does not permit zombie/doomed txns to run
>      */
>     volatile vwLock* LockFor = PSLOCK(Addr);
>     vwLock rdv = LDLOCK(LockFor) & ~LOCKBIT;
>     MEMBARLDLD();
>     Valu = LDNF(Addr);
>     MEMBARLDLD();
>     if (rdv <= Self->rv && LDLOCK(LockFor) == rdv) {
>         if (!Self->IsRO) {
>             if (!TrackLoad(Self, LockFor)) {
>                 PROF_STM_READ_END();
>                 TxAbort(Self);
>             }
>         }
>         PROF_STM_READ_END();
>         return Valu;
>     }
>
>
Torvald Riegel Jan. 24, 2013, 5:29 p.m. UTC | #12
On Mon, 2012-12-17 at 13:52 +0400, Dmitry Vyukov wrote:
> resend in plain text
> 
> On Mon, Dec 17, 2012 at 1:50 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
> >
> > On Fri, Dec 14, 2012 at 5:43 PM, Torvald Riegel <triegel@redhat.com> wrote:
> > > On Thu, 2012-12-13 at 10:02 +0100, Jakub Jelinek wrote:
> > >> On Thu, Dec 13, 2012 at 10:38:13AM +0400, Dmitry Vyukov wrote:
> > >> > On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > >> > > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
> > >> > > The problem is that asan.c pass adds calls to builtins that weren't there
> > >> > > before and TM is upset about it.  The __asan_report* are all like
> > >> > > abort, in correctly written program they shouldn't have a user visible
> > >> > > effect, in bad program they will terminate the process, but in any case
> > >> > > it doesn't matter how many times they are retried as part of a transaction,
> > >> > > there is no state to roll back on transaction cancellation.
> > >> > > __asan_handle_no_return, while not being noreturn, just marks the stack as
> > >> > > unprotected, so again in correctly written application no effect, in bad app
> > >> > > might result in some issues being undetected, but still, it can be done many
> > >> > > times and isn't irreversible.
> > >> >
> > >> > I was only loosely following tm-languages discussions. Does gcc tm
> > >> > model guarantees strong consistency for all memory accesses? I mean
> > >> > there are tm implementations that allow transient inconsistencies,
> > >>
> > >> Will leave this to Torvald.
> > >
> > > This has two parts: (1) how TM fits into the C++11/C11 memory model, and
> > > (2) which guarantees the compiler and the TM runtime library agree on at
> > > the level of the TM ABI that we use in GCC.
> > >
> > > Regarding the first part, all transactions provide guarantees similar to
> > > a global lock.  Specifically, there are virtual transaction start/end
> > > events that take part in sequenced-before (similar to acquisition and
> > > release of the global lock), whose are then guaranteed to execute
> > > (without transactions interleaving with each other) in a global total
> > > order (let's call this order TO).  TO then contributes to
> > > happens-before.
> > >
> > > On the ABI level, the TM runtime is allowed to execute speculatively as
> > > long as (1) it does not expose any speculative execution to
> > > nontransactional code and (2) speculation doesn't violate the language's
> > > as-if rules (i.e., no visible side effects other than the abstract
> > > machine; no signals due to seg faults etc.).  This means that, for
> > > example, the TM will not access data at a wider granularity than what
> > > nontransactional code that conforms to the C++11 memory model does would
> > > do.
> > > Second, transactions can have a tentative position in TO, but they will
> > > only expose final TO choices to nontxnal code.  So, each transaction
> > > will execute code that would be valid when executed in isolation -- but
> > > it is possible that several transactions noncommitted transactions are
> > > in flight concurrently that may conflict with each other.  The TM
> > > ensures that such speculative execution is safe and not visible to a
> > > race-free program.  So, when a transaction commits at a certain position
> > > in TO, it will make sure that all other active transactions reach
> > > consensus on TO (up to this position) before it returns to the execution
> > > of nontxnal code.  Those active transactions will either see that they
> > > would be still valid at a new TO position (after the committing txn), or
> > > they abort and then signal that they agree to this TO.  That means that
> > > the nontxnal code will not be affected by any speculative execution,
> > > even if the prior txn privatized some data (this is called privatization
> > > safety in TM jargon).
> > > The sort-of counterpart to privatization safety is publication safety
> > > (ie, transactions can safely make some data shared).  While
> > > privatization safety is handled by the TM runtime, publication safety is
> > > ensured by the compiler by not allowing any dangerous load/load
> > > reordering, basicallly.  Publication safety is not yet ensured always,
> > > but Aldy is working on this.
> > >
> > >> > than are detected later and trx is restarted. Can't asan trigger false
> > >> > positives in this case?
> > >>
> > >> I can't imagine any.
> > >
> > > I also don't see any, because all loads/stores of all transactions, even
> > > those with a tentative TO position, would be a valid execution.  For
> > > malloc/free in transactions, AFAIR, ASAN hooks into malloc/free
> > > directly, so when libitm handles those including rollback of an
> > > allocation, there shouldn't be false positives.  However, there might be
> > > false negatives in case of free() because deallocations are deferred
> > > until transaction commit (they can't be rolled back).  Could we tell
> > > ASAN about free() directly using a call added by the TM instrumentation
> > > pass?  That would at least help catch the false negatives for all
> > > free()-like functions that the compiler knows about.
> >
> > I do not think that false positive is super important.  We have a similar false negative in case of racy use after free, when the free the just happen to happen after the use.
> >
> > However, it must be possible to support, because in case of asan we do can "rollback" free.
> > But won't it lead to false positives in case of:
> >
> > __transaction {
> >   free(p);
> >   p = 0;
> > }
> >
> > __transaction {
> >   r = 0;
> >   if (p)
> >     r = p->x;
> >   ...
> >
> > }
> > ?

(First, sorry for the late reply.)

You raise a good point.  For the thread executing the free(), the free()
should take immediate effect in the realm of asan checking.  For other
threads, it's more complicated because they can virtually execute at
older TO positions (see above).
The simplest solution would probably be again to execute transactions
serially.  Otherwise, we could use an STM with visible reads, which
doesn't switch TO position during execution of transactions (but there's
no STM method with visible reads implemented in libitm yet);  or, we
could invisible reads and replay all memory accesses whenever a
transaction switches it's TO position.

> >
> >
> > > All of this is different for TSAN, of course, because there a memory
> > > access does alter the state that TSAN keeps, so if we roll back the
> > > accesses in the TM we would also have to roll back the TSAN state.
> >
> >
> > I think the simplest way to solve it for now, it to use... well, single global lock.
> > I.e. replace __txn_start() with global pthread_mutex_t acquisition, __txn_commit() with lock release. And no transactional instrumentation inside of the trx. It should be correct transformation, right. However, I am not sure what to do with __txn_abort()...

This is already an execution mode supported by libitm.  It can be forced
by setting an env var: LIBITM_DEFAULT_METHOD=serial

Should we just tell users (in the docs) to set this env var when using
TSAN, or can TSAN set it, or should there be a way for TSAN to set the
mode using another mechanism?

> > >> > Also, what is the order of instrumentation in tm+asan setting? I mean
> > >> > that neither tm must instrument asan instrumentation, nor asan must
> > >> > instrument tm instrumentation. Is it the case? There also can be
> > >> > conflicts related to ordering of instrumentation in the following
> > >> > case:
> > >> > asan_check();
> > >> > speculative_load();
> > >> > tm_check();
> > >
> > > The ordering of instrumentation is an interesting question, but I think
> > > that putting the ASAN check before the TM load/store is the right thing
> > > to do.  It will catch any illegal access before it's performed.  It
> > > doesn't suffer from false positives because the TM will only allow valid
> > > (even though speculative) executions.  For this ordering to not be valid
> > > (ie, tm_check before asan_check), transactions would need to be able to
> > > prevent access to a certain variable by writing to them (which doesn't
> > > work).  Other cases in which the transaction would perform the access
> > > because of values of other variables that it loaded previously are
> > > covered by privatization safety.
> > >
> > >> I'm not aware of TM having speculative loads, libgtm certainly doesn't
> > >> install a SIGSEGV handler (and testing whether some memory is
> > >> readable/writable without actually dereferencing would be terribly slow).
> > >> If a memory load or store segfaults, whether in a transaction or outside of
> > >> it, it is a program bug and it is right if asan terminates the program.
> > >
> > > Right, memory accesses performed by the TM are only speculative to the
> > > extent described above.
> >
> > There was a project called Transactional Locking II, if you are interested:
> >
> > https://github.com/daveboutcher/tl2-x86-mp/blob/master/tl2.c
> >     /*
> >      * Fetch tentative value
> >      * Use either SPARC non-fault loads

The only architecture that has non-faulting loads is SPARC, AFAIK.

> or complicit signal handlers.

The signal handlers are probably too fragile in practice.  The TM
runtime library would have to prevent all other parts of the program
from overwriting the handler, and the faults are still visible in the OS
and thus perhaps visible to other components.  I've not seen a
rock-solid, practical implementation of masking such faults yet.

Privatization safety can avoid this issue, and it's necessary anyway
with time-based STMs such as TL2 (which don't provide privatization
safety).  This trade-off might be different for single-orec STM
algorithms such as NOrec which provide privatization safety except this
issue of pending loads.


Torvald
Dmitry Vyukov Jan. 24, 2013, 5:44 p.m. UTC | #13
On Thu, Jan 24, 2013 at 9:29 PM, Torvald Riegel <triegel@redhat.com> wrote:
> On Mon, 2012-12-17 at 13:52 +0400, Dmitry Vyukov wrote:
>> resend in plain text
>>
>> On Mon, Dec 17, 2012 at 1:50 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
>> >
>> > On Fri, Dec 14, 2012 at 5:43 PM, Torvald Riegel <triegel@redhat.com> wrote:
>> > > On Thu, 2012-12-13 at 10:02 +0100, Jakub Jelinek wrote:
>> > >> On Thu, Dec 13, 2012 at 10:38:13AM +0400, Dmitry Vyukov wrote:
>> > >> > On Wed, Dec 12, 2012 at 11:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > >> > > Various TM tests ICE when built with -fgnu-tm -fsanitizer=address.
>> > >> > > The problem is that asan.c pass adds calls to builtins that weren't there
>> > >> > > before and TM is upset about it.  The __asan_report* are all like
>> > >> > > abort, in correctly written program they shouldn't have a user visible
>> > >> > > effect, in bad program they will terminate the process, but in any case
>> > >> > > it doesn't matter how many times they are retried as part of a transaction,
>> > >> > > there is no state to roll back on transaction cancellation.
>> > >> > > __asan_handle_no_return, while not being noreturn, just marks the stack as
>> > >> > > unprotected, so again in correctly written application no effect, in bad app
>> > >> > > might result in some issues being undetected, but still, it can be done many
>> > >> > > times and isn't irreversible.
>> > >> >
>> > >> > I was only loosely following tm-languages discussions. Does gcc tm
>> > >> > model guarantees strong consistency for all memory accesses? I mean
>> > >> > there are tm implementations that allow transient inconsistencies,
>> > >>
>> > >> Will leave this to Torvald.
>> > >
>> > > This has two parts: (1) how TM fits into the C++11/C11 memory model, and
>> > > (2) which guarantees the compiler and the TM runtime library agree on at
>> > > the level of the TM ABI that we use in GCC.
>> > >
>> > > Regarding the first part, all transactions provide guarantees similar to
>> > > a global lock.  Specifically, there are virtual transaction start/end
>> > > events that take part in sequenced-before (similar to acquisition and
>> > > release of the global lock), whose are then guaranteed to execute
>> > > (without transactions interleaving with each other) in a global total
>> > > order (let's call this order TO).  TO then contributes to
>> > > happens-before.
>> > >
>> > > On the ABI level, the TM runtime is allowed to execute speculatively as
>> > > long as (1) it does not expose any speculative execution to
>> > > nontransactional code and (2) speculation doesn't violate the language's
>> > > as-if rules (i.e., no visible side effects other than the abstract
>> > > machine; no signals due to seg faults etc.).  This means that, for
>> > > example, the TM will not access data at a wider granularity than what
>> > > nontransactional code that conforms to the C++11 memory model does would
>> > > do.
>> > > Second, transactions can have a tentative position in TO, but they will
>> > > only expose final TO choices to nontxnal code.  So, each transaction
>> > > will execute code that would be valid when executed in isolation -- but
>> > > it is possible that several transactions noncommitted transactions are
>> > > in flight concurrently that may conflict with each other.  The TM
>> > > ensures that such speculative execution is safe and not visible to a
>> > > race-free program.  So, when a transaction commits at a certain position
>> > > in TO, it will make sure that all other active transactions reach
>> > > consensus on TO (up to this position) before it returns to the execution
>> > > of nontxnal code.  Those active transactions will either see that they
>> > > would be still valid at a new TO position (after the committing txn), or
>> > > they abort and then signal that they agree to this TO.  That means that
>> > > the nontxnal code will not be affected by any speculative execution,
>> > > even if the prior txn privatized some data (this is called privatization
>> > > safety in TM jargon).
>> > > The sort-of counterpart to privatization safety is publication safety
>> > > (ie, transactions can safely make some data shared).  While
>> > > privatization safety is handled by the TM runtime, publication safety is
>> > > ensured by the compiler by not allowing any dangerous load/load
>> > > reordering, basicallly.  Publication safety is not yet ensured always,
>> > > but Aldy is working on this.
>> > >
>> > >> > than are detected later and trx is restarted. Can't asan trigger false
>> > >> > positives in this case?
>> > >>
>> > >> I can't imagine any.
>> > >
>> > > I also don't see any, because all loads/stores of all transactions, even
>> > > those with a tentative TO position, would be a valid execution.  For
>> > > malloc/free in transactions, AFAIR, ASAN hooks into malloc/free
>> > > directly, so when libitm handles those including rollback of an
>> > > allocation, there shouldn't be false positives.  However, there might be
>> > > false negatives in case of free() because deallocations are deferred
>> > > until transaction commit (they can't be rolled back).  Could we tell
>> > > ASAN about free() directly using a call added by the TM instrumentation
>> > > pass?  That would at least help catch the false negatives for all
>> > > free()-like functions that the compiler knows about.
>> >
>> > I do not think that false positive is super important.  We have a similar false negative in case of racy use after free, when the free the just happen to happen after the use.
>> >
>> > However, it must be possible to support, because in case of asan we do can "rollback" free.
>> > But won't it lead to false positives in case of:
>> >
>> > __transaction {
>> >   free(p);
>> >   p = 0;
>> > }
>> >
>> > __transaction {
>> >   r = 0;
>> >   if (p)
>> >     r = p->x;
>> >   ...
>> >
>> > }
>> > ?
>
> (First, sorry for the late reply.)
>
> You raise a good point.  For the thread executing the free(), the free()
> should take immediate effect in the realm of asan checking.  For other
> threads, it's more complicated because they can virtually execute at
> older TO positions (see above).
> The simplest solution would probably be again to execute transactions
> serially.  Otherwise, we could use an STM with visible reads, which
> doesn't switch TO position during execution of transactions (but there's
> no STM method with visible reads implemented in libitm yet);  or, we
> could invisible reads and replay all memory accesses whenever a
> transaction switches it's TO position.
>
>> >
>> >
>> > > All of this is different for TSAN, of course, because there a memory
>> > > access does alter the state that TSAN keeps, so if we roll back the
>> > > accesses in the TM we would also have to roll back the TSAN state.
>> >
>> >
>> > I think the simplest way to solve it for now, it to use... well, single global lock.
>> > I.e. replace __txn_start() with global pthread_mutex_t acquisition, __txn_commit() with lock release. And no transactional instrumentation inside of the trx. It should be correct transformation, right. However, I am not sure what to do with __txn_abort()...
>
> This is already an execution mode supported by libitm.  It can be forced
> by setting an env var: LIBITM_DEFAULT_METHOD=serial
>
> Should we just tell users (in the docs) to set this env var when using
> TSAN, or can TSAN set it, or should there be a way for TSAN to set the
> mode using another mechanism?

Tsan can set LIBITM_DEFAULT_METHOD during initialization. Other modes
won't work with tsan, and users don't usually read docs. Users must
not be able to override the mode.
Does somebody tried to execute some transactional code with tsan? Does
it work at all (with LIBITM_DEFAULT_METHOD=serial)?



>> > >> > Also, what is the order of instrumentation in tm+asan setting? I mean
>> > >> > that neither tm must instrument asan instrumentation, nor asan must
>> > >> > instrument tm instrumentation. Is it the case? There also can be
>> > >> > conflicts related to ordering of instrumentation in the following
>> > >> > case:
>> > >> > asan_check();
>> > >> > speculative_load();
>> > >> > tm_check();
>> > >
>> > > The ordering of instrumentation is an interesting question, but I think
>> > > that putting the ASAN check before the TM load/store is the right thing
>> > > to do.  It will catch any illegal access before it's performed.  It
>> > > doesn't suffer from false positives because the TM will only allow valid
>> > > (even though speculative) executions.  For this ordering to not be valid
>> > > (ie, tm_check before asan_check), transactions would need to be able to
>> > > prevent access to a certain variable by writing to them (which doesn't
>> > > work).  Other cases in which the transaction would perform the access
>> > > because of values of other variables that it loaded previously are
>> > > covered by privatization safety.
>> > >
>> > >> I'm not aware of TM having speculative loads, libgtm certainly doesn't
>> > >> install a SIGSEGV handler (and testing whether some memory is
>> > >> readable/writable without actually dereferencing would be terribly slow).
>> > >> If a memory load or store segfaults, whether in a transaction or outside of
>> > >> it, it is a program bug and it is right if asan terminates the program.
>> > >
>> > > Right, memory accesses performed by the TM are only speculative to the
>> > > extent described above.
>> >
>> > There was a project called Transactional Locking II, if you are interested:
>> >
>> > https://github.com/daveboutcher/tl2-x86-mp/blob/master/tl2.c
>> >     /*
>> >      * Fetch tentative value
>> >      * Use either SPARC non-fault loads
>
> The only architecture that has non-faulting loads is SPARC, AFAIK.
>
>> or complicit signal handlers.
>
> The signal handlers are probably too fragile in practice.  The TM
> runtime library would have to prevent all other parts of the program
> from overwriting the handler, and the faults are still visible in the OS
> and thus perhaps visible to other components.  I've not seen a
> rock-solid, practical implementation of masking such faults yet.
>
> Privatization safety can avoid this issue, and it's necessary anyway
> with time-based STMs such as TL2 (which don't provide privatization
> safety).  This trade-off might be different for single-orec STM
> algorithms such as NOrec which provide privatization safety except this
> issue of pending loads.

Agree.
Torvald Riegel Jan. 24, 2013, 6:33 p.m. UTC | #14
On Thu, 2013-01-24 at 21:44 +0400, Dmitry Vyukov wrote:
> On Thu, Jan 24, 2013 at 9:29 PM, Torvald Riegel <triegel@redhat.com> wrote:
> > On Mon, 2012-12-17 at 13:52 +0400, Dmitry Vyukov wrote:
> >> > I think the simplest way to solve it for now, it to use... well, single global lock.
> >> > I.e. replace __txn_start() with global pthread_mutex_t acquisition, __txn_commit() with lock release. And no transactional instrumentation inside of the trx. It should be correct transformation, right. However, I am not sure what to do with __txn_abort()...
> >
> > This is already an execution mode supported by libitm.  It can be forced
> > by setting an env var: LIBITM_DEFAULT_METHOD=serial
> >
> > Should we just tell users (in the docs) to set this env var when using
> > TSAN, or can TSAN set it, or should there be a way for TSAN to set the
> > mode using another mechanism?
> 
> Tsan can set LIBITM_DEFAULT_METHOD during initialization. Other modes
> won't work with tsan, and users don't usually read docs. Users must
> not be able to override the mode.

The only way to influence the mode is through the env var, so if Tsan
sets it before the first transaction is executed, this should be fine I
guess.

> Does somebody tried to execute some transactional code with tsan? Does
> it work at all (with LIBITM_DEFAULT_METHOD=serial)?

I haven't yet.


Torvald
diff mbox

Patch

--- gcc/builtin-attrs.def.jj	2012-10-22 08:42:23.000000000 +0200
+++ gcc/builtin-attrs.def	2012-12-12 11:56:54.942938879 +0100
@@ -263,6 +263,11 @@  DEF_ATTR_TREE_LIST (ATTR_TMPURE_MALLOC_N
 DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LIST,
 		   ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LIST)
 
+DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LEAF_LIST,
+		    ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
+DEF_ATTR_TREE_LIST (ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST,
+		    ATTR_TM_TMPURE, ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+
 /* Construct a tree for a format_arg attribute.  */
 #define DEF_FORMAT_ARG_ATTRIBUTE(FA)					\
   DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_##FA, ATTR_FORMAT_ARG,		\
--- gcc/asan.c.jj	2012-12-11 13:05:36.000000000 +0100
+++ gcc/asan.c	2012-12-12 11:57:59.626550534 +0100
@@ -1611,8 +1611,13 @@  initialize_sanitizer_builtins (void)
 #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
 #undef ATTR_NOTHROW_LEAF_LIST
 #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
+#undef ATTR_TMPURE_NOTHROW_LEAF_LIST
+#define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
 #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
 #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
+#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
+#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
+  ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
 #undef DEF_SANITIZER_BUILTIN
 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
   decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,		\
--- gcc/sanitizer.def.jj	2012-12-11 11:28:10.000000000 +0100
+++ gcc/sanitizer.def	2012-12-12 11:57:12.714833945 +0100
@@ -32,25 +32,25 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT
 /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
    relies on this order.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD2, "__asan_report_load2",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD4, "__asan_report_load4",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD8, "__asan_report_load8",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD16, "__asan_report_load16",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE1, "__asan_report_store1",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE2, "__asan_report_store2",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE4, "__asan_report_store4",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE8, "__asan_report_store8",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
-		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
 		      "__asan_register_globals",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
@@ -59,7 +59,7 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNRE
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN,
 		      "__asan_handle_no_return",
-		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+		      BT_FN_VOID, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",