1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#pragma once
#include "../backend/backend.h"
#include "base_constants.h"
namespace snmalloc
{
/**
* Range that carefully ensures meta-data and object data cannot be in
* the same memory range. Once memory has is used for either meta-data
* or object data it can never be recycled to the other.
*
* This configuration also includes guard pages and randomisation.
*
* PAL is the underlying PAL that is used to Commit memory ranges.
*
* Base is where memory is sourced from.
*
* MinSizeBits is the minimum request size that can be passed to Base.
* On Windows this 16 as VirtualAlloc cannot reserve less than 64KiB.
* Alternative configurations might make this 2MiB so that huge pages
* can be used.
*/
template<
typename PAL,
typename Pagemap,
typename Base,
size_t MinSizeBits = MinBaseSizeBits<PAL>()>
struct MetaProtectedRangeLocalState : BaseLocalStateConstants
{
private:
// Global range of memory
using GlobalR = Pipe<
Base,
LargeBuddyRange<
GlobalCacheSizeBits,
bits::BITS - 1,
Pagemap,
MinSizeBits>,
LogRange<2>,
GlobalRange>;
static constexpr size_t page_size_bits =
bits::next_pow2_bits_const(PAL::page_size);
static constexpr size_t max_page_chunk_size_bits =
bits::max(page_size_bits, MIN_CHUNK_BITS);
// Central source of object-range, does not pass back to GlobalR as
// that would allow flows from Objects to Meta-data, and thus UAF
// would be able to corrupt meta-data.
using CentralObjectRange = Pipe<
GlobalR,
LargeBuddyRange<GlobalCacheSizeBits, bits::BITS - 1, Pagemap>,
LogRange<3>,
GlobalRange,
CommitRange<PAL>,
StatsRange>;
// Controls the padding around the meta-data range.
// The larger the padding range the more randomisation that
// can be used.
static constexpr size_t SubRangeRatioBits = 6;
// Centralised source of meta-range
using CentralMetaRange = Pipe<
GlobalR,
SubRange<PAL, SubRangeRatioBits>, // Use SubRange to introduce guard
// pages.
LargeBuddyRange<
GlobalCacheSizeBits,
bits::BITS - 1,
Pagemap,
page_size_bits>,
CommitRange<PAL>,
// In case of huge pages, we don't want to give each thread its own huge
// page, so commit in the global range.
stl::conditional_t<
(max_page_chunk_size_bits > MIN_CHUNK_BITS),
LargeBuddyRange<
max_page_chunk_size_bits,
max_page_chunk_size_bits,
Pagemap,
page_size_bits>,
NopRange>,
LogRange<4>,
GlobalRange,
StatsRange>;
// Local caching of object range
using ObjectRange = Pipe<
CentralObjectRange,
LargeBuddyRange<
LocalCacheSizeBits,
LocalCacheSizeBits,
Pagemap,
page_size_bits>,
LogRange<5>>;
// Local caching of meta-data range
using MetaRange = Pipe<
CentralMetaRange,
LargeBuddyRange<
LocalCacheSizeBits - SubRangeRatioBits,
bits::BITS - 1,
Pagemap>,
SmallBuddyRange>;
ObjectRange object_range;
MetaRange meta_range;
public:
using Stats = StatsCombiner<CentralObjectRange, CentralMetaRange>;
ObjectRange* get_object_range()
{
return &object_range;
}
MetaRange& get_meta_range()
{
return meta_range;
}
// Create global range that can service small meta-data requests.
// Don't want to add the SmallBuddyRange to the CentralMetaRange as that
// would require committing memory inside the main global lock.
using GlobalMetaRange =
Pipe<CentralMetaRange, SmallBuddyRange, GlobalRange>;
};
} // namespace snmalloc