Coverage Report

Created: 2026-05-12 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/base/internal/low_level_alloc.cc
Line
Count
Source
1
// Copyright 2017 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
// A low-level allocator that can be used by other low-level
16
// modules without introducing dependency cycles.
17
// This allocator is slow and wasteful of memory;
18
// it should not be used when performance is key.
19
20
#include "absl/base/internal/low_level_alloc.h"
21
22
#include <stdint.h>
23
24
#include <optional>
25
#include <type_traits>
26
27
#include "absl/base/call_once.h"
28
#include "absl/base/config.h"
29
#include "absl/base/internal/direct_mmap.h"
30
#include "absl/base/internal/scheduling_mode.h"
31
#include "absl/base/macros.h"
32
#include "absl/base/thread_annotations.h"
33
34
// LowLevelAlloc requires that the platform support low-level
35
// allocation of virtual memory. Platforms lacking this cannot use
36
// LowLevelAlloc.
37
#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
38
39
#ifndef _WIN32
40
#include <pthread.h>
41
#include <signal.h>
42
#include <sys/mman.h>
43
#include <unistd.h>
44
#else
45
#include <windows.h>
46
#endif
47
48
#ifdef __linux__
49
#include <sys/prctl.h>
50
#ifndef PR_SET_VMA
51
21
#define PR_SET_VMA 0x53564d41
52
#endif
53
#ifndef PR_SET_VMA_ANON_NAME
54
21
#define PR_SET_VMA_ANON_NAME 0
55
#endif
56
#endif
57
58
#include <string.h>
59
60
#include <algorithm>
61
#include <atomic>
62
#include <cerrno>
63
#include <cstddef>
64
#include <new>  // for placement-new
65
66
#include "absl/base/dynamic_annotations.h"
67
#include "absl/base/internal/raw_logging.h"
68
#include "absl/base/internal/spinlock.h"
69
70
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
71
#define MAP_ANONYMOUS MAP_ANON
72
#endif
73
74
namespace absl {
75
ABSL_NAMESPACE_BEGIN
76
namespace base_internal {
77
78
// A first-fit allocator with amortized logarithmic free() time.
79
80
// ---------------------------------------------------------------------------
81
static const int kMaxLevel = 30;
82
83
namespace {
84
// This struct describes one allocated block, or one free block.
85
struct AllocList {
86
  struct Header {
87
    // Size of entire region, including this field. Must be
88
    // first. Valid in both allocated and unallocated blocks.
89
    uintptr_t size;
90
91
    // kMagicAllocated or kMagicUnallocated xor this.
92
    uintptr_t magic;
93
94
    // Pointer to parent arena.
95
    LowLevelAlloc::Arena *arena;
96
97
    // Aligns regions to 0 mod 2*sizeof(void*).
98
    void *dummy_for_alignment;
99
  } header;
100
101
  // Next two fields: in unallocated blocks: freelist skiplist data
102
  //                  in allocated blocks: overlaps with client data
103
104
  // Levels in skiplist used.
105
  int levels;
106
107
  // Actually has levels elements. The AllocList node may not have room
108
  // for all kMaxLevel entries. See max_fit in LLA_SkiplistLevels().
109
  AllocList *next[kMaxLevel];
110
};
111
}  // namespace
112
113
// ---------------------------------------------------------------------------
114
// A trivial skiplist implementation.  This is used to keep the freelist
115
// in address order while taking only logarithmic time per insert and delete.
116
117
// An integer approximation of log2(size/base)
118
// Requires size >= base.
119
4.56k
static int IntLog2(size_t size, size_t base) {
120
4.56k
  int result = 0;
121
31.7k
  for (size_t i = size; i > base; i >>= 1) {  // i == floor(size/2**result)
122
27.1k
    result++;
123
27.1k
  }
124
  //    floor(size / 2**result) <= base < floor(size / 2**(result-1))
125
  // =>     log2(size/(base+1)) <= result < 1+log2(size/base)
126
  // => result ~= log2(size/base)
127
4.56k
  return result;
128
4.56k
}
129
130
// Return a random integer n:  p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
131
2.27k
static int Random(uint32_t *state) {
132
2.27k
  uint32_t r = *state;
133
2.27k
  int result = 1;
134
4.54k
  while ((((r = r * 1103515245 + 12345) >> 30) & 1) == 0) {
135
2.27k
    result++;
136
2.27k
  }
137
2.27k
  *state = r;
138
2.27k
  return result;
139
2.27k
}
140
141
// Return a number of skiplist levels for a node of size bytes, where
142
// base is the minimum node size.  Compute level=log2(size / base)+n
143
// where n is 1 if random is false and otherwise a random number generated with
144
// the standard distribution for a skiplist:  See Random() above.
145
// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
146
// term, so first-fit searches touch fewer nodes.  "level" is clipped so
147
// level<kMaxLevel and next[level-1] will fit in the node.
148
// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel
149
4.56k
static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) {
150
  // max_fit is the maximum number of levels that will fit in a node for the
151
  // given size.   We can't return more than max_fit, no matter what the
152
  // random number generator says.
153
4.56k
  size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *);
154
4.56k
  int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1);
155
4.56k
  if (static_cast<size_t>(level) > max_fit) level = static_cast<int>(max_fit);
156
4.56k
  if (level > kMaxLevel - 1) level = kMaxLevel - 1;
157
4.56k
  ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level");
158
4.56k
  return level;
159
4.56k
}
160
161
// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
162
// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
163
// points to the last element at level i in the AllocList less than *e, or is
164
// head if no such element exists.
165
static AllocList *LLA_SkiplistSearch(AllocList *head, AllocList *e,
166
4.53k
                                     AllocList **prev) {
167
4.53k
  AllocList *p = head;
168
44.8k
  for (int level = head->levels - 1; level >= 0; level--) {
169
46.6k
    for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) {
170
6.37k
    }
171
40.3k
    prev[level] = p;
172
40.3k
  }
173
4.53k
  return (head->levels == 0) ? nullptr : prev[0]->next[0];
174
4.53k
}
175
176
// Insert element *e into AllocList *head.  Set prev[] as LLA_SkiplistSearch.
177
// Requires that e->levels be previously set by the caller (using
178
// LLA_SkiplistLevels())
179
static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
180
2.27k
                               AllocList **prev) {
181
2.27k
  LLA_SkiplistSearch(head, e, prev);
182
12.7k
  for (; head->levels < e->levels; head->levels++) {  // extend prev pointers
183
10.4k
    prev[head->levels] = head;                        // to all *e's levels
184
10.4k
  }
185
27.0k
  for (int i = 0; i != e->levels; i++) {  // add element to list
186
24.8k
    e->next[i] = prev[i]->next[i];
187
24.8k
    prev[i]->next[i] = e;
188
24.8k
  }
189
2.27k
}
190
191
// Remove element *e from AllocList *head.  Set prev[] as LLA_SkiplistSearch().
192
// Requires that e->levels be previous set by the caller (using
193
// LLA_SkiplistLevels())
194
static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
195
2.26k
                               AllocList **prev) {
196
2.26k
  AllocList *found = LLA_SkiplistSearch(head, e, prev);
197
2.26k
  ABSL_RAW_CHECK(e == found, "element not in freelist");
198
27.0k
  for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
199
24.7k
    prev[i]->next[i] = e->next[i];
200
24.7k
  }
201
12.7k
  while (head->levels > 0 && head->next[head->levels - 1] == nullptr) {
202
10.4k
    head->levels--;  // reduce head->levels if level unused
203
10.4k
  }
204
2.26k
}
205
206
// ---------------------------------------------------------------------------
207
// Arena implementation
208
209
// Metadata for an LowLevelAlloc arena instance.
210
struct LowLevelAlloc::Arena {
211
  // Constructs an arena with the given LowLevelAlloc flags.
212
  explicit Arena(uint32_t flags_value);
213
214
  base_internal::SpinLock mu;
215
  // Head of free list, sorted by address
216
  AllocList freelist ABSL_GUARDED_BY(mu);
217
  // Count of allocated blocks
218
  int32_t allocation_count ABSL_GUARDED_BY(mu);
219
  // flags passed to NewArena
220
  const uint32_t flags;
221
  // Result of sysconf(_SC_PAGESIZE)
222
  const size_t pagesize;
223
  // Lowest power of two >= max(16, sizeof(AllocList))
224
  const size_t round_up;
225
  // Smallest allocation block size
226
  const size_t min_size;
227
  // PRNG state
228
  uint32_t random ABSL_GUARDED_BY(mu);
229
};
230
231
// ---------------------------------------------------------------
232
// An async-signal-safe arena for LowLevelAlloc
233
static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
234
235
0
base_internal::LowLevelAlloc::Arena *SigSafeArena() {
236
0
  return g_sig_safe_arena.load(std::memory_order_acquire);
237
0
}
238
239
0
void InitSigSafeArena() {
240
0
  if (SigSafeArena() == nullptr) {
241
0
    uint32_t flags = 0;
242
0
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
243
0
    flags |= base_internal::LowLevelAlloc::kAsyncSignalSafe;
244
0
#endif
245
0
    base_internal::LowLevelAlloc::Arena *new_arena =
246
0
        base_internal::LowLevelAlloc::NewArena(flags);
247
0
    base_internal::LowLevelAlloc::Arena *old_value = nullptr;
248
0
    if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
249
0
                                                  std::memory_order_release,
250
0
                                                  std::memory_order_relaxed)) {
251
      // We lost a race to allocate an arena; deallocate.
252
0
      base_internal::LowLevelAlloc::DeleteArena(new_arena);
253
0
    }
254
0
  }
255
0
}
256
257
namespace {
258
// Static storage space for the lazily-constructed, default global arena
259
// instances.  We require this space because the whole point of LowLevelAlloc
260
// is to avoid relying on malloc/new.
261
alignas(LowLevelAlloc::Arena) unsigned char default_arena_storage[sizeof(
262
    LowLevelAlloc::Arena)];
263
alignas(LowLevelAlloc::Arena) unsigned char unhooked_arena_storage[sizeof(
264
    LowLevelAlloc::Arena)];
265
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
266
alignas(
267
    LowLevelAlloc::Arena) unsigned char unhooked_async_sig_safe_arena_storage
268
    [sizeof(LowLevelAlloc::Arena)];
269
#endif
270
271
// We must use LowLevelCallOnce here to construct the global arenas, rather than
272
// using function-level statics, to avoid recursively invoking the scheduler.
273
absl::once_flag create_globals_once;
274
275
1
void CreateGlobalArenas() {
276
1
  new (&default_arena_storage)
277
1
      LowLevelAlloc::Arena(LowLevelAlloc::kCallMallocHook);
278
1
  new (&unhooked_arena_storage) LowLevelAlloc::Arena(0);
279
1
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
280
1
  new (&unhooked_async_sig_safe_arena_storage)
281
1
      LowLevelAlloc::Arena(LowLevelAlloc::kAsyncSignalSafe);
282
1
#endif
283
1
}
284
285
// Returns a global arena that does not call into hooks.  Used by NewArena()
286
// when kCallMallocHook is not set.
287
1
LowLevelAlloc::Arena *UnhookedArena() {
288
1
  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
289
1
  return reinterpret_cast<LowLevelAlloc::Arena *>(&unhooked_arena_storage);
290
1
}
291
292
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
293
// Returns a global arena that is async-signal safe.  Used by NewArena() when
294
// kAsyncSignalSafe is set.
295
0
LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() {
296
0
  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
297
0
  return reinterpret_cast<LowLevelAlloc::Arena *>(
298
0
      &unhooked_async_sig_safe_arena_storage);
299
0
}
300
#endif
301
302
}  // namespace
303
304
// Returns the default arena, as used by LowLevelAlloc::Alloc() and friends.
305
4
LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
306
4
  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
307
4
  return reinterpret_cast<LowLevelAlloc::Arena *>(&default_arena_storage);
308
4
}
309
310
// magic numbers to identify allocated and unallocated blocks
311
static const uintptr_t kMagicAllocated = 0x4c833e95U;
312
static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
313
314
namespace {
315
class ABSL_SCOPED_LOCKABLE ArenaLock {
316
 public:
317
  explicit ArenaLock(LowLevelAlloc::Arena *arena)
318
      ABSL_EXCLUSIVE_LOCK_FUNCTION(arena->mu)
319
2.27k
      : arena_(arena) {
320
2.27k
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
321
2.27k
    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
322
0
      sigset_t all;
323
0
      sigfillset(&all);
324
0
      mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0;
325
0
    }
326
2.27k
#endif
327
2.27k
    arena_->mu.lock();
328
2.27k
  }
329
2.27k
  ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
330
2.27k
  void Leave() ABSL_UNLOCK_FUNCTION() {
331
2.27k
    arena_->mu.unlock();
332
2.27k
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
333
2.27k
    if (mask_valid_) {
334
0
      const int err = pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
335
0
      if (err != 0) {
336
0
        ABSL_RAW_LOG(FATAL, "pthread_sigmask failed: %d", err);
337
0
      }
338
0
    }
339
2.27k
#endif
340
2.27k
    left_ = true;
341
2.27k
  }
342
343
 private:
344
  bool left_ = false;  // whether left region
345
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
346
  bool mask_valid_ = false;
347
  sigset_t mask_;  // old mask of blocked signals
348
#endif
349
  LowLevelAlloc::Arena *arena_;
350
  ArenaLock(const ArenaLock &) = delete;
351
  ArenaLock &operator=(const ArenaLock &) = delete;
352
};
353
}  // namespace
354
355
// create an appropriate magic number for an object at "ptr"
356
// "magic" should be kMagicAllocated or kMagicUnallocated
357
13.1k
inline static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr) {
358
13.1k
  return magic ^ reinterpret_cast<uintptr_t>(ptr);
359
13.1k
}
360
361
namespace {
362
4
size_t GetPageSize() {
363
#ifdef _WIN32
364
  SYSTEM_INFO system_info;
365
  GetSystemInfo(&system_info);
366
  return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
367
#elif defined(__wasm__) || defined(__asmjs__) || defined(__hexagon__)
368
  return static_cast<size_t>(getpagesize());
369
#else
370
4
  return static_cast<size_t>(sysconf(_SC_PAGESIZE));
371
4
#endif
372
4
}
373
374
4
size_t RoundedUpBlockSize() {
375
  // Round up block sizes to a power of two close to the header size.
376
4
  size_t round_up = 16;
377
8
  while (round_up < sizeof(AllocList::Header)) {
378
4
    round_up += round_up;
379
4
  }
380
4
  return round_up;
381
4
}
382
383
}  // namespace
384
385
LowLevelAlloc::Arena::Arena(uint32_t flags_value)
386
4
    : mu(base_internal::SCHEDULE_KERNEL_ONLY),
387
4
      allocation_count(0),
388
4
      flags(flags_value),
389
4
      pagesize(GetPageSize()),
390
4
      round_up(RoundedUpBlockSize()),
391
4
      min_size(2 * round_up),
392
4
      random(0) {
393
4
  freelist.header.size = 0;
394
4
  freelist.header.magic = Magic(kMagicUnallocated, &freelist.header);
395
4
  freelist.header.arena = this;
396
4
  freelist.levels = 0;
397
4
  memset(freelist.next, 0, sizeof(freelist.next));
398
4
}
399
400
// L < meta_data_arena->mu
401
1
LowLevelAlloc::Arena *LowLevelAlloc::NewArena(uint32_t flags) {
402
1
  Arena *meta_data_arena = DefaultArena();
403
1
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
404
1
  if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
405
0
    meta_data_arena = UnhookedAsyncSigSafeArena();
406
0
  } else  // NOLINT(readability/braces)
407
1
#endif
408
1
      if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
409
1
    meta_data_arena = UnhookedArena();
410
1
  }
411
1
  Arena *result =
412
1
      new (AllocWithArena(sizeof(*result), meta_data_arena)) Arena(flags);
413
1
  return result;
414
1
}
415
416
// L < arena->mu, L < arena->arena->mu
417
0
bool LowLevelAlloc::DeleteArena(Arena *arena) {
418
0
  ABSL_RAW_CHECK(
419
0
      arena != nullptr && arena != DefaultArena() && arena != UnhookedArena(),
420
0
      "may not delete default arena");
421
0
  ArenaLock section(arena);
422
0
  if (arena->allocation_count != 0) {
423
0
    section.Leave();
424
0
    return false;
425
0
  }
426
0
  while (arena->freelist.next[0] != nullptr) {
427
0
    AllocList *region = arena->freelist.next[0];
428
0
    size_t size = region->header.size;
429
0
    arena->freelist.next[0] = region->next[0];
430
0
    ABSL_RAW_CHECK(
431
0
        region->header.magic == Magic(kMagicUnallocated, &region->header),
432
0
        "bad magic number in DeleteArena()");
433
0
    ABSL_RAW_CHECK(region->header.arena == arena,
434
0
                   "bad arena pointer in DeleteArena()");
435
0
    ABSL_RAW_CHECK(size % arena->pagesize == 0,
436
0
                   "empty arena has non-page-aligned block size");
437
0
    ABSL_RAW_CHECK(reinterpret_cast<uintptr_t>(region) % arena->pagesize == 0,
438
0
                   "empty arena has non-page-aligned block");
439
0
    int munmap_result;
440
#ifdef _WIN32
441
    munmap_result = VirtualFree(region, 0, MEM_RELEASE);
442
    ABSL_RAW_CHECK(munmap_result != 0,
443
                   "LowLevelAlloc::DeleteArena: VitualFree failed");
444
#else
445
0
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
446
0
    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
447
0
      munmap_result = munmap(region, size);
448
0
    } else {
449
0
      munmap_result = base_internal::DirectMunmap(region, size);
450
0
    }
451
#else
452
    munmap_result = munmap(region, size);
453
#endif  // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
454
0
    if (munmap_result != 0) {
455
0
      ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
456
0
                   errno);
457
0
    }
458
0
#endif  // _WIN32
459
0
  }
460
0
  section.Leave();
461
0
  arena->~Arena();
462
0
  Free(arena);
463
0
  return true;
464
0
}
465
466
// ---------------------------------------------------------------------------
467
468
// Addition, checking for overflow.  The intent is to die if an external client
469
// manages to push through a request that would cause arithmetic to fail.
470
6.81k
static inline uintptr_t CheckedAdd(uintptr_t a, uintptr_t b) {
471
6.81k
  uintptr_t sum = a + b;
472
6.81k
  ABSL_RAW_CHECK(sum >= a, "LowLevelAlloc arithmetic overflow");
473
6.81k
  return sum;
474
6.81k
}
475
476
// Return value rounded up to next multiple of align.
477
// align must be a power of two.
478
2.28k
static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) {
479
2.28k
  return CheckedAdd(addr, align - 1) & ~(align - 1);
480
2.28k
}
481
482
// Equivalent to "return prev->next[i]" but with sanity checking
483
// that the freelist is in the correct order, that it
484
// consists of regions marked "unallocated", and that no two regions
485
// are adjacent in memory (they should have been coalesced).
486
static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
487
4.04k
    ABSL_EXCLUSIVE_LOCKS_REQUIRED(arena->mu) {
488
4.04k
  ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
489
4.04k
  AllocList *next = prev->next[i];
490
4.04k
  if (next != nullptr) {
491
4.02k
    ABSL_RAW_CHECK(
492
4.02k
        next->header.magic == Magic(kMagicUnallocated, &next->header),
493
4.02k
        "bad magic number in Next()");
494
4.02k
    ABSL_RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()");
495
4.02k
    if (prev != &arena->freelist) {
496
1.74k
      ABSL_RAW_CHECK(prev < next, "unordered freelist");
497
1.74k
      ABSL_RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size <
498
1.74k
                         reinterpret_cast<char *>(next),
499
1.74k
                     "malformed freelist");
500
1.74k
    }
501
4.02k
  }
502
4.04k
  return next;
503
4.04k
}
504
505
// Coalesce list item "a" with its successor if they are adjacent.
506
4.55k
static void Coalesce(AllocList *a) {
507
4.55k
  AllocList *n = a->next[0];
508
4.55k
  if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size ==
509
4.29k
                          reinterpret_cast<char *>(n)) {
510
0
    LowLevelAlloc::Arena *arena = a->header.arena;
511
0
    arena->mu.AssertHeld();
512
0
    a->header.size += n->header.size;
513
0
    n->header.magic = 0;
514
0
    n->header.arena = nullptr;
515
0
    AllocList *prev[kMaxLevel];
516
0
    LLA_SkiplistDelete(&arena->freelist, n, prev);
517
0
    LLA_SkiplistDelete(&arena->freelist, a, prev);
518
0
    a->levels =
519
0
        LLA_SkiplistLevels(a->header.size, arena->min_size, &arena->random);
520
0
    LLA_SkiplistInsert(&arena->freelist, a, prev);
521
0
  }
522
4.55k
}
523
524
// Adds block at location "v" to the free list
525
static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena)
526
2.27k
    ABSL_EXCLUSIVE_LOCKS_REQUIRED(arena->mu) {
527
2.27k
  AllocList *f = reinterpret_cast<AllocList *>(reinterpret_cast<char *>(v) -
528
2.27k
                                               sizeof(f->header));
529
2.27k
  ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
530
2.27k
                 "bad magic number in AddToFreelist()");
531
2.27k
  ABSL_RAW_CHECK(f->header.arena == arena,
532
2.27k
                 "bad arena pointer in AddToFreelist()");
533
2.27k
  f->levels =
534
2.27k
      LLA_SkiplistLevels(f->header.size, arena->min_size, &arena->random);
535
2.27k
  AllocList *prev[kMaxLevel];
536
2.27k
  LLA_SkiplistInsert(&arena->freelist, f, prev);
537
2.27k
  f->header.magic = Magic(kMagicUnallocated, &f->header);
538
2.27k
  Coalesce(f);        // maybe coalesce with successor
539
2.27k
  Coalesce(prev[0]);  // maybe coalesce with predecessor
540
2.27k
}
541
542
// Frees storage allocated by LowLevelAlloc::Alloc().
543
// L < arena->mu
544
8
void LowLevelAlloc::Free(void *v) {
545
8
  if (v != nullptr) {
546
8
    AllocList *f = reinterpret_cast<AllocList *>(reinterpret_cast<char *>(v) -
547
8
                                                 sizeof(f->header));
548
8
    LowLevelAlloc::Arena *arena = f->header.arena;
549
8
    ArenaLock section(arena);
550
8
    AddToFreelist(v, arena);
551
8
    ABSL_RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
552
8
    arena->allocation_count--;
553
8
    section.Leave();
554
8
  }
555
8
}
556
557
// allocates and returns a block of size bytes, to be freed with Free()
558
// L < arena->mu
559
2.26k
static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
560
2.26k
  void *result = nullptr;
561
2.26k
  if (request != 0) {
562
2.26k
    AllocList *s;  // will point to region that satisfies request
563
2.26k
    ArenaLock section(arena);
564
    // round up with header
565
2.26k
    size_t req_rnd =
566
2.26k
        RoundUp(CheckedAdd(request, sizeof(s->header)), arena->round_up);
567
2.28k
    for (;;) {  // loop until we find a suitable region
568
      // find the minimum levels that a block of this size must have
569
2.28k
      int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1;
570
2.28k
      if (i < arena->freelist.levels) {        // potential blocks exist
571
2.28k
        AllocList *before = &arena->freelist;  // predecessor of s
572
4.04k
        while ((s = Next(i, before, arena)) != nullptr &&
573
4.02k
               s->header.size < req_rnd) {
574
1.76k
          before = s;
575
1.76k
        }
576
2.28k
        if (s != nullptr) {  // we found a region
577
2.26k
          break;
578
2.26k
        }
579
2.28k
      }
580
      // we unlock before mmap() both because mmap() may call a callback hook,
581
      // and because it may be slow.
582
21
      arena->mu.unlock();
583
      // mmap generous 64K chunks to decrease
584
      // the chances/impact of fragmentation:
585
21
      size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
586
21
      void *new_pages;
587
#ifdef _WIN32
588
      new_pages = VirtualAlloc(nullptr, new_pages_size,
589
                               MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
590
      ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed");
591
#else
592
21
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
593
21
      if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
594
0
        new_pages = base_internal::DirectMmap(nullptr, new_pages_size,
595
0
            PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
596
21
      } else {
597
21
        new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
598
21
                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
599
21
      }
600
#else
601
      new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
602
                       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
603
#endif  // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
604
21
      if (new_pages == MAP_FAILED) {
605
0
        ABSL_RAW_LOG(FATAL, "mmap error: %d", errno);
606
0
      }
607
608
21
#ifdef __linux__
609
21
#if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
610
      // Attempt to name the allocated address range in /proc/$PID/smaps on
611
      // Linux.
612
      //
613
      // This invocation of prctl() may fail if the Linux kernel was not
614
      // configured with the CONFIG_ANON_VMA_NAME option.  This is OK since
615
      // the naming of arenas is primarily a debugging aid.
616
21
      prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, new_pages, new_pages_size,
617
21
            "absl");
618
21
#endif
619
21
#endif  // __linux__
620
21
#endif  // _WIN32
621
21
      arena->mu.lock();
622
21
      s = reinterpret_cast<AllocList *>(new_pages);
623
21
      s->header.size = new_pages_size;
624
      // Pretend the block is allocated; call AddToFreelist() to free it.
625
21
      s->header.magic = Magic(kMagicAllocated, &s->header);
626
21
      s->header.arena = arena;
627
21
      AddToFreelist(&s->levels, arena);  // insert new region into free list
628
21
    }
629
2.26k
    AllocList *prev[kMaxLevel];
630
2.26k
    LLA_SkiplistDelete(&arena->freelist, s, prev);  // remove from free list
631
    // s points to the first free region that's big enough
632
2.26k
    if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) {
633
      // big enough to split
634
2.24k
      AllocList *n =
635
2.24k
          reinterpret_cast<AllocList *>(req_rnd + reinterpret_cast<char *>(s));
636
2.24k
      n->header.size = s->header.size - req_rnd;
637
2.24k
      n->header.magic = Magic(kMagicAllocated, &n->header);
638
2.24k
      n->header.arena = arena;
639
2.24k
      s->header.size = req_rnd;
640
2.24k
      AddToFreelist(&n->levels, arena);
641
2.24k
    }
642
2.26k
    s->header.magic = Magic(kMagicAllocated, &s->header);
643
2.26k
    ABSL_RAW_CHECK(s->header.arena == arena, "");
644
2.26k
    arena->allocation_count++;
645
2.26k
    section.Leave();
646
2.26k
    result = &s->levels;
647
2.26k
  }
648
2.26k
  ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
649
2.26k
  return result;
650
2.26k
}
651
652
3
void *LowLevelAlloc::Alloc(size_t request) {
653
3
  void *result = DoAllocWithArena(request, DefaultArena());
654
3
  return result;
655
3
}
656
657
2.26k
void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
658
2.26k
  ABSL_RAW_CHECK(arena != nullptr, "must pass a valid arena");
659
2.26k
  void *result = DoAllocWithArena(request, arena);
660
2.26k
  return result;
661
2.26k
}
662
663
}  // namespace base_internal
664
ABSL_NAMESPACE_END
665
}  // namespace absl
666
667
#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING