├── .editorconfig ├── APPLE_LICENSE ├── ObjectiveC-swiftoverlay-Test-Dylib └── Trees.swift ├── ObjectiveC.xctestplan ├── ObjectiveC ├── ObjectiveC.swift ├── ObjectiveC.xcconfig ├── ObjectiveCRPathInstallName.c └── ObjectiveCRPathInstallName.h ├── ObjectiveCTests ├── Creatures.swift ├── ObjectiveC.swift ├── StdlibUnittest checkEquatable.swift └── StdlibUnittest checkHashable.swift ├── ReleaseNotes.rtf ├── markgc.cpp ├── objc-vfs-overlay └── write-vfs-overlay.sh ├── objc.sln ├── objc.xcconfig ├── objc.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── ObjectiveC.xcscheme ├── objc4.plist ├── objcdt ├── json.h ├── json.mm ├── objcdt-entitlements.plist ├── objcdt.1 └── objcdt.mm ├── objcrt └── objcrt.vcproj ├── prebuild.bat ├── runtime ├── DenseMapExtras.h ├── InitWrappers.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 │ └── ObjectiveC.modulemap ├── ModulePrivate │ ├── ObjectiveC_Private.apinotes │ └── ObjectiveC_Private.modulemap ├── NSObjCRuntime.h ├── NSObject-internal.h ├── NSObject-private.h ├── NSObject.h ├── NSObject.mm ├── Object.h ├── Object.mm ├── OldClasses.subproj │ └── List.h ├── PointerUnion.h ├── Protocol.h ├── Protocol.mm ├── Threading │ ├── c11threads.h │ ├── darwin.h │ ├── lockdebug.h │ ├── mixins.h │ ├── nothreads.h │ ├── pthreads.h │ ├── threading.h │ └── tls.h ├── 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.mm ├── objc-class.h ├── objc-class.mm ├── objc-config.h ├── objc-env.h ├── objc-errors.mm ├── objc-exception.h ├── objc-exception.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.mm ├── objc-locks.h ├── objc-magicsel.m ├── objc-malloc-instance.h ├── objc-object.h ├── objc-opt.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.h ├── objc-runtime.mm ├── objc-sel-table.s ├── objc-sel.mm ├── objc-sync.h ├── objc-sync.mm ├── objc-test-env.c ├── objc-test-env.h ├── objc-typeencoding.mm ├── objc-vm.h ├── objc-weak.h ├── objc-weak.mm ├── objc-zalloc.h ├── objc-zalloc.mm ├── objc.h ├── objcrt.h ├── retain-release-helpers-arm64.s └── runtime.h ├── scripts ├── exclave-run ├── print-image-loading └── time-startup ├── test ├── 00-defines.c ├── 01-headers.c ├── 02-concurrentcat.m ├── 03-load-parallel.m ├── 04-load-image-notification.m ├── 05-load-image-notification2.m ├── 06-ARCLayoutsWithoutWeak.m ├── ARCBase.h ├── ARCBase.m ├── ARCLayouts.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-error.m ├── arr-weak.m ├── asm-placeholder.s ├── association.m ├── associationForbidden.h ├── associationForbidden.m ├── associationForbidden2.m ├── associationForbidden3.m ├── associationForbidden4.m ├── atomicProperty.mm ├── badAltHandler.m ├── badCache.m ├── badPool.m ├── badPoolCompat-ios-simulator.m ├── badPoolCompat-ios.m ├── badPoolCompat-macos.m ├── badPoolCompat-tvos-simulator.m ├── badPoolCompat-tvos.m ├── badPoolCompat-watchos-simulator.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 ├── class-structures.h ├── classgetclass.m ├── classname.m ├── classpair-stress.m ├── classpair.mm ├── classpairAddMethod.m ├── classversion.m ├── concurrentcat_category.m ├── consolidatePoolPointers.m ├── copyFixupHandler.mm ├── copyIvarList.m ├── copyMethodList.m ├── copyPropertyList.m ├── copyProtocolList.m ├── createInstance.m ├── customDeallocInitiation.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.expected ├── defines.sh ├── definitions.c ├── designatedinit.m ├── duplicateClass.m ├── duplicateProtocols.m ├── duplicatedClasses.m ├── duplicatedClasses0.m ├── duplicatedClasses2.m ├── duplicatedClasses3.m ├── enumClasses.h ├── enumClasses.m ├── enumClasses0.m ├── enumClasses1.m ├── evil-class-def.m ├── exc.m ├── exchangeImp.m ├── fakeRealizedClass.m ├── fakeRealizedClass2.m ├── faultLeaks.m ├── foreach.m ├── fork.m ├── forkInitialize.m ├── forkInitializeDisabled.m ├── forkInitializeSingleThreaded.m ├── forkSync.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.sh ├── imageAPIs.m ├── imageorder.h ├── imageorder.m ├── imageorder1.m ├── imageorder2.m ├── imageorder3.m ├── imports.c ├── include-warnings.c ├── includes-objc2.c ├── includes.c ├── initialize-autorelease.m ├── initialize.m ├── initializePriorityDonation.m ├── initializeVersusWeak.m ├── instanceSize.m ├── isaValidation.mm ├── ismeta.m ├── ivar.m ├── ivarSlide.h ├── ivarSlide.m ├── ivarSlide1.m ├── lazyClassName.m ├── lazyClassNameRace.swift ├── libraryPath.c ├── literals.m ├── load-image-notification-dylib.m ├── load-map-images.m ├── load-order.m ├── load-order1.m ├── load-order2.m ├── load-order3.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-macos.m ├── msgSend-performance.m ├── msgSend.m ├── nilAPIArgs.m ├── nonpointerisa.m ├── nopool.m ├── nscdtors.mm ├── nsexc.m ├── nsobject.m ├── nsprotocol.m ├── objectCopy.m ├── osVersion.m ├── partiallyRealizedClass.m ├── patch-class-root.m ├── preAttachedCategories.mm ├── preopt-caches.entitlements ├── preopt-caches.mm ├── property.m ├── propertyDesc.m ├── protocol.m ├── protocolSmall.m ├── protocol_copyMethodList.m ├── protocol_copyPropertyList.m ├── ptrauth.m ├── rawisa.m ├── readClassPair.m ├── readClassPairIvarFixup.m ├── realizedClassGenerationCount.m ├── release-race.m ├── release-workaround.m ├── resolve.m ├── restartableRangesSynchronizeStress.m ├── restartableRangesSynchronizeStress2.m ├── retain-release-helpers.m ├── rootMissingCategoryClass.m ├── rootMissingSuperclass.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 ├── signedMethodSelectors.m ├── subscripting.m ├── super.m ├── supported-inline-refcnt.m ├── swift-allocateClassPair.swift ├── swift-class-def.m ├── swiftMetaMeta.swift ├── swiftMetadataInitializer.m ├── swiftMetadataInitializerRealloc-dylib1.m ├── swiftMetadataInitializerRealloc-dylib2.m ├── swiftMetadataInitializerRealloc.m ├── swiftStubClassList.m ├── swiftobject-no-custom-core.mm ├── sync-error-checking.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-simulator.sh ├── test-simulator │ ├── Package.swift │ └── Sources │ │ └── test-simulator │ │ └── test_simulator.swift ├── test.h ├── test.pl ├── testroot.i ├── timeout.pl ├── unexpectedBuildOutput.mm ├── uniquelyref.m ├── unload.h ├── unload.m ├── unload2.m ├── unload3.c ├── unload4.m ├── unload5.m ├── unrealizedClassSafety.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 /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style=space 5 | indent_size=4 6 | -------------------------------------------------------------------------------- /ObjectiveC-swiftoverlay-Test-Dylib/Trees.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Trees.swift 3 | // Trees 4 | // 5 | // Created by Alastair Houghton on 02/09/2021. 6 | // Copyright © 2021 Apple. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @objc 12 | protocol Tree { 13 | func name() -> String 14 | func isEvergreen() -> Bool 15 | } 16 | 17 | @objc 18 | class Oak: NSObject, Tree { 19 | public func name() -> String { return "oak" } 20 | public func isEvergreen() -> Bool { return false } 21 | } 22 | 23 | @objc 24 | class Birch: NSObject, Tree { 25 | public func name() -> String { return "birch" } 26 | public func isEvergreen() -> Bool { return false } 27 | } 28 | 29 | @objc 30 | class Pine: NSObject, Tree { 31 | public func name() -> String { return "birch" } 32 | public func isEvergreen() -> Bool { return false } 33 | } 34 | 35 | @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) 36 | @_cdecl("testEnumerateClassesFromDylib") 37 | public func testEnumerateClassesFromDylib() -> Bool { 38 | // This should enumerate the classes *in the dylib* 39 | let trees = objc_enumerateClasses().map{ "\($0)" } 40 | if trees == [ "Oak", "Birch", "Pine" ] { 41 | return true 42 | } else { 43 | print("FAILED: trees was \(trees)!") 44 | return false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ObjectiveC.xctestplan: -------------------------------------------------------------------------------- 1 | { 2 | "configurations" : [ 3 | { 4 | "id" : "A96CEB60-D6D0-40A5-9F09-DA83D83BA6D0", 5 | "name" : "Test Scheme Action", 6 | "options" : { 7 | 8 | } 9 | } 10 | ], 11 | "defaultOptions" : { 12 | "codeCoverage" : false 13 | }, 14 | "testTargets" : [ 15 | { 16 | "target" : { 17 | "containerPath" : "container:objc.xcodeproj", 18 | "identifier" : "8425816A2CEEB869007C1920", 19 | "name" : "ObjectiveCTests" 20 | } 21 | } 22 | ], 23 | "version" : 1 24 | } 25 | -------------------------------------------------------------------------------- /ObjectiveC/ObjectiveCRPathInstallName.c: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectiveCRPathInstallName.c 3 | // ObjectiveC 4 | // 5 | // Copyright © 2024 Apple Inc. All rights reserved. 6 | // 7 | 8 | #include "ObjectiveCRPathInstallName.h" 9 | 10 | const char ld_previous_objectivec_rpath = '\0'; 11 | -------------------------------------------------------------------------------- /objc-vfs-overlay/write-vfs-overlay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Create a VFS overlay to virtually install the build products into the SDK. 4 | # The LLVM virtual filesystem is documented here. 5 | # http://llvm.org/doxygen/classllvm_1_1vfs_1_1RedirectingFileSystem.html#details 6 | if [ "$RC_XBS" = "YES" -a "$RC_BUILDIT" != "YES" ] 7 | then 8 | # The overlay is not needed in an XBS environment where installhdrs merges the 9 | # build products into the SDK before the other targets run installapi/install. 10 | roots=" []" 11 | else 12 | roots=" 13 | - 14 | type: directory 15 | name: ${SDKROOT}/usr/include 16 | contents: 17 | - 18 | type: file 19 | name: ObjectiveC.apinotes 20 | external-contents: ${BASE_DIRECTORY}/usr/include/ObjectiveC.apinotes 21 | - 22 | type: file 23 | name: ObjectiveC.modulemap 24 | external-contents: ${BASE_DIRECTORY}/usr/include/ObjectiveC.modulemap 25 | - 26 | type: directory-remap 27 | name: objc 28 | external-contents: ${BASE_DIRECTORY}/usr/include/objc 29 | - 30 | type: directory 31 | name: ${SDKROOT}/usr/local/include 32 | contents: 33 | - 34 | type: file 35 | name: ObjectiveC_Private.apinotes 36 | external-contents: ${BASE_DIRECTORY}/usr/local/include/ObjectiveC_Private.apinotes 37 | - 38 | type: file 39 | name: ObjectiveC_Private.modulemap 40 | external-contents: ${BASE_DIRECTORY}/usr/local/include/ObjectiveC_Private.modulemap 41 | - 42 | type: directory-remap 43 | name: objc 44 | external-contents: ${BASE_DIRECTORY}/usr/local/include/objc" 45 | fi 46 | 47 | printf "\ 48 | version: 0 49 | roots:%s" \ 50 | "$roots" > "$SCRIPT_OUTPUT_FILE_0" 51 | -------------------------------------------------------------------------------- /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.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS[sdk=exclavekit*] = $(inherited) DTRACE_PROBES_DISABLED=1 2 | INSTALL_FEATURE_FLAGS[sdk=exclavekit*] = NO 3 | 4 | INSTALLHDRS_SCRIPT_PHASE = YES 5 | 6 | SCRIPT_OUTPUT_DIR = $(SCRIPT_OUTPUT_DIR__$(DEPLOYMENT_LOCATION:default=NO)) 7 | SCRIPT_OUTPUT_DIR__NO = $(TARGET_BUILD_DIR) 8 | SCRIPT_OUTPUT_DIR__YES = $(DSTROOT) 9 | 10 | MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH = $(SCRIPT_OUTPUT_DIR)/$(PRIVATE_HEADERS_FOLDER_PATH) 11 | MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH[sdk=macosx*] = $(SCRIPT_OUTPUT_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH) 12 | 13 | MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS = $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/List.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/Object.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/Protocol.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/hashtable.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/hashtable2.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/objc-class.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/objc-load.h $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS_FOLDER_PATH)/objc-runtime.h 14 | 15 | TAPI_EXTRA_PUBLIC_HEADERS[sdk=macosx*] = $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS) 16 | 17 | TAPI_EXTRA_PRIVATE_HEADERS = $(MACOSPUBLIC_OTHERWISEPRIVATE_HEADERS) 18 | TAPI_EXTRA_PRIVATE_HEADERS[sdk=macosx*] = 19 | -------------------------------------------------------------------------------- /objc4.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | autoreleaseFaultsMacOS 6 | 7 | Enabled 8 | 9 | 10 | preoptimizedCaches 11 | 12 | Enabled 13 | 14 | 15 | classRxSigning 16 | 17 | Enabled 18 | 19 | 20 | classRoSigningFaults 21 | 22 | Enabled 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /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/DenseMapExtras.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 DENSEMAPEXTRAS_H 25 | #define DENSEMAPEXTRAS_H 26 | 27 | #include "InitWrappers.h" 28 | #include "llvm-DenseMap.h" 29 | #include "llvm-DenseSet.h" 30 | 31 | namespace objc { 32 | 33 | // Convenience class for Dense Maps & Sets 34 | template 35 | class ExplicitInitDenseMap : public ExplicitInit> { }; 36 | 37 | template 38 | class LazyInitDenseMap : public LazyInit> { }; 39 | 40 | template 41 | class ExplicitInitDenseSet : public ExplicitInit> { }; 42 | 43 | template 44 | class LazyInitDenseSet : public LazyInit> { }; 45 | 46 | } // namespace objc 47 | 48 | #endif /* DENSEMAPEXTRAS_H */ 49 | -------------------------------------------------------------------------------- /runtime/Module/ObjectiveC.modulemap: -------------------------------------------------------------------------------- 1 | module ObjectiveC [system] { 2 | // These must all be set in the GCC_PREPROCESSOR_DEFINITIONS Xcode build 3 | // setting, or passed on the command line with -D in order to have an 4 | // effect. #define won't do anything for any of these. 5 | #if 0 6 | // config_macros communicates this, but it had to be temporarily disabled due to 7 | // rdar://95261458 (Swift is converting `-Xcc -DABC` to `#define ABC` when building bridging headers, triggers warnings from config_macros) 8 | #endif 9 | // config_macros 10 | // // 11 | // NS_BUILD_32_LIKE_64, 12 | // 13 | // // , 14 | // OBJC_TYPES_DEFINED, 15 | 16 | umbrella "objc" 17 | export * 18 | module * { 19 | export * 20 | } 21 | 22 | module NSObject { 23 | requires objc 24 | header "objc/NSObject.h" 25 | export * 26 | } 27 | #if defined(BUILD_FOR_OSX) 28 | 29 | module Object { 30 | requires objc 31 | header "objc/Object.h" 32 | export * 33 | } 34 | 35 | module Protocol { 36 | requires objc 37 | header "objc/Protocol.h" 38 | export * 39 | } 40 | #endif 41 | } 42 | -------------------------------------------------------------------------------- /runtime/ModulePrivate/ObjectiveC_Private.apinotes: -------------------------------------------------------------------------------- 1 | --- 2 | Name: ObjectiveC_Private 3 | Classes: 4 | - Name: List 5 | Methods: 6 | - Selector: init 7 | MethodKind: Instance 8 | NullabilityOfRet: N 9 | - Selector: 'isEqual:' 10 | MethodKind: Instance 11 | Nullability: 12 | - O 13 | NullabilityOfRet: S 14 | - Name: Object 15 | Methods: 16 | - Selector: init 17 | MethodKind: Instance 18 | NullabilityOfRet: N 19 | - Selector: 'isEqual:' 20 | MethodKind: Instance 21 | Nullability: 22 | - O 23 | NullabilityOfRet: S 24 | -------------------------------------------------------------------------------- /runtime/ModulePrivate/ObjectiveC_Private.modulemap: -------------------------------------------------------------------------------- 1 | module ObjectiveC_Private [system] { 2 | umbrella "objc" 3 | explicit module * { export * } 4 | #ifndef BUILD_FOR_OSX 5 | 6 | explicit module Object { 7 | requires objc 8 | header "objc/Object.h" 9 | export * 10 | } 11 | 12 | explicit module Protocol { 13 | requires objc 14 | header "objc/Protocol.h" 15 | export * 16 | } 17 | #endif 18 | } 19 | -------------------------------------------------------------------------------- /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 | #include 11 | 12 | #if __LP64__ || NS_BUILD_32_LIKE_64 13 | typedef long NSInteger; 14 | typedef unsigned long NSUInteger; 15 | #else 16 | typedef int NSInteger; 17 | typedef unsigned int NSUInteger; 18 | #endif 19 | 20 | #define NSIntegerMax LONG_MAX 21 | #define NSIntegerMin LONG_MIN 22 | #define NSUIntegerMax ULONG_MAX 23 | 24 | #define NSINTEGER_DEFINED 1 25 | 26 | #ifndef NS_DESIGNATED_INITIALIZER 27 | #if __has_attribute(objc_designated_initializer) 28 | #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 29 | #else 30 | #define NS_DESIGNATED_INITIALIZER 31 | #endif 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /runtime/Object.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2003, 2005-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 | Object.h 25 | Copyright 1988-1996 NeXT Software, Inc. 26 | 27 | DEFINED AS: A common class 28 | HEADER FILES: 29 | 30 | */ 31 | 32 | #ifndef _OBJC_OBJECT_H_ 33 | #define _OBJC_OBJECT_H_ 34 | 35 | #include 36 | #include 37 | 38 | #endif /* _OBJC_OBJECT_H_ */ 39 | -------------------------------------------------------------------------------- /runtime/Object.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-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 | Object.m 25 | Copyright 1988-1996 NeXT Software, Inc. 26 | */ 27 | 28 | #include "objc-private.h" 29 | 30 | #undef id 31 | #undef Class 32 | 33 | typedef struct objc_class *Class; 34 | typedef struct objc_object *id; 35 | 36 | @implementation Object 37 | 38 | + (id)initialize 39 | { 40 | return self; 41 | } 42 | 43 | + (id)class 44 | { 45 | return self; 46 | } 47 | 48 | -(id) retain 49 | { 50 | return _objc_rootRetain(self); 51 | } 52 | 53 | -(void) release 54 | { 55 | _objc_rootRelease(self); 56 | } 57 | 58 | -(id) autorelease 59 | { 60 | return _objc_rootAutorelease(self); 61 | } 62 | 63 | +(id) retain 64 | { 65 | return self; 66 | } 67 | 68 | +(void) release 69 | { 70 | } 71 | 72 | +(id) autorelease 73 | { 74 | return self; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /runtime/OldClasses.subproj/List.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2002, 2005-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 | List.h 25 | Copyright 1988-1996 NeXT Software, Inc. 26 | 27 | DEFINED AS: A common class 28 | HEADER FILES: objc/List.h 29 | 30 | */ 31 | 32 | #ifndef _OBJC_LIST_H_ 33 | #define _OBJC_LIST_H_ 34 | 35 | // This file intentionally left blank 36 | 37 | #endif /* _OBJC_LIST_H_ */ 38 | -------------------------------------------------------------------------------- /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 | #else 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/Threading/threading.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 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 | * threading.h 26 | * Threading support 27 | **********************************************************************/ 28 | 29 | #ifndef _OBJC_THREADING_H 30 | #define _OBJC_THREADING_H 31 | 32 | // TLS key identifiers 33 | enum class tls_key { 34 | main = 0, 35 | sync_data = 1, 36 | sync_count = 2, 37 | autorelease_pool = 3, 38 | #if SUPPORT_RETURN_AUTORELEASE 39 | return_autorelease_object = 4, 40 | return_autorelease_address = 5 41 | #endif 42 | }; 43 | 44 | #if OBJC_THREADING_PACKAGE == OBJC_THREADING_NONE 45 | #include "nothreads.h" 46 | #elif OBJC_THREADING_PACKAGE == OBJC_THREADING_DARWIN 47 | #include "darwin.h" 48 | #elif OBJC_THREADING_PACKAGE == OBJC_THREADING_PTHREADS 49 | #include "pthreads.h" 50 | #elif OBJC_THREADING_PACKAGE == OBJC_THREADING_C11THREADS 51 | #include "c11threads.h" 52 | #else 53 | #error No threading package selected in objc-config.h 54 | #endif 55 | 56 | #include "mixins.h" 57 | #include "lockdebug.h" 58 | #include "tls.h" 59 | 60 | using objc_lock_t = locker_mixin>; 61 | using objc_recursive_lock_t = 62 | locker_mixin>; 63 | using objc_nodebug_lock_t = locker_mixin; 64 | 65 | #endif // _OBJC_THREADING_H 66 | -------------------------------------------------------------------------------- /runtime/hashtable.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /runtime/objc-class.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-file.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-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 | #include "objc-private.h" 25 | #include "objc-file.h" 26 | -------------------------------------------------------------------------------- /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 | extern void classInitializeAtforkPrepare(); 40 | extern void classInitializeAtforkParent(); 41 | extern void classInitializeAtforkChild(); 42 | 43 | __END_DECLS 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /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-load.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2001, 2004-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 | /* 25 | * objc-load.m 26 | * Copyright 1988-1996, NeXT Software, Inc. 27 | * Author: s. naroff 28 | * 29 | */ 30 | 31 | #include "objc-private.h" 32 | #include "objc-load.h" 33 | 34 | -------------------------------------------------------------------------------- /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-magicsel.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 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 | #include 25 | 26 | // All shared cache relative method lists names are offsets from this selector. 27 | // C++ doesn't like emoji identifiers, and this causes ObjC++ to reject this 28 | // @selector expression (rdar://84895077). This probably needs a different long 29 | // term fix, but for now work around the problem by putting this into an ObjC 30 | // file. 31 | uintptr_t sharedCacheRelativeMethodBase() { 32 | SEL sel = @selector(🤯); 33 | return (uintptr_t)sel; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /runtime/objc-malloc-instance.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 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_MALLOC_INSTANCE_H 25 | #define _OBJC_MALLOC_INSTANCE_H 26 | 27 | #include 28 | #if _MALLOC_TYPE_ENABLED 29 | # include 30 | #endif 31 | 32 | namespace objc { 33 | 34 | static inline id 35 | malloc_instance(size_t size, Class cls __unused) 36 | { 37 | #if _MALLOC_TYPE_ENABLED 38 | malloc_type_descriptor_t desc = {}; 39 | desc.summary.type_kind = MALLOC_TYPE_KIND_OBJC; 40 | return (id)malloc_type_calloc(1, size, desc.type_id); 41 | #else 42 | return (id)calloc(1, size); 43 | #endif 44 | } 45 | 46 | } // namespace objc 47 | 48 | #endif // _OBJC_MALLOC_INSTANCE_H 49 | -------------------------------------------------------------------------------- /runtime/objc-opt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 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-opt.h 26 | Management of optimizations in the dyld shared cache 27 | */ 28 | 29 | #ifndef _OBJC_OPT_H 30 | #define _OBJC_OPT_H 31 | 32 | #include 33 | 34 | typedef struct header_info_rw { 35 | 36 | bool getLoaded() const { 37 | return isLoaded; 38 | } 39 | 40 | void setLoaded(bool v) { 41 | isLoaded = v ? 1: 0; 42 | } 43 | 44 | struct header_info *getNext() const { 45 | return (struct header_info *)(next << 2); 46 | } 47 | 48 | void setNext(struct header_info *v) { 49 | next = ((uintptr_t)v) >> 2; 50 | } 51 | 52 | private: 53 | #ifdef __LP64__ 54 | uintptr_t isLoaded : 1; 55 | [[maybe_unused]] uintptr_t unused : 1; 56 | uintptr_t next : 62; 57 | #else 58 | uintptr_t isLoaded : 1; 59 | [[maybe_unused]] uintptr_t unused : 1; 60 | uintptr_t next : 30; 61 | #endif 62 | } header_info_rw; 63 | 64 | struct objc_headeropt_rw_t { 65 | uint32_t count; 66 | uint32_t entsize; 67 | header_info_rw headers[0]; // sorted by mhdr address 68 | }; 69 | 70 | #endif // _OBJC_OPT_H 71 | -------------------------------------------------------------------------------- /runtime/objc-probes.d: -------------------------------------------------------------------------------- 1 | typedef void *Class; 2 | typedef const char *SEL; 3 | typedef void *IMP; 4 | 5 | provider objc_runtime 6 | { 7 | // Exception handling 8 | probe objc_exception_throw(void *id); 9 | probe objc_exception_rethrow(); 10 | 11 | // Initialization time things; you may need to use 12 | // 13 | // dtrace -x evaltime=preinit -Z 14 | // 15 | // in order to catch everything 16 | probe load_image(const char *name, int bundle, int hasClassProperties, int preoptimized); 17 | 18 | // Different phases of initialization 19 | probe first_time__start(); 20 | probe first_time__end(); 21 | 22 | probe fixup_selectors__start(); 23 | probe fixup_selectors__end(); 24 | 25 | probe discover_classes__start(); 26 | probe discover_classes__end(); 27 | 28 | probe remap_classes__start(); 29 | probe remap_classes__end(); 30 | 31 | probe fixup_vtables__start(); 32 | probe fixup_vtables__end(); 33 | 34 | probe discover_protocols__start(); 35 | probe discover_protocols__end(); 36 | 37 | probe fixup_protocols__start(); 38 | probe fixup_protocols__end(); 39 | 40 | probe discover_categories__start(); 41 | probe discover_categories__end(); 42 | 43 | probe realize_non_lazy_classes__start(); 44 | probe realize_non_lazy_classes__end(); 45 | 46 | probe realize_future_classes__start(); 47 | probe realize_future_classes__end(); 48 | 49 | // Method cache 50 | probe cache_miss(void *id, SEL sel, Class cls); 51 | probe cache_flush(Class cls); 52 | 53 | // Autorelease 54 | probe autorelease_pool__push(void *token); 55 | probe autorelease_pool__pop(void *token); 56 | 57 | // Fires when we add a new page to an autorelease pool 58 | probe autorelease_pool__grow(int depth); 59 | }; 60 | -------------------------------------------------------------------------------- /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_associations(id object, bool deallocating); 39 | 40 | __END_DECLS 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /runtime/objc-runtime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /runtime/objc-sel-table.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include "objc-vm.h" 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 | lobjc_opt_ptrs: 43 | PTR(.objc_class_name_Protocol) 44 | #else 45 | // new ABI 46 | .globl _OBJC_CLASS_$_Protocol 47 | lobjc_opt_ptrs: 48 | PTR(_OBJC_CLASS_$_Protocol) 49 | #endif 50 | 51 | .no_dead_strip lobjc_opt_ptrs 52 | -------------------------------------------------------------------------------- /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/objc-test-env.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 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-test-env.h" 25 | 26 | #include 27 | #include 28 | 29 | // This is a dummy placeholder, so we can link 30 | char **_objc_test_get_environ(void) { 31 | return NULL; 32 | } 33 | -------------------------------------------------------------------------------- /runtime/objc-test-env.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 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_TEST_ENV_ 25 | #define _OBJC_TEST_ENV_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | // Retrieve the environment when using a compiled environment library 32 | char **_objc_test_get_environ(void) __attribute__((weak_import, visibility("default"))); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif // _OBJC_TEST_ENV_ 39 | -------------------------------------------------------------------------------- /runtime/objc-vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 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_VM_H 25 | #define _OBJC_VM_H 26 | 27 | /* 28 | * WARNING DANGER HAZARD BEWARE EEK 29 | * 30 | * Everything in this file is for Apple Internal use only. 31 | * These will change in arbitrary OS updates and in unpredictable ways. 32 | * When your program breaks, you get to keep both pieces. 33 | */ 34 | 35 | /* 36 | * objc-vm.h: defines PAGE_SIZE, PAGE_MIN/MAX_SIZE and PAGE_MAX_SHIFT 37 | */ 38 | 39 | // N.B. This file must be usable FROM ASSEMBLY SOURCE FILES 40 | 41 | #include 42 | 43 | #if __has_include() 44 | # include 45 | 46 | # define OBJC_VM_MAX_ADDRESS MACH_VM_MAX_ADDRESS 47 | #elif __arm64__ 48 | # define PAGE_SIZE 16384 49 | # define PAGE_MIN_SIZE 16384 50 | # define PAGE_MAX_SIZE 16384 51 | # define PAGE_MAX_SHIFT 14 52 | #if TARGET_OS_EXCLAVEKIT 53 | # define OBJC_VM_MAX_ADDRESS 0x0000000ffffffff8ULL 54 | #else 55 | # define OBJC_VM_MAX_ADDRESS 0x00007ffffffffff8ULL 56 | #endif 57 | #else 58 | # error Unknown platform - please define PAGE_SIZE et al. 59 | #endif 60 | 61 | #endif // _OBJC_VM_H 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/time-startup: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/dtrace -qs 2 | 3 | // 4 | // Measure start-up time 5 | // 6 | 7 | dtrace:::BEGIN { 8 | self->start = timestamp; 9 | self->vstart = vtimestamp; 10 | } 11 | 12 | objc$target:NSApplication:-finishLaunching:return { 13 | this->elapsed = timestamp - self->start; 14 | this->on_cpu = vtimestamp - self->vstart; 15 | 16 | printf("\n** STARTUP TIME **\n"); 17 | printf("Elapsed time: %d ns\n", this->elapsed); 18 | printf("On CPU: %d ns\n", this->on_cpu); 19 | printf("\n"); 20 | } 21 | -------------------------------------------------------------------------------- /test/00-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/00-defines.c -o 00-defines.exe 7 | END 8 | */ 9 | 10 | 11 | #include "test.h" 12 | 13 | int main() 14 | { 15 | succeed(__FILE__); 16 | } 17 | -------------------------------------------------------------------------------- /test/01-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/01-headers.c -o 01-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/06-ARCLayoutsWithoutWeak.m: -------------------------------------------------------------------------------- 1 | // Same as test ARCLayouts but with MRC __weak support disabled. 2 | /* 3 | TEST_CONFIG MEM=arc OS=!exclavekit 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=\"06-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 06-ARCLayoutsWithoutWeak.exe 11 | END 12 | */ 13 | -------------------------------------------------------------------------------- /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/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/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/arr-weak-error.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | // TEST_ENV OBJC_DEBUG_WEAK_ERRORS=fatal 3 | // TEST_CRASHES 4 | /* 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: __weak variable at 0x[0-9a-f]+ holds 0x[0-9a-f]+ instead of 0x[0-9a-f]+. This is probably incorrect use of objc_storeWeak\(\) and objc_loadWeak\(\). 7 | objc\[\d+\]: HALTED 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | int main() 16 | { 17 | id weakVar = nil; 18 | @autoreleasepool { 19 | id obj = [NSObject new]; 20 | objc_storeWeak(&weakVar, obj); 21 | weakVar = [NSObject new]; 22 | [obj release]; 23 | } 24 | 25 | fail("should have crashed"); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /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 | 42 | #if __x86_64__ 43 | // Only request 4kB alignment on Intel. It doesn't support any greater 44 | // alignment anyway, and the linker complains if we ask. rdar://119847439 45 | .align 12 46 | #else 47 | .align 14 48 | #endif 49 | 50 | _main: 51 | // at least 1024 instruction bytes on all architectures 52 | NOP256 53 | NOP256 54 | NOP256 55 | NOP256 56 | -------------------------------------------------------------------------------- /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 * __ptrauth_objc_isa_pointer isa; 15 | void * __ptrauth_objc_super_pointer superclass; 16 | void *cachePtr; 17 | uintptr_t maskAndOccupied; 18 | struct minimal_class_ro * __ptrauth_objc_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 | ptrauth_strip(localForbidden->ro, ptrauth_key_process_independent_data)->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/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]+\. Set a breakpoint .* 9 | objc\[\d+\]: Invalid autorelease pools are a fatal error 10 | objc\[\d+\]: HALTED 11 | END 12 | */ 13 | 14 | #include "test.h" 15 | 16 | int main() 17 | { 18 | void *outer = objc_autoreleasePoolPush(); 19 | void *inner = objc_autoreleasePoolPush(); 20 | objc_autoreleasePoolPop(outer); 21 | objc_autoreleasePoolPop(inner); 22 | 23 | #if !OLD 24 | fail("should have crashed already with new SDK"); 25 | #else 26 | // should only warn once 27 | outer = objc_autoreleasePoolPush(); 28 | inner = objc_autoreleasePoolPush(); 29 | objc_autoreleasePoolPop(outer); 30 | objc_autoreleasePoolPop(inner); 31 | 32 | succeed(__FILE__); 33 | #endif 34 | } 35 | 36 | -------------------------------------------------------------------------------- /test/badPoolCompat-ios-simulator.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=iphonesimulator ARCH=x86_64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker ios-simulator -Xlinker 9.0 -Xlinker 9.0 -mios-simulator-version-min=9.0 6 | 7 | /* 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /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 ARCH=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_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /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_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /test/badPoolCompat-tvos-simulator.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=appletvsimulator ARCH=x86_64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker tvos-simulator -Xlinker 9.0 -Xlinker 9.0 -mtvos-simulator-version-min=9.0 6 | 7 | /* 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /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 ARCH=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_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /test/badPoolCompat-watchos-simulator.m: -------------------------------------------------------------------------------- 1 | // Run test badPool as if it were built with an old SDK. 2 | 3 | // TEST_CONFIG MEM=mrc OS=watchsimulator ARCH=x86_64 4 | // TEST_CRASHES 5 | // TEST_CFLAGS -DOLD=1 -Xlinker -platform_version -Xlinker watchos-simulator -Xlinker 2.0 -Xlinker 2.0 -mwatchos-simulator-version-min=2.0 6 | 7 | /* 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /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 ARCH=armv7k,arm64_32 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_RUN_OUTPUT 9 | objc\[\d+\]: Invalid or prematurely-freed autorelease pool 0x[0-9a-fA-f]+\. Set a breakpoint .* 10 | objc\[\d+\]: Proceeding anyway.* 11 | OK: badPool.m 12 | END 13 | */ 14 | 15 | #include "badPool.m" 16 | -------------------------------------------------------------------------------- /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_CFLAGS -Wno-nonnull 3 | TEST_CRASHES 4 | TEST_RUN_OUTPUT 5 | objc\[\d+\]: tag index 1 used for two different classes \(was 0x[0-9a-fA-F]+ NSObject, now 0x[0-9a-fA-F]+ TestRoot\) 6 | objc\[\d+\]: HALTED 7 | OR 8 | no tagged pointers 9 | OK: badTagClass.m 10 | END 11 | */ 12 | 13 | #include "test.h" 14 | #include "testroot.i" 15 | 16 | #include 17 | #include 18 | 19 | #if OBJC_HAVE_TAGGED_POINTERS 20 | 21 | int main() 22 | { 23 | // re-registration and nil registration allowed 24 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 25 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 26 | _objc_registerTaggedPointerClass(OBJC_TAG_1, nil); 27 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [NSObject class]); 28 | 29 | // colliding registration disallowed 30 | _objc_registerTaggedPointerClass(OBJC_TAG_1, [TestRoot class]); 31 | 32 | fail(__FILE__); 33 | } 34 | 35 | #else 36 | 37 | int main() 38 | { 39 | // provoke the same nullability warning as the real test 40 | objc_getClass(nil); 41 | 42 | fprintf(stderr, "no tagged pointers\n"); 43 | succeed(__FILE__); 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /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/bool.c: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -funsigned-char 2 | // TEST_CONFIG LANGUAGE=c,c++,objc,objc++ 3 | // (verify -funsigned-char doesn't change the definition of BOOL) 4 | 5 | #include "test.h" 6 | #include 7 | 8 | #if TARGET_OS_OSX 9 | # if __x86_64__ 10 | # define RealBool 0 11 | # else 12 | # define RealBool 1 13 | # endif 14 | #elif TARGET_OS_IOS || TARGET_OS_BRIDGE 15 | # if (__arm__ && !__armv7k__) || __i386__ 16 | # define RealBool 0 17 | # else 18 | # define RealBool 1 19 | # endif 20 | #else 21 | # define RealBool 1 22 | #endif 23 | 24 | #if __OBJC__ && !defined(__OBJC_BOOL_IS_BOOL) 25 | # error no __OBJC_BOOL_IS_BOOL 26 | #endif 27 | 28 | #if RealBool != OBJC_BOOL_IS_BOOL 29 | # error wrong OBJC_BOOL_IS_BOOL 30 | #endif 31 | 32 | #if RealBool == OBJC_BOOL_IS_CHAR 33 | # error wrong OBJC_BOOL_IS_CHAR 34 | #endif 35 | 36 | int main() 37 | { 38 | const char *expected __unused = 39 | #if RealBool 40 | "B" 41 | #else 42 | "c" 43 | #endif 44 | ; 45 | #if __OBJC__ 46 | const char *enc = @encode(BOOL); 47 | testassert(0 == strcmp(enc, expected)); 48 | #endif 49 | succeed(__FILE__); 50 | } 51 | -------------------------------------------------------------------------------- /test/cacheflush-constant.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit 2 | // TEST_CFLAGS -framework Foundation 3 | /* 4 | TEST_RUN_OUTPUT 5 | foo 6 | bar 7 | bar 8 | foo 9 | END 10 | */ 11 | 12 | // NOTE: This test won't catch problems when running against a root, so it's of 13 | // limited utility, but it would at least catch things when testing against the 14 | // shared cache. 15 | 16 | #include 17 | #include 18 | 19 | @interface NSBlock: NSObject @end 20 | 21 | // NSBlock is a conveniently accessible superclass that (currently) has a constant cache. 22 | @interface MyBlock: NSBlock 23 | +(void)foo; 24 | +(void)bar; 25 | @end 26 | @implementation MyBlock 27 | +(void)foo { 28 | printf("foo\n"); 29 | } 30 | +(void)bar { 31 | printf("bar\n"); 32 | } 33 | @end 34 | 35 | int main() { 36 | [MyBlock foo]; 37 | [MyBlock bar]; 38 | 39 | Method m1 = class_getClassMethod([MyBlock class], @selector(foo)); 40 | Method m2 = class_getClassMethod([MyBlock class], @selector(bar)); 41 | method_exchangeImplementations(m1, m2); 42 | 43 | [MyBlock foo]; 44 | [MyBlock bar]; 45 | } 46 | -------------------------------------------------------------------------------- /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 -install_name $T{DYLIBDIR}/cacheflush0.dylib -o cacheflush0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/cacheflush2.m -x none cacheflush0.dylib -install_name $T{DYLIBDIR}/cacheflush2.dylib -o cacheflush2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/cacheflush3.m -x none cacheflush0.dylib -install_name $T{DYLIBDIR}/cacheflush3.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 | #if !TARGET_OS_EXCLAVEKIT 37 | // Dynamically load a category 38 | dlopen("cacheflush2.dylib", 0); 39 | 40 | // Make sure old cache results are gone 41 | testassert(2 == [TestRoot classMethod]); 42 | testassert(2 == [sup instanceMethod]); 43 | 44 | testassert(2 == [Sub classMethod]); 45 | testassert(2 == [sub instanceMethod]); 46 | 47 | // Dynamically load another category 48 | dlopen("cacheflush3.dylib", 0); 49 | 50 | // Make sure old cache results are gone 51 | testassert(3 == [TestRoot classMethod]); 52 | testassert(3 == [sup instanceMethod]); 53 | 54 | testassert(3 == [Sub classMethod]); 55 | testassert(3 == [sub instanceMethod]); 56 | #endif // !TARGET_OS_EXCLAVEKIT 57 | 58 | // fixme test subclasses 59 | 60 | // fixme test objc_flush_caches(), class_addMethod(), class_addMethods() 61 | 62 | succeed(__FILE__); 63 | } 64 | -------------------------------------------------------------------------------- /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 | #define __APPLE_API_PRIVATE 1 4 | #include "test.h" 5 | #include 6 | #include 7 | #import 8 | 9 | @interface Foo:NSObject 10 | @end 11 | @implementation Foo 12 | @end 13 | 14 | int main() 15 | { 16 | testassert(gdb_class_getClass([Foo class]) == [Foo class]); 17 | succeed(__FILE__); 18 | } 19 | -------------------------------------------------------------------------------- /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 | memset(buf, 0, 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/classpair-stress.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | // Allocate a large number of classes and make sure their instances work. 10 | // This is mostly to ensure that the indexed class system on 32-bit works 11 | // correctly for the full range of values, and when we run off the end. 12 | 13 | // The indexed class array is currently 32,768 entries. Each iteration will 14 | // use two (class and metaclass). 15 | int count = 20000; 16 | for (int i = 0; i < count; i++) { 17 | testprintf("Testing iteration %d\n", i); 18 | 19 | char *name; 20 | asprintf(&name, "TestClass-%d", i); 21 | 22 | Class c = objc_allocateClassPair([NSObject class], name, 0); 23 | objc_registerClassPair(c); 24 | 25 | testprintf("%s is at %p\n", name, c); 26 | 27 | free(name); 28 | 29 | RELEASE_VALUE([[c alloc] init]); 30 | } 31 | 32 | succeed(__FILE__); 33 | } 34 | -------------------------------------------------------------------------------- /test/classpairAddMethod.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | #include "test.h" 4 | 5 | #include "testroot.i" 6 | #include 7 | 8 | void fakeIMP() {} 9 | IMP testIMP = (IMP)fakeIMP; 10 | 11 | int main() 12 | { 13 | // Make sure that method_getDescription doesn't return a stale cached 14 | // description when creating and destroying dynamic subclasses 15 | // (rdar://91521212). This is a UaF so it's not completely reliable, but 16 | // empirically it happens reliably after five iterations. Run 100 just to be 17 | // safe. 18 | for (int i = 0; i < 100; i++) { 19 | char *name; 20 | asprintf(&name, "test-%d", i); 21 | SEL sel = sel_getUid(name); 22 | Class c = objc_allocateClassPair([TestRoot class], name, 0); 23 | class_addMethod(c, sel, testIMP, name); 24 | objc_registerClassPair(c); 25 | 26 | Method m = class_getInstanceMethod(c, sel); 27 | struct objc_method_description *desc = method_getDescription(m); 28 | testassert(strcmp(desc->types, name) == 0); 29 | testassertequal(desc->name, sel); 30 | 31 | free(name); 32 | objc_disposeClassPair(c); 33 | } 34 | 35 | succeed(__FILE__); 36 | } -------------------------------------------------------------------------------- /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 | (void)keyPath; 47 | (void)object; 48 | (void)change; 49 | (void)context; 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_FILTER .*( OS_|inherited).* 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 14 | OK: customrr-nsobject-awz.exe 15 | END 16 | 17 | */ 18 | 19 | -------------------------------------------------------------------------------- /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_FILTER .*( OS_|inherited).* 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: CUSTOM Core: NSObject \(meta\) 14 | objc\[\d+\]: CUSTOM Core: NSObject 15 | OK: customrr-nsobject-core.exe 16 | OR 17 | objc\[\d+\]: CUSTOM Core: NSObject 18 | objc\[\d+\]: CUSTOM Core: NSObject \(meta\) 19 | OK: customrr-nsobject-core.exe 20 | END 21 | 22 | */ 23 | 24 | -------------------------------------------------------------------------------- /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_RUN_OUTPUT_FILTER .*( OS_|inherited).* 7 | 8 | TEST_BUILD 9 | $C{COMPILE} $DIR/customrr-nsobject.m -o customrr-nsobject-none.exe -fno-objc-convert-messages-to-runtime-calls 10 | END 11 | 12 | TEST_RUN_OUTPUT 13 | OK: customrr-nsobject-none.exe 14 | END 15 | 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /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_FILTER .*( OS_|inherited).* 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: CUSTOM RR: NSObject 14 | OK: customrr-nsobject-rr.exe 15 | END 16 | 17 | */ 18 | 19 | -------------------------------------------------------------------------------- /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_FILTER .*( OS_|inherited).* 11 | 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 14 | objc\[\d+\]: CUSTOM RR: NSObject 15 | OK: customrr-nsobject-rrawz.exe 16 | OR 17 | objc\[\d+\]: CUSTOM RR: NSObject 18 | objc\[\d+\]: CUSTOM AWZ: NSObject \(meta\) 19 | OK: customrr-nsobject-rrawz.exe 20 | END 21 | 22 | */ 23 | 24 | -------------------------------------------------------------------------------- /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.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 28 | 29 | ERROR= 30 | 31 | extract_defines() { 32 | echo "$INCLUDES" | $1 - -dM -E \ 33 | | sed 's/\(#define [_A-Za-z][_A-Za-z0-9]*\).*/\1/g' \ 34 | | sort | uniq 35 | } 36 | 37 | get_new_lines() { 38 | diff -u -U 0 $1 $2 | grep -v "^+++" | grep "^+" | cut -c2- || true 39 | } 40 | 41 | run_test() { 42 | extract_defines "$1 $CFLAGS" > base-defines 43 | extract_defines "$1 $CFLAGS $FILES" > objc-defines 44 | get_new_lines base-defines objc-defines > objc-defines-only 45 | if [[ ! -s objc-defines-only ]]; then 46 | echo "ERROR: objc-defines-only is somehow empty." 47 | exit 1 48 | fi 49 | get_new_lines defines.expected objc-defines-only > objc-defines-unexpected 50 | if [[ -s objc-defines-unexpected ]]; then 51 | echo "ERROR: unknown #defines found in headers. If these are expected, add them to test/defines.expected." 52 | echo "$1" 53 | cat objc-defines-unexpected 54 | ERROR=1 55 | fi 56 | rm base-defines objc-defines objc-defines-only objc-defines-unexpected 57 | } 58 | 59 | run_test "$COMPILE_C $CFLAGS" 60 | run_test "$COMPILE_CXX $CFLAGS" 61 | run_test "$COMPILE_M $CFLAGS" 62 | run_test "$COMPILE_MM $CFLAGS" 63 | for STDC in '99' '11' ; do 64 | run_test "$COMPILE_C $CFLAGS -std=c$STDC" 65 | run_test "$COMPILE_M $CFLAGS -std=c$STDC" 66 | done 67 | for STDCXX in '98' '03' '11' '14' '17' ; do 68 | run_test "$COMPILE_CXX $CFLAGS -std=c++$STDCXX" 69 | run_test "$COMPILE_MM $CFLAGS -std=c++$STDCXX" 70 | done 71 | 72 | if [[ $ERROR == 1 ]]; then 73 | echo "Unknown #defines found in headers." 74 | exit 1 75 | fi 76 | -------------------------------------------------------------------------------- /test/definitions.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,arc LANGUAGE=c,c++,objc,objc++ 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/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_CONFIG OS=!exclavekit 5 | // TEST_ENV OBJC_DEBUG_DUPLICATE_CLASSES=FATAL OBJC_DISABLE_PREOPTIMIZATION=YES 6 | // TEST_CRASHES 7 | /* 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: Class [^\s]+ is implemented in both .+ \(0x[0-9a-f]+\) and .+ \(0x[0-9a-f]+\)\. This may cause spurious casting failures and mysterious crashes\. One of the duplicates must be removed or renamed\. 10 | objc\[\d+\]: HALTED 11 | OR 12 | OK: duplicatedClasses.m 13 | END 14 | */ 15 | 16 | #include "test.h" 17 | #include "testroot.i" 18 | 19 | @interface WKWebView : TestRoot @end 20 | @implementation WKWebView @end 21 | 22 | int main() 23 | { 24 | void *dl = dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", RTLD_LAZY); 25 | if (!dl) fail("couldn't open WebKit"); 26 | fail("should have crashed already"); 27 | } 28 | -------------------------------------------------------------------------------- /test/duplicatedClasses0.m: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "testroot.i" 3 | 4 | @interface DuplicatedClass : TestRoot @end 5 | @implementation DuplicatedClass @end 6 | -------------------------------------------------------------------------------- /test/duplicatedClasses2.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=!exclavekit 3 | TEST_BUILD 4 | $C{COMPILE} $DIR/duplicatedClasses0.m -fvisibility=hidden -DTestRoot=TestRoot2 -install_name $T{DYLIBDIR}/duplicatedClasses0.dylib -o duplicatedClasses0.dylib -dynamiclib 5 | $C{COMPILE} $DIR/duplicatedClasses2.m -o duplicatedClasses2.exe 6 | END 7 | */ 8 | 9 | // TEST_ENV OBJC_DEBUG_DUPLICATE_CLASSES=FATAL 10 | // TEST_CRASHES 11 | /* 12 | TEST_RUN_OUTPUT 13 | objc\[\d+\]: Class DuplicatedClass is implemented in both .+ \(0x[0-9a-f]+\) and .+ \(0x[0-9a-f]+\)\. This may cause spurious casting failures and mysterious crashes\. One of the duplicates must be removed or renamed\. 14 | objc\[\d+\]: HALTED 15 | END 16 | */ 17 | 18 | #include "duplicatedClasses0.m" 19 | 20 | int main() 21 | { 22 | void *dl = dlopen("duplicatedClasses0.dylib", RTLD_LAZY); 23 | if (!dl) fail("couldn't open dylib"); 24 | fail("should have crashed already"); 25 | } 26 | -------------------------------------------------------------------------------- /test/duplicatedClasses3.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_BUILD 3 | $C{COMPILE} $DIR/duplicatedClasses0.m -fvisibility=hidden -DTestRoot=TestRoot2 -install_name $T{DYLIBDIR}/duplicatedClasses0.dylib -o duplicatedClasses0.dylib -dynamiclib 4 | $C{COMPILE} $DIR/duplicatedClasses3.m -x none duplicatedClasses0.dylib -o duplicatedClasses3.exe 5 | END 6 | */ 7 | 8 | // TEST_ENV OBJC_DEBUG_DUPLICATE_CLASSES=FATAL 9 | // TEST_CRASHES 10 | /* 11 | TEST_RUN_OUTPUT 12 | objc\[\d+\]: Class DuplicatedClass is implemented in both .+ \(0x[0-9a-f]+\) and .+ \(0x[0-9a-f]+\)\. This may cause spurious casting failures and mysterious crashes\. One of the duplicates must be removed or renamed\. 13 | objc\[\d+\]: HALTED 14 | END 15 | */ 16 | 17 | #include "duplicatedClasses0.m" 18 | 19 | int main() 20 | { 21 | fail("should have crashed already"); 22 | } 23 | -------------------------------------------------------------------------------- /test/enumClasses.h: -------------------------------------------------------------------------------- 1 | /* Emacs, this is -*-objc-*- */ 2 | 3 | #ifndef ENUMCLASSES_H_ 4 | #define ENUMCLASSES_H_ 5 | 6 | #include "test.h" 7 | 8 | typedef enum { 9 | UnknownSize = -1, 10 | MinasculeSize, 11 | SmallSize, 12 | MediumSize, 13 | BigSize, 14 | HugeSize, 15 | } creature_size_t; 16 | 17 | typedef enum { 18 | BlackAndOrange, 19 | GrayAndBlack, 20 | Plaid, 21 | } stripe_color_t; 22 | 23 | @protocol Creature 24 | - (const char *)name; 25 | - (creature_size_t)size; 26 | @end 27 | 28 | @protocol Claws 29 | - (void)retract; 30 | - (void)extend; 31 | @end 32 | 33 | @protocol Stripes 34 | - (stripe_color_t)stripeColor; 35 | @end 36 | 37 | // Animal 38 | @interface Animal : TestRoot 39 | 40 | - (const char *)name; 41 | - (creature_size_t)size; 42 | 43 | @end 44 | 45 | @interface Dog : Animal 46 | 47 | - (const char *)name; 48 | 49 | @end 50 | 51 | @interface Cat : Animal 52 | 53 | - (const char *)name; 54 | 55 | @end 56 | 57 | @interface Elephant : Animal 58 | 59 | - (const char *)name; 60 | - (creature_size_t)size; 61 | 62 | @end 63 | 64 | #endif /* ENUMCLASSES_H_ */ 65 | -------------------------------------------------------------------------------- /test/enumClasses0.m: -------------------------------------------------------------------------------- 1 | #include "enumClasses.h" 2 | #include "testroot.i" 3 | 4 | // Animal 5 | @implementation Animal 6 | 7 | - (const char *)name { return "animal"; } 8 | - (creature_size_t)size { return UnknownSize; } 9 | 10 | @end 11 | 12 | // Cat 13 | @implementation Cat 14 | 15 | - (const char *)name { return "cat"; } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /test/enumClasses1.m: -------------------------------------------------------------------------------- 1 | #include "enumClasses.h" 2 | 3 | // Cats have retractable claws (using a category) 4 | @interface Cat (Category) 5 | 6 | - (void)retract; 7 | - (void)extend; 8 | 9 | @end 10 | 11 | @implementation Cat (Category) 12 | 13 | - (void)retract { 14 | } 15 | - (void)extend { 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /test/fakeRealizedClass.m: -------------------------------------------------------------------------------- 1 | /* 2 | Make sure we detect classes with the RW_REALIZED bit set in the binary. rdar://problem/67692760 3 | 4 | (Note that on arm64e, this problem will cause a pointer auth failure.) 5 | 6 | TEST_CONFIG OS=macosx ARCH=!arm64e 7 | TEST_CRASHES 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: realized class 0x[0-9a-fA-F]+ has corrupt data pointer: malloc_size\(0x[0-9a-fA-F]+\) = 0 10 | objc\[\d+\]: HALTED 11 | END 12 | */ 13 | 14 | #include "test.h" 15 | #include "class-structures.h" 16 | 17 | #include 18 | 19 | #define RW_REALIZED (1U<<31) 20 | 21 | // This test only runs on macOS, so we won't bother with the conditionals around 22 | // this value. Just use the one value macOS always has. 23 | #define FAST_IS_RW_POINTER 0x8000000000000000UL 24 | 25 | __attribute__((section("__DATA,__objc_const"))) 26 | struct ObjCClass_ro FakeSuperclassRO = { 27 | .flags = RW_REALIZED 28 | }; 29 | 30 | struct ObjCClass FakeSuperclass = { 31 | &OBJC_METACLASS_$_NSObject, 32 | &OBJC_METACLASS_$_NSObject, 33 | NULL, 34 | 0, 35 | (struct ObjCClass_ro *)((uintptr_t)&FakeSuperclassRO + FAST_IS_RW_POINTER) 36 | }; 37 | 38 | __attribute__((section("__DATA,__objc_const"))) 39 | struct ObjCClass_ro FakeSubclassRO; 40 | 41 | struct ObjCClass FakeSubclass = { 42 | &FakeSuperclass, 43 | &FakeSuperclass, 44 | NULL, 45 | 0, 46 | &FakeSubclassRO 47 | }; 48 | 49 | static struct ObjCClass *class_ptr __attribute__((used)) __attribute((section("__DATA,__objc_nlclslist"))) = &FakeSubclass; 50 | 51 | int main() {} 52 | -------------------------------------------------------------------------------- /test/fakeRealizedClass2.m: -------------------------------------------------------------------------------- 1 | /* 2 | Variant on fakeRealizedClass which tests a fake class with no superclass rdar://problem/67692760 3 | 4 | (On arm64e, this will cause a pointer auth failure.) 5 | 6 | TEST_CONFIG OS=macosx ARCH=!arm64e 7 | TEST_CRASHES 8 | TEST_RUN_OUTPUT 9 | objc\[\d+\]: realized class 0x[0-9a-fA-F]+ has corrupt data pointer: malloc_size\(0x[0-9a-fA-F]+\) = 0 10 | objc\[\d+\]: HALTED 11 | END 12 | */ 13 | 14 | #include "test.h" 15 | 16 | #include 17 | 18 | #define RW_REALIZED (1U<<31) 19 | 20 | // This test only runs on macOS, so we won't bother with the conditionals around 21 | // this value. Just use the one value macOS always has. 22 | #define FAST_IS_RW_POINTER 0x8000000000000000UL 23 | 24 | struct ObjCClass { 25 | struct ObjCClass * __ptrauth_objc_isa_pointer isa; 26 | struct ObjCClass * __ptrauth_objc_super_pointer superclass; 27 | void *cachePtr; 28 | uintptr_t zero; 29 | uintptr_t data; 30 | }; 31 | 32 | struct ObjCClass_ro { 33 | uint32_t flags; 34 | uint32_t instanceStart; 35 | uint32_t instanceSize; 36 | #ifdef __LP64__ 37 | uint32_t reserved; 38 | #endif 39 | 40 | union { 41 | const uint8_t * ivarLayout; 42 | struct ObjCClass * nonMetaClass; 43 | }; 44 | 45 | const char * name; 46 | struct ObjCMethodList * __ptrauth_objc_method_list_pointer baseMethodList; 47 | struct protocol_list_t * baseProtocols; 48 | const struct ivar_list_t * ivars; 49 | 50 | const uint8_t * weakIvarLayout; 51 | struct property_list_t *baseProperties; 52 | }; 53 | 54 | extern struct ObjCClass OBJC_METACLASS_$_NSObject; 55 | extern struct ObjCClass OBJC_CLASS_$_NSObject; 56 | 57 | __attribute__((section("__DATA,__objc_const"))) 58 | struct ObjCClass_ro FakeSuperclassRO = { 59 | .flags = RW_REALIZED 60 | }; 61 | 62 | struct ObjCClass FakeSuperclass = { 63 | &OBJC_METACLASS_$_NSObject, 64 | NULL, 65 | NULL, 66 | 0, 67 | (uintptr_t)&FakeSuperclassRO + FAST_IS_RW_POINTER 68 | }; 69 | 70 | __attribute__((section("__DATA,__objc_const"))) 71 | struct ObjCClass_ro FakeSubclassRO; 72 | 73 | struct ObjCClass FakeSubclass = { 74 | &FakeSuperclass, 75 | &FakeSuperclass, 76 | NULL, 77 | 0, 78 | (uintptr_t)&FakeSubclassRO 79 | }; 80 | 81 | static struct ObjCClass *class_ptr __attribute__((used)) __attribute((section("__DATA,__objc_nlclslist"))) = &FakeSubclass; 82 | 83 | int main() {} 84 | -------------------------------------------------------------------------------- /test/faultLeaks.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc, LANGUAGE=objective-c 2 | // TEST_ENV OBJC_DEBUG_SYNC_ERRORS=Fault 3 | /* TEST_RUN_OUTPUT 4 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 5 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 6 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 7 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 8 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 9 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 10 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 11 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 12 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 13 | objc\[\d+\]: objc_sync_exit\(0x[a-fA-F0-9]+\) returned error -1 14 | [\S\s]*0 leaks for 0 total leaked bytes[\S\s]* 15 | OK: faultLeaks.m 16 | END 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "test.h" 25 | #include "testroot.i" 26 | 27 | int main() { 28 | id obj = [TestRoot alloc]; 29 | 30 | // objc_sync_exit on an object that isn't locked will provoke a fault from 31 | // OBJC_DEBUG_SYNC_ERRORS=Fault. Do this several times to ensure any leak is 32 | // detected. 33 | objc_sync_exit(obj); 34 | objc_sync_exit(obj); 35 | objc_sync_exit(obj); 36 | objc_sync_exit(obj); 37 | objc_sync_exit(obj); 38 | objc_sync_exit(obj); 39 | objc_sync_exit(obj); 40 | objc_sync_exit(obj); 41 | objc_sync_exit(obj); 42 | objc_sync_exit(obj); 43 | 44 | char *pidstr; 45 | int result = asprintf(&pidstr, "%u", getpid()); 46 | testassert(result); 47 | 48 | extern char **environ; 49 | char *argv[] = { "/usr/bin/leaks", pidstr, NULL }; 50 | pid_t pid; 51 | result = posix_spawn(&pid, "/usr/bin/leaks", NULL, NULL, argv, environ); 52 | if (result) { 53 | perror("posix_spawn"); 54 | exit(1); 55 | } 56 | wait4(pid, NULL, 0, NULL); 57 | 58 | free(pidstr); 59 | [obj release]; 60 | 61 | succeed(__FILE__); 62 | } 63 | -------------------------------------------------------------------------------- /test/fork.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit 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_FILTER .*INITIALIZE: thread.* 9 | TEST_RUN_OUTPUT 10 | objc\[\d+\]: INITIALIZE: disabling \+initialize fork safety enforcement because the app has a __DATA,__objc_fork_ok section 11 | OK: forkInitializeDisabled\.m 12 | END 13 | */ 14 | 15 | #include "test.h" 16 | 17 | asm(".section __DATA, __objc_fork_ok\n.long 0\n"); 18 | 19 | int main() 20 | { 21 | succeed(__FILE__); 22 | } 23 | -------------------------------------------------------------------------------- /test/forkInitializeSingleThreaded.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG OS=!exclavekit 3 | 4 | TEST_RUN_OUTPUT 5 | OK: forkInitialize\.m 6 | OK: forkInitialize\.m 7 | END 8 | */ 9 | #define SINGLETHREADED 1 10 | #include "forkInitialize.m" 11 | -------------------------------------------------------------------------------- /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/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/get_task_allow_entitlement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | 5 | #include "test.h" 6 | #include "testroot.i" 7 | 8 | @interface Foo: TestRoot @end 9 | @implementation Foo @end 10 | @interface Bar: Foo @end 11 | @implementation Bar @end 12 | 13 | int main(int argc __unused, const char **argv) 14 | { 15 | // Make sure we show up in the list of image names. 16 | unsigned int count; 17 | const char **imageNames = objc_copyImageNames(&count); 18 | testassert(imageNames); 19 | testassertequal(imageNames[count], NULL); 20 | 21 | char myBaseName[MAXPATHLEN]; 22 | basename_r(argv[0], myBaseName); 23 | const char *myImageName = NULL; 24 | for (unsigned int i = 0; i < count; i++) { 25 | char imageBaseName[MAXPATHLEN]; 26 | basename_r(imageNames[i], imageBaseName); 27 | if (strcmp(imageBaseName, myBaseName) == 0) 28 | myImageName = imageNames[i]; 29 | } 30 | testassert(myImageName); 31 | free(imageNames); 32 | 33 | // Make sure our classes show up in the class names. 34 | const char **classNames = objc_copyClassNamesForImage(myImageName, &count); 35 | testassert(classNames); 36 | testassertequal(classNames[count], NULL); 37 | 38 | int sawFoo = 0; 39 | int sawBar = 0; 40 | for (unsigned int i = 0; i < count; i++) { 41 | if (strcmp(classNames[i], "Foo") == 0) 42 | sawFoo++; 43 | if (strcmp(classNames[i], "Bar") == 0) 44 | sawBar++; 45 | } 46 | testassertequal(sawFoo, 1); 47 | testassertequal(sawBar, 1); 48 | free(classNames); 49 | 50 | // Make sure our classes show up in the classes list. 51 | sawFoo = 0; 52 | sawBar = 0; 53 | Class *classes = objc_copyClassesForImage(myImageName, &count); 54 | testassert(classes); 55 | testassertequal(classes[count], NULL); 56 | for (unsigned int i = 0; i < count; i++) { 57 | if (strcmp(class_getName(classes[i]), "Foo") == 0) 58 | sawFoo++; 59 | if (strcmp(class_getName(classes[i]), "Bar") == 0) 60 | sawBar++; 61 | } 62 | testassertequal(sawFoo, 1); 63 | testassertequal(sawBar, 1); 64 | free(classes); 65 | 66 | // Make sure bad names return NULL. 67 | testassertequal(objc_copyClassNamesForImage("aaaaaaaaaaaaaaaaaaa", NULL), NULL); 68 | testassertequal(objc_copyClassesForImage("aaaaaaaaaaaaaaaaaaa", NULL), NULL); 69 | 70 | succeed(__FILE__); 71 | } 72 | -------------------------------------------------------------------------------- /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 -install_name $T{DYLIBDIR}/imageorder1.dylib -o imageorder1.dylib -dynamiclib 4 | $C{COMPILE} $DIR/imageorder2.m -x none imageorder1.dylib -install_name $T{DYLIBDIR}/imageorder2.dylib -o imageorder2.dylib -dynamiclib 5 | $C{COMPILE} $DIR/imageorder3.m -x none imageorder2.dylib -install_name $T{DYLIBDIR}/imageorder3.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 | test -e $C{TESTLIB} && $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\)' | grep -v 'weak external __objc_test_get_environ \(from libobjc-env\)' | egrep '(weak external| external (___cxa_atexit|___cxa_guard_acquire|___cxa_guard_release))' || true 28 | test -e $C{TESTLIB} && $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_CONFIG MEM=mrc,arc LANGUAGE=c,c++,objc,objc++ 3 | TEST_BUILD 4 | $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 -Wno-declaration-after-statement 2>&1 | grep -v 'In file' | grep objc || true 5 | END 6 | 7 | TEST_RUN_OUTPUT 8 | OK: includes.c 9 | END 10 | */ 11 | 12 | // Detect warnings inside any header. 13 | // The build command above filters out warnings inside non-objc headers 14 | // (which are noisy with -Weverything). 15 | // -Wno-undef suppresses warnings about `#if __cplusplus` and the like. 16 | // -Wno-old-style-cast is tough to avoid in mixed C/C++ code. 17 | // -Wno-nullability-extension disables a warning about non-portable 18 | // _Nullable etc which we already handle correctly in objc-abi.h. 19 | // -Wno-c++98-compat disables warnings about things that already 20 | // have guards against C++98. 21 | // -Wno-declaration-after-statement disables a warning about mixing declarations 22 | // and code while building for a standard earlier than C99 23 | 24 | #include "includes.c" 25 | -------------------------------------------------------------------------------- /test/includes-objc2.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,arc LANGUAGE=c,c++,objc,objc++ 2 | // TEST_CFLAGS -D__OBJC2__ 3 | 4 | // Verify that all headers can be included in any language, even if 5 | // the client is C code that defined __OBJC2__. 6 | 7 | // This is the definition that Instruments uses in its build. 8 | #if defined(__OBJC2__) 9 | #undef __OBJC2__ 10 | #endif 11 | #define __OBJC2__ 1 12 | 13 | #define NAME "includes-objc2.c" 14 | #include "includes.c" 15 | -------------------------------------------------------------------------------- /test/includes.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc,arc LANGUAGE=c,c++,objc,objc++ 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(int argc __unused, char **argv __unused) 45 | { 46 | succeed(NAME); 47 | } 48 | -------------------------------------------------------------------------------- /test/initialize-autorelease.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | 5 | #include 6 | #include 7 | 8 | bool didDealloc; 9 | 10 | @interface TestClass: NSObject @end 11 | 12 | @implementation TestClass 13 | 14 | + (void)initialize { 15 | // Verify that autoreleasing an object in +initialize doesn't leak. 16 | id instance = [[TestClass alloc] init]; 17 | [instance autorelease]; 18 | } 19 | 20 | - (void)dealloc { 21 | didDealloc = true; 22 | [super dealloc]; 23 | } 24 | 25 | @end 26 | 27 | int main() 28 | { 29 | @autoreleasepool { 30 | // We need to get to objc_retainAutoreleaseReturnValue without 31 | // triggering initialization, but we do want it to be realized. Looking 32 | // up the class by name avoids initialization. 33 | Class c = objc_getClass("TestClass"); 34 | 35 | // Getting the instance size triggers realization if needed. 36 | class_getInstanceSize(c); 37 | 38 | // Make the call. 39 | objc_retainAutoreleaseReturnValue(c); 40 | } 41 | testassert(didDealloc); 42 | 43 | succeed(__FILE__); 44 | } 45 | -------------------------------------------------------------------------------- /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/lazyClassNameRace.swift: -------------------------------------------------------------------------------- 1 | // TEST_ENV MallocProbGuard=1 MallocProbGuardMemoryBudgetInKB=10000 MallocProbGuardSampleRate=1 2 | 3 | import ObjectiveC 4 | import Dispatch 5 | 6 | // Race to be the first to get the name of a bunch of different generic classes. 7 | // This tests the thread safety of lazy name installation. The MallocProbGuard 8 | // variables help to more deterministically catch use-after-frees from this 9 | // race. rdar://130280263 10 | class C { 11 | func doit(depth: Int, names: inout [String]) { 12 | if depth <= 0 { return } 13 | 14 | DispatchQueue.concurrentPerform(iterations: 2, execute: { _ in 15 | class_getName(object_getClass(self)) 16 | }) 17 | 18 | names.append(String(cString: class_getName(object_getClass(self)))) 19 | 20 | C>().doit(depth: depth - 1, names: &names) 21 | C, U>().doit(depth: depth - 1, names: &names) 22 | } 23 | } 24 | 25 | var names: [String] = [] 26 | C().doit(depth: 10, names: &names) 27 | 28 | for name in names { 29 | _ = objc_getClass(name) 30 | } 31 | 32 | print("OK:", #file.split(separator: "/").last!) 33 | -------------------------------------------------------------------------------- /test/libraryPath.c: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit 2 | // TEST_CFLAGS -lobjc 3 | 4 | #include "test.h" 5 | #include 6 | 7 | // We use DYLD_LIBRARY_PATH to run the tests against a particular copy of 8 | // libobjc. If this fails somehow (path is wrong, codesigning prevents loading, 9 | // etc.) then the typical result is a silent failure and we end up testing 10 | // /usr/lib/libobjc.A.dylib instead. This test detects when DYLD_LIBRARY_PATH is 11 | // set but libobjc isn't loaded from it. 12 | int main(int argc __unused, char **argv) { 13 | char *containingDirectory = realpath(dirname(argv[0]), NULL); 14 | testprintf("containingDirectory is %s\n", containingDirectory); 15 | 16 | char *dyldLibraryPath = getenv("DYLD_LIBRARY_PATH"); 17 | testprintf("DYLD_LIBRARY_PATH is %s\n", dyldLibraryPath); 18 | 19 | if (dyldLibraryPath != NULL && strlen(dyldLibraryPath) > 0) { 20 | int foundMatch = 0; 21 | int foundNonMatch = 0; 22 | 23 | dyldLibraryPath = strdup(dyldLibraryPath); 24 | 25 | Dl_info info; 26 | int success = dladdr((void *)objc_msgSend, &info); 27 | testassert(success); 28 | 29 | testprintf("libobjc is located at %s\n", info.dli_fname); 30 | 31 | char *cursor = dyldLibraryPath; 32 | char *path; 33 | while ((path = strsep(&cursor, ":"))) { 34 | char *resolved = realpath(path, NULL); 35 | testprintf("Resolved %s to %s\n", path, resolved); 36 | if (strcmp(resolved, containingDirectory) == 0) { 37 | testprintf("This is equal to our containing directory, ignoring.\n"); 38 | continue; 39 | } 40 | testprintf("Comparing %s and %s\n", resolved, info.dli_fname); 41 | int comparison = strncmp(resolved, info.dli_fname, strlen(resolved)); 42 | free(resolved); 43 | if (comparison == 0) { 44 | testprintf("Found a match!\n"); 45 | foundMatch = 1; 46 | break; 47 | } else { 48 | foundNonMatch = 1; 49 | } 50 | } 51 | 52 | testprintf("Finished searching, foundMatch=%d foundNonMatch=%d\n", foundMatch, foundNonMatch); 53 | testassert(foundMatch || !foundNonMatch); 54 | } 55 | succeed(__FILE__); 56 | } 57 | -------------------------------------------------------------------------------- /test/literals.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit LANGUAGE=objc,objc++ 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #include "test.h" 10 | 11 | int main() { 12 | PUSH_POOL { 13 | 14 | #if __has_feature(objc_bool) // placeholder until we get a more precise macro. 15 | NSArray *array = @[ @1, @2, @YES, @NO, @"Hello", @"World" ]; 16 | testassert([array count] == 6); 17 | NSDictionary *dict = @{ @"Name" : @"John Q. Public", @"Age" : @42 }; 18 | testassert([dict count] == 2); 19 | NSDictionary *numbers = @{ @"π" : @M_PI, @"e" : @M_E }; 20 | testassert([[numbers objectForKey:@"π"] doubleValue] == M_PI); 21 | testassert([[numbers objectForKey:@"e"] doubleValue] == M_E); 22 | 23 | BOOL yesBool = YES; 24 | BOOL noBool = NO; 25 | array = @[ 26 | @(true), 27 | @(YES), 28 | [NSNumber numberWithBool:YES], 29 | @YES, 30 | @(yesBool), 31 | @((BOOL)YES), 32 | 33 | @(false), 34 | @(NO), 35 | [NSNumber numberWithBool:NO], 36 | @NO, 37 | @(noBool), 38 | @((BOOL)NO), 39 | ]; 40 | NSData * jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:nil]; 41 | NSString * string = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 42 | #if __cplusplus 43 | testassert([string isEqualToString:@"[true,true,true,true,true,true,false,false,false,false,false,false]"]); 44 | #else 45 | // C99 @(true) and @(false) evaluate to @(1) and @(0). 46 | testassert([string isEqualToString:@"[1,true,true,true,true,true,0,false,false,false,false,false]"]); 47 | #endif 48 | 49 | #endif 50 | 51 | } POP_POOL; 52 | 53 | succeed(__FILE__); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /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 -install_name $T{DYLIBDIR}/load-order3.dylib -o load-order3.dylib -dynamiclib 4 | $C{COMPILE} $DIR/load-order2.m -install_name $T{DYLIBDIR}/load-order2.dylib -o load-order2.dylib -x none load-order3.dylib -dynamiclib 5 | $C{COMPILE} $DIR/load-order1.m -install_name $T{DYLIBDIR}/load-order1.dylib -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-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_CONFIG OS=!exclavekit 3 | TEST_BUILD 4 | $C{COMPILE} $DIR/load-reentrant.m -o load-reentrant.exe 5 | $C{COMPILE} $DIR/load-reentrant2.m -o libload-reentrant2.dylib -bundle -bundle_loader load-reentrant.exe 6 | END 7 | */ 8 | 9 | #include "test.h" 10 | #include 11 | 12 | int state1 = 0; 13 | int *state2_p; 14 | 15 | OBJC_ROOT_CLASS 16 | @interface One @end 17 | @implementation One 18 | +(void)load 19 | { 20 | state1 = 111; 21 | 22 | // Re-entrant +load doesn't get to complete until we do 23 | void *dlh = dlopen("libload-reentrant2.dylib", RTLD_LAZY); 24 | testassert(dlh); 25 | state2_p = (int *)dlsym(dlh, "state2"); 26 | testassert(state2_p); 27 | testassert(*state2_p == 0); 28 | 29 | state1 = 1; 30 | } 31 | @end 32 | 33 | int main() 34 | { 35 | testassert(state1 == 1 && state2_p && *state2_p == 2); 36 | succeed(__FILE__); 37 | } 38 | -------------------------------------------------------------------------------- /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/methodCacheLeaks.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc LANGUAGE=objective-c ARCH=!arm64e,!arm64 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 OS=!exclavekit 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/msgSend-performance-macos.m: -------------------------------------------------------------------------------- 1 | // macOS builds of this test require -loah, which is not valid for other OSes. 2 | // This test provides separate cflags for msgSend-performance.m when 3 | // targeting macOS. 4 | // TEST_CONFIG OS=macosx 5 | // TEST_CFLAGS -loah 6 | 7 | const char *FileName = __FILE__; 8 | #define TEST_NAME FileName 9 | #include "msgSend-performance.m" -------------------------------------------------------------------------------- /test/nilAPIArgs.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CFLAGS -Wno-nonnull 3 | */ 4 | 5 | #include "test.h" 6 | 7 | #import 8 | 9 | int main() { 10 | // ensure various bits of API don't crash when tossed nil parameters 11 | class_conformsToProtocol(nil, nil); 12 | method_setImplementation(nil, NULL); 13 | 14 | succeed(__FILE__); 15 | } 16 | -------------------------------------------------------------------------------- /test/nopool.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc OS=!exclavekit 2 | 3 | #include "test.h" 4 | #include "testroot.i" 5 | 6 | @implementation TestRoot (Loader) 7 | +(void)load 8 | { 9 | [[TestRoot new] autorelease]; 10 | testassertequal((int)TestRootAutorelease, 1); 11 | testassertequal((int)TestRootDealloc, 0); 12 | } 13 | @end 14 | 15 | int main() 16 | { 17 | // +load's autoreleased object should have deallocated 18 | testassertequal((int)TestRootDealloc, 1); 19 | 20 | [[TestRoot new] autorelease]; 21 | testassertequal((int)TestRootAutorelease, 2); 22 | 23 | 24 | objc_autoreleasePoolPop(objc_autoreleasePoolPush()); 25 | [[TestRoot new] autorelease]; 26 | testassertequal((int)TestRootAutorelease, 3); 27 | 28 | 29 | testonthread(^{ 30 | [[TestRoot new] autorelease]; 31 | testassertequal((int)TestRootAutorelease, 4); 32 | testassertequal((int)TestRootDealloc, 1); 33 | }); 34 | // thread's autoreleased object should have deallocated 35 | testassertequal((int)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 | testassertequal((int)TestRootAutorelease, 5); 44 | testassertequal((int)TestRootDealloc, 2); 45 | }); 46 | testassert(TestRootDealloc == 3 47 | ); 48 | succeed(__FILE__); 49 | } 50 | -------------------------------------------------------------------------------- /test/nscdtors.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit 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_CONFIG OS=!exclavekit MEM=mrc,arc LANGUAGE=objc,objc++ 4 | TEST_CFLAGS -fobjc-arc-exceptions -framework Foundation 5 | */ 6 | 7 | #define USE_FOUNDATION 1 8 | #include "exc.m" 9 | -------------------------------------------------------------------------------- /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 | @interface TestSELs : NSObject { 15 | SEL sel1, sel2, sel3; 16 | } 17 | @end 18 | @implementation TestSELs 19 | 20 | - (id)init { 21 | sel1 = @selector(sel1); 22 | sel2 = @selector(sel2); 23 | sel3 = @selector(sel3); 24 | return self; 25 | } 26 | 27 | - (void)compareWith: (TestSELs *)other { 28 | testassert(sel1 == other->sel1); 29 | testassert(sel2 == other->sel2); 30 | testassert(sel3 == other->sel3); 31 | } 32 | 33 | @end 34 | 35 | int main() 36 | { 37 | Test *o0 = [Test new]; 38 | [o0 retain]; 39 | Test *o1 = class_createInstance([Test class], 32); 40 | [o1 retain]; 41 | id o2 = object_copy(o0, 0); 42 | id o3 = object_copy(o1, 0); 43 | id o4 = object_copy(o1, 32); 44 | 45 | testassert(malloc_size(o0) == 32); 46 | testassert(malloc_size(o1) == 64); 47 | testassert(malloc_size(o2) == 32); 48 | testassert(malloc_size(o3) == 32); 49 | testassert(malloc_size(o4) == 64); 50 | 51 | testassert([o0 retainCount] == 2); 52 | testassert([o1 retainCount] == 2); 53 | testassert([o2 retainCount] == 1); 54 | testassert([o3 retainCount] == 1); 55 | testassert([o4 retainCount] == 1); 56 | 57 | TestSELs *sels = [TestSELs new]; 58 | TestSELs *selsCopy = object_copy(sels, 0); 59 | [sels compareWith: selsCopy]; 60 | 61 | succeed(__FILE__); 62 | } 63 | -------------------------------------------------------------------------------- /test/osVersion.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | #include "test.h" 5 | #include "mach-o/dyld_priv.h" 6 | #include 7 | 8 | extern uintptr_t objc_debug_realized_class_generation_count; 9 | 10 | // Make sure we're testing on the same OS version that libobjc was built for. 11 | int main(int argc __unused, char **argv __unused) { 12 | const struct mach_header *libobjcHeader = dyld_image_header_containing_address(&objc_debug_realized_class_generation_count); 13 | // dyld_get_min_os_version tries to normalize to iOS-aligned numbers, which 14 | // is not what we want. dyld_get_image_versions gives us the raw info we 15 | // want. 16 | __block unsigned libobjcVersion = -1; 17 | dyld_get_image_versions(libobjcHeader, ^(dyld_platform_t platform, uint32_t sdk_version __unused, uint32_t min_version) { 18 | if (platform == dyld_get_active_platform()) { 19 | libobjcVersion = min_version; 20 | } 21 | }); 22 | unsigned libobjcMajor = libobjcVersion >> 16; 23 | unsigned libobjcMinor = (libobjcVersion >> 8) & 0xFF; 24 | testprintf("libobjc minos is %u.%u\n", libobjcMajor, libobjcMinor); 25 | 26 | NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; 27 | testprintf("OS version is %u.%u\n", (unsigned)osVersion.majorVersion, (unsigned)osVersion.minorVersion); 28 | testassertequal(libobjcMajor, osVersion.majorVersion); 29 | testassertequal(libobjcMinor, osVersion.minorVersion); 30 | 31 | succeed(__FILE__); 32 | } 33 | -------------------------------------------------------------------------------- /test/partiallyRealizedClass.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | #include 3 | #include "test.h" 4 | 5 | @interface AccessStatic: NSObject @end 6 | @implementation AccessStatic @end 7 | 8 | // EXTERN_C id objc_retainAutoreleaseReturnValue(id); 9 | // EXTERN_C id objc_alloc(id); 10 | 11 | // Verify that objc_retainAutoreleaseReturnValue on an unrealized class doesn't 12 | // put the class into a half-baked state where the metaclass is realized but the 13 | // class is not. rdar://101151980 14 | int main() { 15 | extern char OBJC_CLASS_$_AccessStatic; 16 | id st = (__bridge id)(void *)&OBJC_CLASS_$_AccessStatic; 17 | 18 | objc_retainAutoreleaseReturnValue(st); 19 | objc_alloc(st); 20 | 21 | succeed(__FILE__); 22 | } 23 | -------------------------------------------------------------------------------- /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/ptrauth.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG ARCH=arm64e 3 | TEST_BUILD 4 | $C{COMPILE} $DIR/ptrauth.m -Wno-deprecated-objc-isa-usage -Wno-deprecated-declarations -framework Foundation -o ptrauth.exe 5 | END 6 | TEST_RUN_OUTPUT 7 | doSomething 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | int count = 0; 19 | 20 | @interface ParentClass : NSObject 21 | 22 | - (void)doSomething; 23 | 24 | @end 25 | 26 | @implementation ParentClass 27 | 28 | - (void)doSomething 29 | { 30 | if (++count == 1) { 31 | printf("doSomething\n"); 32 | fflush(stdout); 33 | } 34 | } 35 | 36 | @end 37 | 38 | int main() 39 | { 40 | for (int n = 0; n < 128; ++n) { 41 | char name[32]; 42 | snprintf(name, sizeof(name), "PtrAuthTest%d", n); 43 | 44 | Class testClass = objc_allocateClassPair([ParentClass class], name, 0); 45 | 46 | // This should work, because the isa pointer will be signed 47 | id obj = [[testClass alloc] init]; 48 | [obj doSomething]; 49 | 50 | // Hacking the isa pointer to an unsigned value should cause a crash 51 | ((__bridge struct objc_object *)obj)->isa = testClass; 52 | [obj doSomething]; 53 | } 54 | 55 | fail("should have crashed when attempting to invoke -doSomething"); 56 | } 57 | -------------------------------------------------------------------------------- /test/rawisa.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG 3 | TEST_CFLAGS -Xlinker -sectcreate -Xlinker __DATA -Xlinker __objc_rawisa -Xlinker /dev/null 4 | TEST_ENV OBJC_PRINT_RAW_ISA=YES 5 | 6 | TEST_RUN_OUTPUT 7 | objc\[\d+\]: RAW ISA: disabling non-pointer isa because the app has a __DATA,__objc_rawisa section 8 | (.* RAW ISA: .*\n)* 9 | OK: rawisa.m(\n.* RAW ISA: .*)* 10 | OR 11 | (.* RAW ISA: .*\n)* 12 | no __DATA,__rawisa support 13 | OK: rawisa.m(\n.* RAW ISA: .*)* 14 | END 15 | 16 | "RAW ISA" is allowed after "OK" because of static destructors 17 | that provoke class realization. 18 | */ 19 | 20 | #include "test.h" 21 | 22 | int main() 23 | { 24 | fprintf(stderr, "\n"); 25 | #if ! (SUPPORT_NONPOINTER_ISA && TARGET_OS_OSX) 26 | // only 64-bit Mac supports this 27 | fprintf(stderr, "no __DATA,__rawisa support\n"); 28 | #endif 29 | succeed(__FILE__); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/readClassPairIvarFixup.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | /* 3 | TEST_RUN_OUTPUT 4 | objc\[\d+\]: Class Sub1 is implemented in both.* 5 | objc\[\d+\]: Class SubSub is implemented in both.* 6 | OK: readClassPairIvarFixup.m 7 | END 8 | */ 9 | 10 | #include "test.h" 11 | #include 12 | 13 | @interface Bigger: NSObject { 14 | id a, b, c, d; 15 | } 16 | @end 17 | @implementation Bigger 18 | @end 19 | 20 | @interface Sub1: NSObject { 21 | id x; 22 | } 23 | @end 24 | @implementation Sub1 @end 25 | 26 | @interface Sub2: NSObject { 27 | id x; 28 | } 29 | @end 30 | @implementation Sub2 @end 31 | 32 | @interface SubSub: Sub2 { 33 | id y; 34 | } 35 | @end 36 | @implementation SubSub @end 37 | 38 | int main() { 39 | objc_image_info info = {}; 40 | 41 | extern char OBJC_CLASS_$_Sub1; 42 | Class sub1Ptr = (Class)&OBJC_CLASS_$_Sub1; 43 | 44 | // Make sure objc_readClassPair slides our ivars when needed. 45 | // Reading a class that's statically known to the runtime will emit a 46 | // duplicate class warning, but that's OK for our testing. 47 | class_setSuperclass(sub1Ptr, [Bigger class]); 48 | objc_readClassPair(sub1Ptr, &info); 49 | 50 | unsigned count1; 51 | Ivar *ivars1 = class_copyIvarList(sub1Ptr, &count1); 52 | testassertequal(count1, 1); 53 | testassert(ivars1); 54 | testassertequal(ivar_getOffset(ivars1[0]), 5 * sizeof(id)); 55 | 56 | 57 | // And make sure it slides our ivars even when there's another unrealized 58 | // class in between. 59 | extern char OBJC_CLASS_$_Sub2; 60 | Class sub2Ptr = (Class)&OBJC_CLASS_$_Sub2; 61 | 62 | extern char OBJC_CLASS_$_SubSub; 63 | Class subSubPtr = (Class)&OBJC_CLASS_$_SubSub; 64 | 65 | class_setSuperclass(sub2Ptr, [Bigger class]); 66 | objc_readClassPair(subSubPtr, &info); 67 | 68 | unsigned count2; 69 | Ivar *ivars2 = class_copyIvarList(subSubPtr, &count2); 70 | testassertequal(count2, 1); 71 | testassert(ivars2); 72 | testassertequal(ivar_getOffset(ivars2[0]), 6 * sizeof(id)); 73 | 74 | succeed(__FILE__); 75 | } 76 | -------------------------------------------------------------------------------- /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 | Class c; 16 | 17 | #if !TARGET_OS_EXCLAVEKIT 18 | void *handle = dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY); 19 | testassert(handle); 20 | c = objc_getClass("NSFileManager"); 21 | testassert(c); 22 | testassert(objc_debug_realized_class_generation_count > prev); 23 | #endif 24 | 25 | prev = objc_debug_realized_class_generation_count; 26 | c = objc_allocateClassPair([TestRoot class], "Dynamic", 0); 27 | testassert(objc_debug_realized_class_generation_count > prev); 28 | prev = objc_debug_realized_class_generation_count; 29 | objc_registerClassPair(c); 30 | testassert(objc_debug_realized_class_generation_count == prev); 31 | 32 | succeed(__FILE__); 33 | } 34 | -------------------------------------------------------------------------------- /test/release-race.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc LANGUAGE=objective-c 2 | 3 | #import 4 | #import 5 | #import "test.h" 6 | 7 | @interface MyEncoder : NSObject 8 | { 9 | int x; 10 | } 11 | @end 12 | 13 | @implementation MyEncoder 14 | 15 | - (id)init 16 | { 17 | x = 1; 18 | return self; 19 | } 20 | 21 | - (void)close 22 | { 23 | x = 2; 24 | [self release]; 25 | } 26 | 27 | - (void)dealloc 28 | { 29 | // Make sure that release has the appropriate barriers so that we're 30 | // guaranteed to see the x=2 above. 31 | testassertequal(x, 2); 32 | [super dealloc]; 33 | } 34 | @end 35 | 36 | int main() { 37 | // The 1 thread worker pool on simulators makes this slow and pointless. 38 | #if !TARGET_OS_SIMULATOR 39 | for (unsigned long long i = 0; i < 100000000ULL; i++) { 40 | if (i % 100000 == 0) 41 | testprintf("%llu\n", i); 42 | 43 | MyEncoder *enc = [MyEncoder new]; 44 | [enc retain]; // For the first dispatch 45 | [enc retain]; // For the second one 46 | MyEncoder __unsafe_unretained *enc_weak = enc; 47 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 48 | [enc_weak close]; 49 | }); 50 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 51 | [enc_weak release]; 52 | }); 53 | [enc release]; // Drop top level reference 54 | } 55 | #endif 56 | succeed(__FILE__); 57 | } 58 | -------------------------------------------------------------------------------- /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/restartableRangesSynchronizeStress2.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=arc LANGUAGE=objective-c OS=!exclavekit 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/rootMissingCategoryClass.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_RUN_OUTPUT 3 | objc\[[0-9]+\]: Class of category TestCategory at 0x[a-fA-f0-9]+ in .*rootMissingCategoryClass.exe is set to 0xbad4007, indicating it is missing from an installed root 4 | END 5 | */ 6 | 7 | #include "class-structures.h" 8 | #include "test.h" 9 | 10 | #include 11 | 12 | #define BAD_ROOT_ADDRESS 0xbad4007 13 | 14 | static struct ObjCCategory testCategory = { 15 | "TestCategory", 16 | (struct ObjCClass *)BAD_ROOT_ADDRESS 17 | }; 18 | 19 | static struct ObjCCategory *testCategoryListEntry __attribute__((used)) __attribute__((section("__DATA, __objc_catlist"))) = &testCategory; 20 | 21 | 22 | int main() { 23 | fail("This test is supposed to crash before main()"); 24 | } 25 | -------------------------------------------------------------------------------- /test/rootMissingSuperclass.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_RUN_OUTPUT 3 | objc\[[0-9]+\]: Superclass of TestClass at 0x[a-fA-f0-9]+ in .*rootMissingSuperclass.exe is set to 0x[0-9a-fA-F]*bad4007, indicating it is missing from an installed root 4 | END 5 | */ 6 | 7 | #include "class-structures.h" 8 | #include "test.h" 9 | 10 | #include 11 | 12 | #if __arm64e__ 13 | // dyld signs the 0xbad4007 sentinel. It's hard to get it to sign it for us 14 | // in a test, but the runtime should just strip the signature anyway, so we'll 15 | // fake it by manually setting a signature bit. 16 | #define BAD_ROOT_ADDRESS 0x004000000bad4007 17 | #else 18 | #define BAD_ROOT_ADDRESS 0xbad4007 19 | #endif 20 | 21 | extern struct ObjCClass OBJC_METACLASS_$_NSObject; 22 | extern struct ObjCClass OBJC_CLASS_$_NSObject; 23 | 24 | static struct ObjCClass_ro TestClassMeta_ro __attribute__((section("__DATA,__objc_const"))) = { 25 | .flags = RO_META, 26 | .instanceStart = 40, 27 | .instanceSize = 40, 28 | }; 29 | 30 | static struct ObjCClass TestClassMeta __attribute__((section("__DATA, __objc_data"))) = { 31 | .isa = &OBJC_METACLASS_$_NSObject, 32 | .superclass = &OBJC_METACLASS_$_NSObject, 33 | .cachePtr = &_objc_empty_cache, 34 | .data = &TestClassMeta_ro, 35 | }; 36 | 37 | static struct ObjCClass_ro TestClass_ro __attribute__((section("__DATA,__objc_const"))) = { 38 | .instanceStart = sizeof(void *), 39 | .instanceSize = sizeof(void *), 40 | .name = "TestClass", 41 | }; 42 | 43 | static struct ObjCClass TestClass __attribute__((section("__DATA, __objc_data"))) = { 44 | .isa = &TestClassMeta, 45 | .superclass = (struct ObjCClass *)BAD_ROOT_ADDRESS, 46 | .cachePtr = &_objc_empty_cache, 47 | .data = &TestClass_ro, 48 | }; 49 | 50 | static struct ObjCClass *testClassListEntry __attribute__((used)) __attribute__((section("__DATA, __objc_classlist"))) = &TestClass; 51 | 52 | int main() { 53 | fail("This test is supposed to crash before main()"); 54 | } 55 | -------------------------------------------------------------------------------- /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 OBJC_DEBUG_POOL_DEPTH=-1 4 | // TEST_CFLAGS -framework Foundation 5 | // TEST_CONFIG MEM=mrc OS=!exclavekit 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 OS=!exclavekit 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 OS=!exclavekit 3 | 4 | #define FOUNDATION 1 5 | #define NAME "rr-nsautorelease" 6 | 7 | #include "rr-autorelease2.m" 8 | -------------------------------------------------------------------------------- /test/rr-sidetable.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG OS=!exclavekit MEM=mrc ARCH=x86_64 2 | // TEST_CFLAGS -framework Foundation 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_CFLAGS -Wno-nonnull 3 | */ 4 | 5 | #include "test.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | // Make sure @selector values are correctly fixed up 14 | testassert(@selector(foo) == sel_registerName("foo")); 15 | 16 | // sel_getName recognizes the zero SEL 17 | testassert(0 == strcmp("", sel_getName(0))); 18 | 19 | // sel_lookUpByName returns NULL for NULL string 20 | testassert(NULL == sel_lookUpByName(NULL)); 21 | 22 | // sel_lookUpByName returns NULL for unregistered and matches later registered selector 23 | { 24 | SEL sel; 25 | testassert(NULL == sel_lookUpByName("__testSelectorLookUp:")); 26 | testassert(NULL != (sel = sel_registerName("__testSelectorLookUp:"))); 27 | testassert(sel == sel_lookUpByName("__testSelectorLookUp:")); 28 | } 29 | 30 | // sel_lookUpByName matches @selector value 31 | testassert(@selector(foo2) == sel_lookUpByName("foo2")); 32 | 33 | succeed(__FILE__); 34 | } 35 | -------------------------------------------------------------------------------- /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 | // Intel simulator doesn't support this method. 28 | #if !TARGET_OS_SIMULATOR || !__x86_64__ 29 | id obj = [TestRoot new]; 30 | id value = [TestRoot new]; 31 | const void *key = "key"; 32 | objc_setAssociatedObject(obj, key, value, OBJC_ASSOCIATION_RETAIN); 33 | testassert(hasAssociations == true); 34 | 35 | id out = objc_getAssociatedObject(obj, key); 36 | testassert(out == value); 37 | 38 | hasAssociations = false; 39 | key = "key2"; 40 | objc_setAssociatedObject(obj, key, value, OBJC_ASSOCIATION_RETAIN); 41 | testassert(hasAssociations == false); //only called once 42 | 43 | 44 | out = objc_getAssociatedObject(obj, key); 45 | testassert(out == value); 46 | #endif 47 | 48 | succeed(__FILE__); 49 | } 50 | -------------------------------------------------------------------------------- /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/swift-allocateClassPair.swift: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | 3 | import Darwin 4 | import ObjectiveC 5 | 6 | var didFail = false 7 | 8 | func fail(_ msg: String) { 9 | print("BAD: \(msg)") 10 | didFail = true 11 | } 12 | 13 | func basePointer(class cls: AnyClass) -> UnsafeRawPointer { 14 | let ptr = unsafeBitCast(cls, to: UnsafeRawPointer.self) 15 | 16 | // The classAddressOffset comes after the ObjC class structure (5 pointers), 17 | // then after 4 uint32_t's and 2 uint16_t's. 18 | let classAddressOffsetOffset = 19 | MemoryLayout.size * 5 20 | + MemoryLayout.size * 4 21 | + MemoryLayout.size * 2; 22 | let classAddressOffset = ptr.load(fromByteOffset: classAddressOffsetOffset, as: UInt32.self) 23 | return ptr - Int(classAddressOffset) 24 | } 25 | 26 | class SwiftClass {} 27 | 28 | // Track how many times malloc_zone_from_ptr returned something for a disposed 29 | // class. This could happen if something else allocated something new in that 30 | // location, but that should not happen 100 times in a row, so we'll tolerate 31 | // false positives but not 100% false positives. 32 | var disposedZoneCount = 0 33 | let iterations = 100 34 | for _ in 0.. {} 13 | 14 | // Ensure that a Swift generic metaclass has properly signed isa/superclass 15 | // pointers. Work with raw pointers to avoid retain/release on the class 16 | // objects, which Swift ARC likes to do. 17 | let genericRaw = unsafeBitCast(Generic.self, to: UnsafeRawPointer.self) 18 | 19 | let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2) 20 | typealias classToClassFn = @convention(c) (UnsafeRawPointer?) -> UnsafeRawPointer? 21 | 22 | let object_getClassRaw = dlsym(RTLD_DEFAULT, "object_getClass") 23 | let object_getClass = unsafeBitCast(object_getClassRaw, to: classToClassFn.self) 24 | 25 | let class_getSuperClassRaw = dlsym(RTLD_DEFAULT, "class_getSuperclass") 26 | let class_getSuperClass = unsafeBitCast(class_getSuperClassRaw, to: classToClassFn.self) 27 | 28 | // Check for nil, but we're really checking for ptrauth failures in the call. 29 | 30 | if object_getClass(object_getClass(genericRaw)) == nil { 31 | fail("metaclass of metaclass is nil") 32 | } 33 | 34 | if class_getSuperClass(object_getClass(genericRaw)) == nil { 35 | fail("superclass of metaclass is nil") 36 | } 37 | 38 | if !didFail { 39 | print("OK:", #file.split(separator: "/").last!) 40 | } 41 | -------------------------------------------------------------------------------- /test/swiftMetadataInitializer.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=mrc 2 | 3 | #include "test.h" 4 | #include "swift-class-def.m" 5 | #include 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 | static int SubInits = 0; 21 | Class initSub(Class cls, void *arg) 22 | { 23 | testprintf("initSub callback\n"); 24 | 25 | testassert(SubInits == 0); 26 | SubInits++; 27 | testassert(arg == nil); 28 | testassert(0 == strcmp(class_getName(cls), "SwiftSub")); 29 | testassert(cls == RawSwiftSub); 30 | testassert(!isRealized(RawSwiftSuper)); 31 | testassert(!isRealized(RawSwiftSub)); 32 | 33 | testprintf("initSub beginning _objc_realizeClassFromSwift\n"); 34 | _objc_realizeClassFromSwift(cls, cls); 35 | testprintf("initSub finished _objc_realizeClassFromSwift\n"); 36 | 37 | testassert(isRealized(RawSwiftSuper)); 38 | testassert(isRealized(RawSwiftSub)); 39 | 40 | return cls; 41 | } 42 | 43 | 44 | int main() 45 | { 46 | testassert(SubInits == 0); 47 | testprintf("calling [SwiftSub class]\n"); 48 | [SwiftSub class]; 49 | testprintf("finished [SwiftSub class]\n"); 50 | testassert(SubInits == 1); 51 | [SwiftSuper class]; 52 | succeed(__FILE__); 53 | } 54 | -------------------------------------------------------------------------------- /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/swiftobject-no-custom-core.mm: -------------------------------------------------------------------------------- 1 | // TEST_CFLAGS -framework Foundation 2 | 3 | #include "test.h" 4 | #include 5 | 6 | int CalledHackClass = 0; 7 | 8 | id HackClass(id self, SEL _cmd __unused) 9 | { 10 | CalledHackClass++; 11 | return self; 12 | } 13 | 14 | int main(int argc __unused, char **argv __unused) 15 | { 16 | // Since Foundation now includes the Swift overlay, we can count on 17 | // SwiftObject being loaded when Foundation is loaded. 18 | Class SwiftObject = objc_getClass("_TtCs12_SwiftObject"); 19 | testassert(SwiftObject); 20 | 21 | // Replace +class using the RawUnsafe call so we don't look like an 22 | // override. 23 | Method m = class_getClassMethod(SwiftObject, @selector(class)); 24 | _method_setImplementationRawUnsafe(m, (IMP)HackClass); 25 | 26 | _objc_flush_caches(SwiftObject); 27 | 28 | // Verify the hack worked. 29 | IMP imp = class_getMethodImplementation(object_getClass(SwiftObject), @selector(class)); 30 | testassertequal(imp, (IMP)HackClass); 31 | 32 | // Call +class using the optimized entrypoint. This should not call our 33 | // override. 34 | Class result = objc_opt_class(SwiftObject); 35 | testassert(result == SwiftObject); 36 | testassertequal(CalledHackClass, 0); 37 | 38 | succeed(__FILE__); 39 | } -------------------------------------------------------------------------------- /test/sync-error-checking.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CONFIG MEM=mrc 3 | TEST_ENV OBJC_DEBUG_SYNC_ERRORS=1 4 | 5 | TEST_RUN_OUTPUT 6 | objc\[\d+\]: objc_sync_exit\(0x1\) returned error -1 7 | OK: sync-error-checking.m 8 | END 9 | */ 10 | 11 | #include "test.h" 12 | 13 | #include 14 | 15 | int main() 16 | { 17 | // It's currently impossible for objc_sync_enter to return an error, so we 18 | // only test objc_sync_exit. 19 | objc_sync_exit((id)1); 20 | succeed(__FILE__); 21 | } 22 | -------------------------------------------------------------------------------- /test/taggedPointersDisabled.m: -------------------------------------------------------------------------------- 1 | /* 2 | TEST_CFLAGS -Wno-nonnull 3 | TEST_ENV OBJC_DISABLE_TAGGED_POINTERS=YES 4 | TEST_CRASHES 5 | 6 | TEST_RUN_OUTPUT 7 | objc\[\d+\]: tagged pointers are disabled 8 | objc\[\d+\]: HALTED 9 | OR 10 | OK: taggedPointersDisabled.m 11 | END 12 | */ 13 | 14 | #include "test.h" 15 | #include 16 | 17 | #if !OBJC_HAVE_TAGGED_POINTERS 18 | 19 | int main() 20 | { 21 | // provoke the same nullability warning as the real test 22 | objc_getClass(nil); 23 | 24 | succeed(__FILE__); 25 | } 26 | 27 | #else 28 | 29 | int main() 30 | { 31 | testassert(!_objc_taggedPointersEnabled()); 32 | _objc_registerTaggedPointerClass((objc_tag_index_t)0, nil); 33 | fail("should have crashed in _objc_registerTaggedPointerClass()"); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /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/test-simulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | pushd "$(dirname $0)/test-simulator" 6 | swift build -c release 7 | BIN_PATH="$(swift build -c release --show-bin-path)" 8 | 9 | popd 10 | exec "$BIN_PATH/test-simulator" "$@" 11 | -------------------------------------------------------------------------------- /test/test-simulator/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "test-simulator", 8 | dependencies: [ 9 | .package( 10 | url: "https://github.com/apple/swift-argument-parser", 11 | from: "1.1.4" 12 | ), 13 | ], 14 | targets: [ 15 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 16 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 17 | .executableTarget( 18 | name: "test-simulator", 19 | dependencies: [ 20 | .product(name: "ArgumentParser", package: "swift-argument-parser"), 21 | ]), 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /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/unexpectedBuildOutput.mm: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG MEM=arc 2 | // TEST_CFLAGS -framework Foundation 3 | 4 | #include "test.h" 5 | #include 6 | 7 | int main() 8 | { 9 | NSString *unexpectedBuildOutputFile = @"../../unexpected-build-output"; 10 | if ([[NSFileManager defaultManager] fileExistsAtPath: unexpectedBuildOutputFile]) { 11 | NSData *data = [NSData dataWithContentsOfFile: unexpectedBuildOutputFile]; 12 | if (!data) 13 | data = [@"" dataUsingEncoding: NSUTF8StringEncoding]; 14 | 15 | [[NSFileHandle fileHandleWithStandardOutput] writeData: data]; 16 | 17 | fail(__FILE__); 18 | } else { 19 | succeed(__FILE__); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /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 | __attribute__((weak_import)) 29 | @interface ClassThatIsWeakImportAndMissing : TestRoot @end 30 | 31 | @interface SubclassOfMissingWeakImport : ClassThatIsWeakImportAndMissing @end 32 | @implementation SubclassOfMissingWeakImport 33 | -(void)unload2_category_method { } 34 | @end 35 | 36 | @interface ClassThatIsWeakImportAndMissing (Category) @end 37 | @implementation ClassThatIsWeakImportAndMissing (Category) 38 | -(void)unload2_category_method { } 39 | @end 40 | -------------------------------------------------------------------------------- /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/unload5.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | __attribute__((weak_import)) 4 | @interface ClassThatIsWeakImportAndMissing : NSObject @end 5 | @implementation ClassThatIsWeakImportAndMissing @end 6 | -------------------------------------------------------------------------------- /test/unwind.m: -------------------------------------------------------------------------------- 1 | // TEST_CONFIG 2 | // TEST_ENV OBJC_DEBUG_POOL_DEPTH=-1 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | static int state; 9 | 10 | @interface Foo : NSObject @end 11 | @interface Bar : NSObject @end 12 | 13 | @interface Foo (Unimplemented) 14 | +(void)method; 15 | @end 16 | 17 | @implementation Bar @end 18 | 19 | @implementation Foo 20 | 21 | -(void)check { state++; } 22 | +(void)check { testassert(!"caught class object, not instance"); } 23 | 24 | static id exc; 25 | 26 | static void handler(id unused, void *ctx) __attribute__((used)); 27 | static void handler(id unused __unused, void *ctx __unused) 28 | { 29 | testassert(state == 3); state++; 30 | } 31 | 32 | +(BOOL) resolveClassMethod:(SEL)__unused name 33 | { 34 | testassertequal(state, 1); state++; 35 | #if TARGET_OS_EXCLAVEKIT 36 | state++; // handler would have done this 37 | #elif TARGET_OS_OSX 38 | objc_addExceptionHandler(&handler, 0); 39 | testassertequal(state, 2); 40 | #else 41 | state++; // handler would have done this 42 | #endif 43 | state++; 44 | exc = [Foo new]; 45 | @throw exc; 46 | } 47 | 48 | 49 | @end 50 | 51 | int main() 52 | { 53 | // unwind exception and alt handler through objc_msgSend() 54 | 55 | PUSH_POOL { 56 | 57 | #if TARGET_OS_EXCLAVEKIT 58 | const int count = 256; 59 | #else 60 | const int count = is_guardmalloc() ? 1000 : 100000; 61 | #endif 62 | state = 0; 63 | for (int i = 0; i < count; i++) { 64 | @try { 65 | testassertequal(state, 0); state++; 66 | [Foo method]; 67 | testunreachable(); 68 | } @catch (Bar *e) { 69 | testunreachable(); 70 | } @catch (Foo *e) { 71 | testassertequal(e, exc); 72 | testassertequal(state, 4); state++; 73 | testassertequal(state, 5); [e check]; // state++ 74 | RELEASE_VAR(exc); 75 | } @catch (id e) { 76 | testunreachable(); 77 | } @catch (...) { 78 | testunreachable(); 79 | } @finally { 80 | testassertequal(state, 6); state++; 81 | } 82 | testassertequal(state, 7); state = 0; 83 | } 84 | 85 | } POP_POOL; 86 | 87 | succeed(__FILE__); 88 | } 89 | -------------------------------------------------------------------------------- /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 -install_name $T{DYLIBDIR}/libweakframework.dylib -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 -install_name $T{DYLIBDIR}/libweakframework.dylib -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 -install_name $T{DYLIBDIR}/libweakframework.dylib -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 -install_name $T{DYLIBDIR}/libweakimport.dylib -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 -install_name $T{DYLIBDIR}/libweakimport.dylib -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 -install_name $T{DYLIBDIR}/libweakimport.dylib -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 OS=!exclavekit 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 OS=!exclavekit 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 | --------------------------------------------------------------------------------