1349cc55cSDimitry Andric //===-- sanitizer_stack_store.cpp -------------------------------*- C++ -*-===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric
9349cc55cSDimitry Andric #include "sanitizer_stack_store.h"
10349cc55cSDimitry Andric
11349cc55cSDimitry Andric #include "sanitizer_atomic.h"
12349cc55cSDimitry Andric #include "sanitizer_common.h"
130eae32dcSDimitry Andric #include "sanitizer_internal_defs.h"
140eae32dcSDimitry Andric #include "sanitizer_leb128.h"
150eae32dcSDimitry Andric #include "sanitizer_lzw.h"
160eae32dcSDimitry Andric #include "sanitizer_placement_new.h"
17349cc55cSDimitry Andric #include "sanitizer_stacktrace.h"
18349cc55cSDimitry Andric
19349cc55cSDimitry Andric namespace __sanitizer {
20349cc55cSDimitry Andric
214824e7fdSDimitry Andric namespace {
224824e7fdSDimitry Andric struct StackTraceHeader {
234824e7fdSDimitry Andric static constexpr u32 kStackSizeBits = 8;
24349cc55cSDimitry Andric
254824e7fdSDimitry Andric u8 size;
264824e7fdSDimitry Andric u8 tag;
StackTraceHeader__sanitizer::__anon74b28d1f0111::StackTraceHeader274824e7fdSDimitry Andric explicit StackTraceHeader(const StackTrace &trace)
284824e7fdSDimitry Andric : size(Min<uptr>(trace.size, (1u << 8) - 1)), tag(trace.tag) {
294824e7fdSDimitry Andric CHECK_EQ(trace.tag, static_cast<uptr>(tag));
304824e7fdSDimitry Andric }
StackTraceHeader__sanitizer::__anon74b28d1f0111::StackTraceHeader314824e7fdSDimitry Andric explicit StackTraceHeader(uptr h)
324824e7fdSDimitry Andric : size(h & ((1 << kStackSizeBits) - 1)), tag(h >> kStackSizeBits) {}
334824e7fdSDimitry Andric
ToUptr__sanitizer::__anon74b28d1f0111::StackTraceHeader344824e7fdSDimitry Andric uptr ToUptr() const {
354824e7fdSDimitry Andric return static_cast<uptr>(size) | (static_cast<uptr>(tag) << kStackSizeBits);
364824e7fdSDimitry Andric }
374824e7fdSDimitry Andric };
384824e7fdSDimitry Andric } // namespace
394824e7fdSDimitry Andric
Store(const StackTrace & trace,uptr * pack)404824e7fdSDimitry Andric StackStore::Id StackStore::Store(const StackTrace &trace, uptr *pack) {
414824e7fdSDimitry Andric if (!trace.size && !trace.tag)
424824e7fdSDimitry Andric return 0;
434824e7fdSDimitry Andric StackTraceHeader h(trace);
444824e7fdSDimitry Andric uptr idx = 0;
454824e7fdSDimitry Andric *pack = 0;
464824e7fdSDimitry Andric uptr *stack_trace = Alloc(h.size + 1, &idx, pack);
47*cb14a3feSDimitry Andric // No more space.
48*cb14a3feSDimitry Andric if (stack_trace == nullptr)
49*cb14a3feSDimitry Andric return 0;
504824e7fdSDimitry Andric *stack_trace = h.ToUptr();
514824e7fdSDimitry Andric internal_memcpy(stack_trace + 1, trace.trace, h.size * sizeof(uptr));
524824e7fdSDimitry Andric *pack += blocks_[GetBlockIdx(idx)].Stored(h.size + 1);
534824e7fdSDimitry Andric return OffsetToId(idx);
54349cc55cSDimitry Andric }
55349cc55cSDimitry Andric
Load(Id id)56349cc55cSDimitry Andric StackTrace StackStore::Load(Id id) {
574824e7fdSDimitry Andric if (!id)
584824e7fdSDimitry Andric return {};
594824e7fdSDimitry Andric uptr idx = IdToOffset(id);
604824e7fdSDimitry Andric uptr block_idx = GetBlockIdx(idx);
614824e7fdSDimitry Andric CHECK_LT(block_idx, ARRAY_SIZE(blocks_));
620eae32dcSDimitry Andric const uptr *stack_trace = blocks_[block_idx].GetOrUnpack(this);
634824e7fdSDimitry Andric if (!stack_trace)
644824e7fdSDimitry Andric return {};
654824e7fdSDimitry Andric stack_trace += GetInBlockIdx(idx);
664824e7fdSDimitry Andric StackTraceHeader h(*stack_trace);
674824e7fdSDimitry Andric return StackTrace(stack_trace + 1, h.size, h.tag);
68349cc55cSDimitry Andric }
69349cc55cSDimitry Andric
Allocated() const704824e7fdSDimitry Andric uptr StackStore::Allocated() const {
710eae32dcSDimitry Andric return atomic_load_relaxed(&allocated_) + sizeof(*this);
724824e7fdSDimitry Andric }
734824e7fdSDimitry Andric
Alloc(uptr count,uptr * idx,uptr * pack)744824e7fdSDimitry Andric uptr *StackStore::Alloc(uptr count, uptr *idx, uptr *pack) {
75349cc55cSDimitry Andric for (;;) {
764824e7fdSDimitry Andric // Optimisic lock-free allocation, essentially try to bump the
774824e7fdSDimitry Andric // total_frames_.
784824e7fdSDimitry Andric uptr start = atomic_fetch_add(&total_frames_, count, memory_order_relaxed);
794824e7fdSDimitry Andric uptr block_idx = GetBlockIdx(start);
804824e7fdSDimitry Andric uptr last_idx = GetBlockIdx(start + count - 1);
814824e7fdSDimitry Andric if (LIKELY(block_idx == last_idx)) {
82*cb14a3feSDimitry Andric // Fits into a single block.
83*cb14a3feSDimitry Andric // No more available blocks. Indicate inability to allocate more memory.
84*cb14a3feSDimitry Andric if (block_idx >= ARRAY_SIZE(blocks_))
85*cb14a3feSDimitry Andric return nullptr;
864824e7fdSDimitry Andric *idx = start;
870eae32dcSDimitry Andric return blocks_[block_idx].GetOrCreate(this) + GetInBlockIdx(start);
884824e7fdSDimitry Andric }
894824e7fdSDimitry Andric
904824e7fdSDimitry Andric // Retry. We can't use range allocated in two different blocks.
914824e7fdSDimitry Andric CHECK_LE(count, kBlockSizeFrames);
924824e7fdSDimitry Andric uptr in_first = kBlockSizeFrames - GetInBlockIdx(start);
934824e7fdSDimitry Andric // Mark tail/head of these blocks as "stored".to avoid waiting before we can
944824e7fdSDimitry Andric // Pack().
954824e7fdSDimitry Andric *pack += blocks_[block_idx].Stored(in_first);
964824e7fdSDimitry Andric *pack += blocks_[last_idx].Stored(count - in_first);
97349cc55cSDimitry Andric }
98349cc55cSDimitry Andric }
99349cc55cSDimitry Andric
Map(uptr size,const char * mem_type)1000eae32dcSDimitry Andric void *StackStore::Map(uptr size, const char *mem_type) {
1010eae32dcSDimitry Andric atomic_fetch_add(&allocated_, size, memory_order_relaxed);
1020eae32dcSDimitry Andric return MmapNoReserveOrDie(size, mem_type);
1030eae32dcSDimitry Andric }
1040eae32dcSDimitry Andric
Unmap(void * addr,uptr size)1050eae32dcSDimitry Andric void StackStore::Unmap(void *addr, uptr size) {
1060eae32dcSDimitry Andric atomic_fetch_sub(&allocated_, size, memory_order_relaxed);
1070eae32dcSDimitry Andric UnmapOrDie(addr, size);
1080eae32dcSDimitry Andric }
1090eae32dcSDimitry Andric
Pack(Compression type)1104824e7fdSDimitry Andric uptr StackStore::Pack(Compression type) {
1114824e7fdSDimitry Andric uptr res = 0;
1120eae32dcSDimitry Andric for (BlockInfo &b : blocks_) res += b.Pack(type, this);
1134824e7fdSDimitry Andric return res;
114349cc55cSDimitry Andric }
115349cc55cSDimitry Andric
LockAll()1160eae32dcSDimitry Andric void StackStore::LockAll() {
1170eae32dcSDimitry Andric for (BlockInfo &b : blocks_) b.Lock();
1180eae32dcSDimitry Andric }
1190eae32dcSDimitry Andric
UnlockAll()1200eae32dcSDimitry Andric void StackStore::UnlockAll() {
1210eae32dcSDimitry Andric for (BlockInfo &b : blocks_) b.Unlock();
1220eae32dcSDimitry Andric }
1230eae32dcSDimitry Andric
TestOnlyUnmap()124349cc55cSDimitry Andric void StackStore::TestOnlyUnmap() {
1250eae32dcSDimitry Andric for (BlockInfo &b : blocks_) b.TestOnlyUnmap(this);
126349cc55cSDimitry Andric internal_memset(this, 0, sizeof(*this));
127349cc55cSDimitry Andric }
128349cc55cSDimitry Andric
Get() const1294824e7fdSDimitry Andric uptr *StackStore::BlockInfo::Get() const {
1304824e7fdSDimitry Andric // Idiomatic double-checked locking uses memory_order_acquire here. But
1310eae32dcSDimitry Andric // relaxed is fine for us, justification is similar to
1324824e7fdSDimitry Andric // TwoLevelMap::GetOrCreate.
1334824e7fdSDimitry Andric return reinterpret_cast<uptr *>(atomic_load_relaxed(&data_));
1344824e7fdSDimitry Andric }
1354824e7fdSDimitry Andric
Create(StackStore * store)1360eae32dcSDimitry Andric uptr *StackStore::BlockInfo::Create(StackStore *store) {
1374824e7fdSDimitry Andric SpinMutexLock l(&mtx_);
1384824e7fdSDimitry Andric uptr *ptr = Get();
1394824e7fdSDimitry Andric if (!ptr) {
1400eae32dcSDimitry Andric ptr = reinterpret_cast<uptr *>(store->Map(kBlockSizeBytes, "StackStore"));
1414824e7fdSDimitry Andric atomic_store(&data_, reinterpret_cast<uptr>(ptr), memory_order_release);
1424824e7fdSDimitry Andric }
1434824e7fdSDimitry Andric return ptr;
1444824e7fdSDimitry Andric }
1454824e7fdSDimitry Andric
GetOrCreate(StackStore * store)1460eae32dcSDimitry Andric uptr *StackStore::BlockInfo::GetOrCreate(StackStore *store) {
1474824e7fdSDimitry Andric uptr *ptr = Get();
1484824e7fdSDimitry Andric if (LIKELY(ptr))
1494824e7fdSDimitry Andric return ptr;
1500eae32dcSDimitry Andric return Create(store);
1514824e7fdSDimitry Andric }
1524824e7fdSDimitry Andric
1530eae32dcSDimitry Andric class SLeb128Encoder {
1540eae32dcSDimitry Andric public:
SLeb128Encoder(u8 * begin,u8 * end)1550eae32dcSDimitry Andric SLeb128Encoder(u8 *begin, u8 *end) : begin(begin), end(end) {}
1560eae32dcSDimitry Andric
operator ==(const SLeb128Encoder & other) const1570eae32dcSDimitry Andric bool operator==(const SLeb128Encoder &other) const {
1580eae32dcSDimitry Andric return begin == other.begin;
1590eae32dcSDimitry Andric }
1600eae32dcSDimitry Andric
operator !=(const SLeb128Encoder & other) const1610eae32dcSDimitry Andric bool operator!=(const SLeb128Encoder &other) const {
1620eae32dcSDimitry Andric return begin != other.begin;
1630eae32dcSDimitry Andric }
1640eae32dcSDimitry Andric
operator =(uptr v)1650eae32dcSDimitry Andric SLeb128Encoder &operator=(uptr v) {
1660eae32dcSDimitry Andric sptr diff = v - previous;
1670eae32dcSDimitry Andric begin = EncodeSLEB128(diff, begin, end);
1680eae32dcSDimitry Andric previous = v;
1690eae32dcSDimitry Andric return *this;
1700eae32dcSDimitry Andric }
operator *()1710eae32dcSDimitry Andric SLeb128Encoder &operator*() { return *this; }
operator ++()1720eae32dcSDimitry Andric SLeb128Encoder &operator++() { return *this; }
1730eae32dcSDimitry Andric
base() const1740eae32dcSDimitry Andric u8 *base() const { return begin; }
1750eae32dcSDimitry Andric
1760eae32dcSDimitry Andric private:
1770eae32dcSDimitry Andric u8 *begin;
1780eae32dcSDimitry Andric u8 *end;
1790eae32dcSDimitry Andric uptr previous = 0;
1800eae32dcSDimitry Andric };
1810eae32dcSDimitry Andric
1820eae32dcSDimitry Andric class SLeb128Decoder {
1830eae32dcSDimitry Andric public:
SLeb128Decoder(const u8 * begin,const u8 * end)1840eae32dcSDimitry Andric SLeb128Decoder(const u8 *begin, const u8 *end) : begin(begin), end(end) {}
1850eae32dcSDimitry Andric
operator ==(const SLeb128Decoder & other) const1860eae32dcSDimitry Andric bool operator==(const SLeb128Decoder &other) const {
1870eae32dcSDimitry Andric return begin == other.begin;
1880eae32dcSDimitry Andric }
1890eae32dcSDimitry Andric
operator !=(const SLeb128Decoder & other) const1900eae32dcSDimitry Andric bool operator!=(const SLeb128Decoder &other) const {
1910eae32dcSDimitry Andric return begin != other.begin;
1920eae32dcSDimitry Andric }
1930eae32dcSDimitry Andric
operator *()1940eae32dcSDimitry Andric uptr operator*() {
1950eae32dcSDimitry Andric sptr diff;
1960eae32dcSDimitry Andric begin = DecodeSLEB128(begin, end, &diff);
1970eae32dcSDimitry Andric previous += diff;
1980eae32dcSDimitry Andric return previous;
1990eae32dcSDimitry Andric }
operator ++()2000eae32dcSDimitry Andric SLeb128Decoder &operator++() { return *this; }
2010eae32dcSDimitry Andric
operator ++(int)2020eae32dcSDimitry Andric SLeb128Decoder operator++(int) { return *this; }
2030eae32dcSDimitry Andric
2040eae32dcSDimitry Andric private:
2050eae32dcSDimitry Andric const u8 *begin;
2060eae32dcSDimitry Andric const u8 *end;
2070eae32dcSDimitry Andric uptr previous = 0;
2080eae32dcSDimitry Andric };
2090eae32dcSDimitry Andric
CompressDelta(const uptr * from,const uptr * from_end,u8 * to,u8 * to_end)2100eae32dcSDimitry Andric static u8 *CompressDelta(const uptr *from, const uptr *from_end, u8 *to,
2110eae32dcSDimitry Andric u8 *to_end) {
2120eae32dcSDimitry Andric SLeb128Encoder encoder(to, to_end);
2130eae32dcSDimitry Andric for (; from != from_end; ++from, ++encoder) *encoder = *from;
2140eae32dcSDimitry Andric return encoder.base();
2150eae32dcSDimitry Andric }
2160eae32dcSDimitry Andric
UncompressDelta(const u8 * from,const u8 * from_end,uptr * to,uptr * to_end)2170eae32dcSDimitry Andric static uptr *UncompressDelta(const u8 *from, const u8 *from_end, uptr *to,
2180eae32dcSDimitry Andric uptr *to_end) {
2190eae32dcSDimitry Andric SLeb128Decoder decoder(from, from_end);
2200eae32dcSDimitry Andric SLeb128Decoder end(from_end, from_end);
2210eae32dcSDimitry Andric for (; decoder != end; ++to, ++decoder) *to = *decoder;
2220eae32dcSDimitry Andric CHECK_EQ(to, to_end);
2230eae32dcSDimitry Andric return to;
2240eae32dcSDimitry Andric }
2250eae32dcSDimitry Andric
CompressLzw(const uptr * from,const uptr * from_end,u8 * to,u8 * to_end)2260eae32dcSDimitry Andric static u8 *CompressLzw(const uptr *from, const uptr *from_end, u8 *to,
2270eae32dcSDimitry Andric u8 *to_end) {
2280eae32dcSDimitry Andric SLeb128Encoder encoder(to, to_end);
2290eae32dcSDimitry Andric encoder = LzwEncode<uptr>(from, from_end, encoder);
2300eae32dcSDimitry Andric return encoder.base();
2310eae32dcSDimitry Andric }
2320eae32dcSDimitry Andric
UncompressLzw(const u8 * from,const u8 * from_end,uptr * to,uptr * to_end)2330eae32dcSDimitry Andric static uptr *UncompressLzw(const u8 *from, const u8 *from_end, uptr *to,
2340eae32dcSDimitry Andric uptr *to_end) {
2350eae32dcSDimitry Andric SLeb128Decoder decoder(from, from_end);
2360eae32dcSDimitry Andric SLeb128Decoder end(from_end, from_end);
2370eae32dcSDimitry Andric to = LzwDecode<uptr>(decoder, end, to);
2380eae32dcSDimitry Andric CHECK_EQ(to, to_end);
2390eae32dcSDimitry Andric return to;
2400eae32dcSDimitry Andric }
2410eae32dcSDimitry Andric
24204eeddc0SDimitry Andric #if defined(_MSC_VER) && !defined(__clang__)
24304eeddc0SDimitry Andric # pragma warning(push)
24404eeddc0SDimitry Andric // Disable 'nonstandard extension used: zero-sized array in struct/union'.
24504eeddc0SDimitry Andric # pragma warning(disable : 4200)
24604eeddc0SDimitry Andric #endif
2470eae32dcSDimitry Andric namespace {
2480eae32dcSDimitry Andric struct PackedHeader {
2490eae32dcSDimitry Andric uptr size;
2500eae32dcSDimitry Andric StackStore::Compression type;
2510eae32dcSDimitry Andric u8 data[];
2520eae32dcSDimitry Andric };
2530eae32dcSDimitry Andric } // namespace
25404eeddc0SDimitry Andric #if defined(_MSC_VER) && !defined(__clang__)
25504eeddc0SDimitry Andric # pragma warning(pop)
25604eeddc0SDimitry Andric #endif
2570eae32dcSDimitry Andric
GetOrUnpack(StackStore * store)2580eae32dcSDimitry Andric uptr *StackStore::BlockInfo::GetOrUnpack(StackStore *store) {
2594824e7fdSDimitry Andric SpinMutexLock l(&mtx_);
2604824e7fdSDimitry Andric switch (state) {
2614824e7fdSDimitry Andric case State::Storing:
2624824e7fdSDimitry Andric state = State::Unpacked;
2634824e7fdSDimitry Andric FALLTHROUGH;
2644824e7fdSDimitry Andric case State::Unpacked:
2654824e7fdSDimitry Andric return Get();
2664824e7fdSDimitry Andric case State::Packed:
2674824e7fdSDimitry Andric break;
2684824e7fdSDimitry Andric }
2694824e7fdSDimitry Andric
2700eae32dcSDimitry Andric u8 *ptr = reinterpret_cast<u8 *>(Get());
2714824e7fdSDimitry Andric CHECK_NE(nullptr, ptr);
2720eae32dcSDimitry Andric const PackedHeader *header = reinterpret_cast<const PackedHeader *>(ptr);
2730eae32dcSDimitry Andric CHECK_LE(header->size, kBlockSizeBytes);
2740eae32dcSDimitry Andric CHECK_GE(header->size, sizeof(PackedHeader));
2750eae32dcSDimitry Andric
2760eae32dcSDimitry Andric uptr packed_size_aligned = RoundUpTo(header->size, GetPageSizeCached());
2770eae32dcSDimitry Andric
2780eae32dcSDimitry Andric uptr *unpacked =
2790eae32dcSDimitry Andric reinterpret_cast<uptr *>(store->Map(kBlockSizeBytes, "StackStoreUnpack"));
2800eae32dcSDimitry Andric
2810eae32dcSDimitry Andric uptr *unpacked_end;
2820eae32dcSDimitry Andric switch (header->type) {
2830eae32dcSDimitry Andric case Compression::Delta:
2840eae32dcSDimitry Andric unpacked_end = UncompressDelta(header->data, ptr + header->size, unpacked,
2850eae32dcSDimitry Andric unpacked + kBlockSizeFrames);
2860eae32dcSDimitry Andric break;
2870eae32dcSDimitry Andric case Compression::LZW:
2880eae32dcSDimitry Andric unpacked_end = UncompressLzw(header->data, ptr + header->size, unpacked,
2890eae32dcSDimitry Andric unpacked + kBlockSizeFrames);
2900eae32dcSDimitry Andric break;
2910eae32dcSDimitry Andric default:
2920eae32dcSDimitry Andric UNREACHABLE("Unexpected type");
2930eae32dcSDimitry Andric break;
2940eae32dcSDimitry Andric }
2950eae32dcSDimitry Andric
2960eae32dcSDimitry Andric CHECK_EQ(kBlockSizeFrames, unpacked_end - unpacked);
2970eae32dcSDimitry Andric
2980eae32dcSDimitry Andric MprotectReadOnly(reinterpret_cast<uptr>(unpacked), kBlockSizeBytes);
2990eae32dcSDimitry Andric atomic_store(&data_, reinterpret_cast<uptr>(unpacked), memory_order_release);
3000eae32dcSDimitry Andric store->Unmap(ptr, packed_size_aligned);
3010eae32dcSDimitry Andric
3024824e7fdSDimitry Andric state = State::Unpacked;
3034824e7fdSDimitry Andric return Get();
3044824e7fdSDimitry Andric }
3054824e7fdSDimitry Andric
Pack(Compression type,StackStore * store)3060eae32dcSDimitry Andric uptr StackStore::BlockInfo::Pack(Compression type, StackStore *store) {
3074824e7fdSDimitry Andric if (type == Compression::None)
3084824e7fdSDimitry Andric return 0;
3094824e7fdSDimitry Andric
3104824e7fdSDimitry Andric SpinMutexLock l(&mtx_);
3114824e7fdSDimitry Andric switch (state) {
3124824e7fdSDimitry Andric case State::Unpacked:
3134824e7fdSDimitry Andric case State::Packed:
3144824e7fdSDimitry Andric return 0;
3154824e7fdSDimitry Andric case State::Storing:
3164824e7fdSDimitry Andric break;
3174824e7fdSDimitry Andric }
3184824e7fdSDimitry Andric
3194824e7fdSDimitry Andric uptr *ptr = Get();
3204824e7fdSDimitry Andric if (!ptr || !Stored(0))
3214824e7fdSDimitry Andric return 0;
3224824e7fdSDimitry Andric
3230eae32dcSDimitry Andric u8 *packed =
3240eae32dcSDimitry Andric reinterpret_cast<u8 *>(store->Map(kBlockSizeBytes, "StackStorePack"));
3250eae32dcSDimitry Andric PackedHeader *header = reinterpret_cast<PackedHeader *>(packed);
3260eae32dcSDimitry Andric u8 *alloc_end = packed + kBlockSizeBytes;
3270eae32dcSDimitry Andric
3280eae32dcSDimitry Andric u8 *packed_end = nullptr;
3290eae32dcSDimitry Andric switch (type) {
3300eae32dcSDimitry Andric case Compression::Delta:
3310eae32dcSDimitry Andric packed_end =
3320eae32dcSDimitry Andric CompressDelta(ptr, ptr + kBlockSizeFrames, header->data, alloc_end);
3330eae32dcSDimitry Andric break;
3340eae32dcSDimitry Andric case Compression::LZW:
3350eae32dcSDimitry Andric packed_end =
3360eae32dcSDimitry Andric CompressLzw(ptr, ptr + kBlockSizeFrames, header->data, alloc_end);
3370eae32dcSDimitry Andric break;
3380eae32dcSDimitry Andric default:
3390eae32dcSDimitry Andric UNREACHABLE("Unexpected type");
3400eae32dcSDimitry Andric break;
3410eae32dcSDimitry Andric }
3420eae32dcSDimitry Andric
3430eae32dcSDimitry Andric header->type = type;
3440eae32dcSDimitry Andric header->size = packed_end - packed;
3450eae32dcSDimitry Andric
3460eae32dcSDimitry Andric VPrintf(1, "Packed block of %zu KiB to %zu KiB\n", kBlockSizeBytes >> 10,
3470eae32dcSDimitry Andric header->size >> 10);
3480eae32dcSDimitry Andric
3490eae32dcSDimitry Andric if (kBlockSizeBytes - header->size < kBlockSizeBytes / 8) {
3500eae32dcSDimitry Andric VPrintf(1, "Undo and keep block unpacked\n");
3510eae32dcSDimitry Andric MprotectReadOnly(reinterpret_cast<uptr>(ptr), kBlockSizeBytes);
3520eae32dcSDimitry Andric store->Unmap(packed, kBlockSizeBytes);
3530eae32dcSDimitry Andric state = State::Unpacked;
3540eae32dcSDimitry Andric return 0;
3550eae32dcSDimitry Andric }
3560eae32dcSDimitry Andric
3570eae32dcSDimitry Andric uptr packed_size_aligned = RoundUpTo(header->size, GetPageSizeCached());
3580eae32dcSDimitry Andric store->Unmap(packed + packed_size_aligned,
3590eae32dcSDimitry Andric kBlockSizeBytes - packed_size_aligned);
3600eae32dcSDimitry Andric MprotectReadOnly(reinterpret_cast<uptr>(packed), packed_size_aligned);
3610eae32dcSDimitry Andric
3620eae32dcSDimitry Andric atomic_store(&data_, reinterpret_cast<uptr>(packed), memory_order_release);
3630eae32dcSDimitry Andric store->Unmap(ptr, kBlockSizeBytes);
3640eae32dcSDimitry Andric
3654824e7fdSDimitry Andric state = State::Packed;
3660eae32dcSDimitry Andric return kBlockSizeBytes - packed_size_aligned;
3674824e7fdSDimitry Andric }
3684824e7fdSDimitry Andric
TestOnlyUnmap(StackStore * store)3690eae32dcSDimitry Andric void StackStore::BlockInfo::TestOnlyUnmap(StackStore *store) {
3704824e7fdSDimitry Andric if (uptr *ptr = Get())
3710eae32dcSDimitry Andric store->Unmap(ptr, kBlockSizeBytes);
3724824e7fdSDimitry Andric }
3734824e7fdSDimitry Andric
Stored(uptr n)3744824e7fdSDimitry Andric bool StackStore::BlockInfo::Stored(uptr n) {
3754824e7fdSDimitry Andric return n + atomic_fetch_add(&stored_, n, memory_order_release) ==
3764824e7fdSDimitry Andric kBlockSizeFrames;
3774824e7fdSDimitry Andric }
3784824e7fdSDimitry Andric
IsPacked() const3794824e7fdSDimitry Andric bool StackStore::BlockInfo::IsPacked() const {
3804824e7fdSDimitry Andric SpinMutexLock l(&mtx_);
3814824e7fdSDimitry Andric return state == State::Packed;
3824824e7fdSDimitry Andric }
3834824e7fdSDimitry Andric
384349cc55cSDimitry Andric } // namespace __sanitizer
385