2 // Common definitions for trivial test harness
18 using std::atomic_int
;
19 using std::memory_order_relaxed
;
21 #include <stdatomic.h>
23 #include <sys/errno.h>
24 #include <sys/param.h>
25 #include <malloc/malloc.h>
26 #include <mach/mach.h>
27 #include <mach/vm_param.h>
28 #include <mach/mach_time.h>
29 #include <objc/objc.h>
30 #include <objc/runtime.h>
31 #include <objc/message.h>
32 #include <objc/objc-abi.h>
33 #include <objc/objc-auto.h>
34 #include <objc/objc-internal.h>
35 #include <TargetConditionals.h>
37 #if __has_include(<ptrauth.h>)
41 #include "../runtime/isa.h"
44 # define EXTERN_C extern "C"
46 # define EXTERN_C /*empty*/
52 static inline void succeed(const char *name
) __attribute__((noreturn
));
53 static inline void succeed(const char *name
)
56 char path
[MAXPATHLEN
+1];
58 fprintf(stderr
, "OK: %s\n", basename(path
));
60 fprintf(stderr
, "OK\n");
65 static inline void fail(const char *msg
, ...) __attribute__((noreturn
));
66 static inline void fail(const char *msg
, ...)
70 asprintf(&msg2
, "BAD: %s\n", msg
);
73 vfprintf(stderr
, msg2
, v
);
77 fprintf(stderr
, "BAD\n");
82 #define testassert(cond) \
83 ((void) (((cond) != 0) ? (void)0 : __testassert(#cond, __FILE__, __LINE__)))
84 #define __testassert(cond, file, line) \
85 (fail("failed assertion '%s' at %s:%u", cond, __FILE__, __LINE__))
87 static inline char *hexstring(uint8_t *data
, size_t size
)
91 case sizeof(unsigned long long):
92 asprintf(&str
, "%016llx", *(unsigned long long *)data
);
94 case sizeof(unsigned int):
95 asprintf(&str
, "%08x", *(unsigned int*)data
);
97 case sizeof(uint16_t):
98 asprintf(&str
, "%04x", *(uint16_t *)data
);
101 str
= (char *)malloc(size
* 2 + 1);
102 for (size_t i
= 0; i
< size
; i
++) {
103 sprintf(str
+ i
, "%02x", data
[i
]);
109 static inline void failnotequal(uint8_t *lhs
, size_t lhsSize
, uint8_t *rhs
, size_t rhsSize
, const char *lhsStr
, const char *rhsStr
, const char *file
, unsigned line
)
111 fprintf(stderr
, "BAD: failed assertion '%s != %s' (0x%s != 0x%s) at %s:%u\n", lhsStr
, rhsStr
, hexstring(lhs
, lhsSize
), hexstring(rhs
, rhsSize
), file
, line
);
115 #define testassertequal(lhs, rhs) do {\
116 __typeof__(lhs) __lhs = lhs; \
117 __typeof__(rhs) __rhs = rhs; \
118 if ((lhs) != (rhs)) failnotequal((uint8_t *)&__lhs, sizeof(__lhs), (uint8_t *)&__rhs, sizeof(__rhs), #lhs, #rhs, __FILE__, __LINE__); \
121 /* time-sensitive assertion, disabled under valgrind */
122 #define timecheck(name, time, fast, slow) \
123 if (getenv("VALGRIND") && 0 != strcmp(getenv("VALGRIND"), "NO")) { \
124 /* valgrind; do nothing */ \
125 } else if (time > slow) { \
126 fprintf(stderr, "SLOW: %s %llu, expected %llu..%llu\n", \
127 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \
128 } else if (time < fast) { \
129 fprintf(stderr, "FAST: %s %llu, expected %llu..%llu\n", \
130 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \
132 testprintf("time: %s %llu, expected %llu..%llu\n", \
133 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \
137 // Return true if testprintf() output is enabled.
138 static inline bool testverbose(void)
140 static int verbose
= -1;
141 if (verbose
< 0) verbose
= atoi(getenv("VERBOSE") ?: "0");
143 // VERBOSE=1 prints test harness info only
144 // VERBOSE=2 prints test info
148 // Print debugging info when VERBOSE=2 is set,
149 // without disturbing the test's expected output.
150 static inline void testprintf(const char *msg
, ...)
152 if (msg
&& testverbose()) {
154 asprintf(&msg2
, "VERBOSE: %s", msg
);
157 vfprintf(stderr
, msg2
, v
);
163 // complain to output, but don't fail the test
164 // Use when warning that some test is being temporarily skipped
165 // because of something like a compiler bug.
166 static inline void testwarn(const char *msg
, ...)
170 asprintf(&msg2
, "WARN: %s\n", msg
);
173 vfprintf(stderr
, msg2
, v
);
179 static inline void testnoop() { }
181 // Are we running in dyld3 mode?
182 // Note: checks by looking for the DYLD_USE_CLOSURES environment variable.
183 // This is is always set by our test script, but this won't give the right
184 // answer when being run manually unless that variable is set.
185 static inline bool testdyld3(void) {
188 const char *useClosures
= getenv("DYLD_USE_CLOSURES");
189 dyld
= useClosures
&& useClosures
[0] == '1' ? 3 : 2;
194 // Prevent deprecation warnings from some runtime functions.
196 static inline void test_objc_flush_caches(Class cls
)
198 #pragma clang diagnostic push
199 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
200 _objc_flush_caches(cls
);
201 #pragma clang diagnostic pop
203 #define _objc_flush_caches(c) test_objc_flush_caches(c)
206 static inline Class
test_class_setSuperclass(Class cls
, Class supercls
)
208 #pragma clang diagnostic push
209 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
210 return class_setSuperclass(cls
, supercls
);
211 #pragma clang diagnostic pop
213 #define class_setSuperclass(c, s) test_class_setSuperclass(c, s)
216 static inline void testcollect()
218 _objc_flush_caches(nil
);
222 // Synchronously run test code on another thread.
224 // The block object is unsafe_unretained because we must not allow
225 // ARC to retain them in non-Foundation tests
226 typedef void(^testblock_t
)(void);
227 static __unsafe_unretained testblock_t testcodehack
;
228 static inline void *_testthread(void *arg __unused
)
233 static inline void testonthread(__unsafe_unretained testblock_t code
)
236 testcodehack
= code
; // force GC not-thread-local, avoid ARC void* casts
237 pthread_create(&th
, NULL
, _testthread
, NULL
);
238 pthread_join(th
, NULL
);
241 /* Make sure libobjc does not call global operator new.
242 Any test that DOES need to call global operator new must
243 `#define TEST_CALLS_OPERATOR_NEW` before including test.h.
245 #if __cplusplus && !defined(TEST_CALLS_OPERATOR_NEW)
246 #if !defined(TEST_OVERRIDES_NEW)
247 #define TEST_OVERRIDES_NEW 1
249 #pragma clang diagnostic push
250 #pragma clang diagnostic ignored "-Winline-new-delete"
252 inline void* operator new(std::size_t) { fail("called global operator new"); }
253 inline void* operator new[](std::size_t) { fail("called global operator new[]"); }
254 inline void* operator new(std::size_t, const std::nothrow_t
&) noexcept(true) { fail("called global operator new(nothrow)"); }
255 inline void* operator new[](std::size_t, const std::nothrow_t
&) noexcept(true) { fail("called global operator new[](nothrow)"); }
256 inline void operator delete(void*) noexcept(true) { fail("called global operator delete"); }
257 inline void operator delete[](void*) noexcept(true) { fail("called global operator delete[]"); }
258 inline void operator delete(void*, const std::nothrow_t
&) noexcept(true) { fail("called global operator delete(nothrow)"); }
259 inline void operator delete[](void*, const std::nothrow_t
&) noexcept(true) { fail("called global operator delete[](nothrow)"); }
260 #pragma clang diagnostic pop
265 Fails if total malloc memory in use at leak_check(n)
266 is more than n bytes above that at leak_mark().
269 static inline void leak_recorder(task_t task __unused
, void *ctx
, unsigned type __unused
, vm_range_t
*ranges
, unsigned count
)
271 size_t *inuse
= (size_t *)ctx
;
273 *inuse
+= ranges
[count
].size
;
277 static inline size_t leak_inuse(void)
282 malloc_get_all_zones(mach_task_self(), NULL
, &zones
, &count
);
283 for (unsigned i
= 0; i
< count
; i
++) {
285 malloc_zone_t
*zone
= (malloc_zone_t
*)zones
[i
];
286 if (!zone
->introspect
|| !zone
->introspect
->enumerator
) continue;
288 // skip DispatchContinuations because it sometimes claims to be
289 // using lots of memory that then goes away later
290 if (0 == strcmp(zone
->zone_name
, "DispatchContinuations")) continue;
292 zone
->introspect
->enumerator(mach_task_self(), &inuse
, MALLOC_PTR_IN_USE_RANGE_TYPE
, (vm_address_t
)zone
, NULL
, leak_recorder
);
293 // fprintf(stderr, "%zu in use for zone %s\n", inuse, zone->zone_name);
301 static inline void leak_dump_heap(const char *msg
)
303 fprintf(stderr
, "%s\n", msg
);
305 // Make `heap` write to stderr
306 int outfd
= dup(STDOUT_FILENO
);
307 dup2(STDERR_FILENO
, STDOUT_FILENO
);
308 pid_t pid
= getpid();
310 // environment variables reset for iOS simulator use
311 sprintf(cmd
, "DYLD_LIBRARY_PATH= DYLD_ROOT_PATH= /usr/bin/heap -addresses all %d", (int)pid
);
313 #pragma clang diagnostic push
314 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
316 #pragma clang diagnostic pop
318 dup2(outfd
, STDOUT_FILENO
);
322 static size_t _leak_start
;
323 static inline void leak_mark(void)
326 if (getenv("LEAK_HEAP")) {
327 leak_dump_heap("HEAP AT leak_mark");
329 _leak_start
= leak_inuse();
332 #define leak_check(n) \
334 const char *_check = getenv("LEAK_CHECK"); \
336 if (_check && 0 == strcmp(_check, "NO")) break; \
338 if (getenv("LEAK_HEAP")) { \
339 leak_dump_heap("HEAP AT leak_check"); \
341 inuse = leak_inuse(); \
342 if (inuse > _leak_start + (n)) { \
343 fprintf(stderr, "BAD: %zu bytes leaked at %s:%u " \
344 "(try LEAK_HEAP and HANG_ON_LEAK to debug)\n", \
345 inuse - _leak_start, __FILE__, __LINE__); \
346 if (getenv("HANG_ON_LEAK")) { \
347 fprintf(stderr, "Hanging after leaks detected. " \
348 "Leaks command:\n"); \
349 fprintf(stderr, "leaks %d\n", getpid()); \
350 while (1) sleep(1); \
355 // true when running under Guard Malloc
356 static inline bool is_guardmalloc(void)
358 const char *env
= getenv("GUARDMALLOC");
359 return (env
&& 0 == strcmp(env
, "1"));
362 // true when running a debug build of libobjc
363 static inline bool is_debug(void)
365 static int debugness
= -1;
366 if (debugness
== -1) {
367 debugness
= dlsym(RTLD_DEFAULT
, "_objc_isDebugBuild") ? 1 : 0;
369 return (bool)debugness
;
373 /* Memory management compatibility macros */
375 static id
self_fn(id x
) __attribute__((used
));
376 static id
self_fn(id x
) { return x
; }
378 #if __has_feature(objc_arc_weak)
380 # define WEAK_STORE(dst, val) (dst = (val))
381 # define WEAK_LOAD(src) (src)
384 # define WEAK_STORE(dst, val) objc_storeWeak((id *)&dst, val)
385 # define WEAK_LOAD(src) objc_loadWeak((id *)&src)
388 #if __has_feature(objc_arc)
390 # define RELEASE_VAR(x) x = nil
391 # define SUPER_DEALLOC()
392 # define RETAIN(x) (self_fn(x))
393 # define RELEASE_VALUE(x) ((void)self_fn(x))
394 # define AUTORELEASE(x) (self_fn(x))
398 # define RELEASE_VAR(x) do { [x release]; x = nil; } while (0)
399 # define SUPER_DEALLOC() [super dealloc]
400 # define RETAIN(x) [x retain]
401 # define RELEASE_VALUE(x) [x release]
402 # define AUTORELEASE(x) [x autorelease]
405 /* gcc compatibility macros */
406 /* <rdar://problem/9412038> @autoreleasepool should generate objc_autoreleasePoolPush/Pop on 10.7/5.0 */
407 //#if !defined(__clang__)
408 # define PUSH_POOL { void *pool = objc_autoreleasePoolPush();
409 # define POP_POOL objc_autoreleasePoolPop(pool); }
411 //# define PUSH_POOL @autoreleasepool
417 /* General purpose root class */
420 @interface TestRoot
{
434 +(id
) allocWithZone
:(void*)zone
;
440 @interface
TestRoot (RR
)
442 -(oneway
void) release
;
444 -(unsigned long) retainCount
;
445 -(id
) copyWithZone
:(void *)zone
;
446 -(id
) mutableCopyWithZone
:(void*)zone
;
449 // incremented for each call of TestRoot's methods
450 extern atomic_int TestRootLoad
;
451 extern atomic_int TestRootInitialize
;
452 extern atomic_int TestRootAlloc
;
453 extern atomic_int TestRootAllocWithZone
;
454 extern atomic_int TestRootCopy
;
455 extern atomic_int TestRootCopyWithZone
;
456 extern atomic_int TestRootMutableCopy
;
457 extern atomic_int TestRootMutableCopyWithZone
;
458 extern atomic_int TestRootInit
;
459 extern atomic_int TestRootDealloc
;
460 extern atomic_int TestRootRetain
;
461 extern atomic_int TestRootRelease
;
462 extern atomic_int TestRootAutorelease
;
463 extern atomic_int TestRootRetainCount
;
464 extern atomic_int TestRootTryRetain
;
465 extern atomic_int TestRootIsDeallocating
;
466 extern atomic_int TestRootPlusRetain
;
467 extern atomic_int TestRootPlusRelease
;
468 extern atomic_int TestRootPlusAutorelease
;
469 extern atomic_int TestRootPlusRetainCount
;
474 // Struct that does not return in registers on any architecture
489 static inline BOOL
stret_equal(struct stret a
, struct stret b
)
491 return (a
.a
== b
.a
&&
503 static struct stret STRET_RESULT
__attribute__((used
)) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
506 #if TARGET_OS_SIMULATOR
507 // Force cwd to executable's directory during launch.
508 // sim used to do this but simctl does not.
509 #include <crt_externs.h>
510 __attribute__((constructor
))
511 static void hack_cwd(void)
513 if (!getenv("HACKED_CWD")) {
514 chdir(dirname((*_NSGetArgv())[0]));
515 setenv("HACKED_CWD", "1", 1);