├── .gitignore ├── APPLE_LICENSE ├── LICENSE ├── README.md ├── ReleaseNotes.rtf ├── include ├── Block_private.h ├── CrashReporterClient.h ├── System │ ├── machine │ │ └── cpu_capabilities.h │ └── pthread_machdep.h ├── _simple.h ├── kern │ └── restartable.h ├── mach-o │ └── dyld_priv.h ├── objc-shared-cache.h ├── os │ ├── base_private.h │ ├── linker_set.h │ ├── lock_private.h │ ├── reason_private.h │ ├── tsd.h │ └── variant_private.h ├── pthread │ ├── spinlock_private.h │ └── tsd_private.h └── sys │ └── reason.h ├── interposable.txt ├── lastGitDiff ├── lastGitStatus ├── markgc.cpp ├── objc.sln ├── objc.vcproj ├── objc.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── objc4.plist ├── objc_debug └── main.m ├── objcdt ├── json.h ├── json.mm ├── objcdt-entitlements.plist ├── objcdt.1 └── objcdt.mm ├── objcrt └── objcrt.vcproj ├── prebuild.bat ├── runtime ├── DenseMapExtras.h ├── Messengers.subproj │ ├── objc-msg-arm.s │ ├── objc-msg-arm64.s │ ├── objc-msg-i386.s │ ├── objc-msg-simulator-i386.s │ ├── objc-msg-simulator-x86_64.s │ ├── objc-msg-win32.m │ └── objc-msg-x86_64.s ├── Module │ ├── ObjectiveC.apinotes │ └── module.modulemap ├── ModulePrivate │ └── module.modulemap ├── NSObjCRuntime.h ├── NSObject-internal.h ├── NSObject-private.h ├── NSObject.h ├── NSObject.mm ├── Object.h ├── Object.mm ├── OldClasses.subproj │ ├── List.h │ └── List.m ├── PointerUnion.h ├── Protocol.h ├── Protocol.mm ├── arm64-asm.h ├── dummy-library-mac-i386.c ├── hashtable.h ├── hashtable2.h ├── hashtable2.mm ├── isa.h ├── llvm-AlignOf.h ├── llvm-DenseMap.h ├── llvm-DenseMapInfo.h ├── llvm-DenseSet.h ├── llvm-MathExtras.h ├── llvm-type_traits.h ├── maptable.h ├── maptable.mm ├── message.h ├── objc-abi.h ├── objc-accessors.mm ├── objc-api.h ├── objc-auto.h ├── objc-auto.mm ├── objc-block-trampolines.h ├── objc-block-trampolines.mm ├── objc-blocktramps-arm.s ├── objc-blocktramps-arm64.s ├── objc-blocktramps-i386.s ├── objc-blocktramps-x86_64.s ├── objc-cache-old.h ├── objc-cache-old.mm ├── objc-cache.mm ├── objc-class-old.mm ├── objc-class.h ├── objc-class.mm ├── objc-config.h ├── objc-env.h ├── objc-errors.mm ├── objc-exception.h ├── objc-exception.mm ├── objc-file-old.h ├── objc-file-old.mm ├── objc-file.h ├── objc-file.mm ├── objc-gdb.h ├── objc-initialize.h ├── objc-initialize.mm ├── objc-internal.h ├── objc-layout.mm ├── objc-load.h ├── objc-load.mm ├── objc-loadmethod.h ├── objc-loadmethod.mm ├── objc-lockdebug.h ├── objc-lockdebug.mm ├── objc-locks-new.h ├── objc-locks-old.h ├── objc-locks.h ├── objc-object.h ├── objc-opt.mm ├── objc-os.h ├── objc-os.mm ├── objc-private.h ├── objc-probes.d ├── objc-ptrauth.h ├── objc-references.h ├── objc-references.mm ├── objc-runtime-new.h ├── objc-runtime-new.mm ├── objc-runtime-old.h ├── objc-runtime-old.mm ├── objc-runtime.h ├── objc-runtime.mm ├── objc-sel-old.mm ├── objc-sel-set.h ├── objc-sel-set.mm ├── objc-sel-table.s ├── objc-sel.mm ├── objc-sync.h ├── objc-sync.mm ├── objc-typeencoding.mm ├── objc-weak.h ├── objc-weak.mm ├── objc-zalloc.h ├── objc-zalloc.mm ├── objc.h ├── objcrt.c ├── objcrt.h └── runtime.h ├── test ├── ARCBase.h ├── ARCBase.m ├── ARCLayouts.m ├── ARCLayoutsWithoutWeak.m ├── ARCMRC.h ├── ARCMRC.m ├── MRCARC.h ├── MRCARC.m ├── MRCBase.h ├── MRCBase.m ├── accessors.m ├── accessors2.m ├── addMethod.m ├── addMethods.m ├── addProtocol.m ├── applescriptobjc.m ├── arr-cast.m ├── arr-weak.m ├── asm-placeholder.s ├── association-cf.m ├── association.m ├── associationForbidden.h ├── associationForbidden.m ├── associationForbidden2.m ├── associationForbidden3.m ├── associationForbidden4.m ├── atomicProperty.mm ├── badAltHandler.m ├── badCache.m ├── badPool.m ├── badPoolCompat-ios.m ├── badPoolCompat-macos.m ├── badPoolCompat-tvos.m ├── badPoolCompat-watchos.m ├── badSuperclass.m ├── badSuperclass2.m ├── badTagClass.m ├── badTagIndex.m ├── bigrc.m ├── blocksAsImps.m ├── bool.c ├── cacheflush-constant.m ├── cacheflush.h ├── cacheflush.m ├── cacheflush0.m ├── cacheflush2.m ├── cacheflush3.m ├── category.m ├── cdtors.mm ├── classgetclass.m ├── classname.m ├── classpair.mm ├── classversion.m ├── concurrentcat.m ├── concurrentcat_category.m ├── consolidatePoolPointers.m ├── copyFixupHandler.mm ├── copyIvarList.m ├── copyMethodList.m ├── copyPropertyList.m ├── copyProtocolList.m ├── createInstance.m ├── customrr-cat1.m ├── customrr-cat2.m ├── customrr-nsobject-awz.m ├── customrr-nsobject-core.m ├── customrr-nsobject-none.m ├── customrr-nsobject-rr.m ├── customrr-nsobject-rrawz.m ├── customrr-nsobject.m ├── customrr.m ├── customrr2.m ├── debugScanWeakTables.m ├── defines.c ├── defines.expected ├── defines.sh ├── definitions.c ├── designatedinit.m ├── duplicateClass.m ├── duplicateProtocols.m ├── duplicatedClasses.m ├── evil-class-def.m ├── exc.m ├── exchangeImp.m ├── fakeRealizedClass.m ├── fakeRealizedClass2.m ├── foreach.m ├── fork.m ├── forkInitialize.m ├── forkInitializeDisabled.m ├── forkInitializeSingleThreaded.m ├── forward.m ├── forwardDefault.m ├── forwardDefaultStret.m ├── future.h ├── future.m ├── future0.m ├── future2.m ├── gdb.m ├── getClassHook.m ├── getImageNameHook.m ├── getMethod.m ├── get_task_allow_entitlement.plist ├── headers.c ├── headers.sh ├── imageAPIs.m ├── imageorder.h ├── imageorder.m ├── imageorder1.m ├── imageorder2.m ├── imageorder3.m ├── imports.c ├── include-warnings.c ├── includes-objc2.c ├── includes.c ├── initialize.m ├── initializeVersusWeak.m ├── instanceSize.m ├── isaValidation.m ├── ismeta.m ├── ivar.m ├── ivarSlide.h ├── ivarSlide.m ├── ivarSlide1.m ├── lazyClassName.m ├── libraryPath.c ├── literals.m ├── load-image-notification-dylib.m ├── load-image-notification.m ├── load-order.m ├── load-order1.m ├── load-order2.m ├── load-order3.m ├── load-parallel.m ├── load-parallel0.m ├── load-parallel00.m ├── load-reentrant.m ├── load-reentrant2.m ├── load.m ├── methodArgs.m ├── methodCacheLeaks.m ├── methodListSize.m ├── methodListSmall.h ├── methodListSmall.mm ├── msgSend-performance.m ├── msgSend.m ├── nilAPIArgs.m ├── nonpointerisa.m ├── nopool.m ├── nscdtors.mm ├── nsexc.m ├── nsobject.m ├── nsprotocol.m ├── objectCopy.m ├── preopt-caches.entitlements ├── preopt-caches.mm ├── property.m ├── propertyDesc.m ├── protocol.m ├── protocolSmall.m ├── protocol_copyMethodList.m ├── protocol_copyPropertyList.m ├── rawisa.m ├── readClassPair.m ├── realizedClassGenerationCount.m ├── release-workaround.m ├── resolve.m ├── restartableRangesSynchronizeStress.m ├── restartableRangesSynchronizeStress2.m ├── rr-autorelease-fast.m ├── rr-autorelease-fastarc.m ├── rr-autorelease-stacklogging.m ├── rr-autorelease.m ├── rr-autorelease2.m ├── rr-nsautorelease.m ├── rr-sidetable.m ├── runtime.m ├── sel.m ├── setAssociatedObjectHook.m ├── setSuper.m ├── subscripting.m ├── super.m ├── supported-inline-refcnt.m ├── swift-class-def.m ├── swiftMetadataInitializer.m ├── swiftMetadataInitializerRealloc-dylib1.m ├── swiftMetadataInitializerRealloc-dylib2.m ├── swiftMetadataInitializerRealloc.m ├── swiftStubClassList.m ├── synchronized-counter.m ├── synchronized-grid.m ├── synchronized.m ├── taggedNSPointers.m ├── taggedPointers.m ├── taggedPointersAllClasses.m ├── taggedPointersDisabled.m ├── taggedPointersTagObfuscationDisabled.m ├── tbi.c ├── test-defines.h ├── test.h ├── test.pl ├── testroot.i ├── timeout.pl ├── unload.h ├── unload.m ├── unload2.m ├── unload3.c ├── unload4.m ├── unwind.m ├── weak.h ├── weak.m ├── weak2.m ├── weakReferenceHook.m ├── weakcopy.m ├── weakframework-missing.m ├── weakframework-not-missing.m ├── weakimport-missing.m ├── weakimport-not-missing.m ├── weakrace.m ├── willInitializeClassFunc.m └── zone.m ├── unexported_symbols ├── version.bat └── version.rc /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | .DS_Store 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | # CocoaPods 33 | # 34 | # We recommend against adding the Pods directory to your .gitignore. However 35 | # you should judge for yourself, the pros and cons are mentioned at: 36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 37 | # 38 | # Pods/ 39 | 40 | # Carthage 41 | # 42 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 43 | # Carthage/Checkouts 44 | 45 | Carthage/Build 46 | 47 | # fastlane 48 | # 49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 50 | # screenshots whenever they are needed. 51 | # For more information about the recommended setup visit: 52 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 53 | 54 | fastlane/report.xml 55 | fastlane/Preview.html 56 | fastlane/screenshots 57 | fastlane/test_output 58 | 59 | # Code Injection 60 | # 61 | # After new code Injection tools there's a generated folder /iOSInjectionProject 62 | # https://github.com/johnno1962/injectionforxcode 63 | 64 | iOSInjectionProject/ 65 | 66 | #Visual Studio Code 67 | 68 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 可调试的、基于M1芯片、macOS 12系统的objc4. 2 | 3 | 4 | ![build_status](https://github.com/0xxd0/objc4/workflows/build/badge.svg) 5 | [![Join the chat at https://gitter.im/0xxd0/objc4](https://badges.gitter.im/0xxd0/objc4.svg)](https://gitter.im/0xxd0/objc4?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | ![support](https://img.shields.io/badge/support-macOS%20%7C%20iOS-orange.svg) 7 | 8 | - [Version](#Version) 9 | - [Installation](#Installation) 10 | - [Usage](#Usage) 11 | - [License](#license) 12 | 13 | 14 | ## **Version** 15 | 16 | | macOS | macOS Version | Xcode Version | objc4 tarball version | 17 | | - | - | - | - | 18 | | macOS Monterey | 12.0.1 | 13.2 (13C90) | objc4-838 | 19 | 20 | ## **Installation** 21 | 22 | Download zip or clone this repo, select **objc_debug** 、 **My Mac** and build. 23 | 24 | 25 | ## **Usage** 26 | 27 | 手动把编译产物`libobjc.A.dylib`加入到你的工程,或者直接在`objc_debug`的main文件打断点调试。 28 | 如果没有办法在main函数打断点,可以尝试写个类,提供一个方法,方法里面设置断点,在main函数里调用这个方法。 29 | 30 | 31 | ## License 32 | This project is released under the **MIT License**. The objc4 project is released under the **APPLE PUBLIC SOURCE LICENSE Version 2.0**. 33 | -------------------------------------------------------------------------------- /include/CrashReporterClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 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 | * Not to be installed in /usr/local/include 26 | ***********************************************************************/ 27 | //Libc-825.40.1/include/CrashReporterClient.h 28 | #ifndef _LIBC_CRASHREPORTERCLIENT_H 29 | #define _LIBC_CRASHREPORTERCLIENT_H 30 | 31 | #ifdef LIBC_NO_LIBCRASHREPORTERCLIENT 32 | 33 | /* Fake the CrashReporterClient API */ 34 | #define CRGetCrashLogMessage() 0 35 | #define CRSetCrashLogMessage(x) /* nothing */ 36 | 37 | #else /* !LIBC_NO_LIBCRASHREPORTERCLIENT */ 38 | 39 | /* Include the real CrashReporterClient.h */ 40 | #include_next 41 | 42 | #endif /* !LIBC_NO_LIBCRASHREPORTERCLIENT */ 43 | 44 | #endif /* _LIBC_CRASHREPORTERCLIENT_H */ 45 | -------------------------------------------------------------------------------- /include/System/machine/cpu_capabilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | ///11.5-xnu-xnu-7195.141.2/osfmk/machine/cpu_capabilities.h 29 | #ifdef PRIVATE 30 | 31 | #ifndef _MACHINE_CPU_CAPABILITIES_H 32 | #define _MACHINE_CPU_CAPABILITIES_H 33 | 34 | #ifdef KERNEL_PRIVATE 35 | #if defined (__i386__) || defined (__x86_64__) 36 | #include "i386/cpu_capabilities.h" 37 | #elif defined (__arm__) || defined (__arm64__) 38 | #include "arm/cpu_capabilities.h" 39 | #else 40 | #error architecture not supported 41 | #endif 42 | 43 | #else /* !KERNEL_PRIVATE -- System Framework header */ 44 | #if defined (__i386__) || defined(__x86_64__) 45 | #include 46 | #elif defined (__arm__) || defined(__arm64__) 47 | #include 48 | #else 49 | #error architecture not supported 50 | #endif 51 | #endif /* KERNEL_PRIVATE */ 52 | 53 | #endif /* _MACHINE_CPU_CAPABILITIES_H */ 54 | #endif /* PRIVATE */ 55 | -------------------------------------------------------------------------------- /include/os/base_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2013 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | /// 11.5-xnu-xnu-7195.141.2/libkern/os/base_private.h 22 | #ifndef __OS_BASE_PRIVATE__ 23 | #define __OS_BASE_PRIVATE__ 24 | 25 | #ifndef KERNEL 26 | #include 27 | #endif 28 | #include 29 | 30 | #ifndef os_fastpath 31 | #define os_fastpath(x) ((__typeof__(x))OS_EXPECT((long)(x), ~0l)) 32 | #endif 33 | #ifndef os_slowpath 34 | #define os_slowpath(x) ((__typeof__(x))OS_EXPECT((long)(x), 0l)) 35 | #endif 36 | #ifndef os_likely 37 | #define os_likely(x) OS_EXPECT(!!(x), 1) 38 | #endif 39 | #ifndef os_unlikely 40 | #define os_unlikely(x) OS_EXPECT(!!(x), 0) 41 | #endif 42 | 43 | 44 | #endif // __OS_BASE_PRIVATE__ 45 | -------------------------------------------------------------------------------- /include/os/reason_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | //11.5-xnu-xnu-7195.141.2/libkern/os/reason_private.h 29 | #ifndef OS_REASON_PRIVATE_H 30 | #define OS_REASON_PRIVATE_H 31 | 32 | #include 33 | #include 34 | 35 | /* Codes in the OS_REASON_LIBSYSTEM namespace */ 36 | 37 | OS_ENUM(os_reason_libsystem_code, uint64_t, 38 | OS_REASON_LIBSYSTEM_CODE_WORKLOOP_OWNERSHIP_LEAK = 1, 39 | OS_REASON_LIBSYSTEM_CODE_FAULT = 2, /* generated by os_log_fault */ 40 | OS_REASON_LIBSYSTEM_CODE_SECINIT_INITIALIZER = 3, 41 | OS_REASON_LIBSYSTEM_CODE_PTHREAD_CORRUPTION = 4, 42 | ); 43 | 44 | #ifndef KERNEL 45 | 46 | /* 47 | * similar to abort_with_payload, but for faults. 48 | * 49 | * [EBUSY] too many corpses are being generated at the moment 50 | * [EQFULL] the process used all its user fault quota 51 | * [ENOTSUP] generating simulated abort with reason is disabled 52 | * [EPERM] generating simulated abort with reason for this namespace is not turned on 53 | */ 54 | int 55 | os_fault_with_payload(uint32_t reason_namespace, uint64_t reason_code, 56 | void *payload, uint32_t payload_size, const char *reason_string, 57 | uint64_t reason_flags) __attribute__((cold)); 58 | 59 | #endif // !KERNEL 60 | 61 | #endif // OS_REASON_PRIVATE_H 62 | -------------------------------------------------------------------------------- /interposable.txt: -------------------------------------------------------------------------------- 1 | _objc_release 2 | -------------------------------------------------------------------------------- /lastGitStatus: -------------------------------------------------------------------------------- 1 | On branch main 2 | Your branch is up to date with 'origin/main'. 3 | 4 | Changes to be committed: 5 | (use "git restore --staged ..." to unstage) 6 | new file: LICENSE 7 | new file: README.md 8 | new file: include/Block_private.h 9 | new file: include/CrashReporterClient.h 10 | new file: include/System/machine/cpu_capabilities.h 11 | new file: include/System/pthread_machdep.h 12 | new file: include/_simple.h 13 | new file: include/kern/restartable.h 14 | new file: include/mach-o/dyld_priv.h 15 | new file: include/objc-shared-cache.h 16 | new file: include/os/base_private.h 17 | new file: include/os/linker_set.h 18 | new file: include/os/lock_private.h 19 | new file: include/os/reason_private.h 20 | new file: include/os/tsd.h 21 | new file: include/os/variant_private.h 22 | new file: include/pthread/spinlock_private.h 23 | new file: include/pthread/tsd_private.h 24 | new file: include/sys/reason.h 25 | new file: objc_debug/main.m 26 | 27 | Changes not staged for commit: 28 | (use "git add/rm ..." to update what will be committed) 29 | (use "git restore ..." to discard changes in working directory) 30 | deleted: LICENSE 31 | deleted: README.md 32 | modified: include/Block_private.h 33 | modified: include/CrashReporterClient.h 34 | modified: include/System/machine/cpu_capabilities.h 35 | modified: include/System/pthread_machdep.h 36 | modified: include/_simple.h 37 | modified: include/kern/restartable.h 38 | modified: include/mach-o/dyld_priv.h 39 | modified: include/objc-shared-cache.h 40 | modified: include/os/linker_set.h 41 | modified: include/os/lock_private.h 42 | modified: include/os/reason_private.h 43 | modified: include/os/tsd.h 44 | modified: include/os/variant_private.h 45 | modified: include/pthread/spinlock_private.h 46 | modified: include/pthread/tsd_private.h 47 | modified: include/sys/reason.h 48 | modified: objc.xcodeproj/project.pbxproj 49 | modified: objc_debug/main.m 50 | modified: runtime/NSObject.mm 51 | modified: runtime/objc-cache.mm 52 | modified: runtime/objc-opt.mm 53 | modified: runtime/objc-os.mm 54 | modified: runtime/objc-runtime-new.mm 55 | modified: runtime/objc-runtime.mm 56 | 57 | Untracked files: 58 | (use "git add ..." to include in what will be committed) 59 | .DS_Store 60 | include/.DS_Store 61 | lastGitDiff 62 | lastGitStatus 63 | objc.xcodeproj/project.xcworkspace/ 64 | objc.xcodeproj/xcuserdata/ 65 | 66 | -------------------------------------------------------------------------------- /objc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual C++ Express 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objc", "objc.vcproj", "{B3408263-0CF1-47BE-83CC-56070EFC9BC1}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objcrt", "objcrt\objcrt.vcproj", "{E38C1996-8B3D-4050-A4B2-DC85957B047D}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1} = {B3408263-0CF1-47BE-83CC-56070EFC9BC1} 9 | EndProjectSection 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Win32 = Debug|Win32 14 | DebugDLL|Win32 = DebugDLL|Win32 15 | Release|Win32 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.Build.0 = Debug|Win32 20 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 21 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 22 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.ActiveCfg = Release|Win32 23 | {B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.Build.0 = Release|Win32 24 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.Build.0 = Debug|Win32 26 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.ActiveCfg = Debug|Win32 27 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.Build.0 = Debug|Win32 28 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.ActiveCfg = Release|Win32 29 | {E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /objc.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /objc.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /objc4.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | preoptimizedCaches 6 | 7 | Enabled 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /objc_debug/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // objc_debug 4 | // 5 | // Created by 单晓辉 on 2022/2/14. 6 | // 7 | 8 | #import 9 | 10 | int main(int argc, const char * argv[]) { 11 | @autoreleasepool { 12 | // insert code here... 13 | NSLog(@"You can start debugging objc here\n"); 14 | NSLog(@"你可以开始debug objc了\n"); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /objcdt/json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 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 | #ifndef _OBJC_OBJCDT_JSON_H_ 25 | #define _OBJC_OBJCDT_JSON_H_ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace json { 33 | 34 | enum context: uint8_t { 35 | root, 36 | array_value, 37 | object_value, 38 | object_key, 39 | done, 40 | }; 41 | 42 | class writer { 43 | private: 44 | FILE *_file; 45 | context _context; 46 | int _depth; 47 | bool _needs_comma; 48 | 49 | void begin_value(int sep = '\0'); 50 | void advance(context old); 51 | void key(const char *key); 52 | 53 | public: 54 | 55 | writer(FILE *f); 56 | ~writer(); 57 | 58 | void object(std::function); 59 | void object(const char *key, std::function); 60 | 61 | void array(std::function); 62 | void array(const char *key, std::function); 63 | 64 | void boolean(bool value); 65 | void boolean(const char *key, bool value); 66 | 67 | void number(uint64_t value); 68 | void number(const char *key, uint64_t value); 69 | 70 | void string(const char *s); 71 | void string(const char *key, const char *s); 72 | 73 | __printflike(2, 3) 74 | void stringf(const char *fmt, ...); 75 | 76 | __printflike(3, 4) 77 | void stringf(const char *key, const char *fmt, ...); 78 | }; 79 | 80 | } 81 | 82 | #endif /* _OBJC_OBJCDT_JSON_H_ */ 83 | -------------------------------------------------------------------------------- /objcdt/objcdt-entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | task_for_pid-allow 6 | 7 | com.apple.system-task-ports 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /objcdt/objcdt.1: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2019, Apple Computer, Inc. All rights reserved. 2 | .\" 3 | .Dd September 9, 2019 \" DATE 4 | .Dt objcdt 1 \" Program name and manual section number 5 | .Os "OS X" 6 | .Sh NAME 7 | .Nm objcdt 8 | .Nd Tool to debug objective-C usage in live processes 9 | .Sh SYNOPSIS 10 | .Nm objcdt 11 | .Sh DESCRIPTION 12 | The 13 | .Nm 14 | utility is a small CLI with embedded help that can dump some information about 15 | the Objective-C runtime state in live processes. 16 | .Pp 17 | Help can be obtained using 18 | .Nm 19 | .Ar help 20 | -------------------------------------------------------------------------------- /objcdt/objcdt.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 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 | #include "objc-private.h" 25 | #include "objc-ptrauth.h" 26 | #include "NSObject-private.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int main(int argc, const char *argv[]) 35 | { 36 | return EX_UNAVAILABLE; 37 | } 38 | -------------------------------------------------------------------------------- /prebuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo prebuild: installing headers 4 | xcopy /Y "%ProjectDir%runtime\objc.h" "%DSTROOT%\AppleInternal\include\objc\" 5 | xcopy /Y "%ProjectDir%runtime\objc-api.h" "%DSTROOT%\AppleInternal\include\objc\" 6 | xcopy /Y "%ProjectDir%runtime\objc-auto.h" "%DSTROOT%\AppleInternal\include\objc\" 7 | xcopy /Y "%ProjectDir%runtime\objc-exception.h" "%DSTROOT%\AppleInternal\include\objc\" 8 | xcopy /Y "%ProjectDir%runtime\message.h" "%DSTROOT%\AppleInternal\include\objc\" 9 | xcopy /Y "%ProjectDir%runtime\runtime.h" "%DSTROOT%\AppleInternal\include\objc\" 10 | xcopy /Y "%ProjectDir%runtime\hashtable.h" "%DSTROOT%\AppleInternal\include\objc\" 11 | xcopy /Y "%ProjectDir%runtime\hashtable2.h" "%DSTROOT%\AppleInternal\include\objc\" 12 | xcopy /Y "%ProjectDir%runtime\maptable.h" "%DSTROOT%\AppleInternal\include\objc\" 13 | 14 | echo prebuild: setting version 15 | version 16 | -------------------------------------------------------------------------------- /runtime/Module/module.modulemap: -------------------------------------------------------------------------------- 1 | module ObjectiveC [system] [extern_c] { 2 | umbrella "." 3 | export * 4 | module * { 5 | export * 6 | } 7 | 8 | module NSObject { 9 | requires objc 10 | header "NSObject.h" 11 | export * 12 | } 13 | 14 | #if defined(BUILD_FOR_OSX) 15 | module List { 16 | // Uses @defs, which does not work in ObjC++ or non-ARC. 17 | requires objc, !objc_arc, !cplusplus 18 | header "List.h" 19 | export * 20 | } 21 | 22 | module Object { 23 | requires objc 24 | header "Object.h" 25 | export * 26 | } 27 | 28 | module Protocol { 29 | requires objc 30 | header "Protocol.h" 31 | export * 32 | } 33 | #endif 34 | 35 | #if !defined(BUILD_FOR_OSX) 36 | // These file are not available outside macOS. 37 | exclude header "hashtable.h" 38 | exclude header "hashtable2.h" 39 | #endif 40 | } 41 | -------------------------------------------------------------------------------- /runtime/ModulePrivate/module.modulemap: -------------------------------------------------------------------------------- 1 | module ObjectiveC_Private [system] { 2 | umbrella "." 3 | explicit module * { export * } 4 | } 5 | -------------------------------------------------------------------------------- /runtime/NSObjCRuntime.h: -------------------------------------------------------------------------------- 1 | /* NSObjCRuntime.h 2 | Copyright (c) 1994-2012, Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef _OBJC_NSOBJCRUNTIME_H_ 6 | #define _OBJC_NSOBJCRUNTIME_H_ 7 | 8 | #include 9 | #include 10 | 11 | #if __LP64__ || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 12 | typedef long NSInteger; 13 | typedef unsigned long NSUInteger; 14 | #else 15 | typedef int NSInteger; 16 | typedef unsigned int NSUInteger; 17 | #endif 18 | 19 | #define NSIntegerMax LONG_MAX 20 | #define NSIntegerMin LONG_MIN 21 | #define NSUIntegerMax ULONG_MAX 22 | 23 | #define NSINTEGER_DEFINED 1 24 | 25 | #ifndef NS_DESIGNATED_INITIALIZER 26 | #if __has_attribute(objc_designated_initializer) 27 | #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 28 | #else 29 | #define NS_DESIGNATED_INITIALIZER 30 | #endif 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /runtime/NSObject-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2021 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 | #ifndef _NSOBJECT_PRIVATE_H 25 | #define _NSOBJECT_PRIVATE_H 26 | 27 | #include "objc-private.h" 28 | #include "objc-weak.h" 29 | #include "DenseMapExtras.h" 30 | 31 | namespace { 32 | 33 | struct RefcountMapValuePurgeable { 34 | static inline bool isPurgeable(size_t x) { 35 | return x == 0; 36 | } 37 | }; 38 | 39 | // RefcountMap disguises its pointers because we 40 | // don't want the table to act as a root for `leaks`. 41 | typedef objc::DenseMap,size_t,RefcountMapValuePurgeable> RefcountMap; 42 | 43 | // Template parameters. 44 | enum HaveOld { DontHaveOld = false, DoHaveOld = true }; 45 | enum HaveNew { DontHaveNew = false, DoHaveNew = true }; 46 | 47 | struct SideTable { 48 | spinlock_t slock; 49 | RefcountMap refcnts; 50 | weak_table_t weak_table; 51 | 52 | SideTable() { 53 | memset(&weak_table, 0, sizeof(weak_table)); 54 | } 55 | 56 | ~SideTable() { 57 | _objc_fatal("Do not delete SideTable."); 58 | } 59 | 60 | void lock() { slock.lock(); } 61 | void unlock() { slock.unlock(); } 62 | void forceReset() { slock.forceReset(); } 63 | 64 | // Address-ordered lock discipline for a pair of side tables. 65 | 66 | template 67 | static void lockTwo(SideTable *lock1, SideTable *lock2); 68 | template 69 | static void unlockTwo(SideTable *lock1, SideTable *lock2); 70 | }; 71 | 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /runtime/Protocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2003, 2006-2007 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 | Protocol.h 25 | Copyright 1991-1996 NeXT Software, Inc. 26 | */ 27 | 28 | #ifndef _OBJC_PROTOCOL_H_ 29 | #define _OBJC_PROTOCOL_H_ 30 | 31 | #if !__OBJC__ 32 | 33 | // typedef Protocol is here: 34 | #include 35 | 36 | 37 | #elif __OBJC2__ 38 | 39 | #include 40 | 41 | // All methods of class Protocol are unavailable. 42 | // Use the functions in objc/runtime.h instead. 43 | 44 | OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0) 45 | @interface Protocol : NSObject 46 | @end 47 | 48 | #endif 49 | 50 | #endif /* _OBJC_PROTOCOL_H_ */ 51 | -------------------------------------------------------------------------------- /runtime/hashtable.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /runtime/objc-block-trampolines.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 | #ifndef _OBJC_TRAMPOLINES_H 26 | #define _OBJC_TRAMPOLINES_H 27 | 28 | /* 29 | * WARNING DANGER HAZARD BEWARE EEK 30 | * 31 | * Everything in this file is for Apple Internal use only. 32 | * These will change in arbitrary OS updates and in unpredictable ways. 33 | * When your program breaks, you get to keep both pieces. 34 | */ 35 | 36 | /* 37 | * objc-block-trampolines.h: Symbols for IMP block trampolines 38 | */ 39 | 40 | // WARNING: remapped code and dtrace do not play well together. Dtrace 41 | // will place trap instructions to instrument the code, which then get 42 | // remapped along with everything else. The remapped traps are not 43 | // recognized by dtrace and the process crashes. To avoid this, dtrace 44 | // blacklists this library by name. Do not change the name of this 45 | // library. rdar://problem/42627391 46 | 47 | #include 48 | 49 | OBJC_EXPORT const char _objc_blockTrampolineImpl 50 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0); 51 | 52 | OBJC_EXPORT const char _objc_blockTrampolineStart 53 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0); 54 | 55 | OBJC_EXPORT const char _objc_blockTrampolineLast 56 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0); 57 | 58 | 59 | OBJC_EXPORT const char _objc_blockTrampolineImpl_stret 60 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0) 61 | OBJC_ARM64_UNAVAILABLE; 62 | 63 | OBJC_EXPORT const char _objc_blockTrampolineStart_stret 64 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0) 65 | OBJC_ARM64_UNAVAILABLE; 66 | 67 | OBJC_EXPORT const char _objc_blockTrampolineLast_stret 68 | OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0) 69 | OBJC_ARM64_UNAVAILABLE; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /runtime/objc-cache-old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 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 | #ifndef _OBJC_CACHE_OLD_H 25 | #define _OBJC_CACHE_OLD_H 26 | 27 | #include "objc-private.h" 28 | 29 | __BEGIN_DECLS 30 | 31 | extern IMP _cache_getImp(Class cls, SEL sel); 32 | extern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp); 33 | 34 | extern void cache_init(void); 35 | extern void flush_cache(Class cls); 36 | extern bool _cache_fill(Class cls, Method meth, SEL sel); 37 | extern void _cache_addForwardEntry(Class cls, SEL sel); 38 | extern IMP _cache_addIgnoredEntry(Class cls, SEL sel); 39 | extern void _cache_free(Cache cache); 40 | extern void _cache_collect(bool collectALot); 41 | 42 | __END_DECLS 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /runtime/objc-class.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-file-old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 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 | #ifndef _OBJC_FILE_OLD_H 25 | #define _OBJC_FILE_OLD_H 26 | 27 | #if !__OBJC2__ 28 | 29 | #include "objc-os.h" 30 | 31 | struct objc_module; 32 | struct old_protocol; 33 | struct old_class; 34 | 35 | __BEGIN_DECLS 36 | 37 | extern struct objc_module *_getObjcModules(const header_info *hi, size_t *nmodules); 38 | extern SEL *_getObjcSelectorRefs(const header_info *hi, size_t *nmess); 39 | extern struct old_protocol **_getObjcProtocols(const header_info *hi, size_t *nprotos); 40 | extern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses); 41 | extern const char *_getObjcClassNames(const header_info *hi, size_t *size); 42 | 43 | using UnsignedInitializer = void(*)(void); 44 | extern UnsignedInitializer* getLibobjcInitializers(const headerType *mhdr, size_t *count); 45 | 46 | __END_DECLS 47 | 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /runtime/objc-initialize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005-2006 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 | #ifndef _OBJC_INITIALIZE_H 25 | #define _OBJC_INITIALIZE_H 26 | 27 | #include "objc-private.h" 28 | 29 | __BEGIN_DECLS 30 | 31 | struct _objc_initializing_classes; 32 | 33 | extern void initializeNonMetaClass(Class cls); 34 | 35 | extern void _destroyInitializingClassList(struct _objc_initializing_classes *list); 36 | 37 | extern bool _thisThreadIsInitializingClass(Class cls); 38 | 39 | __END_DECLS 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /runtime/objc-load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2001, 2005-2006 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 | * objc-load.h 25 | * Copyright 1988-1996, NeXT Software, Inc. 26 | */ 27 | 28 | #ifndef _OBJC_LOAD_H_ 29 | #define _OBJC_LOAD_H_ 30 | 31 | #include 32 | 33 | #include 34 | 35 | // This file intentionally left blank. 36 | 37 | #endif /* _OBJC_LOAD_H_ */ 38 | -------------------------------------------------------------------------------- /runtime/objc-loadmethod.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2006 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 | * objc-loadmethod.h 26 | * Support for +load methods. 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_LOADMETHOD_H 30 | #define _OBJC_LOADMETHOD_H 31 | 32 | #include "objc-private.h" 33 | 34 | __BEGIN_DECLS 35 | 36 | extern void add_class_to_loadable_list(Class cls); 37 | extern void add_category_to_loadable_list(Category cat); 38 | extern void remove_class_from_loadable_list(Class cls); 39 | extern void remove_category_from_loadable_list(Category cat); 40 | 41 | extern void call_load_methods(void); 42 | 43 | __END_DECLS 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /runtime/objc-locks-new.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 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 | * objc-locks-new.h 26 | * Declarations of all locks used in the runtime. 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_LOCKS_NEW_H 30 | #define _OBJC_LOCKS_NEW_H 31 | 32 | // fork() safety requires careful tracking of all locks used in the runtime. 33 | // Thou shalt not declare any locks outside this file. 34 | 35 | extern mutex_t runtimeLock; 36 | extern mutex_t DemangleCacheLock; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /runtime/objc-locks-old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 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 | * objc-locks-old.h 26 | * Declarations of all locks used in the runtime. 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_LOCKS_OLD_H 30 | #define _OBJC_LOCKS_OLD_H 31 | 32 | // fork() safety requires careful tracking of all locks used in the runtime. 33 | // Thou shalt not declare any locks outside this file. 34 | 35 | extern mutex_t classLock; 36 | extern mutex_t methodListLock; 37 | extern mutex_t NXUniqueStringLock; 38 | extern spinlock_t impLock; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /runtime/objc-locks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 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 | * objc-locks.h 26 | * Declarations of all locks used in the runtime. 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_LOCKS_H 30 | #define _OBJC_LOCKS_H 31 | 32 | // fork() safety requires careful tracking of all locks used in the runtime. 33 | // Thou shalt not declare any locks outside this file. 34 | 35 | // Lock ordering is declared in _objc_fork_prepare() 36 | // and is enforced by lockdebug. 37 | 38 | extern monitor_t classInitLock; 39 | extern mutex_t selLock; 40 | #if CONFIG_USE_CACHE_LOCK 41 | extern mutex_t cacheUpdateLock; 42 | #endif 43 | extern recursive_mutex_t loadMethodLock; 44 | extern mutex_t crashlog_lock; 45 | extern spinlock_t objcMsgLogLock; 46 | extern mutex_t AltHandlerDebugLock; 47 | extern mutex_t AssociationsManagerLock; 48 | extern StripedMap PropertyLocks; 49 | extern StripedMap StructLocks; 50 | extern StripedMap CppObjectLocks; 51 | 52 | // SideTable lock is buried awkwardly. Call a function to manipulate it. 53 | extern void SideTableLockAll(); 54 | extern void SideTableUnlockAll(); 55 | extern void SideTableForceResetAll(); 56 | extern void SideTableDefineLockOrder(); 57 | extern void SideTableLocksPrecedeLock(const void *newlock); 58 | extern void SideTableLocksSucceedLock(const void *oldlock); 59 | extern void SideTableLocksPrecedeLocks(StripedMap& newlocks); 60 | extern void SideTableLocksSucceedLocks(StripedMap& oldlocks); 61 | 62 | #if __OBJC2__ 63 | #include "objc-locks-new.h" 64 | #else 65 | #include "objc-locks-old.h" 66 | #endif 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /runtime/objc-probes.d: -------------------------------------------------------------------------------- 1 | provider objc_runtime 2 | { 3 | probe objc_exception_throw(void *id); 4 | probe objc_exception_rethrow(); 5 | }; 6 | -------------------------------------------------------------------------------- /runtime/objc-references.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 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 | * objc-references.h 25 | */ 26 | 27 | #ifndef _OBJC_REFERENCES_H_ 28 | #define _OBJC_REFERENCES_H_ 29 | 30 | #include "objc-api.h" 31 | #include "objc-config.h" 32 | 33 | __BEGIN_DECLS 34 | 35 | extern void _objc_associations_init(); 36 | extern void _object_set_associative_reference(id object, const void *key, id value, uintptr_t policy); 37 | extern id _object_get_associative_reference(id object, const void *key); 38 | extern void _object_remove_assocations(id object, bool deallocating); 39 | 40 | __END_DECLS 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /runtime/objc-runtime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-sel-set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004 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 | * objc-sel-set.h 26 | * A set of SELs used for SEL uniquing. 27 | */ 28 | 29 | #ifndef _OBJC_SEL_SET_H_ 30 | #define _OBJC_SEL_SET_H_ 31 | 32 | #if !__OBJC2__ 33 | 34 | #include 35 | #include "objc-os.h" 36 | 37 | __BEGIN_DECLS 38 | 39 | struct __objc_sel_set; 40 | 41 | extern struct __objc_sel_set *__objc_sel_set_create(size_t selrefCount); 42 | extern SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate); 43 | extern void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value); 44 | 45 | __END_DECLS 46 | 47 | #endif 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /runtime/objc-sel-table.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if __LP64__ 5 | #if __arm64e__ 6 | // 0x6AE1 7 | # define PTR(x) .quad x@AUTH(da, 27361, addr) 8 | #else 9 | # define PTR(x) .quad x 10 | #endif 11 | #else 12 | # define PTR(x) .long x 13 | #endif 14 | 15 | // These offsets are populated by the dyld shared cache builder. 16 | // They point to memory allocatd elsewhere in the shared cache. 17 | 18 | .section __TEXT,__objc_opt_ro 19 | .align 3 20 | .private_extern __objc_opt_data 21 | __objc_opt_data: 22 | .long 16 /* table.version */ 23 | .long 0 /* table.flags */ 24 | .long 0 /* table.selopt_offset */ 25 | .long 0 /* table.headeropt_ro_offset */ 26 | .long 0 /* table.clsopt_offset */ 27 | .long 0 /* table.protocolopt_offset */ 28 | .long 0 /* table.headeropt_rw_offset */ 29 | .long 0 /* table.unused_protocolopt2_offset */ 30 | .long 0 /* table.largeSharedCachesClassOffset */ 31 | .long 0 /* table.largeSharedCachesProtocolOffset */ 32 | .space PAGE_MAX_SIZE-40 33 | 34 | 35 | /* section of pointers that the shared cache optimizer wants to know about */ 36 | .section __DATA,__objc_opt_ptrs 37 | .align 3 38 | 39 | #if TARGET_OS_OSX && __i386__ 40 | // old ABI 41 | .globl .objc_class_name_Protocol 42 | PTR(.objc_class_name_Protocol) 43 | #else 44 | // new ABI 45 | .globl _OBJC_CLASS_$_Protocol 46 | PTR(_OBJC_CLASS_$_Protocol) 47 | #endif 48 | -------------------------------------------------------------------------------- /runtime/objc-sync.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2002, 2006 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 | #ifndef __OBJC_SNYC_H_ 25 | #define __OBJC_SNYC_H_ 26 | 27 | #include 28 | 29 | 30 | /** 31 | * Begin synchronizing on 'obj'. 32 | * Allocates recursive pthread_mutex associated with 'obj' if needed. 33 | * 34 | * @param obj The object to begin synchronizing on. 35 | * 36 | * @return OBJC_SYNC_SUCCESS once lock is acquired. 37 | */ 38 | OBJC_EXPORT int 39 | objc_sync_enter(id _Nonnull obj) 40 | OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0); 41 | 42 | /** 43 | * End synchronizing on 'obj'. 44 | * 45 | * @param obj The object to end synchronizing on. 46 | * 47 | * @return OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR 48 | */ 49 | OBJC_EXPORT int 50 | objc_sync_exit(id _Nonnull obj) 51 | OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0); 52 | 53 | enum { 54 | OBJC_SYNC_SUCCESS = 0, 55 | OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1 56 | }; 57 | 58 | 59 | #endif // __OBJC_SYNC_H_ 60 | -------------------------------------------------------------------------------- /runtime/objcrt.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBJC_RT_H_ 2 | #define _OBJC_RT_H_ 3 | 4 | #include 5 | 6 | 7 | typedef struct { 8 | int count; // number of pointer pairs that follow 9 | void *modStart; 10 | void *modEnd; 11 | void *protoStart; 12 | void *protoEnd; 13 | void *iiStart; 14 | void *iiEnd; 15 | void *selrefsStart; 16 | void *selrefsEnd; 17 | void *clsrefsStart; 18 | void *clsrefsEnd; 19 | } objc_sections; 20 | 21 | OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects); 22 | OBJC_EXPORT void _objc_load_image(HMODULE image, void *hinfo); 23 | OBJC_EXPORT void _objc_unload_image(HMODULE image, void *hinfo); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/ARCBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // ARCBase.h 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ARCMisalign : NSObject { 12 | char misalign1; 13 | } 14 | @end 15 | 16 | @interface ARCBase : ARCMisalign 17 | @property long number; 18 | @property(retain) id object; 19 | @property void *pointer; 20 | @property(weak) __weak id delegate; 21 | @end 22 | -------------------------------------------------------------------------------- /test/ARCBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // ARCBase.m 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ARCBase.h" 10 | 11 | // ARCMisalign->misalign1 and ARCBase->misalign2 together cause 12 | // ARCBase's instanceStart to be misaligned, which exercises handling 13 | // of storage that is not represented in the class's ivar layout bitmaps. 14 | 15 | @implementation ARCMisalign 16 | @end 17 | 18 | @interface ARCBase () { 19 | @private 20 | char misalign2; 21 | long number; 22 | id object; 23 | void *pointer; 24 | __weak id delegate; 25 | } 26 | @end 27 | 28 | @implementation ARCBase 29 | @synthesize number, object, pointer, delegate; 30 | @end 31 | -------------------------------------------------------------------------------- /test/ARCLayoutsWithoutWeak.m: -------------------------------------------------------------------------------- 1 | // Same as test ARCLayouts but with MRC __weak support disabled. 2 | /* 3 | TEST_CONFIG MEM=arc 4 | TEST_BUILD 5 | mkdir -p $T{OBJDIR} 6 | $C{COMPILE_NOLINK_NOMEM} -c $DIR/MRCBase.m -o $T{OBJDIR}/MRCBase.o -fno-objc-weak 7 | $C{COMPILE_NOLINK_NOMEM} -c $DIR/MRCARC.m -o $T{OBJDIR}/MRCARC.o -fno-objc-weak 8 | $C{COMPILE_NOLINK} -c $DIR/ARCBase.m -o $T{OBJDIR}/ARCBase.o 9 | $C{COMPILE_NOLINK} -c $DIR/ARCMRC.m -o $T{OBJDIR}/ARCMRC.o 10 | $C{COMPILE} '-DNAME=\"ARCLayoutsWithoutWeak.m\"' -fobjc-arc $DIR/ARCLayouts.m -x none $T{OBJDIR}/MRCBase.o $T{OBJDIR}/MRCARC.o $T{OBJDIR}/ARCBase.o $T{OBJDIR}/ARCMRC.o -framework Foundation -o ARCLayoutsWithoutWeak.exe 11 | END 12 | */ 13 | -------------------------------------------------------------------------------- /test/ARCMRC.h: -------------------------------------------------------------------------------- 1 | // 2 | // ARCMRC.h 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MRCBase.h" 10 | 11 | @interface ARCMRC : MRCBase 12 | @property(retain) id dataSource; 13 | @end 14 | -------------------------------------------------------------------------------- /test/ARCMRC.m: -------------------------------------------------------------------------------- 1 | // 2 | // ARCMRC.m 3 | // 4 | 5 | #import "ARCMRC.h" 6 | 7 | @implementation ARCMRC 8 | 9 | @synthesize dataSource; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /test/MRCARC.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRCARC.h 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ARCBase.h" 10 | 11 | @interface MRCARC : ARCBase 12 | @property(retain) id dataSource; 13 | @end 14 | -------------------------------------------------------------------------------- /test/MRCARC.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRCARC.m 3 | // 4 | 5 | #import "MRCARC.h" 6 | 7 | @implementation MRCARC 8 | 9 | @synthesize dataSource; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /test/MRCBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRCBase.h 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // YES if MRC compiler supports ARC-style weak 12 | extern bool supportsMRCWeak; 13 | 14 | #if __LP64__ 15 | #define DOUBLEWORD_ALIGNED __attribute__((aligned(16))) 16 | #else 17 | #define DOUBLEWORD_ALIGNED __attribute__((aligned(8))) 18 | #endif 19 | 20 | @interface MRCBase : NSObject 21 | @property double number; 22 | @property(retain) id object; 23 | @property void *pointer; 24 | @property(weak) __weak id delegate; 25 | @end 26 | 27 | // Call object_copy from MRC. 28 | extern id __attribute__((ns_returns_retained)) docopy(id obj); 29 | -------------------------------------------------------------------------------- /test/MRCBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRCBase.m 3 | // TestARCLayouts 4 | // 5 | // Created by Patrick Beard on 3/8/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #include "MRCBase.h" 10 | #include "test.h" 11 | 12 | // MRCBase->alignment ensures that there is a gap between the end of 13 | // NSObject's ivars and the start of MRCBase's ivars, which exercises 14 | // handling of storage that is not represented in any class's ivar 15 | // layout bitmaps. 16 | 17 | #if __has_feature(objc_arc_weak) 18 | bool supportsMRCWeak = true; 19 | #else 20 | bool supportsMRCWeak = false; 21 | #endif 22 | 23 | @interface MRCBase () { 24 | @private 25 | double DOUBLEWORD_ALIGNED alignment; 26 | uintptr_t pad[3]; // historically this made OBJC2 layout bitmaps match OBJC1 27 | double number; 28 | id object; 29 | void *pointer; 30 | #if __has_feature(objc_arc_weak) 31 | __weak 32 | #endif 33 | id delegate; 34 | } 35 | @end 36 | 37 | @implementation MRCBase 38 | @synthesize number, object, pointer, delegate; 39 | @end 40 | 41 | // Call object_copy from MRC. 42 | extern id __attribute__((ns_returns_retained)) 43 | docopy(id obj) 44 | { 45 | return object_copy(obj, 0); 46 | } 47 | -------------------------------------------------------------------------------- /test/accessors.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #import 4 | #import 5 | #import 6 | #include "test.h" 7 | 8 | @interface Test : NSObject { 9 | NSString *_value; 10 | // _object is at the last optimized property offset 11 | id _object __attribute__((aligned(64))); 12 | } 13 | @property(readonly) Class cls; 14 | @property(copy) NSString *value; 15 | @property(assign) id object; 16 | @end 17 | 18 | typedef struct { 19 | void *isa; 20 | void *_value; 21 | // _object is at the last optimized property offset 22 | void *_object __attribute__((aligned(64))); 23 | } TestDefs; 24 | 25 | @implementation Test 26 | 27 | // Question: why can't this code be automatically generated? 28 | 29 | #if !__has_feature(objc_arc) 30 | - (void)dealloc { 31 | self.value = nil; 32 | self.object = nil; 33 | [super dealloc]; 34 | } 35 | #endif 36 | 37 | - (Class)cls { return objc_getProperty(self, _cmd, 0, YES); } 38 | 39 | - (NSString*)value { return (NSString*) objc_getProperty(self, _cmd, offsetof(TestDefs, _value), YES); } 40 | - (void)setValue:(NSString*)inValue { objc_setProperty(self, _cmd, offsetof(TestDefs, _value), inValue, YES, YES); } 41 | 42 | - (id)object { return objc_getProperty(self, _cmd, offsetof(TestDefs, _object), YES); } 43 | - (void)setObject:(id)inObject { objc_setProperty(self, _cmd, offsetof(TestDefs, _object), inObject, YES, NO); } 44 | 45 | - (NSString *)description { 46 | return [NSString stringWithFormat:@"value = %@, object = %@", self.value, self.object]; 47 | } 48 | 49 | @end 50 | 51 | int main() { 52 | PUSH_POOL { 53 | 54 | NSMutableString *value = [NSMutableString stringWithUTF8String:"test"]; 55 | id object = [NSNumber numberWithInt:11]; 56 | Test *t = AUTORELEASE([Test new]); 57 | t.value = value; 58 | [value setString:@"yuck"]; // mutate the string. 59 | testassert(t.value != value); // must copy, since it was mutable. 60 | testassert([t.value isEqualToString:@"test"]); 61 | 62 | Class testClass = [Test class]; 63 | Class cls = t.cls; 64 | testassert(testClass == cls); 65 | cls = t.cls; 66 | testassert(testClass == cls); 67 | 68 | t.object = object; 69 | t.object = object; 70 | 71 | // NSLog(@"t.object = %@, t.value = %@", t.object, t.value); 72 | // NSLog(@"t.object = %@, t.value = %@", t.object, t.value); // second call will optimized getters. 73 | 74 | } POP_POOL; 75 | 76 | succeed(__FILE__); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /test/applescriptobjc.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=macosx 2 | // TEST_CFLAGS -framework AppleScriptObjC -framework Foundation 3 | 4 | // Verify that trivial AppleScriptObjC apps run with GC off. 5 | 6 | #include 7 | #include "test.h" 8 | 9 | int main() 10 | { 11 | [NSBundle class]; 12 | succeed(__FILE__); 13 | } 14 | -------------------------------------------------------------------------------- /test/arr-cast.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | // objc.h redefines these calls into bridge casts. 6 | // This test verifies that the function implementations are exported. 7 | __BEGIN_DECLS 8 | extern void *retainedObject(void *arg) __asm__("_objc_retainedObject"); 9 | extern void *unretainedObject(void *arg) __asm__("_objc_unretainedObject"); 10 | extern void *unretainedPointer(void *arg) __asm__("_objc_unretainedPointer"); 11 | __END_DECLS 12 | 13 | int main() 14 | { 15 | void *p = (void*)&main; 16 | testassert(p == retainedObject(p)); 17 | testassert(p == unretainedObject(p)); 18 | testassert(p == unretainedPointer(p)); 19 | succeed(__FILE__); 20 | } 21 | -------------------------------------------------------------------------------- /test/asm-placeholder.s: -------------------------------------------------------------------------------- 1 | .macro NOP16 2 | nop 3 | nop 4 | nop 5 | nop 6 | nop 7 | nop 8 | nop 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | .endmacro 19 | 20 | .macro NOP256 21 | NOP16 22 | NOP16 23 | NOP16 24 | NOP16 25 | NOP16 26 | NOP16 27 | NOP16 28 | NOP16 29 | NOP16 30 | NOP16 31 | NOP16 32 | NOP16 33 | NOP16 34 | NOP16 35 | NOP16 36 | NOP16 37 | .endmacro 38 | 39 | .text 40 | .globl _main 41 | .align 14 42 | _main: 43 | // at least 1024 instruction bytes on all architectures 44 | NOP256 45 | NOP256 46 | NOP256 47 | NOP256 48 | -------------------------------------------------------------------------------- /test/association-cf.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework CoreFoundation 2 | // TEST_CONFIG MEM=mrc 3 | // not for ARC because ARC memory management doesn't 4 | // work on CF types whose ObjC side is not yet loaded 5 | 6 | #include 7 | #include 8 | 9 | #include "test.h" 10 | 11 | #if __has_feature(objc_arc) 12 | 13 | int main() 14 | { 15 | testwarn("rdar://11368528 confused by Foundation"); 16 | succeed(__FILE__); 17 | } 18 | 19 | #else 20 | 21 | int main() 22 | { 23 | // rdar://6164781 setAssociatedObject on unresolved future class crashes 24 | 25 | id mp = (id)CFMachPortCreate(0, 0, 0, 0); 26 | testassert(mp); 27 | 28 | testassert(! objc_getClass("NSMachPort")); 29 | 30 | objc_setAssociatedObject(mp, (void*)1, mp, OBJC_ASSOCIATION_ASSIGN); 31 | 32 | id obj = objc_getAssociatedObject(mp, (void*)1); 33 | testassert(obj == mp); 34 | 35 | CFRelease((CFTypeRef)mp); 36 | 37 | succeed(__FILE__); 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /test/associationForbidden.h: -------------------------------------------------------------------------------- 1 | #include "testroot.i" 2 | 3 | @interface Normal : TestRoot 4 | @end 5 | @implementation Normal 6 | @end 7 | 8 | @interface Forbidden : TestRoot 9 | @end 10 | @implementation Forbidden 11 | @end 12 | 13 | struct minimal_unrealized_class { 14 | void *isa; 15 | void *superclass; 16 | void *cachePtr; 17 | uintptr_t maskAndOccupied; 18 | struct minimal_class_ro *ro; 19 | }; 20 | 21 | struct minimal_class_ro { 22 | uint32_t flags; 23 | }; 24 | 25 | extern struct minimal_unrealized_class OBJC_CLASS_$_Forbidden; 26 | 27 | #define RO_FORBIDS_ASSOCIATED_OBJECTS (1<<10) 28 | 29 | static void *key = &key; 30 | 31 | static void test(void); 32 | 33 | int main() 34 | { 35 | struct minimal_unrealized_class *localForbidden = &OBJC_CLASS_$_Forbidden; 36 | localForbidden->ro->flags |= RO_FORBIDS_ASSOCIATED_OBJECTS; 37 | test(); 38 | } 39 | 40 | static inline void ShouldSucceed(id obj) { 41 | objc_setAssociatedObject(obj, key, obj, OBJC_ASSOCIATION_ASSIGN); 42 | id assoc = objc_getAssociatedObject(obj, key); 43 | fprintf(stderr, "Associated object is %p\n", assoc); 44 | testassert(obj == assoc); 45 | } 46 | 47 | static inline void ShouldFail(id obj) { 48 | objc_setAssociatedObject(obj, key, obj, OBJC_ASSOCIATION_ASSIGN); 49 | fail("should have crashed trying to set the associated object"); 50 | } 51 | -------------------------------------------------------------------------------- /test/associationForbidden.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | Associated object is 0x[0-9a-fA-F]+ 5 | objc\[\d+\]: objc_setAssociatedObject called on instance \(0x[0-9a-fA-F]+\) of class Forbidden which does not allow associated objects 6 | objc\[\d+\]: HALTED 7 | END 8 | */ 9 | 10 | #include "associationForbidden.h" 11 | 12 | void test(void) 13 | { 14 | ShouldSucceed([Normal alloc]); 15 | ShouldFail([Forbidden alloc]); 16 | } 17 | -------------------------------------------------------------------------------- /test/associationForbidden2.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | Associated object is 0x[0-9a-fA-F]+ 5 | objc\[\d+\]: objc_setAssociatedObject called on instance \(0x[0-9a-fA-F]+\) of class ForbiddenSubclass which does not allow associated objects 6 | objc\[\d+\]: HALTED 7 | END 8 | */ 9 | 10 | #include "associationForbidden.h" 11 | 12 | void test(void) 13 | { 14 | ShouldSucceed([Normal alloc]); 15 | Class ForbiddenSubclass = objc_allocateClassPair([Forbidden class], 16 | "ForbiddenSubclass", 0); 17 | objc_registerClassPair(ForbiddenSubclass); 18 | ShouldFail([ForbiddenSubclass alloc]); 19 | } 20 | -------------------------------------------------------------------------------- /test/associationForbidden3.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | Associated object is 0x[0-9a-fA-F]+ 5 | objc\[\d+\]: objc_setAssociatedObject called on instance \(0x[0-9a-fA-F]+\) of class ForbiddenSubclass which does not allow associated objects 6 | objc\[\d+\]: HALTED 7 | END 8 | */ 9 | 10 | #include "associationForbidden.h" 11 | 12 | @interface ForbiddenSubclass : Forbidden 13 | @end 14 | @implementation ForbiddenSubclass 15 | @end 16 | 17 | void test(void) 18 | { 19 | ShouldSucceed([Normal alloc]); 20 | ShouldSucceed([ForbiddenSubclass alloc]); 21 | } 22 | -------------------------------------------------------------------------------- /test/associationForbidden4.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | Associated object is 0x[0-9a-fA-F]+ 5 | objc\[\d+\]: objc_setAssociatedObject called on instance \(0x[0-9a-fA-F]+\) of class ForbiddenDuplicate which does not allow associated objects 6 | objc\[\d+\]: HALTED 7 | END 8 | */ 9 | 10 | #include "associationForbidden.h" 11 | 12 | void test(void) 13 | { 14 | ShouldSucceed([Normal alloc]); 15 | Class ForbiddenDuplicate = objc_duplicateClass([Forbidden class], 16 | "ForbiddenDuplicate", 0); 17 | ShouldFail([ForbiddenDuplicate alloc]); 18 | } 19 | -------------------------------------------------------------------------------- /test/atomicProperty.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #import 7 | 8 | class SerialNumber { 9 | size_t _number; 10 | public: 11 | SerialNumber() : _number(42) {} 12 | SerialNumber(const SerialNumber &number) : _number(number._number + 1) {} 13 | SerialNumber &operator=(const SerialNumber &number) { _number = number._number + 1; return *this; } 14 | 15 | int operator==(const SerialNumber &number) { return _number == number._number; } 16 | int operator!=(const SerialNumber &number) { return _number != number._number; } 17 | }; 18 | 19 | @interface TestAtomicProperty : NSObject { 20 | SerialNumber number; 21 | } 22 | @property(atomic) SerialNumber number; 23 | @end 24 | 25 | @implementation TestAtomicProperty 26 | 27 | @synthesize number; 28 | 29 | @end 30 | 31 | int main() 32 | { 33 | PUSH_POOL { 34 | SerialNumber number; 35 | TestAtomicProperty *test = [TestAtomicProperty new]; 36 | test.number = number; 37 | testassert(test.number != number); 38 | } POP_POOL; 39 | 40 | succeed(__FILE__); 41 | } 42 | -------------------------------------------------------------------------------- /test/badCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_RUN_OUTPUT 4 | arm 5 | OK: badCache.m 6 | OR 7 | crash now 8 | objc\[\d+\]: Method cache corrupted.* 9 | objc\[\d+\]: .* 10 | objc\[\d+\]: .* 11 | objc\[\d+\]: .* 12 | objc\[\d+\]: .* 13 | objc\[\d+\]: Method cache corrupted.* 14 | objc\[\d+\]: HALTED 15 | END 16 | */ 17 | 18 | 19 | #include "test.h" 20 | 21 | // Test objc_msgSend's detection of infinite loops during cache scan. 22 | 23 | #if __arm__ 24 | 25 | int main() 26 | { 27 | testwarn("objc_msgSend on arm doesn't detect infinite loops"); 28 | fprintf(stderr, "arm\n"); 29 | succeed(__FILE__); 30 | } 31 | 32 | #else 33 | 34 | #include "testroot.i" 35 | 36 | #if __LP64__ 37 | typedef uint32_t mask_t; 38 | #else 39 | typedef uint16_t mask_t; 40 | #endif 41 | 42 | struct bucket_t { 43 | uintptr_t sel; 44 | uintptr_t imp; 45 | }; 46 | 47 | struct cache_t { 48 | uintptr_t buckets; 49 | mask_t mask; 50 | mask_t occupied; 51 | }; 52 | 53 | struct class_t { 54 | void *isa; 55 | void *supercls; 56 | struct cache_t cache; 57 | }; 58 | 59 | @interface Subclass : TestRoot @end 60 | @implementation Subclass @end 61 | 62 | int main() 63 | { 64 | Class cls = [TestRoot class]; 65 | id obj = [cls new]; 66 | [obj self]; 67 | 68 | struct cache_t *cache = &((__bridge struct class_t *)cls)->cache; 69 | 70 | // Figure out which cache mask scheme is in use by examining the existing bits. 71 | int low4 = 0; 72 | #if __LP64__ 73 | int top16 = 0; 74 | #endif 75 | int outlined = 0; 76 | 77 | if (cache->buckets & 0xf) { 78 | low4 = 1; 79 | #if __LP64__ 80 | } else if ((cache->buckets & (0xffffULL << 48))) { 81 | top16 = 1; 82 | #endif 83 | } else { 84 | outlined = 1; 85 | } 86 | 87 | # define COUNT 4 88 | # define COUNTSHIFT 14 89 | struct bucket_t *buckets = (struct bucket_t *)calloc(sizeof(struct bucket_t), COUNT+1); 90 | for (int i = 0; i < COUNT; i++) { 91 | buckets[i].sel = ~0; 92 | buckets[i].imp = ~0; 93 | } 94 | buckets[COUNT].sel = 1; 95 | buckets[COUNT].imp = (uintptr_t)buckets; 96 | 97 | if (low4) { 98 | cache->buckets = (uintptr_t)buckets | COUNTSHIFT; 99 | #if __LP64__ 100 | } else if (top16) { 101 | cache->buckets = ((uintptr_t)(COUNT - 1) << 48) | (uintptr_t)buckets; 102 | #endif 103 | } else if (outlined) { 104 | cache->mask = COUNT-1; 105 | cache->buckets = (uintptr_t)buckets; 106 | } 107 | 108 | cache->occupied = 0; 109 | 110 | fprintf(stderr, "crash now\n"); 111 | [obj self]; 112 | 113 | fail("should have crashed"); 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /test/badPool.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | // TEST_CRASHES 3 | 4 | // Test badPoolCompat also uses this file. 5 | 6 | /* 7 | TEST_RUN_OUTPUT 8 | objc\[\d+\]: [Ii]nvalid or prematurely-freed autorelease pool 0x[0-9a-fA-F]+\.? 9 | objc\[\d+\]: HALTED 10 | END 11 | */ 12 | 13 | #include "test.h" 14 | 15 | int main() 16 | { 17 | void *outer = objc_autoreleasePoolPush(); 18 | void *inner = objc_autoreleasePoolPush(); 19 | objc_autoreleasePoolPop(outer); 20 | objc_autoreleasePoolPop(inner); 21 | 22 | #if !OLD 23 | fail("should have crashed already with new SDK"); 24 | #else 25 | // should only warn once 26 | outer = objc_autoreleasePoolPush(); 27 | inner = objc_autoreleasePoolPush(); 28 | objc_autoreleasePoolPop(outer); 29 | objc_autoreleasePoolPop(inner); 30 | 31 | succeed(__FILE__); 32 | #endif 33 | } 34 | 35 | -------------------------------------------------------------------------------- /test/badPoolCompat-ios.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=iphoneos,iphonesimulator ARCH=x86_64,arm64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker ios -Xlinker 9.0 -Xlinker 9.0 -miphoneos-version-min=9.0 6 | 7 | /* 8 | TEST_BUILD_OUTPUT 9 | ld: warning: passed two min versions.*for platform.* 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* Proceeding anyway .* 14 | OK: badPool.m 15 | END 16 | */ 17 | 18 | #include "badPool.m" 19 | -------------------------------------------------------------------------------- /test/badPoolCompat-macos.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=macosx ARCH=x86_64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker macos -Xlinker 10.11 -Xlinker 10.11 -mmacosx-version-min=10.11 6 | 7 | /* 8 | TEST_BUILD_OUTPUT 9 | ld: warning: passed two min versions.*for platform.* 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* Proceeding anyway .* 14 | OK: badPool.m 15 | END 16 | */ 17 | 18 | #include "badPool.m" 19 | -------------------------------------------------------------------------------- /test/badPoolCompat-tvos.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=appletvos,appletvsimulator ARCH=x86_64,arm64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker tvos -Xlinker 9.0 -Xlinker 9.0 -mtvos-version-min=9.0 6 | 7 | /* 8 | TEST_BUILD_OUTPUT 9 | ld: warning: passed two min versions.*for platform.* 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* Proceeding anyway .* 14 | OK: badPool.m 15 | END 16 | */ 17 | 18 | #include "badPool.m" 19 | -------------------------------------------------------------------------------- /test/badPoolCompat-watchos.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=watchos,watchsimulator 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker watchos -Xlinker 2.0 -Xlinker 2.0 -mwatchos-version-min=2.0 6 | 7 | /* 8 | TEST_BUILD_OUTPUT 9 | ld: warning: passed two min versions.*for platform.* 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* Proceeding anyway .* 14 | OK: badPool.m 15 | END 16 | */ 17 | 18 | #include "badPool.m" 19 | -------------------------------------------------------------------------------- /test/badSuperclass.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: Memory corruption in class list\. 5 | objc\[\d+\]: HALTED 6 | END 7 | */ 8 | 9 | #include "test.h" 10 | #include "testroot.i" 11 | 12 | @interface Super : TestRoot @end 13 | @implementation Super @end 14 | 15 | @interface Sub : Super @end 16 | @implementation Sub @end 17 | 18 | int main() 19 | { 20 | alarm(10); 21 | 22 | Class supercls = [Super class]; 23 | Class subcls = [Sub class]; 24 | id subobj __unused = [Sub alloc]; 25 | 26 | // Create a cycle in a superclass chain (Sub->supercls == Sub) 27 | // then attempt to walk that chain. Runtime should halt eventually. 28 | _objc_flush_caches(supercls); 29 | ((Class __ptrauth_objc_super_pointer *)(__bridge void *)subcls)[1] = subcls; 30 | #ifdef CACHE_FLUSH 31 | _objc_flush_caches(supercls); 32 | #else 33 | [subobj class]; 34 | #endif 35 | 36 | fail("should have crashed"); 37 | } 38 | -------------------------------------------------------------------------------- /test/badSuperclass2.m: -------------------------------------------------------------------------------- 1 | // TEST_CRASHES 2 | /* 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: Memory corruption in class list\. 5 | objc\[\d+\]: HALTED 6 | OR 7 | old abi 8 | OK: badSuperclass\.m 9 | END 10 | */ 11 | 12 | #define CACHE_FLUSH 13 | #include "badSuperclass.m" 14 | -------------------------------------------------------------------------------- /test/badTagClass.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_BUILD_OUTPUT 4 | .*badTagClass.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\] 5 | END 6 | TEST_RUN_OUTPUT 7 | objc\[\d+\]: tag index 1 used for two different classes \(was 0x[0-9a-fA-F]+ NSObject, now 0x[0-9a-fA-F]+ TestRoot\) 8 | objc\[\d+\]: HALTED 9 | OR 10 | no tagged pointers 11 | OK: badTagClass.m 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | #include "testroot.i" 17 | 18 | #include 19 | #include 20 | 21 | #if OBJC_HAVE_TAGGED_POINTERS 22 | 23 | int main() 24 | { 25 | // re-registration and nil registration allowed 26 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 27 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 28 | _objc_registerTaggedPointerClass(OBJC_TAG_1, nil); 29 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 30 | 31 | // colliding registration disallowed 32 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [TestRoot class]); 33 | 34 | fail(__FILE__); 35 | } 36 | 37 | #else 38 | 39 | int main() 40 | { 41 | // provoke the same nullability warning as the real test 42 | objc_getClass(nil); 43 | 44 | fprintf(stderr, "no tagged pointers\n"); 45 | succeed(__FILE__); 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /test/badTagIndex.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CRASHES 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: tag index 264 is invalid 5 | objc\[\d+\]: HALTED 6 | OR 7 | no tagged pointers 8 | OK: badTagIndex.m 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | 14 | #include 15 | #include 16 | 17 | #if OBJC_HAVE_TAGGED_POINTERS 18 | 19 | int main() 20 | { 21 | _objc_registerTaggedPointerClass((objc_tag_index_t)(OBJC_TAG_Last52BitPayload+1), [NSObject class]); 22 | fail(__FILE__); 23 | } 24 | 25 | #else 26 | 27 | int main() 28 | { 29 | fprintf(stderr, "no tagged pointers\n"); 30 | succeed(__FILE__); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /test/bigrc.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | static size_t LOTS; 7 | 8 | @interface Deallocator : TestRoot @end 9 | @implementation Deallocator 10 | 11 | -(void)dealloc 12 | { 13 | id o = self; 14 | 15 | 16 | testprintf("Retain/release during dealloc\n"); 17 | 18 | testassertequal([o retainCount], 0); 19 | [o retain]; 20 | testassertequal([o retainCount], 0); 21 | [o release]; 22 | testassertequal([o retainCount], 0); 23 | 24 | [super dealloc]; 25 | } 26 | 27 | @end 28 | 29 | size_t clz(uintptr_t isa) { 30 | if (sizeof(uintptr_t) == 4) 31 | return __builtin_clzl(isa); 32 | testassert(sizeof(uintptr_t) == 8); 33 | return __builtin_clzll(isa); 34 | } 35 | 36 | int main() 37 | { 38 | Deallocator *o = [Deallocator new]; 39 | size_t rc = 1; 40 | 41 | [o retain]; 42 | 43 | uintptr_t isa = *(uintptr_t *)o; 44 | if (isa & 1) { 45 | // Assume refcount in high bits. 46 | LOTS = 1 << (4 + clz(isa)); 47 | testprintf("LOTS %zu via cntlzw\n", LOTS); 48 | } else { 49 | LOTS = 0x1000000; 50 | testprintf("LOTS %zu via guess\n", LOTS); 51 | } 52 | 53 | [o release]; 54 | 55 | 56 | testprintf("Retain a lot\n"); 57 | 58 | testassert(rc == 1); 59 | testassert([o retainCount] == rc); 60 | do { 61 | [o retain]; 62 | if (rc % 0x100000 == 0) testprintf("%zx/%zx ++\n", rc, LOTS); 63 | } while (++rc < LOTS); 64 | 65 | testassert([o retainCount] == rc); 66 | 67 | do { 68 | [o release]; 69 | if (rc % 0x100000 == 0) testprintf("%zx/%zx --\n", rc, LOTS); 70 | } while (--rc > 1); 71 | 72 | testassert(rc == 1); 73 | testassert([o retainCount] == rc); 74 | 75 | 76 | testprintf("tryRetain a lot\n"); 77 | 78 | id w; 79 | objc_storeWeak(&w, o); 80 | testassert(w == o); 81 | 82 | testassert(rc == 1); 83 | testassert([o retainCount] == rc); 84 | do { 85 | objc_loadWeakRetained(&w); 86 | if (rc % 0x100000 == 0) testprintf("%zx/%zx ++\n", rc, LOTS); 87 | } while (++rc < LOTS); 88 | 89 | testassert([o retainCount] == rc); 90 | 91 | do { 92 | [o release]; 93 | if (rc % 0x100000 == 0) testprintf("%zx/%zx --\n", rc, LOTS); 94 | } while (--rc > 1); 95 | 96 | testassert(rc == 1); 97 | testassert([o retainCount] == rc); 98 | 99 | testprintf("dealloc\n"); 100 | 101 | testassert(TestRootDealloc == 0); 102 | testassert(w != nil); 103 | [o release]; 104 | testassert(TestRootDealloc == 1); 105 | testassert(w == nil); 106 | 107 | succeed(__FILE__); 108 | } 109 | -------------------------------------------------------------------------------- /test/bool.c: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -funsigned-char 2 | // (verify -funsigned-char doesn't change the definition of BOOL) 3 | 4 | #include "test.h" 5 | #include 6 | 7 | #if TARGET_OS_OSX 8 | # if __x86_64__ 9 | # define RealBool 0 10 | # else 11 | # define RealBool 1 12 | # endif 13 | #elif TARGET_OS_IOS || TARGET_OS_BRIDGE 14 | # if (__arm__ && !__armv7k__) || __i386__ 15 | # define RealBool 0 16 | # else 17 | # define RealBool 1 18 | # endif 19 | #else 20 | # define RealBool 1 21 | #endif 22 | 23 | #if __OBJC__ && !defined(__OBJC_BOOL_IS_BOOL) 24 | # error no __OBJC_BOOL_IS_BOOL 25 | #endif 26 | 27 | #if RealBool != OBJC_BOOL_IS_BOOL 28 | # error wrong OBJC_BOOL_IS_BOOL 29 | #endif 30 | 31 | #if RealBool == OBJC_BOOL_IS_CHAR 32 | # error wrong OBJC_BOOL_IS_CHAR 33 | #endif 34 | 35 | int main() 36 | { 37 | const char *expected __unused = 38 | #if RealBool 39 | "B" 40 | #else 41 | "c" 42 | #endif 43 | ; 44 | #if __OBJC__ 45 | const char *enc = @encode(BOOL); 46 | testassert(0 == strcmp(enc, expected)); 47 | #endif 48 | succeed(__FILE__); 49 | } 50 | -------------------------------------------------------------------------------- /test/cacheflush-constant.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | /* 3 | TEST_RUN_OUTPUT 4 | foo 5 | bar 6 | bar 7 | foo 8 | END 9 | */ 10 | 11 | // NOTE: This test won't catch problems when running against a root, so it's of 12 | // limited utility, but it would at least catch things when testing against the 13 | // shared cache. 14 | 15 | #include 16 | #include 17 | 18 | @interface NSBlock: NSObject @end 19 | 20 | // NSBlock is a conveniently accessible superclass that (currently) has a constant cache. 21 | @interface MyBlock: NSBlock 22 | +(void)foo; 23 | +(void)bar; 24 | @end 25 | @implementation MyBlock 26 | +(void)foo { 27 | printf("foo\n"); 28 | } 29 | +(void)bar { 30 | printf("bar\n"); 31 | } 32 | @end 33 | 34 | int main() { 35 | [MyBlock foo]; 36 | [MyBlock bar]; 37 | 38 | Method m1 = class_getClassMethod([MyBlock class], @selector(foo)); 39 | Method m2 = class_getClassMethod([MyBlock class], @selector(bar)); 40 | method_exchangeImplementations(m1, m2); 41 | 42 | [MyBlock foo]; 43 | [MyBlock bar]; 44 | } 45 | -------------------------------------------------------------------------------- /test/cacheflush.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.h" 3 | 4 | @interface TestRoot(cat) 5 | +(int)classMethod; 6 | -(int)instanceMethod; 7 | @end 8 | -------------------------------------------------------------------------------- /test/cacheflush.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/cacheflush0.m -o cacheflush0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/cacheflush2.m -x none cacheflush0.dylib -o cacheflush2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/cacheflush3.m -x none cacheflush0.dylib -o cacheflush3.dylib -dynamiclib 6 | $C{COMPILE} $DIR/cacheflush.m -x none cacheflush0.dylib -o cacheflush.exe 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | #include 12 | #include 13 | 14 | #include "cacheflush.h" 15 | 16 | @interface Sub : TestRoot @end 17 | @implementation Sub @end 18 | 19 | 20 | int main() 21 | { 22 | TestRoot *sup = [TestRoot new]; 23 | Sub *sub = [Sub new]; 24 | 25 | // Fill method cache 26 | testassert(1 == [TestRoot classMethod]); 27 | testassert(1 == [sup instanceMethod]); 28 | testassert(1 == [TestRoot classMethod]); 29 | testassert(1 == [sup instanceMethod]); 30 | 31 | testassert(1 == [Sub classMethod]); 32 | testassert(1 == [sub instanceMethod]); 33 | testassert(1 == [Sub classMethod]); 34 | testassert(1 == [sub instanceMethod]); 35 | 36 | // Dynamically load a category 37 | dlopen("cacheflush2.dylib", 0); 38 | 39 | // Make sure old cache results are gone 40 | testassert(2 == [TestRoot classMethod]); 41 | testassert(2 == [sup instanceMethod]); 42 | 43 | testassert(2 == [Sub classMethod]); 44 | testassert(2 == [sub instanceMethod]); 45 | 46 | // Dynamically load another category 47 | dlopen("cacheflush3.dylib", 0); 48 | 49 | // Make sure old cache results are gone 50 | testassert(3 == [TestRoot classMethod]); 51 | testassert(3 == [sup instanceMethod]); 52 | 53 | testassert(3 == [Sub classMethod]); 54 | testassert(3 == [sub instanceMethod]); 55 | 56 | // fixme test subclasses 57 | 58 | // fixme test objc_flush_caches(), class_addMethod(), class_addMethods() 59 | 60 | succeed(__FILE__); 61 | } 62 | -------------------------------------------------------------------------------- /test/cacheflush0.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | #include "testroot.i" 3 | 4 | @implementation TestRoot(cat) 5 | +(int)classMethod { return 1; } 6 | -(int)instanceMethod { return 1; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/cacheflush2.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | 3 | @implementation TestRoot (Category2) 4 | +(int)classMethod { return 2; } 5 | -(int)instanceMethod { return 2; } 6 | @end 7 | -------------------------------------------------------------------------------- /test/cacheflush3.m: -------------------------------------------------------------------------------- 1 | #include "cacheflush.h" 2 | 3 | @implementation TestRoot (Category3) 4 | +(int)classMethod { return 3; } 5 | -(int)instanceMethod { return 3; } 6 | @end 7 | -------------------------------------------------------------------------------- /test/classgetclass.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #import 7 | 8 | @interface Foo:NSObject 9 | @end 10 | @implementation Foo 11 | @end 12 | 13 | int main() 14 | { 15 | testassert(gdb_class_getClass([Foo class]) == [Foo class]); 16 | succeed(__FILE__); 17 | } 18 | -------------------------------------------------------------------------------- /test/classname.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | #include 8 | 9 | @interface Fake : TestRoot @end 10 | @implementation Fake @end 11 | 12 | int main() 13 | { 14 | TestRoot *obj = [TestRoot new]; 15 | void *buf = (__bridge void *)(obj); 16 | *(Class __ptrauth_objc_isa_pointer *)buf = [Fake class]; 17 | 18 | testassert(object_getClass(obj) == [Fake class]); 19 | testassert(object_setClass(obj, [TestRoot class]) == [Fake class]); 20 | testassert(object_getClass(obj) == [TestRoot class]); 21 | testassert(object_setClass(nil, [TestRoot class]) == nil); 22 | 23 | testassert(malloc_size(buf) >= sizeof(id)); 24 | bzero(buf, malloc_size(buf)); 25 | testassert(object_setClass(obj, [TestRoot class]) == nil); 26 | 27 | testassert(object_getClass(obj) == [TestRoot class]); 28 | testassert(object_getClass([TestRoot class]) == object_getClass([TestRoot class])); 29 | testassert(object_getClass(nil) == Nil); 30 | 31 | testassert(0 == strcmp(object_getClassName(obj), "TestRoot")); 32 | testassert(0 == strcmp(object_getClassName([TestRoot class]), "TestRoot")); 33 | testassert(0 == strcmp(object_getClassName(nil), "nil")); 34 | 35 | testassert(0 == strcmp(class_getName([TestRoot class]), "TestRoot")); 36 | testassert(0 == strcmp(class_getName(object_getClass([TestRoot class])), "TestRoot")); 37 | testassert(0 == strcmp(class_getName(nil), "nil")); 38 | 39 | succeed(__FILE__); 40 | } 41 | -------------------------------------------------------------------------------- /test/classversion.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | int main() 8 | { 9 | Class cls = [TestRoot class]; 10 | testassert(class_getVersion(cls) == 0); 11 | testassert(class_getVersion(object_getClass(cls)) > 5); 12 | class_setVersion(cls, 100); 13 | testassert(class_getVersion(cls) == 100); 14 | 15 | testassert(class_getVersion(Nil) == 0); 16 | class_setVersion(Nil, 100); 17 | 18 | succeed(__FILE__); 19 | } 20 | -------------------------------------------------------------------------------- /test/concurrentcat_category.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #import 4 | 5 | @interface TargetClass : NSObject 6 | @end 7 | 8 | @interface TargetClass(LoadedMethods) 9 | - (void) m0; 10 | - (void) m1; 11 | - (void) m2; 12 | - (void) m3; 13 | - (void) m4; 14 | - (void) m5; 15 | - (void) m6; 16 | - (void) m7; 17 | - (void) m8; 18 | - (void) m9; 19 | - (void) m10; 20 | - (void) m11; 21 | - (void) m12; 22 | - (void) m13; 23 | - (void) m14; 24 | - (void) m15; 25 | @end 26 | 27 | @interface TN:TargetClass 28 | @end 29 | 30 | @implementation TN 31 | - (void) m1 { [super m1]; } 32 | - (void) m3 { [self m1]; } 33 | 34 | - (void) m2 35 | { 36 | [self willChangeValueForKey: @"m4"]; 37 | [self didChangeValueForKey: @"m4"]; 38 | } 39 | 40 | - (void)observeValueForKeyPath:(NSString *) keyPath 41 | ofObject:(id)object 42 | change:(NSDictionary *)change 43 | context:(void *)context 44 | { 45 | // suppress warning 46 | keyPath = nil; 47 | object = nil; 48 | change = nil; 49 | context = NULL; 50 | } 51 | @end 52 | 53 | @implementation TargetClass(LoadedMethods) 54 | - (void) m0 { ; } 55 | - (void) m1 { ; } 56 | - (void) m2 { ; } 57 | - (void) m3 { ; } 58 | - (void) m4 { ; } 59 | - (void) m5 { ; } 60 | - (void) m6 { ; } 61 | - (void) m7 { ; } 62 | - (void) m8 { ; } 63 | - (void) m9 { ; } 64 | - (void) m10 { ; } 65 | - (void) m11 { ; } 66 | - (void) m12 { ; } 67 | - (void) m13 { ; } 68 | - (void) m14 { ; } 69 | - (void) m15 { ; } 70 | @end 71 | -------------------------------------------------------------------------------- /test/copyProtocolList.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | #include 7 | 8 | @protocol Proto1 9 | +(id)proto1ClassMethod; 10 | -(id)proto1InstanceMethod; 11 | @end 12 | 13 | void noNullEntries(Protocol * _Nonnull __unsafe_unretained * _Nullable protolist, 14 | unsigned int count) 15 | { 16 | for (unsigned int i = 0; i != count; ++i) { 17 | testassert(protolist[i]); 18 | testassert(protocol_getName(protolist[i])); 19 | testprintf("Protocol[%d/%d]: %p %s\n", i, count, protolist[i], protocol_getName(protolist[i])); 20 | } 21 | } 22 | 23 | Protocol* getProtocol(Protocol * _Nonnull __unsafe_unretained * _Nullable protolist, 24 | unsigned int count, const char* name) { 25 | for (unsigned int i = 0; i != count; ++i) { 26 | if (!strcmp(protocol_getName(protolist[i]), name)) 27 | return protolist[i]; 28 | } 29 | return nil; 30 | } 31 | 32 | int main() 33 | { 34 | Protocol * _Nonnull __unsafe_unretained * _Nullable protolist; 35 | unsigned int count; 36 | 37 | count = 100; 38 | protolist = objc_copyProtocolList(&count); 39 | testassert(protolist); 40 | testassert(count != 0); 41 | testassert(malloc_size(protolist) >= (count * sizeof(Protocol*))); 42 | noNullEntries(protolist, count); 43 | testassert(protolist[count] == nil); 44 | // Check for a shared cache protocol, ie, the one we know comes from libobjc 45 | testassert(getProtocol(protolist, count, "NSObject")); 46 | // Test for a protocol we know isn't in the cache 47 | testassert(getProtocol(protolist, count, "Proto1") == @protocol(Proto1)); 48 | // Test for a protocol we know isn't there 49 | testassert(!getProtocol(protolist, count, "Proto2")); 50 | free(protolist); 51 | 52 | // Now add it 53 | Protocol* newproto = objc_allocateProtocol("Proto2"); 54 | objc_registerProtocol(newproto); 55 | 56 | Protocol * _Nonnull __unsafe_unretained * _Nullable newProtolist; 57 | unsigned int newCount; 58 | 59 | newCount = 100; 60 | newProtolist = objc_copyProtocolList(&newCount); 61 | testassert(newProtolist); 62 | testassert(newCount == (count + 1)); 63 | testassert(getProtocol(newProtolist, newCount, "Proto2")); 64 | free(newProtolist); 65 | 66 | 67 | succeed(__FILE__); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /test/createInstance.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #import 4 | #import 5 | #include "test.h" 6 | #include "testroot.i" 7 | 8 | @interface Super : TestRoot @end 9 | @implementation Super @end 10 | 11 | @interface Sub : Super { int array[128]; } @end 12 | @implementation Sub @end 13 | 14 | #if __has_feature(objc_arc) 15 | #define object_dispose(x) do {} while (0) 16 | #endif 17 | 18 | int main() 19 | { 20 | Super *s; 21 | 22 | s = class_createInstance([Super class], 0); 23 | testassert(s); 24 | testassert(object_getClass(s) == [Super class]); 25 | testassert(malloc_size((__bridge const void *)s) >= class_getInstanceSize([Super class])); 26 | 27 | object_dispose(s); 28 | 29 | s = class_createInstance([Sub class], 0); 30 | testassert(s); 31 | testassert(object_getClass(s) == [Sub class]); 32 | testassert(malloc_size((__bridge const void *)s) >= class_getInstanceSize([Sub class])); 33 | 34 | object_dispose(s); 35 | 36 | s = class_createInstance([Super class], 100); 37 | testassert(s); 38 | testassert(object_getClass(s) == [Super class]); 39 | testassert(malloc_size((__bridge const void *)s) >= class_getInstanceSize([Super class]) + 100); 40 | 41 | object_dispose(s); 42 | 43 | s = class_createInstance([Sub class], 100); 44 | testassert(s); 45 | testassert(object_getClass(s) == [Sub class]); 46 | testassert(malloc_size((__bridge const void *)s) >= class_getInstanceSize([Sub class]) + 100); 47 | 48 | object_dispose(s); 49 | 50 | s = class_createInstance(Nil, 0); 51 | testassert(!s); 52 | 53 | testassert(TestRootAlloc == 0); 54 | 55 | #if __has_feature(objc_arc) 56 | // ARC version didn't use object_dispose() 57 | // and should have called -dealloc on 4 objects 58 | testassert(TestRootDealloc == 4); 59 | #else 60 | // MRC version used object_dispose() 61 | // which doesn't call -dealloc 62 | testassert(TestRootDealloc == 0); 63 | #endif 64 | 65 | succeed(__FILE__); 66 | } 67 | -------------------------------------------------------------------------------- /test/customrr-cat1.m: -------------------------------------------------------------------------------- 1 | @interface InheritingSubCat @end 2 | 3 | @interface InheritingSubCat (NonClobberingCategory) @end 4 | 5 | @implementation InheritingSubCat (NonClobberingCategory) 6 | -(id) unrelatedMethod { return self; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/customrr-cat2.m: -------------------------------------------------------------------------------- 1 | @interface InheritingSubCat @end 2 | 3 | @interface InheritingSubCat (ClobberingCategory) @end 4 | 5 | @implementation InheritingSubCat (ClobberingCategory) 6 | -(int) retainCount { return 1; } 7 | @end 8 | -------------------------------------------------------------------------------- /test/customrr-nsobject-awz.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES OBJC_PRINT_CUSTOM_CORE=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-awz.exe -DSWIZZLE_AWZ=1 -fno-objc-convert-messages-to-runtime-calls 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 12 | OK: customrr-nsobject-awz.exe 13 | END 14 | 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /test/customrr-nsobject-core.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES OBJC_PRINT_CUSTOM_CORE=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-core.exe -DSWIZZLE_CORE=1 -fno-objc-convert-messages-to-runtime-calls 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM Core: NSObject 12 | objc\[\d+\]: CUSTOM Core: NSObject \(meta\) 13 | OK: customrr-nsobject-core.exe 14 | END 15 | 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /test/customrr-nsobject-none.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES OBJC_PRINT_CUSTOM_CORE=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-none.exe -fno-objc-convert-messages-to-runtime-calls 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | OK: customrr-nsobject-none.exe 12 | END 13 | 14 | */ 15 | 16 | -------------------------------------------------------------------------------- /test/customrr-nsobject-rr.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES OBJC_PRINT_CUSTOM_CORE=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-rr.exe -DSWIZZLE_RELEASE=1 -fno-objc-convert-messages-to-runtime-calls 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM RR: NSObject 12 | OK: customrr-nsobject-rr.exe 13 | END 14 | 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /test/customrr-nsobject-rrawz.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | TEST_CONFIG MEM=mrc 4 | TEST_ENV OBJC_PRINT_CUSTOM_RR=YES OBJC_PRINT_CUSTOM_AWZ=YES OBJC_PRINT_CUSTOM_CORE=YES 5 | 6 | TEST_BUILD 7 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-rrawz.exe -DSWIZZLE_RELEASE=1 -DSWIZZLE_AWZ=1 -fno-objc-convert-messages-to-runtime-calls 8 | END 9 | 10 | TEST_RUN_OUTPUT 11 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 12 | objc\[\d+\]: CUSTOM RR: NSObject 13 | OK: customrr-nsobject-rrawz.exe 14 | END 15 | 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /test/customrr2.m: -------------------------------------------------------------------------------- 1 | // These options must match customrr.m 2 | // TEST_CONFIG MEM=mrc 3 | /* 4 | TEST_BUILD 5 | $C{COMPILE} $DIR/customrr.m -fvisibility=default -o customrr2.exe -DTEST_EXCHANGEIMPLEMENTATIONS=1 -fno-objc-convert-messages-to-runtime-calls 6 | $C{COMPILE} -bundle -bundle_loader customrr2.exe $DIR/customrr-cat1.m -o customrr-cat1.bundle 7 | $C{COMPILE} -bundle -bundle_loader customrr2.exe $DIR/customrr-cat2.m -o customrr-cat2.bundle 8 | END 9 | */ 10 | -------------------------------------------------------------------------------- /test/debugScanWeakTables.m: -------------------------------------------------------------------------------- 1 | // TEST_ENV OBJC_DEBUG_SCAN_WEAK_TABLES=YES OBJC_DEBUG_SCAN_WEAK_TABLES_INTERVAL_NANOSECONDS=1000 2 | // TEST_CRASHES 3 | // TEST_CONFIG MEM=mrc 4 | /* 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: Starting background scan of weak references. 7 | objc\[\d+\]: Weak reference at 0x[0-9a-fA-F]+ contains 0x[0-9a-fA-F]+, should contain 0x[0-9a-fA-F]+ 8 | objc\[\d+\]: HALTED 9 | END 10 | */ 11 | 12 | #include "test.h" 13 | #include "testroot.i" 14 | 15 | #include 16 | 17 | int main() { 18 | id obj = [TestRoot new]; 19 | id weakLoc = nil; 20 | 21 | objc_storeWeak(&weakLoc, obj); 22 | memset_s(&weakLoc, sizeof(weakLoc), 0x35, sizeof(weakLoc)); 23 | 24 | uint64_t startTime = clock_gettime_nsec_np(CLOCK_UPTIME_RAW_APPROX); 25 | while (clock_gettime_nsec_np(CLOCK_UPTIME_RAW_APPROX) - startTime < 5000000000) { 26 | sleep(1); 27 | printf(".\n"); 28 | } 29 | 30 | fail("Should have crashed scanning weakLoc"); 31 | } -------------------------------------------------------------------------------- /test/defines.c: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG MEM=mrc LANGUAGE=c 3 | 4 | TEST_BUILD 5 | $DIR/defines.sh '$C{TESTINCLUDEDIR}' '$C{TESTLOCALINCLUDEDIR}' '$C{COMPILE_C}' '$C{COMPILE_CXX}' '$C{COMPILE_M}' '$C{COMPILE_MM}' '$VERBOSE' 6 | $C{COMPILE_C} $DIR/defines.c -o defines.exe 7 | END 8 | 9 | TEST_BUILD_OUTPUT 10 | (.|\n)*No unexpected #defines found\. 11 | END 12 | */ 13 | 14 | 15 | #include "test.h" 16 | 17 | int main() 18 | { 19 | succeed(__FILE__); 20 | } 21 | -------------------------------------------------------------------------------- /test/defines.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check ObjC headers for unwanted defines exposed to clients. 4 | 5 | TESTINCLUDEDIR=$1; shift 6 | TESTLOCALINCLUDEDIR=$1; shift 7 | COMPILE_C=$1; shift 8 | COMPILE_CXX=$1; shift 9 | COMPILE_M=$1; shift 10 | COMPILE_MM=$1; shift 11 | VERBOSE=$1; shift 12 | 13 | # stop after any command error 14 | set -e 15 | 16 | # echo commands when verbose 17 | if [ "$VERBOSE" != "0" ]; then 18 | set -x 19 | fi 20 | 21 | FILES="$TESTINCLUDEDIR/objc/*.h $TESTLOCALINCLUDEDIR/objc/*.h" 22 | CFLAGS='-fsyntax-only -Wno-unused-function -D_OBJC_PRIVATE_H_' 23 | 24 | INCLUDES=$(grep -h '#include' $FILES | grep -v ' defines.expected 27 | 28 | ERROR= 29 | 30 | extract_defines() { 31 | echo "$INCLUDES" | $1 - -dM -E \ 32 | | sed 's/\(#define [^(]*\)[( ].*/\1/g' \ 33 | | sort | uniq 34 | } 35 | 36 | get_new_lines() { 37 | diff --old-line-format= --unchanged-line-format= --new-line-format=%L -b $1 $2 || true 38 | } 39 | 40 | run_test() { 41 | extract_defines "$1 $CFLAGS" > base-defines 42 | extract_defines "$1 $CFLAGS $FILES" > objc-defines 43 | get_new_lines base-defines objc-defines > objc-defines-only 44 | if [[ ! -s objc-defines-only ]]; then 45 | echo "ERROR: objc-defines-only is somehow empty." 46 | exit 1 47 | fi 48 | get_new_lines defines.expected objc-defines-only > objc-defines-unexpected 49 | if [[ -s objc-defines-unexpected ]]; then 50 | echo "ERROR: unknown #defines found in headers. If these are expected, add them to test/defines.expected." 51 | echo "$1" 52 | cat objc-defines-unexpected 53 | ERROR=1 54 | fi 55 | rm base-defines objc-defines objc-defines-only objc-defines-unexpected 56 | } 57 | 58 | run_test "$COMPILE_C $CFLAGS" 59 | run_test "$COMPILE_CXX $CFLAGS" 60 | run_test "$COMPILE_M $CFLAGS" 61 | run_test "$COMPILE_MM $CFLAGS" 62 | for STDC in '99' '11' ; do 63 | run_test "$COMPILE_C $CFLAGS -std=c$STDC" 64 | run_test "$COMPILE_M $CFLAGS -std=c$STDC" 65 | done 66 | for STDCXX in '98' '03' '11' '14' '17' ; do 67 | run_test "$COMPILE_CXX $CFLAGS -std=c++$STDCXX" 68 | run_test "$COMPILE_MM $CFLAGS -std=c++$STDCXX" 69 | done 70 | 71 | if [[ $ERROR == "" ]]; then 72 | echo "No unexpected #defines found." 73 | else 74 | echo "Unknown #defines found in headers." 75 | fi 76 | -------------------------------------------------------------------------------- /test/definitions.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | // DO NOT include anything else here 4 | #include 5 | // DO NOT include anything else here 6 | Class c = Nil; 7 | SEL s; 8 | IMP i; 9 | id o = nil; 10 | BOOL b = YES; 11 | BOOL b2 = NO; 12 | #if !__has_feature(objc_arc) 13 | __strong void *p; 14 | #endif 15 | id __unsafe_unretained u; 16 | #if __has_feature(objc_arc_weak) 17 | id __weak w; 18 | #endif 19 | 20 | void fn(void) __unused; 21 | void fn(void) { 22 | id __autoreleasing a __unused; 23 | } 24 | 25 | // check type inference for blocks returning YES and NO (rdar://10118972) 26 | BOOL (^block1)(void) = ^{ return YES; }; 27 | BOOL (^block2)(void) = ^{ return NO; }; 28 | 29 | #include "test.h" 30 | 31 | int main() 32 | { 33 | testassert(YES); 34 | testassert(!NO); 35 | #if __cplusplus 36 | testwarn("rdar://12371870 -Wnull-conversion"); 37 | testassert(!(bool)nil); 38 | testassert(!(bool)Nil); 39 | #else 40 | testassert(!nil); 41 | testassert(!Nil); 42 | #endif 43 | 44 | #if __has_feature(objc_bool) 45 | // YES[array] is disallowed for objc just as true[array] is for C++ 46 | #else 47 | // this will fail if YES and NO do not have enough parentheses 48 | int array[2] = { 888, 999 }; 49 | testassert(NO[array] == 888); 50 | testassert(YES[array] == 999); 51 | #endif 52 | 53 | succeed(__FILE__); 54 | } 55 | -------------------------------------------------------------------------------- /test/designatedinit.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | /* TEST_BUILD_OUTPUT 3 | .*designatedinit.m:\d+:\d+: warning: designated initializer should only invoke a designated initializer on 'super'.* 4 | .*designatedinit.m:\d+:\d+: note: .* 5 | .*designatedinit.m:\d+:\d+: warning: method override for the designated initializer of the superclass '-init' not found.* 6 | .*NSObject.h:\d+:\d+: note: .* 7 | END */ 8 | 9 | #define NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER 1 10 | #include "test.h" 11 | #include 12 | 13 | @interface C : NSObject 14 | -(id) initWithInt:(int)i NS_DESIGNATED_INITIALIZER; 15 | @end 16 | 17 | @implementation C 18 | -(id) initWithInt:(int)__unused i { 19 | return [self init]; 20 | } 21 | @end 22 | 23 | int main() 24 | { 25 | succeed(__FILE__); 26 | } 27 | -------------------------------------------------------------------------------- /test/duplicateProtocols.m: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | 4 | // This test assumes 5 | // - that on launch we don't have NSCoding, NSSecureCoding, or NSDictionary, ie, libSystem doesn't contain those 6 | // - that after dlopening CF, we get NSDictionary and it conforms to NSSecureCoding which conforms to NSCoding 7 | // - that our NSCoding will be used if we ask either NSSecureCoding or NSDictionary if they conform to our test protocol 8 | 9 | @protocol NewNSCodingSuperProto 10 | @end 11 | 12 | @protocol NSCoding 13 | @end 14 | 15 | int main() 16 | { 17 | // Before we dlopen, make sure we are using our NSCoding, not the shared cache version 18 | Protocol* codingSuperProto = objc_getProtocol("NewNSCodingSuperProto"); 19 | Protocol* codingProto = objc_getProtocol("NSCoding"); 20 | if (@protocol(NewNSCodingSuperProto) != codingSuperProto) fail("Protocol mismatch"); 21 | if (@protocol(NSCoding) != codingProto) fail("Protocol mismatch"); 22 | if (!protocol_conformsToProtocol(codingProto, codingSuperProto)) fail("Our NSCoding should conform to NewNSCodingSuperProto"); 23 | 24 | // Also make sure we don't yet have an NSSecureCoding or NSDictionary 25 | if (objc_getProtocol("NSSecureCoding")) fail("Test assumes we don't have NSSecureCoding yet"); 26 | if (objc_getClass("NSDictionary")) fail("Test assumes we don't have NSDictionary yet"); 27 | 28 | void *dl = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_LAZY); 29 | if (!dl) fail("couldn't open CoreFoundation"); 30 | 31 | // We should now have NSSecureCoding and NSDictionary 32 | Protocol* secureCodingProto = objc_getProtocol("NSSecureCoding"); 33 | id dictionaryClass = objc_getClass("NSDictionary"); 34 | if (!secureCodingProto) fail("Should have got NSSecureCoding from CoreFoundation"); 35 | if (!dictionaryClass) fail("Should have got NSDictionary from CoreFoundation"); 36 | 37 | // Now make sure that NSDictionary and NSSecureCoding find our new protocols 38 | if (!protocol_conformsToProtocol(secureCodingProto, codingProto)) fail("NSSecureCoding should conform to our NSCoding"); 39 | if (!protocol_conformsToProtocol(secureCodingProto, codingSuperProto)) fail("NSSecureCoding should conform to our NewNSCodingSuperProto"); 40 | if (!class_conformsToProtocol(dictionaryClass, codingProto)) fail("NSDictionary should conform to our NSCoding"); 41 | if (!class_conformsToProtocol(dictionaryClass, codingSuperProto)) fail("NSDictionary should conform to our NewNSCodingSuperProto"); 42 | } 43 | -------------------------------------------------------------------------------- /test/duplicatedClasses.m: -------------------------------------------------------------------------------- 1 | // fixme rdar://24624435 duplicate class warning fails with the shared cache 2 | // OBJC_DISABLE_PREOPTIMIZATION=YES works around that problem. 3 | 4 | // TEST_ENV OBJC_DEBUG_DUPLICATE_CLASSES=YES OBJC_DISABLE_PREOPTIMIZATION=YES 5 | // TEST_CRASHES 6 | /* 7 | TEST_RUN_OUTPUT 8 | objc\[\d+\]: Class [^\s]+ is implemented in both .+ \(0x[0-9a-f]+\) and .+ \(0x[0-9a-f]+\)\. One of the two will be used\. Which one is undefined\. 9 | objc\[\d+\]: HALTED 10 | OR 11 | OK: duplicatedClasses.m 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | #include "testroot.i" 17 | 18 | @interface WKWebView : TestRoot @end 19 | @implementation WKWebView @end 20 | 21 | int main() 22 | { 23 | void *dl = dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", RTLD_LAZY); 24 | if (!dl) fail("couldn't open WebKit"); 25 | fail("should have crashed already"); 26 | } 27 | -------------------------------------------------------------------------------- /test/fakeRealizedClass.m: -------------------------------------------------------------------------------- 1 | /* 2 | Make sure we detect classes with the RW_REALIZED bit set in the binary. rdar://problem/67692760 3 | TEST_CONFIG OS=macosx 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: realized class 0x[0-9a-fA-F]+ has corrupt data pointer: malloc_size\(0x[0-9a-fA-F]+\) = 0 7 | objc\[\d+\]: HALTED 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | #define RW_REALIZED (1U<<31) 16 | 17 | struct ObjCClass { 18 | struct ObjCClass * __ptrauth_objc_isa_pointer isa; 19 | struct ObjCClass * __ptrauth_objc_super_pointer superclass; 20 | void *cachePtr; 21 | uintptr_t zero; 22 | uintptr_t data; 23 | }; 24 | 25 | struct ObjCClass_ro { 26 | uint32_t flags; 27 | uint32_t instanceStart; 28 | uint32_t instanceSize; 29 | #ifdef __LP64__ 30 | uint32_t reserved; 31 | #endif 32 | 33 | union { 34 | const uint8_t * ivarLayout; 35 | struct ObjCClass * nonMetaClass; 36 | }; 37 | 38 | const char * name; 39 | struct ObjCMethodList * __ptrauth_objc_method_list_pointer baseMethodList; 40 | struct protocol_list_t * baseProtocols; 41 | const struct ivar_list_t * ivars; 42 | 43 | const uint8_t * weakIvarLayout; 44 | struct property_list_t *baseProperties; 45 | }; 46 | 47 | extern struct ObjCClass OBJC_METACLASS_$_NSObject; 48 | extern struct ObjCClass OBJC_CLASS_$_NSObject; 49 | 50 | struct ObjCClass_ro FakeSuperclassRO = { 51 | .flags = RW_REALIZED 52 | }; 53 | 54 | struct ObjCClass FakeSuperclass = { 55 | &OBJC_METACLASS_$_NSObject, 56 | &OBJC_METACLASS_$_NSObject, 57 | NULL, 58 | 0, 59 | (uintptr_t)&FakeSuperclassRO 60 | }; 61 | 62 | struct ObjCClass_ro FakeSubclassRO; 63 | 64 | struct ObjCClass FakeSubclass = { 65 | &FakeSuperclass, 66 | &FakeSuperclass, 67 | NULL, 68 | 0, 69 | (uintptr_t)&FakeSubclassRO 70 | }; 71 | 72 | static struct ObjCClass *class_ptr __attribute__((used)) __attribute((section("__DATA,__objc_nlclslist"))) = &FakeSubclass; 73 | 74 | int main() {} 75 | -------------------------------------------------------------------------------- /test/fakeRealizedClass2.m: -------------------------------------------------------------------------------- 1 | /* 2 | Variant on fakeRealizedClass which tests a fake class with no superclass rdar://problem/67692760 3 | TEST_CONFIG OS=macosx 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: realized class 0x[0-9a-fA-F]+ has corrupt data pointer: malloc_size\(0x[0-9a-fA-F]+\) = 0 7 | objc\[\d+\]: HALTED 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | #define RW_REALIZED (1U<<31) 16 | 17 | struct ObjCClass { 18 | struct ObjCClass * __ptrauth_objc_isa_pointer isa; 19 | struct ObjCClass * __ptrauth_objc_super_pointer superclass; 20 | void *cachePtr; 21 | uintptr_t zero; 22 | uintptr_t data; 23 | }; 24 | 25 | struct ObjCClass_ro { 26 | uint32_t flags; 27 | uint32_t instanceStart; 28 | uint32_t instanceSize; 29 | #ifdef __LP64__ 30 | uint32_t reserved; 31 | #endif 32 | 33 | union { 34 | const uint8_t * ivarLayout; 35 | struct ObjCClass * nonMetaClass; 36 | }; 37 | 38 | const char * name; 39 | struct ObjCMethodList * __ptrauth_objc_method_list_pointer baseMethodList; 40 | struct protocol_list_t * baseProtocols; 41 | const struct ivar_list_t * ivars; 42 | 43 | const uint8_t * weakIvarLayout; 44 | struct property_list_t *baseProperties; 45 | }; 46 | 47 | extern struct ObjCClass OBJC_METACLASS_$_NSObject; 48 | extern struct ObjCClass OBJC_CLASS_$_NSObject; 49 | 50 | struct ObjCClass_ro FakeSuperclassRO = { 51 | .flags = RW_REALIZED 52 | }; 53 | 54 | struct ObjCClass FakeSuperclass = { 55 | &OBJC_METACLASS_$_NSObject, 56 | NULL, 57 | NULL, 58 | 0, 59 | (uintptr_t)&FakeSuperclassRO 60 | }; 61 | 62 | struct ObjCClass_ro FakeSubclassRO; 63 | 64 | struct ObjCClass FakeSubclass = { 65 | &FakeSuperclass, 66 | &FakeSuperclass, 67 | NULL, 68 | 0, 69 | (uintptr_t)&FakeSubclassRO 70 | }; 71 | 72 | static struct ObjCClass *class_ptr __attribute__((used)) __attribute((section("__DATA,__objc_nlclslist"))) = &FakeSubclass; 73 | 74 | int main() {} 75 | -------------------------------------------------------------------------------- /test/fork.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | void *flushthread(void *arg __unused) 6 | { 7 | while (1) { 8 | _objc_flush_caches(nil); 9 | } 10 | } 11 | 12 | int main() 13 | { 14 | pthread_t th; 15 | pthread_create(&th, nil, &flushthread, nil); 16 | 17 | alarm(120); 18 | 19 | [NSObject self]; 20 | [NSObject self]; 21 | 22 | int max = is_guardmalloc() ? 10: 100; 23 | 24 | for (int i = 0; i < max; i++) { 25 | pid_t child; 26 | switch ((child = fork())) { 27 | case -1: 28 | abort(); 29 | case 0: 30 | // child 31 | alarm(10); 32 | [NSObject self]; 33 | _exit(0); 34 | default: { 35 | // parent 36 | int result = 0; 37 | while (waitpid(child, &result, 0) < 0) { 38 | if (errno != EINTR) { 39 | fail("waitpid failed (errno %d %s)", 40 | errno, strerror(errno)); 41 | } 42 | } 43 | if (!WIFEXITED(result)) { 44 | fail("child crashed (waitpid result %d)", result); 45 | } 46 | 47 | [NSObject self]; 48 | break; 49 | } 50 | } 51 | } 52 | 53 | succeed(__FILE__ " parent"); 54 | } 55 | -------------------------------------------------------------------------------- /test/forkInitializeDisabled.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=macosx MEM=mrc ARCH=x86_64 3 | (confused by ARC which loads Foundation which provokes more +initialize logs) 4 | (also confused by i386 OS_object +load workaround) 5 | 6 | TEST_ENV OBJC_PRINT_INITIALIZE_METHODS=YES 7 | 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: INITIALIZE: disabling \+initialize fork safety enforcement because the app has a __DATA,__objc_fork_ok section 10 | OK: forkInitializeDisabled\.m 11 | END 12 | */ 13 | 14 | #include "test.h" 15 | 16 | asm(".section __DATA, __objc_fork_ok\n.long 0\n"); 17 | 18 | int main() 19 | { 20 | succeed(__FILE__); 21 | } 22 | -------------------------------------------------------------------------------- /test/forkInitializeSingleThreaded.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_RUN_OUTPUT 3 | OK: forkInitialize\.m 4 | OK: forkInitialize\.m 5 | END 6 | */ 7 | #define SINGLETHREADED 1 8 | #include "forkInitialize.m" 9 | -------------------------------------------------------------------------------- /test/forwardDefault.m: -------------------------------------------------------------------------------- 1 | /* 2 | no arc, rdar://11368528 confused by Foundation 3 | TEST_CONFIG MEM=mrc 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: \+\[NSObject fakeorama\]: unrecognized selector sent to instance 0x[0-9a-fA-F]+ \(no message forward handler is installed\) 7 | objc\[\d+\]: HALTED 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | @interface NSObject (Fake) 16 | -(void)fakeorama; 17 | @end 18 | 19 | int main() 20 | { 21 | [NSObject fakeorama]; 22 | fail("should have crashed"); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/forwardDefaultStret.m: -------------------------------------------------------------------------------- 1 | /* 2 | no arc, rdar://11368528 confused by Foundation 3 | TEST_CONFIG MEM=mrc 4 | TEST_CRASHES 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: \+\[NSObject fakeorama\]: unrecognized selector sent to instance 0x[0-9a-fA-F]+ \(no message forward handler is installed\) 7 | objc\[\d+\]: HALTED 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | @interface NSObject (Fake) 16 | -(struct stret)fakeorama; 17 | @end 18 | 19 | int main() 20 | { 21 | [NSObject fakeorama]; 22 | fail("should have crashed"); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/future.h: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | @interface Sub1 : TestRoot 4 | +(int)method; 5 | +(Class)classref; 6 | @end 7 | 8 | @interface Sub2 : TestRoot 9 | +(int)method; 10 | +(Class)classref; 11 | @end 12 | 13 | @interface SubSub1 : Sub1 @end 14 | 15 | @interface SubSub2 : Sub2 @end 16 | -------------------------------------------------------------------------------- /test/future.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/future0.m -o future0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/future2.m -x none future0.dylib -o future2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/future.m -x none future0.dylib -o future.exe 6 | END 7 | */ 8 | 9 | #include "test.h" 10 | 11 | #if __has_feature(objc_arc) 12 | 13 | int main() 14 | { 15 | testwarn("rdar://10041403 future class API is not ARC-compatible"); 16 | succeed(__FILE__); 17 | } 18 | 19 | 20 | #else 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "future.h" 27 | 28 | @implementation Sub2 29 | +(int)method { 30 | return 2; 31 | } 32 | +(Class)classref { 33 | return [Sub2 class]; 34 | } 35 | @end 36 | 37 | @implementation SubSub2 38 | +(int)method { 39 | return 1 + [super method]; 40 | } 41 | @end 42 | 43 | int main() 44 | { 45 | Class oldTestRoot; 46 | Class oldSub1; 47 | Class newSub1; 48 | 49 | // objc_getFutureClass with existing class 50 | oldTestRoot = objc_getFutureClass("TestRoot"); 51 | testassert(oldTestRoot == [TestRoot class]); 52 | testassert(! _class_isFutureClass(oldTestRoot)); 53 | 54 | // objc_getFutureClass with missing class 55 | oldSub1 = objc_getFutureClass("Sub1"); 56 | testassert(oldSub1); 57 | testassert(malloc_size((__bridge void*)oldSub1) > 0); 58 | testassert(objc_getClass("Sub1") == Nil); 59 | testassert(_class_isFutureClass(oldSub1)); 60 | testassert(0 == strcmp(class_getName(oldSub1), "Sub1")); 61 | testassert(object_getClass(oldSub1) == Nil); // CF expects this 62 | 63 | // objc_getFutureClass a second time 64 | testassert(oldSub1 == objc_getFutureClass("Sub1")); 65 | 66 | // Load class Sub1 67 | dlopen("future2.dylib", 0); 68 | 69 | // Verify use of future class 70 | newSub1 = objc_getClass("Sub1"); 71 | testassert(oldSub1 == newSub1); 72 | testassert(newSub1 == [newSub1 classref]); 73 | testassert(newSub1 == class_getSuperclass(objc_getClass("SubSub1"))); 74 | testassert(! _class_isFutureClass(newSub1)); 75 | 76 | testassert(1 == [oldSub1 method]); 77 | testassert(1 == [newSub1 method]); 78 | 79 | succeed(__FILE__); 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /test/future0.m: -------------------------------------------------------------------------------- 1 | #include "future.h" 2 | #include "testroot.i" 3 | -------------------------------------------------------------------------------- /test/future2.m: -------------------------------------------------------------------------------- 1 | #include "future.h" 2 | 3 | 4 | @implementation Sub1 5 | +(Class)classref { 6 | return [Sub1 class]; 7 | } 8 | +(int)method { 9 | return 1; 10 | } 11 | @end 12 | 13 | @implementation SubSub1 14 | +(int)method { 15 | return 1 + [super method]; 16 | } 17 | @end 18 | -------------------------------------------------------------------------------- /test/gdb.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -Wno-deprecated-declarations 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | 8 | #define SwiftV1MangledName4 "_TtC6Swiftt13SwiftV1Class4" 9 | __attribute__((objc_runtime_name(SwiftV1MangledName4))) 10 | @interface SwiftV1Class4 : TestRoot @end 11 | @implementation SwiftV1Class4 @end 12 | 13 | int main() 14 | { 15 | // Class hashes 16 | Class result; 17 | 18 | // Class should not be realized yet 19 | // fixme not true during class hash rearrangement 20 | // result = NXMapGet(gdb_objc_realized_classes, "TestRoot"); 21 | // testassert(!result); 22 | 23 | [TestRoot class]; 24 | // Now class should be realized 25 | 26 | if (!testdyld3()) { 27 | // In dyld3 mode, the class will be in the launch closure and not in our table. 28 | result = (__bridge Class)(NXMapGet(gdb_objc_realized_classes, "TestRoot")); 29 | testassert(result); 30 | testassert(result == [TestRoot class]); 31 | } 32 | 33 | Class dynamic = objc_allocateClassPair([TestRoot class], "Dynamic", 0); 34 | objc_registerClassPair(dynamic); 35 | result = (__bridge Class)(NXMapGet(gdb_objc_realized_classes, "Dynamic")); 36 | testassert(result); 37 | testassert(result == dynamic); 38 | 39 | Class *realizedClasses = objc_copyRealizedClassList(NULL); 40 | bool foundTestRoot = false; 41 | bool foundDynamic = false; 42 | for (Class *cursor = realizedClasses; *cursor; cursor++) { 43 | if (*cursor == [TestRoot class]) 44 | foundTestRoot = true; 45 | if (*cursor == dynamic) 46 | foundDynamic = true; 47 | } 48 | free(realizedClasses); 49 | testassert(foundTestRoot); 50 | testassert(foundDynamic); 51 | 52 | result = (__bridge Class)(NXMapGet(gdb_objc_realized_classes, "DoesNotExist")); 53 | testassert(!result); 54 | 55 | // Class structure decoding 56 | 57 | uintptr_t *maskp = (uintptr_t *)dlsym(RTLD_DEFAULT, "objc_debug_class_rw_data_mask"); 58 | testassert(maskp); 59 | 60 | // Raw class names 61 | testassert(strcmp(objc_debug_class_getNameRaw([SwiftV1Class4 class]), SwiftV1MangledName4) == 0); 62 | testassert(strcmp(objc_debug_class_getNameRaw([TestRoot class]), "TestRoot") == 0); 63 | 64 | 65 | succeed(__FILE__); 66 | } 67 | -------------------------------------------------------------------------------- /test/get_task_allow_entitlement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/headers.c: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $DIR/headers.sh '$C{TESTINCLUDEDIR}' '$C{TESTLOCALINCLUDEDIR}' '$C{COMPILE_C}' '$C{COMPILE_CXX}' '$C{COMPILE_M}' '$C{COMPILE_MM}' '$VERBOSE' 4 | $C{COMPILE_C} $DIR/headers.c -o headers.exe 5 | END 6 | 7 | allow `sh -x` output from headers.sh 8 | TEST_BUILD_OUTPUT 9 | (\+ .*\n)*(\+ .*)?done 10 | END 11 | */ 12 | 13 | 14 | #include "test.h" 15 | 16 | int main() 17 | { 18 | succeed(__FILE__); 19 | } 20 | -------------------------------------------------------------------------------- /test/headers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Compile every exported ObjC header as if it were a file in every language. 4 | # This script is executed by test headers.c's TEST_BUILD command. 5 | 6 | TESTINCLUDEDIR=$1; shift 7 | TESTLOCALINCLUDEDIR=$1; shift 8 | COMPILE_C=$1; shift 9 | COMPILE_CXX=$1; shift 10 | COMPILE_M=$1; shift 11 | COMPILE_MM=$1; shift 12 | VERBOSE=$1; shift 13 | 14 | # stop after any command error 15 | set -e 16 | 17 | # echo commands when verbose 18 | if [ "$VERBOSE" != "0" ]; then 19 | set -x 20 | fi 21 | 22 | FILES="$TESTINCLUDEDIR/objc/*.h $TESTLOCALINCLUDEDIR/objc/*.h" 23 | CFLAGS='-fsyntax-only -Wno-unused-function -D_OBJC_PRIVATE_H_' 24 | 25 | $COMPILE_C $CFLAGS $FILES 26 | $COMPILE_CXX $CFLAGS $FILES 27 | $COMPILE_M $CFLAGS $FILES 28 | $COMPILE_MM $CFLAGS $FILES 29 | for STDC in '99' '11' ; do 30 | $COMPILE_C $CFLAGS $FILES -std=c$STDC 31 | $COMPILE_M $CFLAGS $FILES -std=c$STDC 32 | done 33 | for STDCXX in '98' '03' '11' '14' '17' ; do 34 | $COMPILE_CXX $CFLAGS $FILES -std=c++$STDCXX 35 | $COMPILE_MM $CFLAGS $FILES -std=c++$STDCXX 36 | done 37 | 38 | echo done 39 | -------------------------------------------------------------------------------- /test/imageAPIs.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include 4 | #include 5 | 6 | #include "test.h" 7 | #include "testroot.i" 8 | 9 | @interface Foo: TestRoot @end 10 | @implementation Foo @end 11 | @interface Bar: Foo @end 12 | @implementation Bar @end 13 | 14 | int main(int argc __unused, const char **argv) 15 | { 16 | // Make sure we show up in the list of image names. 17 | unsigned int count; 18 | const char **imageNames = objc_copyImageNames(&count); 19 | testassert(imageNames); 20 | testassertequal(imageNames[count], NULL); 21 | 22 | char myBaseName[MAXPATHLEN]; 23 | basename_r(argv[0], myBaseName); 24 | const char *myImageName = NULL; 25 | for (unsigned int i = 0; i < count; i++) { 26 | char imageBaseName[MAXPATHLEN]; 27 | basename_r(imageNames[i], imageBaseName); 28 | if (strcmp(imageBaseName, myBaseName) == 0) 29 | myImageName = imageNames[i]; 30 | } 31 | testassert(myImageName); 32 | free(imageNames); 33 | 34 | // Make sure our classes show up in the class names. 35 | const char **classNames = objc_copyClassNamesForImage(myImageName, &count); 36 | testassert(classNames); 37 | testassertequal(classNames[count], NULL); 38 | 39 | int sawFoo = 0; 40 | int sawBar = 0; 41 | for (unsigned int i = 0; i < count; i++) { 42 | if (strcmp(classNames[i], "Foo") == 0) 43 | sawFoo++; 44 | if (strcmp(classNames[i], "Bar") == 0) 45 | sawBar++; 46 | } 47 | testassertequal(sawFoo, 1); 48 | testassertequal(sawBar, 1); 49 | free(classNames); 50 | 51 | // Make sure our classes show up in the classes list. 52 | sawFoo = 0; 53 | sawBar = 0; 54 | Class *classes = objc_copyClassesForImage(myImageName, &count); 55 | testassert(classes); 56 | testassertequal(classes[count], NULL); 57 | for (unsigned int i = 0; i < count; i++) { 58 | if (strcmp(class_getName(classes[i]), "Foo") == 0) 59 | sawFoo++; 60 | if (strcmp(class_getName(classes[i]), "Bar") == 0) 61 | sawBar++; 62 | } 63 | testassertequal(sawFoo, 1); 64 | testassertequal(sawBar, 1); 65 | free(classes); 66 | 67 | // Make sure bad names return NULL. 68 | testassertequal(objc_copyClassNamesForImage("aaaaaaaaaaaaaaaaaaa", NULL), NULL); 69 | testassertequal(objc_copyClassesForImage("aaaaaaaaaaaaaaaaaaa", NULL), NULL); 70 | 71 | succeed(__FILE__); 72 | } 73 | -------------------------------------------------------------------------------- /test/imageorder.h: -------------------------------------------------------------------------------- 1 | extern int state; 2 | extern int cstate; 3 | 4 | OBJC_ROOT_CLASS 5 | @interface Super { id isa; } 6 | +(void) method; 7 | +(void) method0; 8 | @end 9 | 10 | @interface Super (cat1) 11 | +(void) method1; 12 | @end 13 | 14 | @interface Super (cat2) 15 | +(void) method2; 16 | @end 17 | 18 | @interface Super (cat3) 19 | +(void) method3; 20 | @end 21 | -------------------------------------------------------------------------------- /test/imageorder.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/imageorder1.m -o imageorder1.dylib -dynamiclib 4 | $C{COMPILE} $DIR/imageorder2.m -x none imageorder1.dylib -o imageorder2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/imageorder3.m -x none imageorder2.dylib imageorder1.dylib -o imageorder3.dylib -dynamiclib 6 | $C{COMPILE} $DIR/imageorder.m -x none imageorder3.dylib imageorder2.dylib imageorder1.dylib -o imageorder.exe 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | #include "imageorder.h" 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | // +load methods and C static initializers 18 | testassert(state == 3); 19 | testassert(cstate == 3); 20 | 21 | Class cls = objc_getClass("Super"); 22 | testassert(cls); 23 | 24 | // make sure all categories arrived 25 | state = -1; 26 | [Super method0]; 27 | testassert(state == 0); 28 | [Super method1]; 29 | testassert(state == 1); 30 | [Super method2]; 31 | testassert(state == 2); 32 | [Super method3]; 33 | testassert(state == 3); 34 | 35 | // make sure imageorder3.dylib is the last category to attach 36 | state = 0; 37 | [Super method]; 38 | testassert(state == 3); 39 | 40 | succeed(__FILE__); 41 | } 42 | -------------------------------------------------------------------------------- /test/imageorder1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | int state = -1; 5 | int cstate = 0; 6 | 7 | static void c1(void) __attribute__((constructor)); 8 | static void c1(void) 9 | { 10 | testassert(state == 1); // +load before C/C++ 11 | testassert(cstate == 0); 12 | cstate = 1; 13 | } 14 | 15 | 16 | #if __clang__ 17 | #pragma clang diagnostic push 18 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 19 | #endif 20 | 21 | @implementation Super (cat1) 22 | +(void) method { 23 | fail("+[Super(cat1) method] not replaced!"); 24 | } 25 | +(void) method1 { 26 | state = 1; 27 | } 28 | +(void) load { 29 | testassert(state == 0); 30 | state = 1; 31 | } 32 | @end 33 | 34 | #if __clang__ 35 | #pragma clang diagnostic pop 36 | #endif 37 | 38 | 39 | @implementation Super 40 | +(void) initialize { } 41 | +(void) method { 42 | fail("+[Super method] not replaced!"); 43 | } 44 | +(void) method0 { 45 | state = 0; 46 | } 47 | +(void) load { 48 | testassert(state == -1); 49 | state = 0; 50 | } 51 | @end 52 | 53 | -------------------------------------------------------------------------------- /test/imageorder2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | static void c2(void) __attribute__((constructor)); 5 | static void c2(void) 6 | { 7 | testassert(state == 2); // +load before C/C++ 8 | testassert(cstate == 1); 9 | cstate = 2; 10 | } 11 | 12 | 13 | #if __clang__ 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 16 | #endif 17 | 18 | @implementation Super (cat2) 19 | +(void) method { 20 | fail("+[Super(cat2) method] not replaced!"); 21 | } 22 | +(void) method2 { 23 | state = 2; 24 | } 25 | +(void) load { 26 | testassert(state == 1); 27 | state = 2; 28 | } 29 | @end 30 | 31 | #if __clang__ 32 | #pragma clang diagnostic pop 33 | #endif 34 | -------------------------------------------------------------------------------- /test/imageorder3.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "imageorder.h" 3 | 4 | static void c3(void) __attribute__((constructor)); 5 | static void c3(void) 6 | { 7 | testassert(state == 3); // +load before C/C++ 8 | testassert(cstate == 2); 9 | cstate = 3; 10 | } 11 | 12 | 13 | #if __clang__ 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 16 | #endif 17 | 18 | @implementation Super (cat3) 19 | +(void) method { 20 | state = 3; 21 | } 22 | +(void) method3 { 23 | state = 3; 24 | } 25 | +(void) load { 26 | testassert(state == 2); 27 | state = 3; 28 | } 29 | @end 30 | 31 | #if __clang__ 32 | #pragma clang diagnostic pop 33 | #endif 34 | -------------------------------------------------------------------------------- /test/imports.c: -------------------------------------------------------------------------------- 1 | /* 2 | Disallow some imports into and exports from libobjc.A.dylib. 3 | 4 | To debug, re-run libobjc's link command with 5 | -Xlinker -dead_strip -Xlinker -why_live -Xlinker SYMBOL_NAME_HERE 6 | 7 | Disallowed imports (nm -u): 8 | ___cxa_guard_acquire (C++ function-scope static initializer) 9 | ___cxa_guard_release (C++ function-scope static initializer) 10 | ___cxa_atexit (C++ static destructor) 11 | weak external (any weak externals, including operators new and delete) 12 | 13 | Whitelisted imports: 14 | weak external ____chkstk_darwin (from libSystem) 15 | weak external _objc_bp_assist_cfg_np (from libSystem) 16 | 17 | Disallowed exports (nm -U): 18 | __Z* (any C++-mangled export) 19 | weak external (any weak externals, including operators new and delete) 20 | 21 | fixme rdar://13354718 should disallow anything from libc++ (i.e. not libc++abi) 22 | */ 23 | 24 | /* 25 | TEST_BUILD 26 | echo $C{XCRUN} nm -m -arch $C{ARCH} $C{TESTLIB} 27 | $C{XCRUN} nm -u -m -arch $C{ARCH} $C{TESTLIB} | grep -v 'weak external ____chkstk_darwin \(from libSystem\)' | grep -v 'weak external _objc_bp_assist_cfg_np \(from libSystem\)' | egrep '(weak external| external (___cxa_atexit|___cxa_guard_acquire|___cxa_guard_release))' || true 28 | $C{XCRUN} nm -U -m -arch $C{ARCH} $C{TESTLIB} | egrep '(weak external| external __Z)' || true 29 | $C{COMPILE_C} $DIR/imports.c -o imports.exe 30 | END 31 | 32 | TEST_BUILD_OUTPUT 33 | .*libobjc.A.dylib 34 | END 35 | */ 36 | 37 | #include "test.h" 38 | int main() 39 | { 40 | succeed(__FILE__); 41 | } 42 | -------------------------------------------------------------------------------- /test/include-warnings.c: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/include-warnings.c -o include-warnings.exe -Wsystem-headers -Weverything -Wno-undef -Wno-old-style-cast -Wno-nullability-extension -Wno-c++98-compat 2>&1 | grep -v 'In file' | grep objc || true 4 | END 5 | 6 | TEST_RUN_OUTPUT 7 | OK: includes.c 8 | END 9 | */ 10 | 11 | // Detect warnings inside any header. 12 | // The build command above filters out warnings inside non-objc headers 13 | // (which are noisy with -Weverything). 14 | // -Wno-undef suppresses warnings about `#if __cplusplus` and the like. 15 | // -Wno-old-style-cast is tough to avoid in mixed C/C++ code. 16 | // -Wno-nullability-extension disables a warning about non-portable 17 | // _Nullable etc which we already handle correctly in objc-abi.h. 18 | // -Wno-c++98-compat disables warnings about things that already 19 | // have guards against C++98. 20 | 21 | #include "includes.c" 22 | -------------------------------------------------------------------------------- /test/includes-objc2.c: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -D__OBJC2__ 2 | 3 | // Verify that all headers can be included in any language, even if 4 | // the client is C code that defined __OBJC2__. 5 | 6 | // This is the definition that Instruments uses in its build. 7 | #if defined(__OBJC2__) 8 | #undef __OBJC2__ 9 | #endif 10 | #define __OBJC2__ 1 11 | 12 | #define NAME "includes-objc2.c" 13 | #include "includes.c" 14 | -------------------------------------------------------------------------------- /test/includes.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | // Verify that all headers can be included in any language. 4 | // See also test/include-warnings.c which checks for warnings in these headers. 5 | // See also test/includes-objc2.c which checks for safety even if 6 | // the client is C code that defined __OBJC2__. 7 | 8 | #ifndef NAME 9 | #define NAME "includes.c" 10 | #endif 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #if TARGET_OS_OSX 34 | #include 35 | #include 36 | #include 37 | #endif 38 | 39 | #pragma clang diagnostic push 40 | #pragma clang diagnostic ignored "-Weverything" 41 | #include "test.h" 42 | #pragma clang diagnostic pop 43 | 44 | int main() 45 | { 46 | succeed(NAME); 47 | } 48 | -------------------------------------------------------------------------------- /test/instanceSize.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | 8 | @interface Sub1 : TestRoot { 9 | // id isa; // 0..4 10 | BOOL b; // 4..5 11 | } 12 | @end 13 | 14 | @implementation Sub1 @end 15 | 16 | @interface Sub2 : Sub1 { 17 | // id isa // 0..4 0..8 18 | // BOOL b // 4..5 8..9 19 | BOOL b2; // 5..6 9..10 20 | id o; // 8..12 16..24 21 | } 22 | @end 23 | @implementation Sub2 @end 24 | 25 | @interface Sub3 : Sub1 { 26 | // id isa; // 0..4 0..8 27 | // BOOL b; // 4..5 8..9 28 | id o; // 8..12 16..24 29 | BOOL b2; // 12..13 24..25 30 | } 31 | @end 32 | @implementation Sub3 @end 33 | 34 | int main() 35 | { 36 | testassert(sizeof(id) == class_getInstanceSize([TestRoot class])); 37 | testassert(2*sizeof(id) == class_getInstanceSize([Sub1 class])); 38 | testassert(3*sizeof(id) == class_getInstanceSize([Sub2 class])); 39 | testassert(4*sizeof(id) == class_getInstanceSize([Sub3 class])); 40 | 41 | #if !__has_feature(objc_arc) 42 | id o; 43 | 44 | o = [TestRoot new]; 45 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 46 | RELEASE_VAR(o); 47 | o = [Sub1 new]; 48 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 49 | RELEASE_VAR(o); 50 | o = [Sub2 new]; 51 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 52 | RELEASE_VAR(o); 53 | o = [Sub3 new]; 54 | testassert(object_getIndexedIvars(o) == (char *)o + class_getInstanceSize(object_getClass(o))); 55 | RELEASE_VAR(o); 56 | #endif 57 | 58 | succeed(__FILE__); 59 | } 60 | -------------------------------------------------------------------------------- /test/ismeta.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | int main() 8 | { 9 | testassert(!class_isMetaClass([TestRoot class])); 10 | testassert(class_isMetaClass(object_getClass([TestRoot class]))); 11 | testassert(!class_isMetaClass(nil)); 12 | succeed(__FILE__); 13 | } 14 | -------------------------------------------------------------------------------- /test/ivarSlide.h: -------------------------------------------------------------------------------- 1 | @interface Super : TestRoot { 2 | @public 3 | #if OLD 4 | // nothing 5 | #else 6 | char superIvar; 7 | #endif 8 | } 9 | @end 10 | 11 | 12 | @interface ShrinkingSuper : TestRoot { 13 | @public 14 | #if OLD 15 | id superIvar[5]; 16 | __weak id superIvar2[5]; 17 | #else 18 | // nothing 19 | #endif 20 | } 21 | @end; 22 | 23 | 24 | @interface MoreStrongSuper : TestRoot { 25 | @public 26 | #if OLD 27 | void *superIvar; 28 | #else 29 | id superIvar; 30 | #endif 31 | } 32 | @end; 33 | 34 | 35 | @interface MoreWeakSuper : TestRoot { 36 | @public 37 | #if OLD 38 | id superIvar; 39 | #else 40 | __weak id superIvar; 41 | #endif 42 | } 43 | @end; 44 | 45 | @interface MoreWeak2Super : TestRoot { 46 | @public 47 | #if OLD 48 | void *superIvar; 49 | #else 50 | __weak id superIvar; 51 | #endif 52 | } 53 | @end; 54 | 55 | @interface LessStrongSuper : TestRoot { 56 | @public 57 | #if OLD 58 | id superIvar; 59 | #else 60 | void *superIvar; 61 | #endif 62 | } 63 | @end; 64 | 65 | @interface LessWeakSuper : TestRoot { 66 | @public 67 | #if OLD 68 | __weak id superIvar; 69 | #else 70 | id superIvar; 71 | #endif 72 | } 73 | @end; 74 | 75 | @interface LessWeak2Super : TestRoot { 76 | @public 77 | #if OLD 78 | __weak id superIvar; 79 | #else 80 | void *superIvar; 81 | #endif 82 | } 83 | @end; 84 | 85 | @interface NoGCChangeSuper : TestRoot { 86 | @public 87 | intptr_t d; 88 | char superc1; 89 | #if OLD 90 | // nothing 91 | #else 92 | char superc2; 93 | #endif 94 | } 95 | @end 96 | 97 | @interface RunsOf15 : TestRoot { 98 | @public 99 | id scan1; 100 | intptr_t skip15[15]; 101 | id scan15[15]; 102 | intptr_t skip15_2[15]; 103 | id scan15_2[15]; 104 | #if OLD 105 | // nothing 106 | #else 107 | intptr_t skip1; 108 | #endif 109 | } 110 | @end 111 | -------------------------------------------------------------------------------- /test/ivarSlide1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | #define OLD 0 6 | #include "ivarSlide.h" 7 | 8 | #include "testroot.i" 9 | 10 | @implementation Super @end 11 | 12 | @implementation ShrinkingSuper @end 13 | 14 | @implementation MoreStrongSuper @end 15 | @implementation LessStrongSuper @end 16 | @implementation MoreWeakSuper @end 17 | @implementation MoreWeak2Super @end 18 | @implementation LessWeakSuper @end 19 | @implementation LessWeak2Super @end 20 | @implementation NoGCChangeSuper @end 21 | @implementation RunsOf15 @end 22 | -------------------------------------------------------------------------------- /test/libraryPath.c: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -lobjc 2 | 3 | #include "test.h" 4 | #include 5 | 6 | // We use DYLD_LIBRARY_PATH to run the tests against a particular copy of 7 | // libobjc. If this fails somehow (path is wrong, codesigning prevents loading, 8 | // etc.) then the typical result is a silent failure and we end up testing 9 | // /usr/lib/libobjc.A.dylib instead. This test detects when DYLD_LIBRARY_PATH is 10 | // set but libobjc isn't loaded from it. 11 | int main(int argc __unused, char **argv) { 12 | char *containingDirectory = realpath(dirname(argv[0]), NULL); 13 | testprintf("containingDirectory is %s\n", containingDirectory); 14 | 15 | char *dyldLibraryPath = getenv("DYLD_LIBRARY_PATH"); 16 | testprintf("DYLD_LIBRARY_PATH is %s\n", dyldLibraryPath); 17 | 18 | if (dyldLibraryPath != NULL && strlen(dyldLibraryPath) > 0) { 19 | int foundMatch = 0; 20 | int foundNonMatch = 0; 21 | 22 | dyldLibraryPath = strdup(dyldLibraryPath); 23 | 24 | Dl_info info; 25 | int success = dladdr((void *)objc_msgSend, &info); 26 | testassert(success); 27 | 28 | testprintf("libobjc is located at %s\n", info.dli_fname); 29 | 30 | char *cursor = dyldLibraryPath; 31 | char *path; 32 | while ((path = strsep(&cursor, ":"))) { 33 | char *resolved = realpath(path, NULL); 34 | testprintf("Resolved %s to %s\n", path, resolved); 35 | if (strcmp(resolved, containingDirectory) == 0) { 36 | testprintf("This is equal to our containing directory, ignoring.\n"); 37 | continue; 38 | } 39 | testprintf("Comparing %s and %s\n", resolved, info.dli_fname); 40 | int comparison = strncmp(resolved, info.dli_fname, strlen(resolved)); 41 | free(resolved); 42 | if (comparison == 0) { 43 | testprintf("Found a match!\n"); 44 | foundMatch = 1; 45 | break; 46 | } else { 47 | foundNonMatch = 1; 48 | } 49 | } 50 | 51 | testprintf("Finished searching, foundMatch=%d foundNonMatch=%d\n", foundMatch, foundNonMatch); 52 | testassert(foundMatch || !foundNonMatch); 53 | } 54 | succeed(__FILE__); 55 | } 56 | -------------------------------------------------------------------------------- /test/literals.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #include "test.h" 9 | 10 | int main() { 11 | PUSH_POOL { 12 | 13 | #if __has_feature(objc_bool) // placeholder until we get a more precise macro. 14 | NSArray *array = @[ @1, @2, @YES, @NO, @"Hello", @"World" ]; 15 | testassert([array count] == 6); 16 | NSDictionary *dict = @{ @"Name" : @"John Q. Public", @"Age" : @42 }; 17 | testassert([dict count] == 2); 18 | NSDictionary *numbers = @{ @"π" : @M_PI, @"e" : @M_E }; 19 | testassert([[numbers objectForKey:@"π"] doubleValue] == M_PI); 20 | testassert([[numbers objectForKey:@"e"] doubleValue] == M_E); 21 | 22 | BOOL yesBool = YES; 23 | BOOL noBool = NO; 24 | array = @[ 25 | @(true), 26 | @(YES), 27 | [NSNumber numberWithBool:YES], 28 | @YES, 29 | @(yesBool), 30 | @((BOOL)YES), 31 | 32 | @(false), 33 | @(NO), 34 | [NSNumber numberWithBool:NO], 35 | @NO, 36 | @(noBool), 37 | @((BOOL)NO), 38 | ]; 39 | NSData * jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:nil]; 40 | NSString * string = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 41 | #if __cplusplus 42 | testassert([string isEqualToString:@"[true,true,true,true,true,true,false,false,false,false,false,false]"]); 43 | #else 44 | // C99 @(true) and @(false) evaluate to @(1) and @(0). 45 | testassert([string isEqualToString:@"[1,true,true,true,true,true,0,false,false,false,false,false]"]); 46 | #endif 47 | 48 | #endif 49 | 50 | } POP_POOL; 51 | 52 | succeed(__FILE__); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /test/load-image-notification-dylib.m: -------------------------------------------------------------------------------- 1 | #import "test.h" 2 | 3 | #import 4 | 5 | @interface CLASSNAME: NSObject @end 6 | @implementation CLASSNAME @end 7 | 8 | -------------------------------------------------------------------------------- /test/load-order.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-order3.m -o load-order3.dylib -dynamiclib 4 | $C{COMPILE} $DIR/load-order2.m -o load-order2.dylib -x none load-order3.dylib -dynamiclib 5 | $C{COMPILE} $DIR/load-order1.m -o load-order1.dylib -x none load-order3.dylib load-order2.dylib -dynamiclib 6 | $C{COMPILE} $DIR/load-order.m -o load-order.exe -x none load-order3.dylib load-order2.dylib load-order1.dylib 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | 12 | extern int state1, state2, state3; 13 | 14 | int main() 15 | { 16 | testassert(state1 == 1 && state2 == 2 && state3 == 3); 17 | succeed(__FILE__); 18 | } 19 | -------------------------------------------------------------------------------- /test/load-order1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern int state2, state3; 4 | 5 | int state1 = 0; 6 | 7 | OBJC_ROOT_CLASS 8 | @interface One @end 9 | @implementation One 10 | +(void)load 11 | { 12 | testassert(state2 == 2 && state3 == 3); 13 | state1 = 1; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /test/load-order2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern int state3; 4 | 5 | int state2 = 0; 6 | 7 | OBJC_ROOT_CLASS 8 | @interface Two @end 9 | @implementation Two 10 | +(void)load 11 | { 12 | testassert(state3 == 3); 13 | state2 = 2; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /test/load-order3.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int state3 = 0; 4 | 5 | OBJC_ROOT_CLASS 6 | @interface Three @end 7 | @implementation Three 8 | +(void)load 9 | { 10 | state3 = 3; 11 | } 12 | @end 13 | -------------------------------------------------------------------------------- /test/load-parallel.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-parallel00.m -o load-parallel00.dylib -dynamiclib 4 | $C{COMPILE} $DIR/load-parallel.m -x none load-parallel00.dylib -o load-parallel.exe -DCOUNT=10 5 | 6 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel0.dylib -dynamiclib -DN=0 7 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel1.dylib -dynamiclib -DN=1 8 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel2.dylib -dynamiclib -DN=2 9 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel3.dylib -dynamiclib -DN=3 10 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel4.dylib -dynamiclib -DN=4 11 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel5.dylib -dynamiclib -DN=5 12 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel6.dylib -dynamiclib -DN=6 13 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel7.dylib -dynamiclib -DN=7 14 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel8.dylib -dynamiclib -DN=8 15 | $C{COMPILE} $DIR/load-parallel0.m -x none load-parallel00.dylib -o load-parallel9.dylib -dynamiclib -DN=9 16 | END 17 | */ 18 | 19 | #include "test.h" 20 | 21 | #include 22 | #include 23 | 24 | #ifndef COUNT 25 | #error -DCOUNT=c missing 26 | #endif 27 | 28 | extern atomic_int state; 29 | 30 | void *thread(void *arg) 31 | { 32 | uintptr_t num = (uintptr_t)arg; 33 | char *buf; 34 | 35 | asprintf(&buf, "load-parallel%lu.dylib", (unsigned long)num); 36 | testprintf("%s\n", buf); 37 | void *dlh = dlopen(buf, RTLD_LAZY); 38 | if (!dlh) { 39 | fail("dlopen failed: %s", dlerror()); 40 | } 41 | free(buf); 42 | 43 | return NULL; 44 | } 45 | 46 | int main() 47 | { 48 | pthread_t t[COUNT]; 49 | uintptr_t i; 50 | 51 | for (i = 0; i < COUNT; i++) { 52 | pthread_create(&t[i], NULL, thread, (void *)i); 53 | } 54 | 55 | for (i = 0; i < COUNT; i++) { 56 | pthread_join(t[i], NULL); 57 | } 58 | 59 | testprintf("loaded %d/%d\n", (int)state, COUNT*26); 60 | testassert(state == COUNT*26); 61 | 62 | succeed(__FILE__); 63 | } 64 | -------------------------------------------------------------------------------- /test/load-parallel0.m: -------------------------------------------------------------------------------- 1 | #ifndef N 2 | #error -DN=n missing 3 | #endif 4 | 5 | #import 6 | #include 7 | #include 8 | #include 9 | #include "test.h" 10 | extern atomic_int state; 11 | 12 | #define CLASS0(n,nn) \ 13 | OBJC_ROOT_CLASS \ 14 | @interface C_##n##_##nn @end \ 15 | @implementation C_##n##_##nn \ 16 | +(void)load { \ 17 | atomic_fetch_add_explicit(&state, 1, memory_order_relaxed); \ 18 | usleep(10); } \ 19 | @end 20 | 21 | #define CLASS(n,nn) CLASS0(n,nn) 22 | 23 | CLASS(a,N) 24 | CLASS(b,N) 25 | CLASS(c,N) 26 | CLASS(d,N) 27 | CLASS(e,N) 28 | CLASS(f,N) 29 | CLASS(g,N) 30 | CLASS(h,N) 31 | CLASS(i,N) 32 | CLASS(j,N) 33 | CLASS(k,N) 34 | CLASS(l,N) 35 | CLASS(m,N) 36 | CLASS(n,N) 37 | CLASS(o,N) 38 | CLASS(p,N) 39 | CLASS(q,N) 40 | CLASS(r,N) 41 | CLASS(s,N) 42 | CLASS(t,N) 43 | CLASS(u,N) 44 | CLASS(v,N) 45 | CLASS(w,N) 46 | CLASS(x,N) 47 | CLASS(y,N) 48 | CLASS(z,N) 49 | -------------------------------------------------------------------------------- /test/load-parallel00.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | atomic_int state; 3 | -------------------------------------------------------------------------------- /test/load-reentrant.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/load-reentrant.m -o load-reentrant.exe 4 | $C{COMPILE} $DIR/load-reentrant2.m -o libload-reentrant2.dylib -bundle -bundle_loader load-reentrant.exe 5 | END 6 | */ 7 | 8 | #include "test.h" 9 | #include 10 | 11 | int state1 = 0; 12 | int *state2_p; 13 | 14 | OBJC_ROOT_CLASS 15 | @interface One @end 16 | @implementation One 17 | +(void)load 18 | { 19 | state1 = 111; 20 | 21 | // Re-entrant +load doesn't get to complete until we do 22 | void *dlh = dlopen("libload-reentrant2.dylib", RTLD_LAZY); 23 | testassert(dlh); 24 | state2_p = (int *)dlsym(dlh, "state2"); 25 | testassert(state2_p); 26 | testassert(*state2_p == 0); 27 | 28 | state1 = 1; 29 | } 30 | @end 31 | 32 | int main() 33 | { 34 | testassert(state1 == 1 && state2_p && *state2_p == 2); 35 | succeed(__FILE__); 36 | } 37 | -------------------------------------------------------------------------------- /test/load-reentrant2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int state2 = 0; 4 | extern int state1; 5 | 6 | static void ctor(void) __attribute__((constructor)); 7 | static void ctor(void) 8 | { 9 | // should be called during One's dlopen(), before Two's +load 10 | testassert(state1 == 111); 11 | testassert(state2 == 0); 12 | } 13 | 14 | OBJC_ROOT_CLASS 15 | @interface Two @end 16 | @implementation Two 17 | +(void) load 18 | { 19 | // Does not run until One's +load completes 20 | testassert(state1 == 1); 21 | state2 = 2; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /test/load.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | int state = 0; 7 | int catstate = 0; 8 | int deallocstate = 0; 9 | 10 | @interface Deallocator : TestRoot @end 11 | @implementation Deallocator 12 | -(void)dealloc { 13 | deallocstate = 1; 14 | SUPER_DEALLOC(); 15 | } 16 | @end 17 | 18 | 19 | @interface Super : TestRoot @end 20 | @implementation Super 21 | +(void)initialize { 22 | if (self == [Super class]) { 23 | testprintf("in +[Super initialize]\n"); 24 | testassert(state == 2); 25 | state = 3; 26 | } else { 27 | testprintf("in +[Super initialize] on behalf of Sub\n"); 28 | testassert(state == 3); 29 | state = 4; 30 | } 31 | } 32 | -(void)load { fail("-[Super load] called!"); } 33 | +(void)load { 34 | testprintf("in +[Super load]\n"); 35 | testassert(state == 0); 36 | state = 1; 37 | } 38 | @end 39 | 40 | @interface Sub : Super { } @end 41 | @implementation Sub 42 | +(void)load { 43 | testprintf("in +[Sub load]\n"); 44 | testassert(state == 1); 45 | state = 2; 46 | } 47 | -(void)load { fail("-[Sub load] called!"); } 48 | @end 49 | 50 | @interface SubNoLoad : Super { } @end 51 | @implementation SubNoLoad @end 52 | 53 | @interface Super (Category) @end 54 | @implementation Super (Category) 55 | -(void)load { fail("-[Super(Category) load called!"); } 56 | +(void)load { 57 | testprintf("in +[Super(Category) load]\n"); 58 | testassert(state >= 1); 59 | catstate++; 60 | } 61 | @end 62 | 63 | 64 | @interface Sub (Category) @end 65 | @implementation Sub (Category) 66 | -(void)load { fail("-[Sub(Category) load called!"); } 67 | +(void)load { 68 | testprintf("in +[Sub(Category) load]\n"); 69 | testassert(state >= 2); 70 | catstate++; 71 | 72 | // test autorelease pool 73 | __autoreleasing id x; 74 | x = AUTORELEASE([Deallocator new]); 75 | } 76 | @end 77 | 78 | 79 | @interface SubNoLoad (Category) @end 80 | @implementation SubNoLoad (Category) 81 | -(void)load { fail("-[SubNoLoad(Category) load called!"); } 82 | +(void)load { 83 | testprintf("in +[SubNoLoad(Category) load]\n"); 84 | testassert(state >= 1); 85 | catstate++; 86 | } 87 | @end 88 | 89 | int main() 90 | { 91 | testassert(state == 2); 92 | testassert(catstate == 3); 93 | testassert(deallocstate == 1); 94 | [Sub class]; 95 | testassert(state == 4); 96 | testassert(catstate == 3); 97 | 98 | succeed(__FILE__); 99 | } 100 | -------------------------------------------------------------------------------- /test/methodCacheLeaks.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc LANGUAGE=objective-c 2 | /* 3 | TEST_RUN_OUTPUT 4 | [\S\s]*0 leaks for 0 total leaked bytes[\S\s]* 5 | END 6 | */ 7 | 8 | #include "test.h" 9 | #include "testroot.i" 10 | 11 | #include 12 | #include 13 | 14 | void noopIMP(id self __unused, SEL _cmd __unused) {} 15 | 16 | id test(int n, int methodCount) { 17 | char *name; 18 | asprintf(&name, "TestClass%d", n); 19 | Class c = objc_allocateClassPair([TestRoot class], name, 0); 20 | free(name); 21 | 22 | SEL *sels = malloc(methodCount * sizeof(*sels)); 23 | for(int i = 0; i < methodCount; i++) { 24 | asprintf(&name, "selector%d", i); 25 | sels[i] = sel_getUid(name); 26 | free(name); 27 | } 28 | 29 | for(int i = 0; i < methodCount; i++) { 30 | class_addMethod(c, sels[i], (IMP)noopIMP, "v@:"); 31 | } 32 | 33 | objc_registerClassPair(c); 34 | 35 | id obj = [[c alloc] init]; 36 | for (int i = 0; i < methodCount; i++) { 37 | ((void (*)(id, SEL))objc_msgSend)(obj, sels[i]); 38 | } 39 | free(sels); 40 | return obj; 41 | } 42 | 43 | int main() 44 | { 45 | int classCount = 16; 46 | id *objs = malloc(classCount * sizeof(*objs)); 47 | for (int i = 0; i < classCount; i++) { 48 | objs[i] = test(i, 1 << i); 49 | } 50 | 51 | char *pidstr; 52 | int result = asprintf(&pidstr, "%u", getpid()); 53 | testassert(result); 54 | 55 | extern char **environ; 56 | char *argv[] = { "/usr/bin/leaks", pidstr, NULL }; 57 | pid_t pid; 58 | result = posix_spawn(&pid, "/usr/bin/leaks", NULL, NULL, argv, environ); 59 | if (result) { 60 | perror("posix_spawn"); 61 | exit(1); 62 | } 63 | wait4(pid, NULL, 0, NULL); 64 | 65 | // Clean up. Otherwise leaks can end up seeing this as a leak, oddly enough. 66 | for (int i = 0; i < classCount; i++) { 67 | [objs[i] release]; 68 | } 69 | free(objs); 70 | } 71 | -------------------------------------------------------------------------------- /test/methodListSize.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | // rdar://8052003 rdar://8077031 3 | 4 | #include "test.h" 5 | 6 | #include 7 | #include 8 | 9 | // add SELCOUNT methods to each of CLASSCOUNT classes 10 | #define CLASSCOUNT 100 11 | #define SELCOUNT 200 12 | 13 | int main() 14 | { 15 | int i, j; 16 | malloc_statistics_t start, end; 17 | 18 | Class root; 19 | root = objc_allocateClassPair(NULL, "Root", 0); 20 | objc_registerClassPair(root); 21 | 22 | Class classes[CLASSCOUNT]; 23 | for (i = 0; i < CLASSCOUNT; i++) { 24 | char *classname; 25 | asprintf(&classname, "GrP_class_%d", i); 26 | classes[i] = objc_allocateClassPair(root, classname, 0); 27 | objc_registerClassPair(classes[i]); 28 | free(classname); 29 | } 30 | 31 | SEL selectors[SELCOUNT]; 32 | for (i = 0; i < SELCOUNT; i++) { 33 | char *selname; 34 | asprintf(&selname, "GrP_sel_%d", i); 35 | selectors[i] = sel_registerName(selname); 36 | free(selname); 37 | } 38 | 39 | malloc_zone_statistics(NULL, &start); 40 | 41 | for (i = 0; i < CLASSCOUNT; i++) { 42 | for (j = 0; j < SELCOUNT; j++) { 43 | class_addMethod(classes[i], selectors[j], (IMP)main, ""); 44 | } 45 | } 46 | 47 | malloc_zone_statistics(NULL, &end); 48 | 49 | // expected: 3-word method struct plus two other words 50 | ssize_t expected = (sizeof(void*) * (3+2)) * SELCOUNT * CLASSCOUNT; 51 | ssize_t actual = end.size_in_use - start.size_in_use; 52 | testassert(actual < expected * 3); // allow generous fudge factor 53 | 54 | succeed(__FILE__); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/nilAPIArgs.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD_OUTPUT 3 | .*nilAPIArgs.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\] 4 | .*nilAPIArgs.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\] 5 | END 6 | */ 7 | 8 | #include "test.h" 9 | 10 | #import 11 | 12 | int main() { 13 | // ensure various bits of API don't crash when tossed nil parameters 14 | class_conformsToProtocol(nil, nil); 15 | method_setImplementation(nil, NULL); 16 | 17 | succeed(__FILE__); 18 | } 19 | -------------------------------------------------------------------------------- /test/nopool.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | @implementation TestRoot (Loader) 7 | +(void)load 8 | { 9 | [[TestRoot new] autorelease]; 10 | testassert(TestRootAutorelease == 1); 11 | testassert(TestRootDealloc == 0); 12 | } 13 | @end 14 | 15 | int main() 16 | { 17 | // +load's autoreleased object should have deallocated 18 | testassert(TestRootDealloc == 1); 19 | 20 | [[TestRoot new] autorelease]; 21 | testassert(TestRootAutorelease == 2); 22 | 23 | 24 | objc_autoreleasePoolPop(objc_autoreleasePoolPush()); 25 | [[TestRoot new] autorelease]; 26 | testassert(TestRootAutorelease == 3); 27 | 28 | 29 | testonthread(^{ 30 | [[TestRoot new] autorelease]; 31 | testassert(TestRootAutorelease == 4); 32 | testassert(TestRootDealloc == 1); 33 | }); 34 | // thread's autoreleased object should have deallocated 35 | testassert(TestRootDealloc == 2); 36 | 37 | 38 | // Test no-pool autorelease after a pool was pushed and popped. 39 | // The simplest POOL_SENTINEL check during pop gets this wrong. 40 | testonthread(^{ 41 | objc_autoreleasePoolPop(objc_autoreleasePoolPush()); 42 | [[TestRoot new] autorelease]; 43 | testassert(TestRootAutorelease == 5); 44 | testassert(TestRootDealloc == 2); 45 | }); 46 | testassert(TestRootDealloc == 3 47 | ); 48 | succeed(__FILE__); 49 | } 50 | -------------------------------------------------------------------------------- /test/nscdtors.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | // test cdtors, with NSObject instead of TestRoot as the root class 3 | 4 | #define USE_FOUNDATION 1 5 | #include "cdtors.mm" 6 | 7 | -------------------------------------------------------------------------------- /test/nsexc.m: -------------------------------------------------------------------------------- 1 | /* 2 | need exception-safe ARC for exception deallocation tests 3 | TEST_CFLAGS -fobjc-arc-exceptions -framework Foundation 4 | */ 5 | 6 | #define USE_FOUNDATION 1 7 | #include "exc.m" 8 | -------------------------------------------------------------------------------- /test/nsprotocol.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | 6 | int main() 7 | { 8 | // Class Protocol is always a subclass of NSObject 9 | 10 | testassert(objc_getClass("NSObject")); 11 | 12 | Class cls = objc_getClass("Protocol"); 13 | testassert(class_getInstanceMethod(cls, sel_registerName("isProxy"))); 14 | testassert(class_getSuperclass(cls) == objc_getClass("NSObject")); 15 | 16 | succeed(__FILE__); 17 | } 18 | -------------------------------------------------------------------------------- /test/objectCopy.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include 5 | 6 | @interface Test : NSObject { 7 | @public 8 | char bytes[32-sizeof(void*)]; 9 | } 10 | @end 11 | @implementation Test 12 | @end 13 | 14 | 15 | int main() 16 | { 17 | Test *o0 = [Test new]; 18 | [o0 retain]; 19 | Test *o1 = class_createInstance([Test class], 32); 20 | [o1 retain]; 21 | id o2 = object_copy(o0, 0); 22 | id o3 = object_copy(o1, 0); 23 | id o4 = object_copy(o1, 32); 24 | 25 | testassert(malloc_size(o0) == 32); 26 | testassert(malloc_size(o1) == 64); 27 | testassert(malloc_size(o2) == 32); 28 | testassert(malloc_size(o3) == 32); 29 | testassert(malloc_size(o4) == 64); 30 | 31 | testassert([o0 retainCount] == 2); 32 | testassert([o1 retainCount] == 2); 33 | testassert([o2 retainCount] == 1); 34 | testassert([o3 retainCount] == 1); 35 | testassert([o4 retainCount] == 1); 36 | 37 | succeed(__FILE__); 38 | } 39 | -------------------------------------------------------------------------------- /test/preopt-caches.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.springboard-ui.client 6 | 7 | com.apple.security.system-groups 8 | 9 | systemgroup.com.apple.powerlog 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/rawisa.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CFLAGS -Xlinker -sectcreate -Xlinker __DATA -Xlinker __objc_rawisa -Xlinker /dev/null 3 | TEST_ENV OBJC_PRINT_RAW_ISA=YES 4 | 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: RAW ISA: disabling non-pointer isa because the app has a __DATA,__objc_rawisa section 7 | (.* RAW ISA: .*\n)* 8 | OK: rawisa.m(\n.* RAW ISA: .*)* 9 | OR 10 | (.* RAW ISA: .*\n)* 11 | no __DATA,__rawisa support 12 | OK: rawisa.m(\n.* RAW ISA: .*)* 13 | END 14 | 15 | "RAW ISA" is allowed after "OK" because of static destructors 16 | that provoke class realization. 17 | */ 18 | 19 | #include "test.h" 20 | 21 | int main() 22 | { 23 | fprintf(stderr, "\n"); 24 | #if ! (SUPPORT_NONPOINTER_ISA && TARGET_OS_OSX) 25 | // only 64-bit Mac supports this 26 | fprintf(stderr, "no __DATA,__rawisa support\n"); 27 | #endif 28 | succeed(__FILE__); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /test/realizedClassGenerationCount.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | #include 7 | 8 | extern uintptr_t objc_debug_realized_class_generation_count; 9 | 10 | int main() 11 | { 12 | testassert(objc_debug_realized_class_generation_count > 0); 13 | uintptr_t prev = objc_debug_realized_class_generation_count; 14 | 15 | void *handle = dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY); 16 | testassert(handle); 17 | Class c = objc_getClass("NSFileManager"); 18 | testassert(c); 19 | testassert(objc_debug_realized_class_generation_count > prev); 20 | 21 | prev = objc_debug_realized_class_generation_count; 22 | c = objc_allocateClassPair([TestRoot class], "Dynamic", 0); 23 | testassert(objc_debug_realized_class_generation_count > prev); 24 | prev = objc_debug_realized_class_generation_count; 25 | objc_registerClassPair(c); 26 | testassert(objc_debug_realized_class_generation_count == prev); 27 | 28 | succeed(__FILE__); 29 | } -------------------------------------------------------------------------------- /test/release-workaround.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG ARCH=x86_64 MEM=mrc 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | // rdar://20206767 5 | 6 | #include 7 | #include "test.h" 8 | 9 | 10 | @interface Test : NSObject @end 11 | @implementation Test 12 | @end 13 | 14 | 15 | int main() 16 | { 17 | id buf[1]; 18 | buf[0] = [Test class]; 19 | id obj = (id)buf; 20 | [obj retain]; 21 | [obj retain]; 22 | 23 | uintptr_t rax; 24 | 25 | [obj release]; 26 | asm("mov %%rax, %0" : "=r" (rax)); 27 | testassert(rax == 0); 28 | 29 | objc_release(obj); 30 | asm("mov %%rax, %0" : "=r" (rax)); 31 | testassert(rax == 0); 32 | 33 | succeed(__FILE__); 34 | } 35 | -------------------------------------------------------------------------------- /test/restartableRangesSynchronizeStress.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=macosx,iphoneos,tvos,watchos 2 | // TEST_ENV OBJC_DEBUG_SCRIBBLE_CACHES=YES 3 | // TEST_NO_MALLOC_SCRIBBLE 4 | 5 | // This test checks that objc_msgSend's recovery path works correctly. 6 | // It continuously runs msgSend on some background threads, then 7 | // triggers the recovery path constantly as a stress test. 8 | 9 | #include "test.h" 10 | #include "testroot.i" 11 | #include 12 | 13 | struct Big { 14 | uintptr_t a, b, c, d, e, f, g; 15 | }; 16 | 17 | @interface C1: TestRoot 18 | @end 19 | @implementation C1 20 | - (id)idret { return nil; } 21 | - (double)fpret { return 0.0; } 22 | - (long double)lfpret { return 0.0; } 23 | - (struct Big)stret { return (struct Big){}; } 24 | @end 25 | 26 | @interface C2: C1 27 | @end 28 | @implementation C2 29 | - (id)idret { return [super idret]; } 30 | - (double)fpret { return [super fpret]; } 31 | - (long double)lfpret { return [super lfpret]; } 32 | - (struct Big)stret { return [super stret]; } 33 | @end 34 | 35 | EXTERN_C kern_return_t task_restartable_ranges_synchronize(task_t task); 36 | 37 | EXTERN_C void sendWithMsgLookup(id self, SEL _cmd); 38 | 39 | #if defined(__arm64__) && !__has_feature(ptrauth_calls) 40 | asm( 41 | "_sendWithMsgLookup: \n" 42 | " stp fp, lr, [sp, #-16]! \n" 43 | " mov fp, sp \n" 44 | " bl _objc_msgLookup \n" 45 | " mov sp, fp \n" 46 | " ldp fp, lr, [sp], #16 \n" 47 | " br x17 \n" 48 | ); 49 | #elif defined(__x86_64__) 50 | asm( 51 | "_sendWithMsgLookup: \n" 52 | " pushq %rbp \n" 53 | " movq %rsp, %rbp \n" 54 | " callq _objc_msgLookup \n" 55 | " popq %rbp \n" 56 | " jmpq *%r11 \n" 57 | ); 58 | #else 59 | // Just skip it. 60 | void sendWithMsgLookup(id self __unused, SEL _cmd __unused) {} 61 | #endif 62 | 63 | int main() { 64 | id obj = [C2 new]; 65 | for(int i = 0; i < 2; i++) { 66 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 67 | while(1) { 68 | [obj idret]; 69 | [obj fpret]; 70 | [obj lfpret]; 71 | [obj stret]; 72 | sendWithMsgLookup(obj, @selector(idret)); 73 | } 74 | }); 75 | } 76 | for(int i = 0; i < 1000000; i++) { 77 | task_restartable_ranges_synchronize(mach_task_self()); 78 | } 79 | Class c = [C1 class]; 80 | for(int i = 0; i < 1000000; i++) { 81 | _objc_flush_caches(c); 82 | } 83 | succeed(__FILE__); 84 | } 85 | -------------------------------------------------------------------------------- /test/restartableRangesSynchronizeStress2.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=arc LANGUAGE=objective-c 2 | // TEST_ENV OBJC_DEBUG_SCRIBBLE_CACHES=YES 3 | // TEST_NO_MALLOC_SCRIBBLE 4 | 5 | // Stress test thread-safe cache deallocation and reallocation. 6 | 7 | #include "test.h" 8 | #include "testroot.i" 9 | #include 10 | 11 | @interface MyClass1 : TestRoot 12 | @end 13 | @implementation MyClass1 14 | @end 15 | 16 | @interface MyClass2 : TestRoot 17 | @end 18 | @implementation MyClass2 19 | @end 20 | 21 | @interface MyClass3 : TestRoot 22 | @end 23 | @implementation MyClass3 24 | @end 25 | 26 | @interface MyClass4 : TestRoot 27 | @end 28 | @implementation MyClass4 29 | @end 30 | 31 | int main() { 32 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 33 | usleep(200000); 34 | while (1) { 35 | usleep(1000); 36 | _objc_flush_caches(MyClass1.class); 37 | _objc_flush_caches(MyClass2.class); 38 | _objc_flush_caches(MyClass3.class); 39 | _objc_flush_caches(MyClass4.class); 40 | } 41 | }); 42 | 43 | for (int i = 0; i < 6; i++) { 44 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 45 | long j = 0; 46 | while (1) { 47 | j++; 48 | (void)[[MyClass1 alloc] init]; 49 | (void)[[MyClass2 alloc] init]; 50 | (void)[[MyClass3 alloc] init]; 51 | (void)[[MyClass4 alloc] init]; 52 | } 53 | }); 54 | } 55 | 56 | sleep(5); 57 | 58 | succeed(__FILE__); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /test/rr-autorelease-stacklogging.m: -------------------------------------------------------------------------------- 1 | // Test OBJC_DEBUG_POOL_ALLOCATION (which is also enabled by MallocStackLogging) 2 | 3 | // TEST_ENV OBJC_DEBUG_POOL_ALLOCATION=YES 4 | // TEST_CFLAGS -framework Foundation 5 | // TEST_CONFIG MEM=mrc 6 | 7 | #include "test.h" 8 | 9 | #define FOUNDATION 0 10 | #define NAME "rr-autorelease-stacklogging" 11 | #define DEBUG_POOL_ALLOCATION 1 12 | 13 | #include "rr-autorelease2.m" 14 | -------------------------------------------------------------------------------- /test/rr-autorelease.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc 3 | 4 | #include "test.h" 5 | 6 | #define FOUNDATION 0 7 | #define NAME "rr-autorelease" 8 | 9 | #include "rr-autorelease2.m" 10 | -------------------------------------------------------------------------------- /test/rr-nsautorelease.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc 3 | 4 | #define FOUNDATION 1 5 | #define NAME "rr-nsautorelease" 6 | 7 | #include "rr-autorelease2.m" 8 | -------------------------------------------------------------------------------- /test/rr-sidetable.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | // TEST_CONFIG MEM=mrc ARCH=x86_64 3 | 4 | // Stress-test nonpointer isa's side table retain count transfers. 5 | 6 | // x86_64 only. arm64's side table limit is high enough that bugs 7 | // are harder to reproduce. 8 | 9 | #include "test.h" 10 | #import 11 | 12 | #define OBJECTS 10 13 | #define LOOPS 256 14 | #define THREADS 16 15 | #if __x86_64__ 16 | # define RC_HALF (1ULL<<7) 17 | #else 18 | # error sorry 19 | #endif 20 | #define RC_DELTA RC_HALF 21 | 22 | static bool Deallocated = false; 23 | @interface Deallocator : NSObject @end 24 | @implementation Deallocator 25 | -(void)dealloc { 26 | Deallocated = true; 27 | [super dealloc]; 28 | } 29 | @end 30 | 31 | // This is global to avoid extra retains by the dispatch block objects. 32 | static Deallocator *obj; 33 | 34 | int main() { 35 | dispatch_queue_t queue = 36 | dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 37 | 38 | for (size_t i = 0; i < OBJECTS; i++) { 39 | obj = [Deallocator new]; 40 | 41 | dispatch_apply(THREADS, queue, ^(size_t i __unused) { 42 | for (size_t a = 0; a < LOOPS; a++) { 43 | for (size_t b = 0; b < RC_DELTA; b++) { 44 | [obj retain]; 45 | } 46 | for (size_t b = 0; b < RC_DELTA; b++) { 47 | [obj release]; 48 | } 49 | } 50 | }); 51 | 52 | testassert(!Deallocated); 53 | [obj release]; 54 | testassert(Deallocated); 55 | Deallocated = false; 56 | } 57 | 58 | succeed(__FILE__); 59 | } 60 | -------------------------------------------------------------------------------- /test/sel.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD_OUTPUT 3 | .*sel.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? 4 | .*sel.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? 5 | END 6 | */ 7 | 8 | #include "test.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() 15 | { 16 | // Make sure @selector values are correctly fixed up 17 | testassert(@selector(foo) == sel_registerName("foo")); 18 | 19 | // sel_getName recognizes the zero SEL 20 | testassert(0 == strcmp("", sel_getName(0))); 21 | 22 | // sel_lookUpByName returns NULL for NULL string 23 | testassert(NULL == sel_lookUpByName(NULL)); 24 | 25 | // sel_lookUpByName returns NULL for unregistered and matches later registered selector 26 | { 27 | SEL sel; 28 | testassert(NULL == sel_lookUpByName("__testSelectorLookUp:")); 29 | testassert(NULL != (sel = sel_registerName("__testSelectorLookUp:"))); 30 | testassert(sel == sel_lookUpByName("__testSelectorLookUp:")); 31 | } 32 | 33 | // sel_lookUpByName matches @selector value 34 | testassert(@selector(foo2) == sel_lookUpByName("foo2")); 35 | 36 | succeed(__FILE__); 37 | } 38 | -------------------------------------------------------------------------------- /test/setAssociatedObjectHook.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG MEM=mrc 3 | TEST_ENV OBJC_DISABLE_NONPOINTER_ISA=YES 4 | */ 5 | 6 | #include "test.h" 7 | #include "testroot.i" 8 | 9 | bool hasAssociations = false; 10 | 11 | @interface TestRoot (AssocHooks) 12 | @end 13 | 14 | @implementation TestRoot (AssocHooks) 15 | 16 | - (void)_noteAssociatedObjects { 17 | hasAssociations = true; 18 | } 19 | 20 | // -_noteAssociatedObjects is currently limited to raw-isa custom-rr to avoid overhead 21 | - (void) release { 22 | } 23 | 24 | @end 25 | 26 | int main() { 27 | id obj = [TestRoot new]; 28 | id value = [TestRoot new]; 29 | const void *key = "key"; 30 | objc_setAssociatedObject(obj, key, value, OBJC_ASSOCIATION_RETAIN); 31 | testassert(hasAssociations == true); 32 | 33 | id out = objc_getAssociatedObject(obj, key); 34 | testassert(out == value); 35 | 36 | hasAssociations = false; 37 | key = "key2"; 38 | objc_setAssociatedObject(obj, key, value, OBJC_ASSOCIATION_RETAIN); 39 | testassert(hasAssociations == false); //only called once 40 | 41 | 42 | out = objc_getAssociatedObject(obj, key); 43 | testassert(out == value); 44 | 45 | succeed(__FILE__); 46 | } 47 | -------------------------------------------------------------------------------- /test/setSuper.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | @interface Super1 : TestRoot @end 8 | @implementation Super1 9 | +(int)classMethod { return 1; } 10 | -(int)instanceMethod { return 10000; } 11 | @end 12 | 13 | @interface Super2 : TestRoot @end 14 | @implementation Super2 15 | +(int)classMethod { return 2; } 16 | -(int)instanceMethod { return 20000; } 17 | @end 18 | 19 | @interface Sub : Super1 @end 20 | @implementation Sub 21 | +(int)classMethod { return [super classMethod] + 100; } 22 | -(int)instanceMethod { 23 | return [super instanceMethod] + 1000000; 24 | } 25 | @end 26 | 27 | int main() 28 | { 29 | Class cls; 30 | Sub *obj = [Sub new]; 31 | 32 | testassert(101 == [[Sub class] classMethod]); 33 | testassert(1010000 == [obj instanceMethod]); 34 | 35 | cls = class_setSuperclass([Sub class], [Super2 class]); 36 | 37 | testassert(cls == [Super1 class]); 38 | testassert(object_getClass(cls) == object_getClass([Super1 class])); 39 | 40 | testassert(102 == [[Sub class] classMethod]); 41 | testassert(1020000 == [obj instanceMethod]); 42 | 43 | succeed(__FILE__); 44 | } 45 | -------------------------------------------------------------------------------- /test/super.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | 7 | @interface Sub : TestRoot @end 8 | @implementation Sub @end 9 | 10 | int main() 11 | { 12 | // [super ...] messages are tested in msgSend.m 13 | 14 | testassert(class_getSuperclass([Sub class]) == [TestRoot class]); 15 | testassert(class_getSuperclass(object_getClass([Sub class])) == object_getClass([TestRoot class])); 16 | testassert(class_getSuperclass([TestRoot class]) == Nil); 17 | testassert(class_getSuperclass(object_getClass([TestRoot class])) == [TestRoot class]); 18 | testassert(class_getSuperclass(Nil) == Nil); 19 | 20 | succeed(__FILE__); 21 | } 22 | -------------------------------------------------------------------------------- /test/supported-inline-refcnt.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | // TEST_CFLAGS -framework CoreFoundation -Weverything 3 | 4 | #pragma clang diagnostic push 5 | #pragma clang diagnostic ignored "-Weverything" 6 | #include "test.h" 7 | #pragma clang diagnostic pop 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | // Some warnings just aren't feasible to work around. We'll disable them instead. 14 | #pragma clang diagnostic ignored "-Watomic-implicit-seq-cst" 15 | #pragma clang diagnostic ignored "-Wdirect-ivar-access" 16 | #pragma clang diagnostic ignored "-Wold-style-cast" 17 | 18 | static int deallocCount; 19 | @interface Refcnt: NSObject @end 20 | @implementation Refcnt { 21 | int _rc; 22 | } 23 | 24 | _OBJC_SUPPORTED_INLINE_REFCNT(_rc) 25 | 26 | - (void)dealloc { 27 | deallocCount++; 28 | [super dealloc]; 29 | } 30 | 31 | @end 32 | 33 | @interface MainRefcnt: NSObject @end 34 | @implementation MainRefcnt { 35 | int _rc; 36 | } 37 | 38 | _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc) 39 | 40 | - (void)dealloc { 41 | testassert(pthread_main_np()); 42 | deallocCount++; 43 | [super dealloc]; 44 | } 45 | 46 | @end 47 | 48 | int main() 49 | { 50 | Refcnt *obj = [Refcnt new]; 51 | [obj retain]; 52 | [obj retain]; 53 | [obj retain]; 54 | [obj release]; 55 | [obj release]; 56 | [obj release]; 57 | [obj release]; 58 | testassert(deallocCount == 1); 59 | 60 | MainRefcnt *obj2 = [MainRefcnt new]; 61 | [obj2 retain]; 62 | [obj2 retain]; 63 | [obj2 retain]; 64 | 65 | dispatch_group_t group = dispatch_group_create(); 66 | dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ 67 | [obj2 release]; 68 | }); 69 | dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ 70 | [obj2 release]; 71 | }); 72 | dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ 73 | [obj2 release]; 74 | }); 75 | dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ 76 | [obj2 release]; 77 | }); 78 | 79 | dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 80 | testassert(deallocCount == 2); 81 | succeed(__FILE__); 82 | }); 83 | 84 | CFRunLoopRun(); 85 | } 86 | -------------------------------------------------------------------------------- /test/swiftMetadataInitializer.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include "swift-class-def.m" 5 | 6 | 7 | SWIFT_CLASS(SwiftSuper, NSObject, initSuper); 8 | SWIFT_CLASS(SwiftSub, SwiftSuper, initSub); 9 | 10 | // _objc_swiftMetadataInitializer hooks for the fake Swift classes 11 | 12 | Class initSuper(Class cls __unused, void *arg __unused) 13 | { 14 | // This test provokes objc's callback out of superclass order. 15 | // SwiftSub's init is first. SwiftSuper's init is never called. 16 | 17 | fail("SwiftSuper's init should not have been called"); 18 | } 19 | 20 | bool isRealized(Class cls) 21 | { 22 | // check the is-realized bits directly 23 | 24 | #if __LP64__ 25 | # define mask (~(uintptr_t)7) 26 | #else 27 | # define mask (~(uintptr_t)3) 28 | #endif 29 | #define RW_REALIZED (1<<31) 30 | 31 | uintptr_t rw = ((uintptr_t *)cls)[4] & mask; // class_t->data 32 | return ((uint32_t *)rw)[0] & RW_REALIZED; // class_rw_t->flags 33 | } 34 | 35 | static int SubInits = 0; 36 | Class initSub(Class cls, void *arg) 37 | { 38 | testprintf("initSub callback\n"); 39 | 40 | testassert(SubInits == 0); 41 | SubInits++; 42 | testassert(arg == nil); 43 | testassert(0 == strcmp(class_getName(cls), "SwiftSub")); 44 | testassert(cls == RawSwiftSub); 45 | testassert(!isRealized(RawSwiftSuper)); 46 | testassert(!isRealized(RawSwiftSub)); 47 | 48 | testprintf("initSub beginning _objc_realizeClassFromSwift\n"); 49 | _objc_realizeClassFromSwift(cls, cls); 50 | testprintf("initSub finished _objc_realizeClassFromSwift\n"); 51 | 52 | testassert(isRealized(RawSwiftSuper)); 53 | testassert(isRealized(RawSwiftSub)); 54 | 55 | return cls; 56 | } 57 | 58 | 59 | int main() 60 | { 61 | testassert(SubInits == 0); 62 | testprintf("calling [SwiftSub class]\n"); 63 | [SwiftSub class]; 64 | testprintf("finished [SwiftSub class]\n"); 65 | testassert(SubInits == 1); 66 | [SwiftSuper class]; 67 | succeed(__FILE__); 68 | } 69 | -------------------------------------------------------------------------------- /test/swiftMetadataInitializerRealloc-dylib1.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "swift-class-def.m" 3 | 4 | SWIFT_CLASS(RealSwiftDylib1A, NSObject, nop); 5 | SWIFT_STUB_CLASS(SwiftDylib1A, initSwiftDylib1A); 6 | 7 | SWIFT_CLASS(RealSwiftDylib1B, NSObject, nop); 8 | SWIFT_STUB_CLASS(SwiftDylib1B, initSwiftDylib1B); 9 | 10 | int Dylib1AInits = 0; 11 | 12 | @interface SwiftDylib1A: NSObject @end 13 | @interface SwiftDylib1B: NSObject @end 14 | 15 | @implementation SwiftDylib1A (Category) 16 | - (const char *)dylib1ACategoryInSameDylib { return "dylib1ACategoryInSameDylib"; } 17 | @end 18 | @implementation SwiftDylib1B (Category) 19 | - (const char *)dylib1BCategoryInSameDylib { return "dylib1BCategoryInSameDylib"; } 20 | @end 21 | 22 | EXTERN_C Class initSwiftDylib1A(Class cls, void *arg) 23 | { 24 | Dylib1AInits++; 25 | testassert(arg == nil); 26 | testassert(cls == RawSwiftDylib1A); 27 | 28 | if (Dylib1AInits == 1) 29 | _objc_realizeClassFromSwift(RawRealSwiftDylib1A, cls); 30 | 31 | return RawRealSwiftDylib1A; 32 | } 33 | 34 | int Dylib1BInits = 0; 35 | 36 | EXTERN_C Class initSwiftDylib1B(Class cls, void *arg) 37 | { 38 | Dylib1BInits++; 39 | testassert(arg == nil); 40 | testassert(cls == RawSwiftDylib1B); 41 | 42 | if (Dylib1BInits == 1) 43 | _objc_realizeClassFromSwift(RawRealSwiftDylib1B, cls); 44 | 45 | return RawRealSwiftDylib1B; 46 | } 47 | 48 | EXTERN_C Class objc_loadClassref(_Nullable Class * _Nonnull clsref); 49 | 50 | void Dylib1Test(void) { 51 | testassert((uintptr_t)SwiftDylib1AClassref & 1); 52 | Class SwiftDylib1A = objc_loadClassref(&SwiftDylib1AClassref); 53 | testassert(((uintptr_t)SwiftDylib1AClassref & 1) == 0); 54 | testassert(SwiftDylib1A == [SwiftDylib1A class]); 55 | testassert(SwiftDylib1A == SwiftDylib1AClassref); 56 | testassert(Dylib1AInits == 2); 57 | 58 | testassert((uintptr_t)SwiftDylib1BClassref & 1); 59 | Class SwiftDylib1B = objc_loadClassref(&SwiftDylib1BClassref); 60 | testassert(((uintptr_t)SwiftDylib1BClassref & 1) == 0); 61 | testassert(SwiftDylib1B == [SwiftDylib1B class]); 62 | testassert(SwiftDylib1B == SwiftDylib1BClassref); 63 | testassert(Dylib1BInits == 2); 64 | } 65 | -------------------------------------------------------------------------------- /test/swiftMetadataInitializerRealloc-dylib2.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "swift-class-def.m" 3 | 4 | @interface SwiftDylib1A: NSObject @end 5 | @interface SwiftDylib1B: NSObject @end 6 | 7 | @interface NSObject (DylibCategories) 8 | - (char *)dylib1ACategoryInSameDylib; 9 | - (char *)dylib1BCategoryInSameDylib; 10 | - (char *)dylib1ACategoryInOtherDylib; 11 | - (char *)dylib1BCategoryInOtherDylib; 12 | - (char *)dylib1ACategoryInApp; 13 | - (char *)dylib1BCategoryInApp; 14 | + (void)testFromOtherDylib; 15 | @end 16 | 17 | @implementation SwiftDylib1A (Category) 18 | - (const char *)dylib1ACategoryInOtherDylib { return "dylib1ACategoryInOtherDylib"; } 19 | @end 20 | @implementation SwiftDylib1B (Category) 21 | - (const char *)dylib1BCategoryInOtherDylib { return "dylib1BCategoryInOtherDylib"; } 22 | @end 23 | 24 | SWIFT_STUB_CLASSREF(SwiftDylib1A); 25 | SWIFT_STUB_CLASSREF(SwiftDylib1B); 26 | 27 | Class objc_loadClassref(_Nullable Class * _Nonnull clsref); 28 | 29 | @implementation SwiftDylib1A (Test) 30 | + (void)testFromOtherDylib { 31 | Class SwiftDylib1A = objc_loadClassref(&SwiftDylib1AClassref); 32 | Class SwiftDylib1B = objc_loadClassref(&SwiftDylib1BClassref); 33 | testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInSameDylib], "dylib1ACategoryInSameDylib") == 0); 34 | testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInSameDylib], "dylib1BCategoryInSameDylib") == 0); 35 | testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInApp], "dylib1ACategoryInApp") == 0); 36 | testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInApp], "dylib1BCategoryInApp") == 0); 37 | testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInOtherDylib], "dylib1ACategoryInOtherDylib") == 0); 38 | testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInOtherDylib], "dylib1BCategoryInOtherDylib") == 0); 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /test/synchronized-counter.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // synchronized stress test 13 | // Single locked counter incremented by many threads. 14 | 15 | #if defined(__arm__) 16 | #define THREADS 16 17 | #define COUNT 1024*24 18 | #else 19 | // 64 / 1024*24 test takes about 20s on 4x2.6GHz Mac Pro 20 | #define THREADS 64 21 | #define COUNT 1024*24 22 | #endif 23 | 24 | static id lock; 25 | static int count; 26 | 27 | static void *threadfn(void *arg) 28 | { 29 | int n, d; 30 | int depth = 1 + (int)(intptr_t)arg % 4; 31 | 32 | for (n = 0; n < COUNT; n++) { 33 | // Lock 34 | for (d = 0; d < depth; d++) { 35 | int err = objc_sync_enter(lock); 36 | testassert(err == OBJC_SYNC_SUCCESS); 37 | } 38 | 39 | // Increment 40 | count++; 41 | 42 | // Unlock 43 | for (d = 0; d < depth; d++) { 44 | int err = objc_sync_exit(lock); 45 | testassert(err == OBJC_SYNC_SUCCESS); 46 | } 47 | } 48 | 49 | // Verify lack of objc pthread data (should have used sync fast cache) 50 | #ifdef __PTK_FRAMEWORK_OBJC_KEY0 51 | testassert(! pthread_getspecific(__PTK_FRAMEWORK_OBJC_KEY0)); 52 | #endif 53 | 54 | return NULL; 55 | } 56 | 57 | int main() 58 | { 59 | pthread_t threads[THREADS]; 60 | int t; 61 | int err; 62 | 63 | lock = [[NSObject alloc] init]; 64 | 65 | // Verify objc pthread data on this thread (from +initialize) 66 | // Worker threads shouldn't have any because of sync fast cache. 67 | #ifdef __PTK_FRAMEWORK_OBJC_KEY0 68 | testassert(pthread_getspecific(__PTK_FRAMEWORK_OBJC_KEY0)); 69 | #endif 70 | 71 | // Start the threads 72 | for (t = 0; t < THREADS; t++) { 73 | pthread_create(&threads[t], NULL, &threadfn, (void*)(intptr_t)t); 74 | } 75 | 76 | // Wait for threads to finish 77 | for (t = 0; t < THREADS; t++) { 78 | pthread_join(threads[t], NULL); 79 | } 80 | 81 | // Verify lock: should be available 82 | // Verify count: should be THREADS*COUNT 83 | err = objc_sync_enter(lock); 84 | testassert(err == OBJC_SYNC_SUCCESS); 85 | testassert(count == THREADS*COUNT); 86 | 87 | succeed(__FILE__); 88 | } 89 | -------------------------------------------------------------------------------- /test/taggedNSPointers.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #include "test.h" 4 | #include 5 | #import 6 | 7 | #if OBJC_HAVE_TAGGED_POINTERS 8 | 9 | void testTaggedNumber() 10 | { 11 | NSNumber *taggedNS = [NSNumber numberWithInt: 1234]; 12 | CFNumberRef taggedCF = (__bridge CFNumberRef)taggedNS; 13 | int result; 14 | 15 | testassert( CFGetTypeID(taggedCF) == CFNumberGetTypeID() ); 16 | testassert(_objc_getClassForTag(OBJC_TAG_NSNumber) == [taggedNS class]); 17 | 18 | CFNumberGetValue(taggedCF, kCFNumberIntType, &result); 19 | testassert(result == 1234); 20 | 21 | testassert(_objc_isTaggedPointer(taggedCF)); 22 | testassert(_objc_getTaggedPointerTag(taggedCF) == OBJC_TAG_NSNumber); 23 | testassert(_objc_makeTaggedPointer(_objc_getTaggedPointerTag(taggedCF), _objc_getTaggedPointerValue(taggedCF)) == taggedCF); 24 | 25 | // do some generic object-y things to the taggedPointer instance 26 | CFRetain(taggedCF); 27 | CFRelease(taggedCF); 28 | 29 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 30 | [dict setObject: taggedNS forKey: @"fred"]; 31 | testassert(taggedNS == [dict objectForKey: @"fred"]); 32 | [dict setObject: @"bob" forKey: taggedNS]; 33 | testassert([@"bob" isEqualToString: [dict objectForKey: taggedNS]]); 34 | 35 | NSNumber *iM88 = [NSNumber numberWithInt:-88]; 36 | NSNumber *i12346 = [NSNumber numberWithInt: 12346]; 37 | NSNumber *i12347 = [NSNumber numberWithInt: 12347]; 38 | 39 | NSArray *anArray = [NSArray arrayWithObjects: iM88, i12346, i12347, nil]; 40 | testassert([anArray count] == 3); 41 | testassert([anArray indexOfObject: i12346] == 1); 42 | 43 | NSSet *aSet = [NSSet setWithObjects: iM88, i12346, i12347, nil]; 44 | testassert([aSet count] == 3); 45 | testassert([aSet containsObject: i12346]); 46 | 47 | [taggedNS performSelector: @selector(intValue)]; 48 | testassert(![taggedNS isProxy]); 49 | testassert([taggedNS isKindOfClass: [NSNumber class]]); 50 | testassert([taggedNS respondsToSelector: @selector(intValue)]); 51 | 52 | (void)[taggedNS description]; 53 | } 54 | 55 | int main() 56 | { 57 | PUSH_POOL { 58 | testTaggedNumber(); // should be tested by CF... our tests are wrong, wrong, wrong. 59 | } POP_POOL; 60 | 61 | succeed(__FILE__); 62 | } 63 | 64 | // OBJC_HAVE_TAGGED_POINTERS 65 | #else 66 | // not OBJC_HAVE_TAGGED_POINTERS 67 | 68 | // Tagged pointers not supported. Crash if an NSNumber actually 69 | // is a tagged pointer (which means this test is out of date). 70 | 71 | int main() 72 | { 73 | PUSH_POOL { 74 | testassert(*(void **)(__bridge void *)[NSNumber numberWithInt:1234]); 75 | } POP_POOL; 76 | 77 | succeed(__FILE__); 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /test/taggedPointersAllClasses.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | #include 6 | #include 7 | 8 | #if OBJC_HAVE_TAGGED_POINTERS 9 | 10 | @interface TagSuperclass: TestRoot 11 | 12 | - (void)test; 13 | 14 | @end 15 | 16 | @implementation TagSuperclass 17 | 18 | - (void)test {} 19 | 20 | @end 21 | 22 | int main() 23 | { 24 | Class classes[OBJC_TAG_Last52BitPayload + 1] = {}; 25 | 26 | __block uintptr_t expectedPayload; 27 | __block uintptr_t sawPayload; 28 | __block int sawTag; 29 | 30 | for (int i = 0; i <= OBJC_TAG_Last52BitPayload; i++) { 31 | objc_tag_index_t tag = (objc_tag_index_t)i; 32 | if (i > OBJC_TAG_Last60BitPayload && i < OBJC_TAG_First52BitPayload) 33 | continue; 34 | if (_objc_getClassForTag(tag) != nil) 35 | continue; 36 | 37 | char *name; 38 | asprintf(&name, "Tag%d", i); 39 | classes[i] = objc_allocateClassPair([TagSuperclass class], name, 0); 40 | free(name); 41 | 42 | IMP testIMP = imp_implementationWithBlock(^(void *self) { 43 | testassert(i == _objc_getTaggedPointerTag(self)); 44 | testassert(expectedPayload == _objc_getTaggedPointerValue(self)); 45 | sawPayload = _objc_getTaggedPointerValue(self); 46 | sawTag = i; 47 | }); 48 | class_addMethod(classes[i], @selector(test), testIMP, "v@@"); 49 | 50 | objc_registerClassPair(classes[i]); 51 | _objc_registerTaggedPointerClass(tag, classes[i]); 52 | } 53 | 54 | for (int i = 0; i <= OBJC_TAG_Last52BitPayload; i++) { 55 | objc_tag_index_t tag = (objc_tag_index_t)i; 56 | if (classes[i] == nil) 57 | continue; 58 | 59 | for (int byte = 0; byte <= 0xff; byte++) { 60 | uintptr_t payload; 61 | memset(&payload, byte, sizeof(payload)); 62 | 63 | if (i <= OBJC_TAG_Last60BitPayload) 64 | payload >>= _OBJC_TAG_PAYLOAD_RSHIFT; 65 | else 66 | payload >>= _OBJC_TAG_EXT_PAYLOAD_RSHIFT; 67 | 68 | expectedPayload = payload; 69 | id obj = (__bridge id)_objc_makeTaggedPointer(tag, payload); 70 | [obj test]; 71 | testassert(sawPayload == payload); 72 | testassert(sawTag == i); 73 | } 74 | } 75 | 76 | succeed(__FILE__); 77 | } 78 | 79 | #else 80 | 81 | int main() 82 | { 83 | succeed(__FILE__); 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /test/taggedPointersDisabled.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_ENV OBJC_DISABLE_TAGGED_POINTERS=YES 3 | TEST_CRASHES 4 | 5 | TEST_BUILD_OUTPUT 6 | .*taggedPointersDisabled.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\] 7 | END 8 | 9 | TEST_RUN_OUTPUT 10 | objc\[\d+\]: tagged pointers are disabled 11 | objc\[\d+\]: HALTED 12 | OR 13 | OK: taggedPointersDisabled.m 14 | END 15 | */ 16 | 17 | #include "test.h" 18 | #include 19 | 20 | #if !OBJC_HAVE_TAGGED_POINTERS 21 | 22 | int main() 23 | { 24 | // provoke the same nullability warning as the real test 25 | objc_getClass(nil); 26 | 27 | succeed(__FILE__); 28 | } 29 | 30 | #else 31 | 32 | int main() 33 | { 34 | testassert(!_objc_taggedPointersEnabled()); 35 | _objc_registerTaggedPointerClass((objc_tag_index_t)0, nil); 36 | fail("should have crashed in _objc_registerTaggedPointerClass()"); 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /test/taggedPointersTagObfuscationDisabled.m: -------------------------------------------------------------------------------- 1 | // TEST_ENV OBJC_DISABLE_TAG_OBFUSCATION=YES 2 | 3 | #include "test.h" 4 | #include 5 | 6 | #if !OBJC_HAVE_TAGGED_POINTERS 7 | 8 | int main() 9 | { 10 | succeed(__FILE__); 11 | } 12 | 13 | #else 14 | 15 | int main() 16 | { 17 | #if OBJC_SPLIT_TAGGED_POINTERS 18 | void *obj = (void *)0; 19 | #else 20 | void *obj = (void *)1; 21 | #endif 22 | 23 | testassert(_objc_getTaggedPointerTag(obj) == 0); 24 | succeed(__FILE__); 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /test/tbi.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=iphoneos ARCH=arm64 2 | 3 | #include "test.h" 4 | 5 | #ifndef __arm64__ 6 | #error wrong architecture for TBI hardware feature 7 | #endif 8 | 9 | volatile int x = 123456; 10 | 11 | int main(void) { 12 | testassert(*(int *)((unsigned long)&x | 0xFF00000000000000ul) == 123456); 13 | succeed(__FILE__); 14 | } 15 | -------------------------------------------------------------------------------- /test/test-defines.h: -------------------------------------------------------------------------------- 1 | #define TEST_OVERRIDES_NEW 1 2 | -------------------------------------------------------------------------------- /test/timeout.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | my $usage = "timeout \n"; 6 | my $timeout = shift || die $usage; 7 | alarm($timeout); 8 | exec @ARGV; 9 | die "exec failed: @ARGV"; 10 | -------------------------------------------------------------------------------- /test/unload.h: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | @interface SmallClass : TestRoot @end 4 | 5 | @interface BigClass : TestRoot @end 6 | 7 | -------------------------------------------------------------------------------- /test/unload2.m: -------------------------------------------------------------------------------- 1 | #include "unload.h" 2 | #include "testroot.i" 3 | #import 4 | 5 | @implementation SmallClass : TestRoot 6 | -(void)unload2_instance_method { } 7 | @end 8 | 9 | 10 | @implementation BigClass : TestRoot 11 | @end 12 | 13 | OBJC_ROOT_CLASS 14 | @interface UnusedClass { id isa; } @end 15 | @implementation UnusedClass @end 16 | 17 | 18 | @protocol SmallProtocol 19 | -(void)unload2_category_method; 20 | @end 21 | 22 | @interface SmallClass (Category) @end 23 | 24 | @implementation SmallClass (Category) 25 | -(void)unload2_category_method { } 26 | @end 27 | 28 | // This isn't really weak-import: we link with `-undefined dynamic_lookup` 29 | // instead of providing a valid definition at link time. 30 | // But it looks the same to the runtime. 31 | __attribute__((weak_import)) 32 | @interface ClassThatIsWeakImportAndMissing : TestRoot @end 33 | 34 | @interface SubclassOfMissingWeakImport : ClassThatIsWeakImportAndMissing @end 35 | @implementation SubclassOfMissingWeakImport 36 | -(void)unload2_category_method { } 37 | @end 38 | 39 | @interface ClassThatIsWeakImportAndMissing (Category) @end 40 | @implementation ClassThatIsWeakImportAndMissing (Category) 41 | -(void)unload2_category_method { } 42 | @end 43 | -------------------------------------------------------------------------------- /test/unload3.c: -------------------------------------------------------------------------------- 1 | // unload3: contains imageinfo but no other objc metadata 2 | // libobjc must not keep it open 3 | 4 | #include 5 | 6 | int fake[2] __attribute__((section("__DATA,__objc_imageinfo"))) 7 | = { 0, TARGET_OS_SIMULATOR ? (1<<5) : 0 }; 8 | 9 | // silence "no debug symbols in executable" warning 10 | void fn(void) { } 11 | -------------------------------------------------------------------------------- /test/unload4.m: -------------------------------------------------------------------------------- 1 | // unload4: contains some objc metadata other than imageinfo 2 | // libobjc must keep it open 3 | 4 | int fake2 __attribute__((section("__DATA,__objc_foo"))) = 0; 5 | 6 | // getsectiondata() falls over if __TEXT has no contents 7 | const char *unload4 = "unload4"; 8 | -------------------------------------------------------------------------------- /test/unwind.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | static int state; 8 | 9 | @interface Foo : NSObject @end 10 | @interface Bar : NSObject @end 11 | 12 | @interface Foo (Unimplemented) 13 | +(void)method; 14 | @end 15 | 16 | @implementation Bar @end 17 | 18 | @implementation Foo 19 | 20 | -(void)check { state++; } 21 | +(void)check { testassert(!"caught class object, not instance"); } 22 | 23 | static id exc; 24 | 25 | static void handler(id unused, void *ctx) __attribute__((used)); 26 | static void handler(id unused __unused, void *ctx __unused) 27 | { 28 | testassert(state == 3); state++; 29 | } 30 | 31 | +(BOOL) resolveClassMethod:(SEL)__unused name 32 | { 33 | testassert(state == 1); state++; 34 | #if TARGET_OS_OSX 35 | objc_addExceptionHandler(&handler, 0); 36 | testassert(state == 2); 37 | #else 38 | state++; // handler would have done this 39 | #endif 40 | state++; 41 | exc = [Foo new]; 42 | @throw exc; 43 | } 44 | 45 | 46 | @end 47 | 48 | int main() 49 | { 50 | // unwind exception and alt handler through objc_msgSend() 51 | 52 | PUSH_POOL { 53 | 54 | const int count = is_guardmalloc() ? 1000 : 100000; 55 | state = 0; 56 | for (int i = 0; i < count; i++) { 57 | @try { 58 | testassert(state == 0); state++; 59 | [Foo method]; 60 | testassert(0); 61 | } @catch (Bar *e) { 62 | testassert(0); 63 | } @catch (Foo *e) { 64 | testassert(e == exc); 65 | testassert(state == 4); state++; 66 | testassert(state == 5); [e check]; // state++ 67 | RELEASE_VAR(exc); 68 | } @catch (id e) { 69 | testassert(0); 70 | } @catch (...) { 71 | testassert(0); 72 | } @finally { 73 | testassert(state == 6); state++; 74 | } 75 | testassert(state == 7); state = 0; 76 | } 77 | 78 | } POP_POOL; 79 | 80 | succeed(__FILE__); 81 | } 82 | -------------------------------------------------------------------------------- /test/weak.h: -------------------------------------------------------------------------------- 1 | /* 2 | To test -weak-l or -weak-framework: 3 | * -DWEAK_IMPORT= 4 | * -DWEAK_FRAMEWORK=1 5 | * -UEMPTY when building the weak-not-missing library 6 | * -DEMPTY= when building the weak-missing library 7 | 8 | To test attribute((weak_import)): 9 | * -DWEAK_IMPORT=__attribute__((weak_import)) 10 | * -UWEAK_FRAMEWORK 11 | * -UEMPTY when building the weak-not-missing library 12 | * -DEMPTY= when building the weak-missing library 13 | 14 | */ 15 | 16 | #include "test.h" 17 | #include 18 | 19 | extern int state; 20 | 21 | WEAK_IMPORT OBJC_ROOT_CLASS 22 | @interface MissingRoot { 23 | id isa; 24 | } 25 | +(void) initialize; 26 | +(Class) class; 27 | +(id) alloc; 28 | -(id) init; 29 | -(void) dealloc; 30 | +(int) method; 31 | @end 32 | 33 | @interface MissingRoot (RR) 34 | -(id) retain; 35 | -(void) release; 36 | @end 37 | 38 | WEAK_IMPORT 39 | @interface MissingSuper : MissingRoot { 40 | @public 41 | int ivar; 42 | } 43 | @end 44 | 45 | OBJC_ROOT_CLASS 46 | @interface NotMissingRoot { 47 | id isa; 48 | } 49 | +(void) initialize; 50 | +(Class) class; 51 | +(id) alloc; 52 | -(id) init; 53 | -(void) dealloc; 54 | +(int) method; 55 | @end 56 | 57 | @interface NotMissingRoot (RR) 58 | -(id) retain; 59 | -(void) release; 60 | @end 61 | 62 | @interface NotMissingSuper : NotMissingRoot { 63 | @public 64 | int unused[100]; 65 | int ivar; 66 | } 67 | @end 68 | -------------------------------------------------------------------------------- /test/weakReferenceHook.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG MEM=mrc 3 | TEST_ENV OBJC_DISABLE_NONPOINTER_ISA=YES 4 | */ 5 | 6 | #include "test.h" 7 | #include "testroot.i" 8 | 9 | bool hasWeakRefs = false; 10 | 11 | @interface TestRoot (WeakHooks) 12 | @end 13 | 14 | @implementation TestRoot (WeakHooks) 15 | 16 | - (void)_setWeaklyReferenced { 17 | hasWeakRefs = true; 18 | } 19 | 20 | // -_setWeaklyReferenced is currently limited to raw-isa custom-rr to avoid overhead 21 | - (void) release { 22 | } 23 | 24 | @end 25 | 26 | int main() { 27 | id obj = [TestRoot new]; 28 | id wobj = nil; 29 | objc_storeWeak(&wobj, obj); 30 | testassert(hasWeakRefs == true); 31 | 32 | id out = objc_loadWeak(&wobj); 33 | testassert(out == obj); 34 | 35 | objc_storeWeak(&wobj, nil); 36 | out = objc_loadWeak(&wobj); 37 | testassert(out == nil); 38 | 39 | hasWeakRefs = false; 40 | objc_storeWeak(&wobj, obj); 41 | testassert(hasWeakRefs == true); 42 | 43 | 44 | out = objc_loadWeak(&wobj); 45 | testassert(out == obj); 46 | objc_storeWeak(&wobj, nil); 47 | 48 | succeed(__FILE__); 49 | } 50 | -------------------------------------------------------------------------------- /test/weakcopy.m: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -fobjc-weak 2 | 3 | #include "test.h" 4 | 5 | #include "testroot.i" 6 | #include 7 | #include 8 | #include 9 | 10 | @interface Weak : TestRoot { 11 | @public 12 | __weak id value; 13 | } 14 | @end 15 | @implementation Weak 16 | @end 17 | 18 | Weak *oldObject; 19 | Weak *newObject; 20 | 21 | int main() 22 | { 23 | testonthread(^{ 24 | TestRoot *value; 25 | 26 | PUSH_POOL { 27 | value = [TestRoot new]; 28 | testassert(value); 29 | oldObject = [Weak new]; 30 | testassert(oldObject); 31 | 32 | oldObject->value = value; 33 | testassert(oldObject->value == value); 34 | 35 | newObject = [oldObject copy]; 36 | testassert(newObject); 37 | testassert(newObject->value == oldObject->value); 38 | 39 | newObject->value = nil; 40 | testassert(newObject->value == nil); 41 | testassert(oldObject->value == value); 42 | } POP_POOL; 43 | 44 | testcollect(); 45 | TestRootDealloc = 0; 46 | RELEASE_VAR(value); 47 | }); 48 | 49 | testcollect(); 50 | testassert(TestRootDealloc); 51 | 52 | #if __has_feature(objc_arc_weak) 53 | testassert(oldObject->value == nil); 54 | #endif 55 | testassert(newObject->value == nil); 56 | 57 | RELEASE_VAR(newObject); 58 | RELEASE_VAR(oldObject); 59 | 60 | succeed(__FILE__); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /test/weakframework-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -UEMPTY -dynamiclib -o libweakframework.dylib 4 | 5 | $C{COMPILE} $DIR/weakframework-missing.m -L. -weak-lweakframework -o weakframework-missing.exe 6 | 7 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -DEMPTY= -dynamiclib -o libweakframework.dylib 8 | 9 | END 10 | */ 11 | 12 | #define WEAK_FRAMEWORK 1 13 | #define WEAK_IMPORT 14 | #include "weak.m" 15 | -------------------------------------------------------------------------------- /test/weakframework-not-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -DWEAK_FRAMEWORK=1 -DWEAK_IMPORT= -UEMPTY -dynamiclib -o libweakframework.dylib 4 | 5 | $C{COMPILE} $DIR/weakframework-not-missing.m -L. -weak-lweakframework -o weakframework-not-missing.exe 6 | END 7 | */ 8 | 9 | #define WEAK_FRAMEWORK 1 10 | #define WEAK_IMPORT 11 | #include "weak.m" 12 | -------------------------------------------------------------------------------- /test/weakimport-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -UEMPTY -dynamiclib -o libweakimport.dylib 4 | 5 | $C{COMPILE} $DIR/weakimport-missing.m -L. -weak-lweakimport -o weakimport-missing.exe 6 | 7 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -DEMPTY= -dynamiclib -o libweakimport.dylib 8 | END 9 | */ 10 | 11 | // #define WEAK_FRAMEWORK 12 | #define WEAK_IMPORT __attribute__((weak_import)) 13 | #include "weak.m" 14 | -------------------------------------------------------------------------------- /test/weakimport-not-missing.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/weak2.m -UWEAK_FRAMEWORK -DWEAK_IMPORT=__attribute__\\(\\(weak_import\\)\\) -UEMPTY -dynamiclib -o libweakimport.dylib 4 | 5 | $C{COMPILE} $DIR/weakimport-not-missing.m -L. -weak-lweakimport -o weakimport-not-missing.exe 6 | END 7 | */ 8 | 9 | // #define WEAK_FRAMEWORK 10 | #define WEAK_IMPORT __attribute__((weak_import)) 11 | #include "weak.m" 12 | -------------------------------------------------------------------------------- /test/weakrace.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include 5 | 6 | static semaphore_t go1; 7 | static semaphore_t go2; 8 | static semaphore_t done; 9 | 10 | #define VARCOUNT 100000 11 | static id obj; 12 | static id vars[VARCOUNT]; 13 | 14 | 15 | void *destroyer(void *arg __unused) 16 | { 17 | while (1) { 18 | semaphore_wait(go1); 19 | for (int i = 0; i < VARCOUNT; i++) { 20 | objc_destroyWeak(&vars[i]); 21 | } 22 | semaphore_signal(done); 23 | } 24 | } 25 | 26 | 27 | void *deallocator(void *arg __unused) 28 | { 29 | while (1) { 30 | semaphore_wait(go2); 31 | [obj release]; 32 | semaphore_signal(done); 33 | } 34 | } 35 | 36 | 37 | void cycle(void) 38 | { 39 | // rdar://12896779 objc_destroyWeak() versus weak clear in dealloc 40 | 41 | // Clean up from previous cycle - objc_destroyWeak() doesn't set var to nil 42 | for (int i = 0; i < VARCOUNT; i++) { 43 | vars[i] = nil; 44 | } 45 | 46 | obj = [NSObject new]; 47 | for (int i = 0; i < VARCOUNT; i++) { 48 | objc_storeWeak(&vars[i], obj); 49 | } 50 | 51 | // let destroyer start before deallocator runs 52 | semaphore_signal(go1); 53 | sched_yield(); 54 | semaphore_signal(go2); 55 | 56 | semaphore_wait(done); 57 | semaphore_wait(done); 58 | } 59 | 60 | 61 | int main() 62 | { 63 | semaphore_create(mach_task_self(), &go1, 0, 0); 64 | semaphore_create(mach_task_self(), &go2, 0, 0); 65 | semaphore_create(mach_task_self(), &done, 0, 0); 66 | 67 | pthread_t th[2]; 68 | pthread_create(&th[1], NULL, deallocator, NULL); 69 | pthread_create(&th[1], NULL, destroyer, NULL); 70 | 71 | for (int i = 0; i < 100; i++) { 72 | cycle(); 73 | } 74 | 75 | succeed(__FILE__); 76 | } 77 | -------------------------------------------------------------------------------- /test/zone.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | // Look for malloc zone "ObjC" iff OBJC_USE_INTERNAL_ZONE is set. 8 | // This fails if objc tries to allocate before checking its own 9 | // environment variables (rdar://6688423) 10 | 11 | int main() 12 | { 13 | if (is_guardmalloc()) { 14 | // guard malloc confuses this test 15 | succeed(__FILE__); 16 | } 17 | 18 | kern_return_t kr; 19 | vm_address_t *zones; 20 | unsigned int count, i; 21 | BOOL has_objc = NO, want_objc = NO; 22 | 23 | want_objc = (getenv("OBJC_USE_INTERNAL_ZONE") != NULL) ? YES : NO; 24 | testprintf("want objc %s\n", want_objc ? "YES" : "NO"); 25 | 26 | kr = malloc_get_all_zones(mach_task_self(), NULL, &zones, &count); 27 | testassert(!kr); 28 | for (i = 0; i < count; i++) { 29 | const char *name = malloc_get_zone_name((malloc_zone_t *)zones[i]); 30 | if (name) { 31 | BOOL is_objc = (0 == strcmp(name, "ObjC_Internal")) ? YES : NO; 32 | if (is_objc) has_objc = YES; 33 | testprintf("zone %s\n", name); 34 | } 35 | } 36 | 37 | testassert(want_objc == has_objc); 38 | 39 | succeed(__FILE__); 40 | } 41 | -------------------------------------------------------------------------------- /unexported_symbols: -------------------------------------------------------------------------------- 1 | .objc_class_name___IncompleteProtocol 2 | __Znam 3 | __ZnamRKSt9nothrow_t 4 | __Znwm 5 | __ZnwmRKSt9nothrow_t 6 | __ZdaPv 7 | __ZdaPvRKSt9nothrow_t 8 | __ZdlPv 9 | __ZdlPvRKSt9nothrow_t 10 | __ZTISt9bad_alloc 11 | __ZTISt9exception 12 | __ZTISt11logic_error 13 | __ZTISt12length_error 14 | __ZTSSt9bad_alloc 15 | __ZTSSt9exception 16 | __ZTSSt11logic_error 17 | __ZTSSt12length_error 18 | -------------------------------------------------------------------------------- /version.bat: -------------------------------------------------------------------------------- 1 | :: version.bat 2 | :: Writes version numbers from B&I into version.h for use by version.rc. 3 | 4 | @ECHO OFF 5 | 6 | :: Set default values for environment variables if not set by B&I 7 | IF "%OBJROOT%"=="" SET OBJROOT=. 8 | IF "%RC_PROJECTSOURCEVERSION%"=="" SET RC_PROJECTSOURCEVERSION=0.0 9 | IF "%RC_PROJECTBUILDVERSION%"=="" SET RC_PROJECTBUILDVERSION=0 10 | 11 | :: Get version numbers from environment variables 12 | SET major=1 13 | SET patch=0 14 | FOR /F "tokens=1* eol= delims=." %%i IN ("%RC_PROJECTSOURCEVERSION%") DO ( 15 | SET minor=%%i 16 | IF NOT "%%j"=="" SET patch=%%j 17 | ) 18 | SET build=%RC_PROJECTBUILDVERSION% 19 | 20 | ECHO version %major% . %minor% . %patch% . %build% 21 | 22 | :: Write version.h 23 | ECHO // This file is automatically generated by version.bat. > "%OBJROOT%\version.h" 24 | ECHO // DO NOT EDIT >> "%OBJROOT%\version.h" 25 | ECHO #define major %major% >> "%OBJROOT%\version.h" 26 | ECHO #define minor %minor% >> "%OBJROOT%\version.h" 27 | ECHO #define patch %patch% >> "%OBJROOT%\version.h" 28 | ECHO #define build %build% >> "%OBJROOT%\version.h" 29 | ECHO #define string "%major%,%minor%,%patch%,%build%" >> "%OBJROOT%\version.h" 30 | -------------------------------------------------------------------------------- /version.rc: -------------------------------------------------------------------------------- 1 | #include "Winver.h" 2 | 3 | // built by version.bat; sets variables major, minor, patch, build, string 4 | #include "version.h" 5 | 6 | VS_VERSION_INFO VERSIONINFO 7 | FILEVERSION major,minor,patch,build 8 | PRODUCTVERSION major,minor,patch,build 9 | FILEFLAGSMASK 0x17L 10 | #ifdef _DEBUG 11 | FILEFLAGS VS_FF_DEBUG 12 | #else 13 | FILEFLAGS 0x0L 14 | #endif 15 | FILEOS VOS_NT_WINDOWS32 16 | FILETYPE VFT_DLL 17 | FILESUBTYPE VFT2_UNKNOWN 18 | BEGIN 19 | BLOCK "StringFileInfo" 20 | BEGIN 21 | BLOCK "040904b0" 22 | BEGIN 23 | VALUE "CompanyName", "Apple Inc." 24 | VALUE "FileDescription", "Objective-C Runtime Library" 25 | VALUE "FileVersion", string 26 | VALUE "ProductVersion", string 27 | VALUE "ProductName", "objc4" 28 | VALUE "InternalName", "objc4" 29 | VALUE "LegalCopyright", "Copyright (C) 2007-2009, Apple Inc." 30 | VALUE "OriginalFilename", "objc.dll" 31 | END 32 | END 33 | BLOCK "VarFileInfo" 34 | BEGIN 35 | VALUE "Translation", 0x409, 1200 36 | END 37 | END 38 | 39 | --------------------------------------------------------------------------------