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