13614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===-- sanitizer_stoptheworld_test.cc ------------------------------------===//
23614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//
33614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//                     The LLVM Compiler Infrastructure
43614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//
53614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// This file is distributed under the University of Illinois Open Source
63614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// License. See LICENSE.TXT for details.
73614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//
83614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===----------------------------------------------------------------------===//
93614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//
103614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// Tests for sanitizer_stoptheworld.h
113614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//
123614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===----------------------------------------------------------------------===//
133614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
14a615b26e3e3c2da0b2f950f506f6c2c220430c19Sergey Matveev#include "sanitizer_common/sanitizer_platform.h"
15cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#if SANITIZER_LINUX && defined(__x86_64__)
163614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
173614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_stoptheworld.h"
183614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "gtest/gtest.h"
193614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
203614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_libc.h"
213614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_common.h"
223614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
233614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include <pthread.h>
243614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include <sched.h>
253614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
263614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkonamespace __sanitizer {
273614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
283614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic pthread_mutex_t incrementer_thread_exit_mutex;
293614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
303614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostruct CallbackArgument {
313614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile int counter;
323614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile bool threads_stopped;
333614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile bool callback_executed;
343614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  CallbackArgument()
353614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    : counter(0),
363614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      threads_stopped(false),
373614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      callback_executed(false) {}
383614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko};
393614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
403614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid *IncrementerThread(void *argument) {
413614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  CallbackArgument *callback_argument = (CallbackArgument *)argument;
423614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  while (true) {
433614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    __sync_fetch_and_add(&callback_argument->counter, 1);
443614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    if (pthread_mutex_trylock(&incrementer_thread_exit_mutex) == 0) {
453614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      pthread_mutex_unlock(&incrementer_thread_exit_mutex);
463614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      return NULL;
473614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    } else {
483614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      sched_yield();
493614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    }
503614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  }
513614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
523614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
533614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// This callback checks that IncrementerThread is suspended at the time of its
543614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// execution.
553614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid Callback(const SuspendedThreadsList &suspended_threads_list,
563614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko              void *argument) {
573614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  CallbackArgument *callback_argument = (CallbackArgument *)argument;
583614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  callback_argument->callback_executed = true;
593614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  int counter_at_init = __sync_fetch_and_add(&callback_argument->counter, 0);
603614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  for (uptr i = 0; i < 1000; i++) {
613614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    sched_yield();
623614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    if (__sync_fetch_and_add(&callback_argument->counter, 0) !=
633614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko          counter_at_init) {
643614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      callback_argument->threads_stopped = false;
653614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      return;
663614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    }
673614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  }
683614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  callback_argument->threads_stopped = true;
693614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
703614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
713614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander PotapenkoTEST(StopTheWorld, SuspendThreadsSimple) {
723614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_init(&incrementer_thread_exit_mutex, NULL);
733614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  CallbackArgument argument;
743614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_t thread_id;
753614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  int pthread_create_result;
763614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_lock(&incrementer_thread_exit_mutex);
773614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_create_result = pthread_create(&thread_id, NULL, IncrementerThread,
783614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                                         &argument);
793614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  ASSERT_EQ(0, pthread_create_result);
803614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  StopTheWorld(&Callback, &argument);
813614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_unlock(&incrementer_thread_exit_mutex);
823614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  EXPECT_TRUE(argument.callback_executed);
833614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  EXPECT_TRUE(argument.threads_stopped);
843614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // argument is on stack, so we have to wait for the incrementer thread to
853614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // terminate before we can return from this function.
863614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  ASSERT_EQ(0, pthread_join(thread_id, NULL));
873614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_destroy(&incrementer_thread_exit_mutex);
883614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
893614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
903614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// A more comprehensive test where we spawn a bunch of threads while executing
913614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// StopTheWorld in parallel.
923614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic const uptr kThreadCount = 50;
933614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic const uptr kStopWorldAfter = 10; // let this many threads spawn first
943614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
953614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic pthread_mutex_t advanced_incrementer_thread_exit_mutex;
963614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
973614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostruct AdvancedCallbackArgument {
983614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile uptr thread_index;
993614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile int counters[kThreadCount];
1003614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_t thread_ids[kThreadCount];
1013614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile bool threads_stopped;
1023614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile bool callback_executed;
1033614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  volatile bool fatal_error;
1043614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  AdvancedCallbackArgument()
1053614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    : thread_index(0),
1063614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      threads_stopped(false),
1073614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      callback_executed(false),
1083614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      fatal_error(false) {}
1093614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko};
1103614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1113614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid *AdvancedIncrementerThread(void *argument) {
1123614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  AdvancedCallbackArgument *callback_argument =
1133614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      (AdvancedCallbackArgument *)argument;
1145efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov  uptr this_thread_index = __sync_fetch_and_add(
1155efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov      &callback_argument->thread_index, 1);
1163614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // Spawn the next thread.
1173614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  int pthread_create_result;
1183614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  if (this_thread_index + 1 < kThreadCount) {
1193614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    pthread_create_result =
1203614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko        pthread_create(&callback_argument->thread_ids[this_thread_index + 1],
1213614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                       NULL, AdvancedIncrementerThread, argument);
1223614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    // Cannot use ASSERT_EQ in non-void-returning functions. If there's a
1233614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    // problem, defer failing to the main thread.
1243614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    if (pthread_create_result != 0) {
1253614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      callback_argument->fatal_error = true;
1263614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      __sync_fetch_and_add(&callback_argument->thread_index,
1273614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                           kThreadCount - callback_argument->thread_index);
1283614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    }
1293614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  }
1303614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // Do the actual work.
1313614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  while (true) {
1323614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    __sync_fetch_and_add(&callback_argument->counters[this_thread_index], 1);
1333614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    if (pthread_mutex_trylock(&advanced_incrementer_thread_exit_mutex) == 0) {
1343614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
1353614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      return NULL;
1363614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    } else {
1373614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      sched_yield();
1383614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    }
1393614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  }
1403614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
1413614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1423614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid AdvancedCallback(const SuspendedThreadsList &suspended_threads_list,
1433614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                             void *argument) {
1443614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  AdvancedCallbackArgument *callback_argument =
1453614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      (AdvancedCallbackArgument *)argument;
1463614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  callback_argument->callback_executed = true;
1473614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1483614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  int counters_at_init[kThreadCount];
1493614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  for (uptr j = 0; j < kThreadCount; j++)
1503614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    counters_at_init[j] = __sync_fetch_and_add(&callback_argument->counters[j],
1513614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                                               0);
1523614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  for (uptr i = 0; i < 10; i++) {
1533614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    sched_yield();
1543614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    for (uptr j = 0; j < kThreadCount; j++)
1553614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      if (__sync_fetch_and_add(&callback_argument->counters[j], 0) !=
1563614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko            counters_at_init[j]) {
1573614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko        callback_argument->threads_stopped = false;
1583614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko        return;
1593614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko      }
1603614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  }
1613614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  callback_argument->threads_stopped = true;
1623614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
1633614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1643614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander PotapenkoTEST(StopTheWorld, SuspendThreadsAdvanced) {
1653614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_init(&advanced_incrementer_thread_exit_mutex, NULL);
1663614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  AdvancedCallbackArgument argument;
1673614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1683614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_lock(&advanced_incrementer_thread_exit_mutex);
1693614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  int pthread_create_result;
1703614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_create_result = pthread_create(&argument.thread_ids[0], NULL,
1713614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                                         AdvancedIncrementerThread,
1723614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko                                         &argument);
1733614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  ASSERT_EQ(0, pthread_create_result);
1743614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // Wait for several threads to spawn before proceeding.
1753614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  while (__sync_fetch_and_add(&argument.thread_index, 0) < kStopWorldAfter)
1763614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    sched_yield();
1773614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  StopTheWorld(&AdvancedCallback, &argument);
1783614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  EXPECT_TRUE(argument.callback_executed);
1793614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  EXPECT_TRUE(argument.threads_stopped);
1803614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1813614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // Wait for all threads to spawn before we start terminating them.
1823614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  while (__sync_fetch_and_add(&argument.thread_index, 0) < kThreadCount)
1833614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    sched_yield();
1845efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov  ASSERT_FALSE(argument.fatal_error); // a pthread_create has failed
1853614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  // Signal the threads to terminate.
1863614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex);
1873614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  for (uptr i = 0; i < kThreadCount; i++)
1883614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko    ASSERT_EQ(0, pthread_join(argument.thread_ids[i], NULL));
1893614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko  pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex);
1903614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}
1913614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
1923614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}  // namespace __sanitizer
1933614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko
194cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#endif  // SANITIZER_LINUX && defined(__x86_64__)
195