Move SigSafeArena() out to absl/base/internal/low_level_alloc.h

This allows dynamic memory allocation for computing stack traces to avoid a stack overflow.

PiperOrigin-RevId: 786512779
Change-Id: Ib5ef8fef436672b99d9678137e3b2bb65ca47eba
This commit is contained in:
Abseil Team
2025-07-23 19:12:00 -07:00
committed by Copybara-Service
parent 57bc7edd87
commit 6ad95e1535
3 changed files with 44 additions and 31 deletions

View File

@@ -19,6 +19,8 @@
#include "absl/base/internal/low_level_alloc.h"
#include <stdint.h>
#include <optional>
#include <type_traits>
@@ -220,6 +222,32 @@ struct LowLevelAlloc::Arena {
uint32_t random ABSL_GUARDED_BY(mu);
};
// ---------------------------------------------------------------
// An async-signal-safe arena for LowLevelAlloc
static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
base_internal::LowLevelAlloc::Arena *SigSafeArena() {
return g_sig_safe_arena.load(std::memory_order_acquire);
}
void InitSigSafeArena() {
if (SigSafeArena() == nullptr) {
uint32_t flags = 0;
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
flags |= base_internal::LowLevelAlloc::kAsyncSignalSafe;
#endif
base_internal::LowLevelAlloc::Arena *new_arena =
base_internal::LowLevelAlloc::NewArena(flags);
base_internal::LowLevelAlloc::Arena *old_value = nullptr;
if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
std::memory_order_release,
std::memory_order_relaxed)) {
// We lost a race to allocate an arena; deallocate.
base_internal::LowLevelAlloc::DeleteArena(new_arena);
}
}
}
namespace {
// Static storage space for the lazily-constructed, default global arena
// instances. We require this space because the whole point of LowLevelAlloc

View File

@@ -120,6 +120,12 @@ class LowLevelAlloc {
LowLevelAlloc(); // no instances
};
// Returns a global async-signal-safe arena for LowLevelAlloc.
LowLevelAlloc::Arena *SigSafeArena();
// Ensures the global async-signal-safe arena for LowLevelAlloc is initialized.
void InitSigSafeArena();
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

View File

@@ -232,29 +232,6 @@ struct SymbolCacheLine {
uint32_t age[ASSOCIATIVITY];
};
// ---------------------------------------------------------------
// An async-signal-safe arena for LowLevelAlloc
static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
static base_internal::LowLevelAlloc::Arena *SigSafeArena() {
return g_sig_safe_arena.load(std::memory_order_acquire);
}
static void InitSigSafeArena() {
if (SigSafeArena() == nullptr) {
base_internal::LowLevelAlloc::Arena *new_arena =
base_internal::LowLevelAlloc::NewArena(
base_internal::LowLevelAlloc::kAsyncSignalSafe);
base_internal::LowLevelAlloc::Arena *old_value = nullptr;
if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
std::memory_order_release,
std::memory_order_relaxed)) {
// We lost a race to allocate an arena; deallocate.
base_internal::LowLevelAlloc::DeleteArena(new_arena);
}
}
}
// ---------------------------------------------------------------
// An AddrMap is a vector of ObjFile, using SigSafeArena() for allocation.
@@ -287,7 +264,7 @@ ObjFile *AddrMap::Add() {
size_t new_allocated = allocated_ * 2 + 50;
ObjFile *new_obj_ =
static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena(
new_allocated * sizeof(*new_obj_), SigSafeArena()));
new_allocated * sizeof(*new_obj_), base_internal::SigSafeArena()));
if (obj_) {
memcpy(new_obj_, obj_, allocated_ * sizeof(*new_obj_));
base_internal::LowLevelAlloc::Free(obj_);
@@ -335,8 +312,9 @@ class Symbolizer {
private:
char *CopyString(const char *s) {
size_t len = strlen(s);
char *dst = static_cast<char *>(
base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
char *dst =
static_cast<char *>(base_internal::LowLevelAlloc::AllocWithArena(
len + 1, base_internal::SigSafeArena()));
ABSL_RAW_CHECK(dst != nullptr, "out of memory");
memcpy(dst, s, len + 1);
return dst;
@@ -441,14 +419,14 @@ static size_t SymbolizerSize() {
// Return (and set null) g_cached_symbolized_state if it is not null.
// Otherwise return a new symbolizer.
static Symbolizer *AllocateSymbolizer() {
InitSigSafeArena();
base_internal::InitSigSafeArena();
Symbolizer *symbolizer =
g_cached_symbolizer.exchange(nullptr, std::memory_order_acquire);
if (symbolizer != nullptr) {
return symbolizer;
}
return new (base_internal::LowLevelAlloc::AllocWithArena(
SymbolizerSize(), SigSafeArena())) Symbolizer();
SymbolizerSize(), base_internal::SigSafeArena())) Symbolizer();
}
// Set g_cached_symbolize_state to s if it is null, otherwise
@@ -1678,7 +1656,7 @@ bool RegisterFileMappingHint(const void *start, const void *end,
SAFE_ASSERT(start <= end);
SAFE_ASSERT(filename != nullptr);
InitSigSafeArena();
base_internal::InitSigSafeArena();
if (!g_file_mapping_mu.TryLock()) {
return false;
@@ -1690,8 +1668,9 @@ bool RegisterFileMappingHint(const void *start, const void *end,
} else {
// TODO(ckennelly): Move this into a string copy routine.
size_t len = strlen(filename);
char *dst = static_cast<char *>(
base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
char *dst =
static_cast<char *>(base_internal::LowLevelAlloc::AllocWithArena(
len + 1, base_internal::SigSafeArena()));
ABSL_RAW_CHECK(dst != nullptr, "out of memory");
memcpy(dst, filename, len + 1);