]> git.saurik.com Git - apple/libc.git/blob - libdarwin/h/cleanup.h
Libc-1353.41.1.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 <mach/mach_init.h>
55 #include <mach/port.h>
56 #include <mach/mach_port.h>
57 #include <mach/kern_return.h>
58 #include <mach/mach_right.h>
59
60 __BEGIN_DECLS;
61
62 #if __has_attribute(cleanup)
63 /*!
64 * @define __os_free
65 * An attribute that may be applied to a variable's type. This attribute causes
66 * the variable to be passed to free(3) when it goes out of scope. Applying this
67 * attribute to variables that do not reference heap allocations will result in
68 * undefined behavior.
69 */
70 #define __os_free __attribute__((cleanup(__os_cleanup_free)))
71 static inline void
72 __os_cleanup_free(void *__p)
73 {
74 void **tp = (void **)__p;
75 void *p = *tp;
76 free(p);
77 }
78
79 /*!
80 * @define __os_close
81 * An attribute that may be applied to a variable's type. This attribute causes
82 * the variable to be passed to close(2) when it goes out of scope. Applying
83 * this attribute to variables that do not reference a valid file descriptor
84 * will result in undefined behavior. If the variable's value is -1 upon going
85 * out-of-scope, no cleanup is performed.
86 */
87 #define __os_close __attribute__((cleanup(__os_cleanup_close)))
88 static inline void
89 __os_cleanup_close(int *__fd)
90 {
91 int fd = *__fd;
92 if (fd == -1) {
93 return;
94 }
95 posix_assert_zero(close(fd));
96 }
97
98 /*!
99 * @define __os_fclose
100 * An attribute that may be applied to a variable's type. This attribute causes
101 * the variable to be passed to fclose(3) when it goes out of scope. Applying
102 * this attribute to variables that do not reference a valid FILE* will result
103 * in undefined behavior. If the variable's value is NULL upon going out-of-
104 * scope, no cleanup is performed.
105 */
106 #define __os_fclose __attribute__((cleanup(__os_cleanup_fclose)))
107 static inline void
108 __os_cleanup_fclose(FILE **__fp)
109 {
110 FILE *f = *__fp;
111 int ret = -1;
112
113 if (!f) {
114 return;
115 }
116
117 ret = fclose(f);
118 if (ret == EOF) {
119 os_assert_zero(errno);
120 }
121 }
122
123 /*!
124 * @define __os_close_mach_recv
125 * An attribute that may be applied to a variable's type. This attribute causes
126 * the variable to be wrapped in a mach receive right object and passed to
127 * {@link mach_right_recv_destruct} when it goes out of scope. Applying this
128 * attribute to variables that do not reference a valid Mach port receive right
129 * will result in undefined behavior. If the variable's value is MACH_PORT_NULL
130 * or MACH_PORT_DEAD upon going out-of-scope, no cleanup is performed.
131 */
132 #define __os_close_mach_recv \
133 __attribute__((cleanup(__os_cleanup_close_mach_recv)))
134 static inline void
135 __os_cleanup_close_mach_recv(mach_port_t *__p)
136 {
137 mach_port_t p = *__p;
138 mach_right_recv_t mr = mach_right_recv(p);
139
140 if (!MACH_PORT_VALID(p)) {
141 return;
142 }
143
144 mach_right_recv_destruct(mr, NULL, 0);
145 }
146
147 /*!
148 * @define __os_release_mach_send
149 * An attribute that may be applied to a variable's type. This attribute causes
150 * the variable to be wrapped in a mach send right object and passed to
151 * {@link mach_right_send_release} when it goes out of scope. Applying this
152 * attribute to variables that do not reference a valid Mach port send right or
153 * MACH_PORT_NULL or MACH_PORT_DEAD will result in undefined behavior. If the
154 * variable's value is MACH_PORT_NULL or MACH_PORT_DEAD upon going out-of-scope,
155 * no cleanup is performed.
156 */
157 #define __os_release_mach_send \
158 __attribute__((cleanup(__os_cleanup_release_mach_send)))
159 static inline void
160 __os_cleanup_release_mach_send(mach_port_t *__p)
161 {
162 mach_port_t p = *__p;
163 mach_right_send_t ms = mach_right_send(p);
164
165 if (!MACH_PORT_VALID(p)) {
166 return;
167 }
168
169 mach_right_send_release(ms);
170 }
171
172 /*!
173 * @define __os_preserve_errno
174 * An attribute that may be applied to a variable's type. This attribute sets
175 * the global errno to the value of the variable when the variable goes out of
176 * scope. This attribute is useful for preserving the value of errno upon entry
177 * to a function and guaranteeing that it is restored upon exit.
178 */
179 #define __os_preserve_errno \
180 __unused __attribute__((cleanup(__os_cleanup_errno)))
181 static inline void
182 __os_cleanup_errno(int *__e)
183 {
184 errno = *__e;
185 }
186
187 /*!
188 * @define __os_release
189 * An attribute that may be applied to a variable's type. This attribute causes
190 * the variable to be passed to os_release() when it goes out of scope. Applying
191 * this attribute to a variable which does not reference a valid os_object_t
192 * object will result in undefined behavior. If the variable's value is NULL
193 * upon going out-of-scope, no cleanup is performed.
194 *
195 * This attribute may be applied to dispatch and XPC objects.
196 *
197 * When compiling with ARC, this attribute does nothing.
198 */
199 #if __has_feature(objc_arc)
200 #define __os_release
201 #else
202 #define __os_release __attribute__((cleanup(__os_cleanup_os_release)))
203 static inline void
204 __os_cleanup_os_release(void *__p)
205 {
206 _os_object_t *tp = (_os_object_t *)__p;
207 _os_object_t o = *tp;
208 if (!o) {
209 return;
210 }
211 os_release(o);
212 }
213 #endif
214
215 #if __COREFOUNDATION__
216 /*!
217 * @define __os_cfrelease
218 * An attribute that may be applied to a variable's type. This attribute causes
219 * the variable to be passed to CFRelease() when it goes out of scope. Applying
220 * this attribute to a variable which does not reference a valid CoreFoundation
221 * object will result in undefined behavior. If the variable's value is NULL
222 * upon going out-of-scope, no cleanup is performed.
223 */
224 #define __os_cfrelease __attribute__((cleanup(__os_cleanup_cfrelease)))
225 static inline void
226 __os_cleanup_cfrelease(void *__p)
227 {
228 CFTypeRef *tp = (CFTypeRef *)__p;
229 CFTypeRef cf = *tp;
230 if (!cf) {
231 return;
232 }
233 CFRelease(cf);
234 }
235 #endif // __COREFOUNDATION__
236
237 /*!
238 * @define __os_unfair_unlock
239 * An attribute that may be applied to a variable's type. This attribute causes
240 * the variable to be passed to os_unfair_lock_unlock() when it goes out of
241 * scope. Applying this attribute to a variable which does not reference a valid
242 * os_unfair_lock_t object will result in undefined behavior. If the variable's
243 * value is NULL upon going out-of-scope, no cleanup is performed.
244 *
245 * This attribute is useful even when the target lock is taken conditionally via
246 * the following pattern:
247 *
248 * os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
249 * os_unfair_lock_t __os_unfair_unlock l2un = NULL;
250 *
251 * if (take_the_lock) {
252 * os_unfair_lock_lock(&lock);
253 *
254 * // Guarantee that 'lock' will be unconditionally released when the
255 * // scope containing 'l2un' ends.
256 * l2un = &lock;
257 * }
258 */
259 #define __os_unfair_unlock __attribute__((cleanup(__os_cleanup_unfair_unlock)))
260 static inline void
261 __os_cleanup_unfair_unlock(void *__p)
262 {
263 os_unfair_lock_t *tp = (os_unfair_lock_t *)__p;
264 os_unfair_lock_t ufl = *tp;
265 if (!ufl) {
266 return;
267 }
268 os_unfair_lock_assert_owner(ufl);
269 os_unfair_lock_unlock(ufl);
270 }
271
272 #else // __has_attribute(cleanup)
273 #define __os_cleanup_unsupported \
274 _Pragma("GCC error \"automatic cleanup not supported\"")
275 #define __os_free __os_cleanup_unsupported
276 #define __os_close __os_cleanup_unsupported
277 #define __os_fclose __os_cleanup_unsupported
278 #define __os_close_mach_recv __os_cleanup_unsupported
279 #define __os_release_mach_send __os_cleanup_unsupported
280 #define __os_preserve_errno __os_cleanup_unsupported
281 #define __os_release __os_cleanup_unsupported
282 #define __os_cfrelease __os_cleanup_unsupported
283 #define __os_unfair_unlock __os_cleanup_unsupported
284 #endif // __has_attribute(cleanup)
285
286 __END_DECLS;
287
288 #endif // __DARWIN_CLEANUP_H