Loading...
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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | /* * Copyright (c) 2018 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*! * @header * Attributes to handle automatic clean-up of certain types of variables when * they go out of scope. * * IMPORTANT: These attributes will NOT cause a variable to be cleaned up when * its value changes. For example, this pattern would leak: * * void *__os_free ptr = malloc(10); * ptr = somewhere_else; * return; * * You should only use these attributes for very well-scoped, temporary * allocations. */ #ifndef __DARWIN_CLEANUP_H #define __DARWIN_CLEANUP_H #include <os/base.h> #include <os/api.h> #include <os/assumes.h> #include <os/object_private.h> #include <os/lock.h> #include <sys/errno.h> #include <sys/cdefs.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <dirent.h> #include <mach/mach_init.h> #include <mach/port.h> #include <mach/mach_port.h> #include <mach/kern_return.h> #include <mach/mach_right_private.h> #if DARWIN_TAPI #include "tapi.h" #endif __BEGIN_DECLS; #if __has_attribute(cleanup) /*! * @define __os_free * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to free(3) when it goes out of scope. Applying this * attribute to variables that do not reference heap allocations will result in * undefined behavior. */ #define __os_free __attribute__((cleanup(__os_cleanup_free))) static inline void __os_cleanup_free(void *__p) { void **tp = (void **)__p; void *p = *tp; free(p); } /*! * @define __os_close * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to close(2) when it goes out of scope. Applying * this attribute to variables that do not reference a valid file descriptor * will result in undefined behavior. If the variable's value is -1 upon going * out-of-scope, no cleanup is performed. */ #define __os_close __attribute__((cleanup(__os_cleanup_close))) static inline void __os_cleanup_close(int *__fd) { int fd = *__fd; if (fd == -1) { return; } posix_assert_zero(close(fd)); } /*! * @define __os_fclose * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to fclose(3) when it goes out of scope. Applying * this attribute to variables that do not reference a valid FILE * will result * in undefined behavior. If the variable's value is NULL upon going out-of- * scope, no cleanup is performed. */ #define __os_fclose __attribute__((cleanup(__os_cleanup_fclose))) static inline void __os_cleanup_fclose(FILE **__fp) { FILE *f = *__fp; int ret = -1; if (!f) { return; } ret = fclose(f); if (ret == EOF) { os_assert_zero(errno); } } /*! * @define __os_closedir * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to closedir(3) when it goes out of scope. Applying * this attribute to variables that do not reference a valid DIR * will result * in undefined behavior. If the variable's value is NULL upon going out-of- * scope, no cleanup is performed. */ #define __os_closedir __attribute__((cleanup(__os_cleanup_closedir))) static inline void __os_cleanup_closedir(DIR **__dp) { DIR *dp = *__dp; if (!dp) { return; } posix_assert_zero(closedir(dp)); } /*! * @define __os_close_mach_recv * An attribute that may be applied to a variable's type. This attribute causes * the variable to be wrapped in a mach receive right object and passed to * {@link mach_right_recv_destruct} when it goes out of scope. Applying this * attribute to variables that do not reference a valid Mach port receive right * will result in undefined behavior. If the variable's value is MACH_PORT_NULL * or MACH_PORT_DEAD upon going out-of-scope, no cleanup is performed. */ #define __os_close_mach_recv \ __attribute__((cleanup(__os_cleanup_close_mach_recv))) static inline void __os_cleanup_close_mach_recv(mach_port_t *__p) { mach_port_t p = *__p; mach_right_recv_t mr = mach_right_recv(p); if (!MACH_PORT_VALID(p)) { return; } mach_right_recv_destruct(mr, NULL, 0); } /*! * @define __os_release_mach_send * An attribute that may be applied to a variable's type. This attribute causes * the variable to be wrapped in a mach send right object and passed to * {@link mach_right_send_release} when it goes out of scope. Applying this * attribute to variables that do not reference a valid Mach port send right or * MACH_PORT_NULL or MACH_PORT_DEAD will result in undefined behavior. If the * variable's value is MACH_PORT_NULL or MACH_PORT_DEAD upon going out-of-scope, * no cleanup is performed. */ #define __os_release_mach_send \ __attribute__((cleanup(__os_cleanup_release_mach_send))) static inline void __os_cleanup_release_mach_send(mach_port_t *__p) { mach_port_t p = *__p; mach_right_send_t ms = mach_right_send(p); if (!MACH_PORT_VALID(p)) { return; } mach_right_send_release(ms); } /*! * @define __os_preserve_errno * An attribute that may be applied to a variable's type. This attribute sets * the global errno to the value of the variable when the variable goes out of * scope. This attribute is useful for preserving the value of errno upon entry * to a function and guaranteeing that it is restored upon exit. */ #define __os_preserve_errno \ __unused __attribute__((cleanup(__os_cleanup_errno))) static inline void __os_cleanup_errno(int *__e) { errno = *__e; } /*! * @define __os_release * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to os_release() when it goes out of scope. Applying * this attribute to a variable which does not reference a valid os_object_t * object will result in undefined behavior. If the variable's value is NULL * upon going out-of-scope, no cleanup is performed. * * This attribute may be applied to dispatch and XPC objects. * * When compiling with ARC, this attribute does nothing. */ #if __has_feature(objc_arc) #define __os_release #else #define __os_release __attribute__((cleanup(__os_cleanup_os_release))) static inline void __os_cleanup_os_release(void *__p) { _os_object_t *tp = (_os_object_t *)__p; _os_object_t o = *tp; if (!o) { return; } os_release(o); } #endif #if DARWIN_CLEANUP_CF /*! * @define __os_cfrelease * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to CFRelease() when it goes out of scope. Applying * this attribute to a variable which does not reference a valid CoreFoundation * object will result in undefined behavior. If the variable's value is NULL * upon going out-of-scope, no cleanup is performed. * * In order to use, you must define the DARWIN_CLEANUP_CF macro to 1 prior to * including this header. */ #define __os_cfrelease __attribute__((cleanup(__os_cleanup_cfrelease))) static inline void __os_cleanup_cfrelease(void *__p) { CFTypeRef *tp = (CFTypeRef *)__p; CFTypeRef cf = *tp; if (!cf) { return; } CFRelease(cf); } #endif // DARWIN_CLEANUP_CF #if DARWIN_CLEANUP_IOKIT /*! * @define __os_iorelease * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to IOObjectRelease() when it goes out of scope. * Applying this attribute to a variable which does not reference a valid IOKit * object will result in undefined behavior. If the variable's value is * IO_OBJECT_NULL upon going out-of-scope, no cleanup is performed. * * * In order to use, you must define the DARWIN_CLEANUP_IOKIT macro to 1 prior to * including this header. */ #define __os_iorelease __attribute__((cleanup(__os_cleanup_iorelease))) static inline void __os_cleanup_iorelease(void *__p) { kern_return_t kr = KERN_FAILURE; io_object_t *iop = (io_object_t *)__p; io_object_t io = *iop; if (io == IO_OBJECT_NULL) { return; } kr = IOObjectRelease(io); if (kr) { os_crash("IOObjectRetain: %{mach.errno}d", kr); } } /*! * @define __os_ioclose * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to IOServiceClose() when it goes out of scope. * Applying this attribute to a variable which does not reference a valid IOKit * connection will result in undefined behavior. If the variable's value is * IO_OBJECT_NULL upon going out-of-scope, no cleanup is performed. * * In order to use, you must define the DARWIN_CLEANUP_IOKIT macro to 1 prior to * including this header. */ #define __os_ioclose __attribute__((cleanup(__os_cleanup_ioclose))) static inline void __os_cleanup_ioclose(void *__p) { kern_return_t kr = KERN_FAILURE; io_connect_t *iop = (io_object_t *)__p; io_connect_t io = *iop; if (io == IO_OBJECT_NULL) { return; } kr = IOServiceClose(io); if (kr) { os_crash("IOObjectRelease: %{mach.errno}d", kr); } } #endif // DARWIN_CLEANUP_IOKIT /*! * @define __os_unfair_unlock * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to os_unfair_lock_unlock() when it goes out of * scope. Applying this attribute to a variable which does not reference a valid * os_unfair_lock_t object will result in undefined behavior. If the variable's * value is NULL upon going out-of-scope, no cleanup is performed. * * This attribute is useful even when the target lock is taken conditionally via * the following pattern: * * os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; * os_unfair_lock_t __os_unfair_unlock l2un = NULL; * * if (take_the_lock) { * os_unfair_lock_lock(&lock); * * // Guarantee that 'lock' will be unconditionally released when the * // scope containing 'l2un' ends. * l2un = &lock; * } */ #define __os_unfair_unlock __attribute__((cleanup(__os_cleanup_unfair_unlock))) static inline void __os_cleanup_unfair_unlock(void *__p) { os_unfair_lock_t *tp = (os_unfair_lock_t *)__p; os_unfair_lock_t ufl = *tp; if (!ufl) { return; } os_unfair_lock_assert_owner(ufl); os_unfair_lock_unlock(ufl); } #else // __has_attribute(cleanup) #define __os_cleanup_unsupported \ _Pragma("GCC error \"automatic cleanup not supported\"") #define __os_free __os_cleanup_unsupported #define __os_close __os_cleanup_unsupported #define __os_fclose __os_cleanup_unsupported #define __os_closedir __os_cleanup_unsupported #define __os_close_mach_recv __os_cleanup_unsupported #define __os_release_mach_send __os_cleanup_unsupported #define __os_preserve_errno __os_cleanup_unsupported #define __os_release __os_cleanup_unsupported #define __os_cfrelease __os_cleanup_unsupported #define __os_iorelease __os_cleanup_unsupported #define __os_ioclose __os_cleanup_unsupported #define __os_unfair_unlock __os_cleanup_unsupported #endif // __has_attribute(cleanup) __END_DECLS; #endif // __DARWIN_CLEANUP_H |