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