Просмотр исходного кода

FLEX*Utility bug fixes

- Handle case where protocol method descriptions don't have type information
- Hard-code support for `std::string` to avoid calling it and to make the type readable
Tanner Bennett лет назад: 6
Родитель
Сommit
0f1134e25e
2 измененных файлов с 49 добавлено и 14 удалено
  1. 12 4
      Classes/Utility/FLEXUtility.m
  2. 37 10
      Classes/Utility/Runtime/FLEXRuntimeUtility.m

+ 12 - 4
Classes/Utility/FLEXUtility.m

@@ -421,14 +421,22 @@
     IMP implementation = imp_implementationWithBlock((id)([cls instancesRespondToSelector:selector] ? implementationBlock : undefinedBlock));
     
     Method oldMethod = class_getInstanceMethod(cls, selector);
+    const char *types = methodDescription.types;
     if (oldMethod) {
-        class_addMethod(cls, swizzledSelector, implementation, methodDescription.types);
-        
+        if (!types) {
+            types = method_getTypeEncoding(oldMethod);
+        }
+
+        class_addMethod(cls, swizzledSelector, implementation, types);
         Method newMethod = class_getInstanceMethod(cls, swizzledSelector);
-        
         method_exchangeImplementations(oldMethod, newMethod);
     } else {
-        class_addMethod(cls, selector, implementation, methodDescription.types);
+        if (!types) {
+            // Some protocol method descriptions don't have .types populated
+            // Set the return type to void and ignore arguments
+            types = "v@:";
+        }
+        class_addMethod(cls, selector, implementation, types);
     }
 }
 

+ 37 - 10
Classes/Utility/Runtime/FLEXRuntimeUtility.m

@@ -279,6 +279,12 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
         withArguments:(NSArray *)arguments
                 error:(NSError * __autoreleasing *)error
 {
+    static dispatch_once_t onceToken;
+    static SEL stdStringExclusion = nil;
+    dispatch_once(&onceToken, ^{
+        stdStringExclusion = NSSelectorFromString(@"stdString");
+    });
+
     // Bail if the object won't respond to this selector.
     if (![object respondsToSelector:selector]) {
         if (error) {
@@ -293,6 +299,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
                 userInfo:userInfo
             ];
         }
+
         return nil;
     }
 
@@ -390,14 +397,27 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
             returnObject = objectReturnedFromMethod;
         } else if (returnType[0] != FLEXTypeEncodingVoid) {
             NSAssert(methodSignature.methodReturnLength, @"Memory corruption lies ahead");
-            // Will use arbitrary buffer for return value and box it.
-            void *returnValue = malloc(methodSignature.methodReturnLength);
 
-            if (returnValue) {
-                [invocation getReturnValue:returnValue];
-                returnObject = [self valueForPrimitivePointer:returnValue objCType:returnType];
-                free(returnValue);
+            if (returnType[0] == FLEXTypeEncodingStructBegin) {
+                if (selector == stdStringExclusion && [object isKindOfClass:[NSString class]]) {
+                    // stdString is a C++ object and we will crash if we try to access it
+                    if (error) {
+                        *error = [NSError
+                            errorWithDomain:FLEXRuntimeUtilityErrorDomain
+                            code:FLEXRuntimeUtilityErrorCodeInvocationFailed
+                            userInfo:@{ NSLocalizedDescriptionKey : @"Skipping -[NSString stdString]" }
+                        ];
+                    }
+
+                    return nil;
+                }
             }
+
+            // Will use arbitrary buffer for return value and box it.
+            void *returnValue = malloc(methodSignature.methodReturnLength);
+            [invocation getReturnValue:returnValue];
+            returnObject = [self valueForPrimitivePointer:returnValue objCType:returnType];
+            free(returnValue);
         }
     } @catch (NSException *exception) {
         // Bummer...
@@ -411,9 +431,11 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
                 exception.name, NSStringFromSelector(selector), calledOn, exception.reason
             ];
 
-            *error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain
-                                         code:FLEXRuntimeUtilityErrorCodeInvocationFailed
-                                     userInfo:@{ NSLocalizedDescriptionKey : message }];
+            *error = [NSError
+                errorWithDomain:FLEXRuntimeUtilityErrorDomain
+                code:FLEXRuntimeUtilityErrorCodeInvocationFailed
+                userInfo:@{ NSLocalizedDescriptionKey : message }
+            ];
         }
     }
 
@@ -631,7 +653,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
 + (NSString *)readableTypeForEncoding:(NSString *)encodingString
 {
     if (!encodingString) {
-        return nil;
+        return @"???";
     }
 
     // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
@@ -751,6 +773,11 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
 
     // For structs, we only use the name of the structs
     if (encodingCString[0] == FLEXTypeEncodingStructBegin) {
+        // Special case: std::string
+        if ([encodingString hasPrefix:@"{basic_string<char"]) {
+            return @"std::string";
+        }
+
         const char *equals = strchr(encodingCString, '=');
         if (equals) {
             const char *nameStart = encodingCString + 1;