chromium/components/gwp_asan/client/thread_local_state.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_GWP_ASAN_CLIENT_THREAD_LOCAL_STATE_H_
#define COMPONENTS_GWP_ASAN_CLIENT_THREAD_LOCAL_STATE_H_

#include "base/check.h"
#include "base/compiler_specific.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
// On macOS and Android (before Q), the first use of a `thread_local` variable
// on a new thread will cause an allocation, leading to infinite recursion.
// Also, `thread_local` goes through `emutls` on Android, which is slower than
// `pthread_getspecific`.
#define THREAD_LOCAL_STATE_USES_PARTITION_ALLOC_TLS
#elif BUILDFLAG(IS_POSIX) && defined(COMPONENT_BUILD)
// On POSIX platforms when built as component build, use of a `thread_local`
// variable may or may not cause a call to `free()` depending on an
// implementation of TLS. At least in case of glibc/glibc/elf/dl-tls.c,
// `_dl_update_slotinfo()` calls `free()` (as of Apr 2024).
//
// This is a problem for LUD (Lightweight UaF Detector) and ELUD (Extreme LUD)
// as they call `SamplingState::Sample()` inside `free()`, which leads to
// infinite recursion. (See also https://crbug.com/332234169)
//
// Fortunately, statically-linked executables (non-component builds) do not hit
// the problem because they use the "local-exec" model of TLS (i.e. do not call
// any library function).
#define THREAD_LOCAL_STATE_USES_PARTITION_ALLOC_TLS
#endif

#if defined(THREAD_LOCAL_STATE_USES_PARTITION_ALLOC_TLS)
#include "partition_alloc/partition_tls.h"
#endif

namespace gwp_asan::internal {

// Class that provides the optimal thread-local storage implementation depending
// on the platform.
template <typename T>
class ThreadLocalState {};

#if !defined(THREAD_LOCAL_STATE_USES_PARTITION_ALLOC_TLS)
template <typename T>
thread_local uintptr_t ThreadLocalState<T>::state_ = 0;
#else
template <typename T>
partition_alloc::internal::PartitionTlsKey ThreadLocalState<T>::tls_key_ =;
#endif

}  // namespace gwp_asan::internal

#endif  // COMPONENTS_GWP_ASAN_CLIENT_THREAD_LOCAL_STATE_H_