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