Skip to content

Commit ba5e0a4

Browse files
committed
Enforced arm64 or x86_64 architecture
1 parent 52c7ac1 commit ba5e0a4

File tree

6 files changed

+40
-91
lines changed

6 files changed

+40
-91
lines changed

Sources/ITKSuperBuilder/include/ITKSuperBuilder.h

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
#if __APPLE__
2-
#import <Foundation/Foundation.h>
1+
#if !(defined(__APPLE__) && (defined(__arm64__) || defined(__x86_64__)))
2+
#error "[InterposeKit] Supported only on Apple platforms with arm64 or x86_64 architecture."
33
#endif
44

5+
#import <Foundation/Foundation.h>
6+
57
NS_ASSUME_NONNULL_BEGIN
68

79
/**
@@ -44,7 +46,7 @@ There are a few important details:
4446
4547
@see https://steipete.com/posts/calling-super-at-runtime/
4648
*/
47-
@interface ITKSuperBuilder : NSObject
49+
@interface ITKSuperBuilder: NSObject
4850

4951
/// Adds an empty super implementation instance method to originalClass.
5052
/// If a method already exists, this will return NO and a descriptive error message.
@@ -53,22 +55,14 @@ There are a few important details:
5355
error:(NSError **)error;
5456

5557
/// Check if the instance method in `originalClass` is a super trampoline.
56-
+ (BOOL)isSuperTrampolineForClass:(Class)originalClass selector:(SEL)selector;
57-
58-
/// x86-64 and ARM64 are currently supported.
59-
@property(class, readonly) BOOL isSupportedArchitecture;
60-
61-
#if (defined (__arm64__) || defined (__x86_64__)) && __APPLE__
62-
/// Helper that does not exist if architecture is not supported.
63-
+ (BOOL)isCompileTimeSupportedArchitecture;
64-
#endif
58+
+ (BOOL)isSuperTrampolineForClass:(Class)originalClass
59+
selector:(SEL)selector;
6560

6661
@end
6762

6863
NSString *const ITKSuperBuilderErrorDomain;
6964

7065
typedef NS_ERROR_ENUM(ITKSuperBuilderErrorDomain, ITKSuperBuilderErrorCode) {
71-
SuperBuilderErrorCodeArchitectureNotSupported,
7266
SuperBuilderErrorCodeNoSuperClass,
7367
SuperBuilderErrorCodeNoDynamicallyDispatchedMethodAvailable,
7468
SuperBuilderErrorCodeFailedToAddMethod

Sources/ITKSuperBuilder/src/ITKSuperBuilder.m

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
static IMP ITKGetTrampolineForTypeEncoding(__unused const char *typeEncoding) {
1818
BOOL requiresStructDispatch = NO;
1919
#if defined (__arm64__)
20-
// ARM64 doesn't use stret dispatch. Yay!
20+
// arm64 doesn't use stret dispatch. Yay!
2121
#elif defined (__x86_64__)
22-
// On x86-64, stret dispatch is ~used whenever return type doesn't fit into two registers
22+
// On x86_64, stret dispatch is ~used whenever return type doesn't fit into two registers
2323
//
2424
// http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
2525
// x86_64 is more complicated, including rules for returning floating-point struct fields in FPU registers, and ppc64's rules and exceptions will make your head spin. The gory details are documented in the Mac OS X ABI Guide, though as usual if the documentation and the compiler disagree then the documentation is wrong.
@@ -41,32 +41,12 @@ static IMP ITKGetTrampolineForTypeEncoding(__unused const char *typeEncoding) {
4141

4242
@implementation ITKSuperBuilder
4343

44-
+ (BOOL)isSupportedArchitecture {
45-
#if defined (__arm64__) || defined (__x86_64__)
46-
return YES;
47-
#else
48-
return NO;
49-
#endif
50-
}
51-
52-
#if defined (__arm64__) || defined (__x86_64__)
53-
+ (BOOL)isCompileTimeSupportedArchitecture {
54-
return [self isSupportedArchitecture];
55-
}
56-
#endif
57-
5844
+ (BOOL)isSuperTrampolineForClass:(Class)originalClass selector:(SEL)selector {
59-
// No architecture check needed - will just be NO.
6045
let method = class_getInstanceMethod(originalClass, selector);
6146
return ITKMethodIsSuperTrampoline(method);
6247
}
6348

6449
+ (BOOL)addSuperInstanceMethodToClass:(Class)originalClass selector:(SEL)selector error:(NSError **)error {
65-
if (!self.isSupportedArchitecture) {
66-
let msg = @"Unsupported Architecture. (Support includes ARM64 and x86-64 )";
67-
ERROR_AND_RETURN(SuperBuilderErrorCodeArchitectureNotSupported, msg)
68-
}
69-
7050
// Check that class has a superclass
7151
let superClass = class_getSuperclass(originalClass);
7252
if (superClass == nil) {

Sources/InterposeKit/Hooks/HookStrategy/ObjectHookStrategy/InterposeSubclass.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ class InterposeSubclass {
77
static let subclassSuffix = "InterposeKit_"
88
}
99

10-
/// The object that is being hooked.
11-
let object: AnyObject
12-
1310
/// Subclass that we create on the fly
1411
private(set) var dynamicClass: AnyClass
1512

@@ -19,8 +16,15 @@ class InterposeSubclass {
1916
/// Making KVO and Object-based hooking work at the same time is difficult.
2017
/// If we make a dynamic subclass over KVO, invalidating the token crashes in cache_getImp.
2118
init(object: AnyObject) throws {
22-
self.object = object
23-
self.dynamicClass = try Self.getExistingSubclass(object: object) ?? Self.createSubclass(object: object)
19+
let dynamicClass: AnyClass = try { () throws -> AnyClass in
20+
if let dynamicClass = Self.getExistingSubclass(object: object) {
21+
return dynamicClass
22+
}
23+
24+
return try Self.createSubclass(object: object)
25+
}()
26+
27+
self.dynamicClass = dynamicClass
2428
}
2529

2630
private static func createSubclass(object: AnyObject) throws -> AnyClass {
@@ -63,10 +67,6 @@ class InterposeSubclass {
6367
return nil
6468
}
6569

66-
class var supportsSuperTrampolines: Bool {
67-
ITKSuperBuilder.isSupportedArchitecture
68-
}
69-
7070
func addSuperTrampoline(selector: Selector) {
7171
do {
7272
try ITKSuperBuilder.addSuperInstanceMethod(to: dynamicClass, selector: selector)

Sources/InterposeKit/Hooks/HookStrategy/ObjectHookStrategy/ObjectHookStrategy.swift

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ final class ObjectHookStrategy: HookStrategy {
3030
/// Subclass that we create on the fly
3131
var interposeSubclass: InterposeSubclass?
3232

33-
// Logic switch to use super builder
34-
let generatesSuperIMP = InterposeSubclass.supportsSuperTrampolines
35-
3633
var dynamicSubclass: AnyClass {
3734
interposeSubclass!.dynamicClass
3835
}
@@ -75,46 +72,25 @@ final class ObjectHookStrategy: HookStrategy {
7572
let classImplementsMethod = class_implementsInstanceMethod(self.dynamicSubclass, self.selector)
7673
let encoding = method_getTypeEncoding(method)
7774

78-
if self.generatesSuperIMP {
79-
// If the subclass is empty, we create a super trampoline first.
80-
// If a hook already exists, we must skip this.
81-
if !classImplementsMethod {
82-
// TODO: Make this failable
83-
self.interposeSubclass!.addSuperTrampoline(selector: self.selector)
84-
}
85-
86-
// Replace IMP (by now we guarantee that it exists)
87-
self.storedOriginalIMP = class_replaceMethod(self.dynamicSubclass, self.selector, hookIMP, encoding)
88-
guard self.storedOriginalIMP != nil else {
89-
// This should not happen if the class implements the method or we have installed
90-
// the super trampoline. Instead, we should make the trampoline implementation
91-
// failable.
92-
throw InterposeError.implementationNotFound(
93-
class: self.dynamicSubclass,
94-
selector: self.selector
95-
)
96-
}
97-
Interpose.log("Added -[\(self.class).\(self.selector)] IMP: \(self.storedOriginalIMP!) -> \(hookIMP)")
98-
} else {
99-
// Could potentially be unified in the code paths
100-
if classImplementsMethod {
101-
self.storedOriginalIMP = class_replaceMethod(self.dynamicSubclass, self.selector, hookIMP, encoding)
102-
if self.storedOriginalIMP != nil {
103-
Interpose.log("Added -[\(self.class).\(self.selector)] IMP: \(hookIMP) via replacement")
104-
} else {
105-
Interpose.log("Unable to replace: -[\(self.class).\(self.selector)] IMP: \(hookIMP)")
106-
throw InterposeError.unableToAddMethod(self.class, self.selector)
107-
}
108-
} else {
109-
let didAddMethod = class_addMethod(self.dynamicSubclass, self.selector, hookIMP, encoding)
110-
if didAddMethod {
111-
Interpose.log("Added -[\(self.class).\(self.selector)] IMP: \(hookIMP)")
112-
} else {
113-
Interpose.log("Unable to add: -[\(self.class).\(self.selector)] IMP: \(hookIMP)")
114-
throw InterposeError.unableToAddMethod(self.class, self.selector)
115-
}
116-
}
75+
// If the subclass is empty, we create a super trampoline first.
76+
// If a hook already exists, we must skip this.
77+
if !classImplementsMethod {
78+
// TODO: Make this failable
79+
self.interposeSubclass!.addSuperTrampoline(selector: self.selector)
80+
}
81+
82+
// Replace IMP (by now we guarantee that it exists)
83+
self.storedOriginalIMP = class_replaceMethod(self.dynamicSubclass, self.selector, hookIMP, encoding)
84+
guard self.storedOriginalIMP != nil else {
85+
// This should not happen if the class implements the method or we have installed
86+
// the super trampoline. Instead, we should make the trampoline implementation
87+
// failable.
88+
throw InterposeError.implementationNotFound(
89+
class: self.dynamicSubclass,
90+
selector: self.selector
91+
)
11792
}
93+
Interpose.log("Added -[\(self.class).\(self.selector)] IMP: \(self.storedOriginalIMP!) -> \(hookIMP)")
11894
}
11995

12096
func restoreImplementation() throws {

Sources/InterposeKit/Interpose.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#if !(arch(arm64) || arch(x86_64))
2+
#error("[InterposeKit] This code only supports arm64 and x86_64 architectures.")
3+
#endif
4+
15
import ObjectiveC
26

37
/// Interpose is a modern library to swizzle elegantly in Swift.

Sources/InterposeKit/InterposeError.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ public enum InterposeError: LocalizedError {
4848
/// Unable to register subclass for object-based interposing.
4949
case failedToAllocateClassPair(class: AnyClass, subclassName: String)
5050

51-
/// Unable to add method for object-based interposing.
52-
case unableToAddMethod(AnyClass, Selector)
53-
5451
/// Object-based hooking does not work if an object is using KVO.
5552
/// The KVO mechanism also uses subclasses created at runtime but doesn't check for additional overrides.
5653
/// Adding a hook eventually crashes the KVO management code so we reject hooking altogether in this case.
@@ -89,8 +86,6 @@ extension InterposeError: Equatable {
8986
return "Unexpected Implementation in -[\(klass) \(selector)]: \(String(describing: IMP))"
9087
case .failedToAllocateClassPair(let klass, let subclassName):
9188
return "Failed to allocate class pair: \(klass), \(subclassName)"
92-
case .unableToAddMethod(let klass, let selector):
93-
return "Unable to add method: -[\(klass) \(selector)]"
9489
case .kvoDetected(let obj):
9590
return "Unable to hook object that uses Key Value Observing: \(obj)"
9691
case .objectPosingAsDifferentClass(let obj, let actualClass):

0 commit comments

Comments
 (0)