xref: /xnu-8792.81.2/doc/allocators/api-basics.md (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions# XNU Allocators best practices
2*19c3b8c2SApple OSS Distributions
3*19c3b8c2SApple OSS Distributions## Introduction
4*19c3b8c2SApple OSS Distributions
5*19c3b8c2SApple OSS DistributionsXNU proposes two ways to allocate memory:
6*19c3b8c2SApple OSS Distributions
7*19c3b8c2SApple OSS Distributions- the VM subsystem that provides allocations at the granularity of pages (with
8*19c3b8c2SApple OSS Distributions  `kmem_alloc` and similar interfaces);
9*19c3b8c2SApple OSS Distributions- the zone allocator subsystem (`<kern/zalloc.h>`) which is a slab-allocator of
10*19c3b8c2SApple OSS Distributions  objects of fixed size.
11*19c3b8c2SApple OSS Distributions
12*19c3b8c2SApple OSS DistributionsIn addition to that, `<kern/kalloc.h>` provides a variable-size general purpose
13*19c3b8c2SApple OSS Distributionsallocator implemented as a collection of zones of fixed size, and overflowing to
14*19c3b8c2SApple OSS Distributions`kmem_alloc` for allocations larger than a few pages (32KB when this
15*19c3b8c2SApple OSS Distributionsdocument was being written but this is subject to change/tuning in the future).
16*19c3b8c2SApple OSS Distributions
17*19c3b8c2SApple OSS Distributions
18*19c3b8c2SApple OSS DistributionsThe Core Kernel allocators rely on the following headers:
19*19c3b8c2SApple OSS Distributions
20*19c3b8c2SApple OSS Distributions- `<kern/zalloc.h>` and `<kern/kalloc.h>` for its API surface, which most
21*19c3b8c2SApple OSS Distributions  clients should find sufficient,
22*19c3b8c2SApple OSS Distributions- `<kern/zalloc_internal.h>` for interfaces that need to be exported
23*19c3b8c2SApple OSS Distributions  for introspection and implementation purposes, and is not meant
24*19c3b8c2SApple OSS Distributions  for general consumption.
25*19c3b8c2SApple OSS Distributions
26*19c3b8c2SApple OSS DistributionsThis document will present the best practices to allocate memory
27*19c3b8c2SApple OSS Distributionsin the kernel, from a security perspective.
28*19c3b8c2SApple OSS Distributions
29*19c3b8c2SApple OSS Distributions## Permanent allocations
30*19c3b8c2SApple OSS Distributions
31*19c3b8c2SApple OSS DistributionsThe kernel sometimes needs to provide persistent allocations that depend on
32*19c3b8c2SApple OSS Distributionsparameters that aren't compile time constants, but will not vary over time (NCPU
33*19c3b8c2SApple OSS Distributionsis an obvious example here).
34*19c3b8c2SApple OSS Distributions
35*19c3b8c2SApple OSS DistributionsThe zone subsystem provides a `zalloc_permanent*` family of functions that help
36*19c3b8c2SApple OSS Distributionsallocating memory in such a fashion in a very compact way.
37*19c3b8c2SApple OSS Distributions
38*19c3b8c2SApple OSS DistributionsUnlike the typical zone allocators, this allows for arbitrary sizes, in a
39*19c3b8c2SApple OSS Distributionssimilar fashion to `kalloc`. These functions will never fail (if the allocation
40*19c3b8c2SApple OSS Distributionsfails, the kernel will panic), and always return zeroed memory. Trying to free
41*19c3b8c2SApple OSS Distributionsthese allocations results in a kernel panic.
42*19c3b8c2SApple OSS Distributions
43*19c3b8c2SApple OSS Distributions## Allocation flags
44*19c3b8c2SApple OSS Distributions
45*19c3b8c2SApple OSS DistributionsMost `zalloc` or `kalloc` functions take `zalloc_flags_t` typed flags.
46*19c3b8c2SApple OSS DistributionsWhen flags are expected, exactly one of `Z_WAITOK`, `Z_NOWAIT` or `Z_NOPAGEWAIT`
47*19c3b8c2SApple OSS Distributionsis to be passed:
48*19c3b8c2SApple OSS Distributions
49*19c3b8c2SApple OSS Distributions- `Z_WAITOK` means that the zone allocator can wait and block,
50*19c3b8c2SApple OSS Distributions- `Z_NOWAIT` can be used to require a fully non blocking behavior, which can be
51*19c3b8c2SApple OSS Distributions  used for allocations under spinlock and other preemption disabled contexts;
52*19c3b8c2SApple OSS Distributions- `Z_NOPAGEWAIT` allows for the allocator to block (typically on mutexes),
53*19c3b8c2SApple OSS Distributions  but not to wait for available pages if there are none, this is only useful
54*19c3b8c2SApple OSS Distributions  for the buffer cache, and most client should either use `Z_NOWAIT` or `Z_WAITOK`.
55*19c3b8c2SApple OSS Distributions
56*19c3b8c2SApple OSS DistributionsOther important flags:
57*19c3b8c2SApple OSS Distributions
58*19c3b8c2SApple OSS Distributions- `Z_ZERO` if zeroed memory is expected (nowadays most of the allocations will
59*19c3b8c2SApple OSS Distributions  be zeroed regardless, but it's always clearer to specify it), note that it is
60*19c3b8c2SApple OSS Distributions  often more efficient than calling bzero as the allocator tends to maintain
61*19c3b8c2SApple OSS Distributions  freed memory as zeroed in the first place,
62*19c3b8c2SApple OSS Distributions- `Z_NOFAIL` if the caller knows the allocation can't fail: allocations that are
63*19c3b8c2SApple OSS Distributions   made with `Z_WAITOK` from regular (non exhaustible) zones, or from `kalloc*`
64*19c3b8c2SApple OSS Distributions   interfaces with a size smaller than `KALLOC_SAFE_ALLOC_SIZE`,
65*19c3b8c2SApple OSS Distributions  will never fail (the kernel will instead panic if no memory can be found).
66*19c3b8c2SApple OSS Distributions  `Z_NOFAIL` can be used to denote that the caller knows about this.
67*19c3b8c2SApple OSS Distributions  If `Z_NOFAIL` is incorrectly used, then the zone allocator will panic at runtime.
68*19c3b8c2SApple OSS Distributions
69*19c3b8c2SApple OSS Distributions## Zones (`zalloc`)
70*19c3b8c2SApple OSS Distributions
71*19c3b8c2SApple OSS DistributionsThe first blessed way to allocate memory in the kernel is by using zones.
72*19c3b8c2SApple OSS DistributionsZones are mostly meant to be used in Core XNU and some "BSD" kexts.
73*19c3b8c2SApple OSS Distributions
74*19c3b8c2SApple OSS DistributionsIt is generally recommended to create zones early and to store the `zone_t`
75*19c3b8c2SApple OSS Distributionspointer in read-only memory (using `SECURITY_READ_ONLY_LATE` storage).
76*19c3b8c2SApple OSS Distributions
77*19c3b8c2SApple OSS DistributionsZones are more feature-rich than `kalloc`, and some features can only be
78*19c3b8c2SApple OSS Distributionsused when making a zone:
79*19c3b8c2SApple OSS Distributions
80*19c3b8c2SApple OSS Distributions- the object type being allocated requires extremely strong segregation
81*19c3b8c2SApple OSS Distributions  from other types (typically `zone_require` will be used with this zone),
82*19c3b8c2SApple OSS Distributions- the object type implements some form of security boundary and wants to adopt
83*19c3b8c2SApple OSS Distributions  the read-only allocator (See `ZC_READONLY`),
84*19c3b8c2SApple OSS Distributions- the allocation must be per-cpu,
85*19c3b8c2SApple OSS Distributions- ...
86*19c3b8c2SApple OSS Distributions
87*19c3b8c2SApple OSS DistributionsIn the vast majority of cases however, using `kalloc_type` (or `IOMallocType`)
88*19c3b8c2SApple OSS Distributionsis preferred.
89*19c3b8c2SApple OSS Distributions
90*19c3b8c2SApple OSS Distributions
91*19c3b8c2SApple OSS Distributions## The Typed allocator
92*19c3b8c2SApple OSS Distributions
93*19c3b8c2SApple OSS DistributionsIgnoring VM allocations (or wrappers like `IOMemoryDescriptor`), the only
94*19c3b8c2SApple OSS Distributionsblessed way to allocate typed memory in XNU is using the typed allocator
95*19c3b8c2SApple OSS Distributions`kalloc_type` or one of its variants (like IOKit's `IOMallocType`) and untyped
96*19c3b8c2SApple OSS Distributionsmemory that doesn't contain pointers is using the data API `kalloc_data` or
97*19c3b8c2SApple OSS Distributionsone of its variants (like IOKit's `IOMallocData`). However, this comes with
98*19c3b8c2SApple OSS Distributionsadditional requirements.
99*19c3b8c2SApple OSS Distributions
100*19c3b8c2SApple OSS DistributionsNote that at this time, those interfaces aren't exported to third parties,
101*19c3b8c2SApple OSS Distributionsas its ABI has not yet converged.
102*19c3b8c2SApple OSS Distributions
103*19c3b8c2SApple OSS Distributions### A word about types
104*19c3b8c2SApple OSS Distributions
105*19c3b8c2SApple OSS DistributionsThe typed allocators assume that allocated types fit a very precise model.
106*19c3b8c2SApple OSS DistributionsIf the allocations you perform do not fit the model, then your types
107*19c3b8c2SApple OSS Distributionsmust be restructured to fit, for security reasons.
108*19c3b8c2SApple OSS Distributions
109*19c3b8c2SApple OSS DistributionsA general theme will be the separation of data/primitive types from pointers,
110*19c3b8c2SApple OSS Distributionsas attackers tend to use data/pointer overlaps to carry out their exploitations.
111*19c3b8c2SApple OSS Distributions
112*19c3b8c2SApple OSS DistributionsThe typed allocators use compiler support to infer signatures
113*19c3b8c2SApple OSS Distributionsof the types being allocated. Because some scalars actually represent
114*19c3b8c2SApple OSS Distributionskernel pointers (like `vm_offset_t`,`vm_address_t`, `uintptr_t`, ...),
115*19c3b8c2SApple OSS Distributionstypes or structure members can be decorated with `__kernel_ptr_semantics`
116*19c3b8c2SApple OSS Distributionsto denote when a data-looking type is actually a pointer.
117*19c3b8c2SApple OSS Distributions
118*19c3b8c2SApple OSS DistributionsDo note that `__kernel_data_semantics` and `__kernel_dual_semantics`
119*19c3b8c2SApple OSS Distributionsare also provided but should typically rarely be used.
120*19c3b8c2SApple OSS Distributions
121*19c3b8c2SApple OSS Distributions#### fixed-sized types
122*19c3b8c2SApple OSS Distributions
123*19c3b8c2SApple OSS DistributionsThe first case is fixed size types, this is typically a `struct`, `union`
124*19c3b8c2SApple OSS Distributionsor C++ `class`. Fixed-size types must follow certain rules:
125*19c3b8c2SApple OSS Distributions
126*19c3b8c2SApple OSS Distributions- types should be small enough to fit in the zone allocator:
127*19c3b8c2SApple OSS Distributions  smaller than `KALLOC_SAFE_ALLOC_SIZE`. When this is not the case,
128*19c3b8c2SApple OSS Distributions  we have typically found that there is a large array of data,
129*19c3b8c2SApple OSS Distributions  or some buffer in that type, the solution is to outline this allocation.
130*19c3b8c2SApple OSS Distributions- for union types, data/pointer overlaps should be avoided if possible.
131*19c3b8c2SApple OSS Distributions  when this isn't possible, a zone should be considered.
132*19c3b8c2SApple OSS Distributions
133*19c3b8c2SApple OSS Distributions#### Variable-sized types
134*19c3b8c2SApple OSS Distributions
135*19c3b8c2SApple OSS DistributionsThese come in two variants: arrays, and arrays prefixed with a header.
136*19c3b8c2SApple OSS DistributionsAny other case must be reduced to those, by possibly making more allocations.
137*19c3b8c2SApple OSS Distributions
138*19c3b8c2SApple OSS DistributionsAn array is simply an allocation of several fixed-size types,
139*19c3b8c2SApple OSS Distributionsand the rules of "fixed-sized types" above apply to them.
140*19c3b8c2SApple OSS Distributions
141*19c3b8c2SApple OSS DistributionsThe following rules are expected when dealing with variable sized allocations:
142*19c3b8c2SApple OSS Distributions
143*19c3b8c2SApple OSS Distributions- variable sized allocations should have a single owner and not be refcounted;
144*19c3b8c2SApple OSS Distributions- under the header-prefixed form, if the header contains pointers,
145*19c3b8c2SApple OSS Distributions  then the array element type **must not** be only data.
146*19c3b8c2SApple OSS Distributions
147*19c3b8c2SApple OSS DistributionsIf those rules can't be followed, then the allocation must be split with
148*19c3b8c2SApple OSS Distributionsthe header becoming a fixed-sized type becoming the single owner
149*19c3b8c2SApple OSS Distributionsof an array.
150*19c3b8c2SApple OSS Distributions
151*19c3b8c2SApple OSS Distributions#### Untyped memory
152*19c3b8c2SApple OSS Distributions
153*19c3b8c2SApple OSS DistributionsWhen allocating untyped memory with the data APIs ensure that it doesn't
154*19c3b8c2SApple OSS Distributionscontain kernel pointers. If your untyped allocation contains kernel pointers
155*19c3b8c2SApple OSS Distributionsconsider splitting the allocation into two: one part that is typed and contains
156*19c3b8c2SApple OSS Distributionsthe kernel pointers and the second that is untyped and data-only.
157*19c3b8c2SApple OSS Distributions
158*19c3b8c2SApple OSS Distributions### API surface
159*19c3b8c2SApple OSS Distributions
160*19c3b8c2SApple OSS Distributions<table>
161*19c3b8c2SApple OSS Distributions  <tr>
162*19c3b8c2SApple OSS Distributions    <th>Interface</th>
163*19c3b8c2SApple OSS Distributions    <th>API</th>
164*19c3b8c2SApple OSS Distributions    <th>Notes</th>
165*19c3b8c2SApple OSS Distributions  </tr>
166*19c3b8c2SApple OSS Distributions  <tr>
167*19c3b8c2SApple OSS Distributions    <td>Data/Primitive types</td>
168*19c3b8c2SApple OSS Distributions    <td>
169*19c3b8c2SApple OSS Distributions      <p>
170*19c3b8c2SApple OSS Distributions      <b>Core Kernel</b>:<br/>
171*19c3b8c2SApple OSS Distributions      <tt>kalloc_data(size, flags)</tt><br/>
172*19c3b8c2SApple OSS Distributions      <tt>krealloc_data(ptr, old_size, new_size, flags)</tt><br/>
173*19c3b8c2SApple OSS Distributions      <tt>kfree_data(ptr, size)</tt><br/>
174*19c3b8c2SApple OSS Distributions      <tt>kfree_data_addr(ptr)</tt>
175*19c3b8c2SApple OSS Distributions      </p>
176*19c3b8c2SApple OSS Distributions      <p>
177*19c3b8c2SApple OSS Distributions      <b>IOKit untyped variant (returns <tt>void *</tt>)</b>:<br/>
178*19c3b8c2SApple OSS Distributions      <tt>IOMallocData(size)</tt><br/>
179*19c3b8c2SApple OSS Distributions      <tt>IOMallocZeroData(size)</tt><br/>
180*19c3b8c2SApple OSS Distributions      <tt>IOFreeData(ptr, size)</tt>
181*19c3b8c2SApple OSS Distributions      </p>
182*19c3b8c2SApple OSS Distributions      <p>
183*19c3b8c2SApple OSS Distributions      <b>IOKit typed variant (returns <tt>type_t *</tt>)</b>:<br/>
184*19c3b8c2SApple OSS Distributions      <tt>IONewData(type_t, count)</tt><br/>
185*19c3b8c2SApple OSS Distributions      <tt>IONewZeroData(type_t, count)</tt><br/>
186*19c3b8c2SApple OSS Distributions      <tt>IODeleteData(ptr, type_t, count)</tt>
187*19c3b8c2SApple OSS Distributions      </p>
188*19c3b8c2SApple OSS Distributions    </td>
189*19c3b8c2SApple OSS Distributions    <td>This should be used when the allocated type contains no kernel pointer only</td>
190*19c3b8c2SApple OSS Distributions  </tr>
191*19c3b8c2SApple OSS Distributions  <tr>
192*19c3b8c2SApple OSS Distributions    <td>Fixed-sized type</td>
193*19c3b8c2SApple OSS Distributions    <td>
194*19c3b8c2SApple OSS Distributions      <p>
195*19c3b8c2SApple OSS Distributions      <b>Core Kernel</b>:<br/>
196*19c3b8c2SApple OSS Distributions      <tt>kalloc_type(type_t, flags)</tt><br/>
197*19c3b8c2SApple OSS Distributions      <tt>kfree_type(type_t, ptr)</tt>
198*19c3b8c2SApple OSS Distributions      </p>
199*19c3b8c2SApple OSS Distributions      <p>
200*19c3b8c2SApple OSS Distributions      <b>IOKit:</b><br/>
201*19c3b8c2SApple OSS Distributions      <tt>IOMallocType(type_t)</tt><br/>
202*19c3b8c2SApple OSS Distributions      <tt>IOFreeType(ptr, type_t)</tt>
203*19c3b8c2SApple OSS Distributions      </p>
204*19c3b8c2SApple OSS Distributions    </td>
205*19c3b8c2SApple OSS Distributions    <td>
206*19c3b8c2SApple OSS Distributions      <p>
207*19c3b8c2SApple OSS Distributions      Note that this is absolutely OK to use this variant
208*19c3b8c2SApple OSS Distributions      for data/primitive types, it will be redirected to <tt>kalloc_data</tt>
209*19c3b8c2SApple OSS Distributions      (or <tt>IOMallocData</tt>).
210*19c3b8c2SApple OSS Distributions      </p>
211*19c3b8c2SApple OSS Distributions    </td>
212*19c3b8c2SApple OSS Distributions  </tr>
213*19c3b8c2SApple OSS Distributions  <tr>
214*19c3b8c2SApple OSS Distributions    <td>Arrays of fixed-sized type</td>
215*19c3b8c2SApple OSS Distributions    <td>
216*19c3b8c2SApple OSS Distributions      <p>
217*19c3b8c2SApple OSS Distributions      <b>Core Kernel</b>:<br/>
218*19c3b8c2SApple OSS Distributions      <tt>kalloc_type(type_t, count, flags)</tt><br/>
219*19c3b8c2SApple OSS Distributions      <tt>kfree_type(type_t, count, ptr)</tt>
220*19c3b8c2SApple OSS Distributions      </p>
221*19c3b8c2SApple OSS Distributions      <p>
222*19c3b8c2SApple OSS Distributions      <b>IOKit:</b><br/>
223*19c3b8c2SApple OSS Distributions      <tt>IONew(type_t, count)</tt><br/>
224*19c3b8c2SApple OSS Distributions      <tt>IONewZero(type_t, count)</tt><br/>
225*19c3b8c2SApple OSS Distributions      <tt>IODelete(ptr, type_t, count)</tt>
226*19c3b8c2SApple OSS Distributions      </p>
227*19c3b8c2SApple OSS Distributions    </td>
228*19c3b8c2SApple OSS Distributions    <td>
229*19c3b8c2SApple OSS Distributions      <p>
230*19c3b8c2SApple OSS Distributions      <tt>kalloc_type(type_t, ...)</tt> (resp. <tt>IONew(type_t, 1)</tt>)
231*19c3b8c2SApple OSS Distributions      <b>isn't</b> equivalent to <tt>kalloc_type(type_t, 1, ...)</tt>
232*19c3b8c2SApple OSS Distributions      (resp. <tt>IOMallocType(type_t)</tt>). Mix-and-matching interfaces
233*19c3b8c2SApple OSS Distributions      will result in panics.
234*19c3b8c2SApple OSS Distributions      </p>
235*19c3b8c2SApple OSS Distributions      <p>
236*19c3b8c2SApple OSS Distributions      Note that this is absolutely OK to use this variant
237*19c3b8c2SApple OSS Distributions      for data/primitive types, it will be redirected to <tt>kalloc_data</tt>.
238*19c3b8c2SApple OSS Distributions      </p>
239*19c3b8c2SApple OSS Distributions    </td>
240*19c3b8c2SApple OSS Distributions  </tr>
241*19c3b8c2SApple OSS Distributions  <tr>
242*19c3b8c2SApple OSS Distributions    <td>Header-prefixed arrays of fixed-sized type</td>
243*19c3b8c2SApple OSS Distributions    <td>
244*19c3b8c2SApple OSS Distributions      <p>
245*19c3b8c2SApple OSS Distributions      <b>Core Kernel</b>:<br/>
246*19c3b8c2SApple OSS Distributions      <tt>kalloc_type(hdr_type_t, type_t, count, flags)</tt><br/>
247*19c3b8c2SApple OSS Distributions      <tt>kfree_type(hdr_type_t, type_t, count, ptr)</tt>
248*19c3b8c2SApple OSS Distributions      </p>
249*19c3b8c2SApple OSS Distributions      <p>
250*19c3b8c2SApple OSS Distributions      <b>IOKit:</b><br/>
251*19c3b8c2SApple OSS Distributions      <tt>IONew(hdr_type_t, type_t, count)</tt><br/>
252*19c3b8c2SApple OSS Distributions      <tt>IONewZero(hdr_type_t, type_t, count)</tt><br/>
253*19c3b8c2SApple OSS Distributions      <tt>IODelete(ptr, hdr_type_t, type_t, count)</tt>
254*19c3b8c2SApple OSS Distributions      </p>
255*19c3b8c2SApple OSS Distributions    </td>
256*19c3b8c2SApple OSS Distributions    <td>
257*19c3b8c2SApple OSS Distributions      <p>
258*19c3b8c2SApple OSS Distributions      <tt>hdr_type_t</tt> can't contain a refcount,
259*19c3b8c2SApple OSS Distributions      and <tt>type_t</tt> can't be a primitive type.
260*19c3b8c2SApple OSS Distributions      </p>
261*19c3b8c2SApple OSS Distributions    </td>
262*19c3b8c2SApple OSS Distributions  </tr>
263*19c3b8c2SApple OSS Distributions</table>
264*19c3b8c2SApple OSS Distributions
265*19c3b8c2SApple OSS Distributions## C++ classes and operator new.
266*19c3b8c2SApple OSS Distributions
267*19c3b8c2SApple OSS DistributionsThis section covers how typed allocators should be adopted to use
268*19c3b8c2SApple OSS Distributions`operator new/delete` in C++. For C++ classes, the approach required
269*19c3b8c2SApple OSS Distributionsdiffers based on whether the class inherits from `OSObject` or not.
270*19c3b8c2SApple OSS Distributions
271*19c3b8c2SApple OSS DistributionsMost, if not all, C++ objects used in conjuction with IOKit APIs
272*19c3b8c2SApple OSS Distributionsshould probably use OSObject as a base class. C++ operators
273*19c3b8c2SApple OSS Distributionsand non-POD types should be used seldomly.
274*19c3b8c2SApple OSS Distributions
275*19c3b8c2SApple OSS Distributions### `OSObject` subclasses
276*19c3b8c2SApple OSS Distributions
277*19c3b8c2SApple OSS DistributionsAll subclasses of `OSObject` must declare and define one of IOKit's
278*19c3b8c2SApple OSS Distributions`OSDeclare*` and `OSDefine*` macros. As part of those, an `operator new` and
279*19c3b8c2SApple OSS Distributions`operator delete` are injected that force objects to enroll into `kalloc_type`.
280*19c3b8c2SApple OSS Distributions
281*19c3b8c2SApple OSS DistributionsNote that idiomatic IOKit is supposed to use `OSTypeAlloc(Class)`.
282*19c3b8c2SApple OSS Distributions
283*19c3b8c2SApple OSS Distributions### Other classes
284*19c3b8c2SApple OSS Distributions
285*19c3b8c2SApple OSS DistributionsUnlike `OSObject` subclasses, regular C++ classes must adopt typed allocators
286*19c3b8c2SApple OSS Distributionsmanually. If your struct or class is POD (Plain Old Data), then replacing usage of
287*19c3b8c2SApple OSS Distributions`new/delete` (resp. `new[]/delete[]`) with `IOMallocType/IOFreeType` (resp.
288*19c3b8c2SApple OSS Distributions`IONew/IODelete`) is safe.
289*19c3b8c2SApple OSS Distributions
290*19c3b8c2SApple OSS DistributionsHowever, if you have non default structors, or members of your class/struct
291*19c3b8c2SApple OSS Distributionshave non default structors, you will need to manually enroll it into `kalloc_type`.
292*19c3b8c2SApple OSS DistributionsThis can be accomplished through one of the following approaches, and it lets you
293*19c3b8c2SApple OSS Distributionsto continue to use C++'s new and delete keywords to allocate/deallocate instances.
294*19c3b8c2SApple OSS Distributions
295*19c3b8c2SApple OSS DistributionsThe first approach is to subclass the IOTypedOperatorsMixin struct. This will
296*19c3b8c2SApple OSS Distributionsadopt typed allocators for your class/struct by providing the appropriate
297*19c3b8c2SApple OSS Distributionsimplementations for `operator new/delete`:
298*19c3b8c2SApple OSS Distributions
299*19c3b8c2SApple OSS Distributions```cpp
300*19c3b8c2SApple OSS Distributionsstruct Type : public IOTypedOperatorsMixin<Type> {
301*19c3b8c2SApple OSS Distributions    ...
302*19c3b8c2SApple OSS Distributions};
303*19c3b8c2SApple OSS Distributions```
304*19c3b8c2SApple OSS Distributions
305*19c3b8c2SApple OSS DistributionsAlternatively, if you cannot use the mixin approach, you can use the
306*19c3b8c2SApple OSS Distributions`IOOverrideTypedOperators` macro to override `operator new/delete`
307*19c3b8c2SApple OSS Distributionswithin your class/struct declaration:
308*19c3b8c2SApple OSS Distributions
309*19c3b8c2SApple OSS Distributions```cpp
310*19c3b8c2SApple OSS Distributionsstruct Type {
311*19c3b8c2SApple OSS Distributions    IOOverrideTypedOperators(Type);
312*19c3b8c2SApple OSS Distributions    ...
313*19c3b8c2SApple OSS Distributions};
314*19c3b8c2SApple OSS Distributions```
315*19c3b8c2SApple OSS Distributions
316*19c3b8c2SApple OSS DistributionsFinally, if you need to decouple the declaration of the operators from
317*19c3b8c2SApple OSS Distributionstheir implementation, you can use `IODeclareTypedOperators` paired with
318*19c3b8c2SApple OSS Distributions`IODefineTypedOperators`, to declare the operators within your class/struct
319*19c3b8c2SApple OSS Distributionsdeclaration and then provide their definition out of line:
320*19c3b8c2SApple OSS Distributions
321*19c3b8c2SApple OSS Distributions```cpp
322*19c3b8c2SApple OSS Distributions// declaration
323*19c3b8c2SApple OSS Distributionsstruct Type {
324*19c3b8c2SApple OSS Distributions    IODeclareTypedOperators(Type);
325*19c3b8c2SApple OSS Distributions    ...
326*19c3b8c2SApple OSS Distributions};
327*19c3b8c2SApple OSS Distributions
328*19c3b8c2SApple OSS Distributions// definition
329*19c3b8c2SApple OSS DistributionsIODefineTypedOperators(Type)
330*19c3b8c2SApple OSS Distributions```
331*19c3b8c2SApple OSS Distributions
332*19c3b8c2SApple OSS DistributionsWhen a class/struct adopts typed allocators through one of those approaches,
333*19c3b8c2SApple OSS Distributionsall its subclasses must also explicitly adopt typed allocators. It is not
334*19c3b8c2SApple OSS Distributionssufficient for a common parent within the class hierarchy to enroll, in order to
335*19c3b8c2SApple OSS Distributionsautomatically provide the implementation of the operators for all of its children:
336*19c3b8c2SApple OSS Distributionseach and every subclass in the class hierarchy must also explicitly do the same.
337*19c3b8c2SApple OSS Distributions
338*19c3b8c2SApple OSS Distributions### The case of `operator new[]`
339*19c3b8c2SApple OSS Distributions
340*19c3b8c2SApple OSS DistributionsThe ABI of `operator new[]` is unfortunate, as it denormalizes
341*19c3b8c2SApple OSS Distributionsdata that we prefer to be known by the owning object
342*19c3b8c2SApple OSS Distributions(the element sizes and array element count).
343*19c3b8c2SApple OSS Distributions
344*19c3b8c2SApple OSS DistributionsIt also makes those allocations ripe for abuse in an adversarial
345*19c3b8c2SApple OSS Distributionscontext as this denormalized information is at the begining
346*19c3b8c2SApple OSS Distributionsof the structure, making it relatively easy to attack with
347*19c3b8c2SApple OSS Distributionsout-of-bounds bugs.
348*19c3b8c2SApple OSS Distributions
349*19c3b8c2SApple OSS DistributionsFor this reason, the default variants of the mixin and the macros
350*19c3b8c2SApple OSS Distributionspresented above will delete the implementation of `operator new[]`
351*19c3b8c2SApple OSS Distributionsfrom the class they are applied to.
352*19c3b8c2SApple OSS Distributions
353*19c3b8c2SApple OSS DistributionsHowever, if those must be used, you can add adopt the typed
354*19c3b8c2SApple OSS Distributionsallocators on your class by using the appropriate variant
355*19c3b8c2SApple OSS Distributionswhich explicitly implements the support for array operators:
356*19c3b8c2SApple OSS Distributions- `IOTypedOperatorsMixinSupportingArrayOperators`
357*19c3b8c2SApple OSS Distributions- `IOOverrideTypedOperatorsSupportingArrayOperators`
358*19c3b8c2SApple OSS Distributions- `IO{Declare, Define}TypedOperatorsSupportingArrayOperators`
359*19c3b8c2SApple OSS Distributions
360*19c3b8c2SApple OSS Distributions### Scalar types
361*19c3b8c2SApple OSS Distributions
362*19c3b8c2SApple OSS DistributionsThe only accepted ways of using `operator new/delete` and their variants are the ones
363*19c3b8c2SApple OSS Distributionsdescribed above. You should never use the operators on scalar types. Instead, you
364*19c3b8c2SApple OSS Distributionsshould use the appropriate typed allocator API based on the semantics of the memory
365*19c3b8c2SApple OSS Distributionsbeing allocated (i.e. `IOMallocData` for data only buffers, and `IOMallocType`/`IONew`
366*19c3b8c2SApple OSS Distributionsfor any other type).
367*19c3b8c2SApple OSS Distributions
368*19c3b8c2SApple OSS Distributions### Wrapping C++ type allocation in container OSObjects
369*19c3b8c2SApple OSS DistributionsThe blessed way of wrapping and passing a C++ type allocation for use in the
370*19c3b8c2SApple OSS Distributionslibkern collection is using `OSValueObject`. Please do no use OSData for this
371*19c3b8c2SApple OSS Distributionspurpose as its backing store should not contain kernel pointers.
372*19c3b8c2SApple OSS Distributions
373