Explorar el Código

Get more defensive around calls to NSGetSizeAndAlignment.

It throws exceptions for some type encodings (bitfields).
Ryan Olson hace 12 años
padre
commit
ae2bf10276

+ 48 - 36
Classes/Editing/Argument Input Views/FLEXArgumentInputStructView.m

@@ -61,52 +61,64 @@
         const char *structTypeEncoding = [inputValue objCType];
         if (strcmp([self.typeEncoding UTF8String], structTypeEncoding) == 0) {
             NSUInteger valueSize = 0;
-            NSGetSizeAndAlignment(structTypeEncoding, &valueSize, NULL);
-            void *unboxedValue = malloc(valueSize);
-            [inputValue getValue:unboxedValue];
-            [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName, const char *fieldTypeEncoding, NSString *prettyTypeEncoding, NSUInteger fieldIndex, NSUInteger fieldOffset) {
-                
-                void *fieldPointer = unboxedValue + fieldOffset;
-                FLEXArgumentInputView *inputView = [self.argumentInputViews objectAtIndex:fieldIndex];
-                
-                if (fieldTypeEncoding[0] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
-                    inputView.inputValue = (__bridge id)fieldPointer;
-                } else {
-                    NSValue *boxedField = [FLEXRuntimeUtility valueForPrimitivePointer:fieldPointer objCType:fieldTypeEncoding];
-                    inputView.inputValue = boxedField;
-                }
-            }];
-            free(unboxedValue);
+            @try {
+                // NSGetSizeAndAlignment barfs on type encoding for bitfields.
+                NSGetSizeAndAlignment(structTypeEncoding, &valueSize, NULL);
+            } @catch (NSException *exception) { }
+            
+            if (valueSize > 0) {
+                void *unboxedValue = malloc(valueSize);
+                [inputValue getValue:unboxedValue];
+                [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName, const char *fieldTypeEncoding, NSString *prettyTypeEncoding, NSUInteger fieldIndex, NSUInteger fieldOffset) {
+                    
+                    void *fieldPointer = unboxedValue + fieldOffset;
+                    FLEXArgumentInputView *inputView = [self.argumentInputViews objectAtIndex:fieldIndex];
+                    
+                    if (fieldTypeEncoding[0] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
+                        inputView.inputValue = (__bridge id)fieldPointer;
+                    } else {
+                        NSValue *boxedField = [FLEXRuntimeUtility valueForPrimitivePointer:fieldPointer objCType:fieldTypeEncoding];
+                        inputView.inputValue = boxedField;
+                    }
+                }];
+                free(unboxedValue);
+            }
         }
     }
 }
 
 - (id)inputValue
 {
+    NSValue *boxedStruct = nil;
     const char *structTypeEncoding = [self.typeEncoding UTF8String];
     NSUInteger structSize = 0;
-    NSGetSizeAndAlignment(structTypeEncoding, &structSize, NULL);
-    void *unboxedStruct = malloc(structSize);
+    @try {
+        // NSGetSizeAndAlignment barfs on type encoding for bitfields.
+        NSGetSizeAndAlignment(structTypeEncoding, &structSize, NULL);
+    } @catch (NSException *exception) { }
     
-    [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName, const char *fieldTypeEncoding, NSString *prettyTypeEncoding, NSUInteger fieldIndex, NSUInteger fieldOffset) {
-        
-        void *fieldPointer = unboxedStruct + fieldOffset;
-        FLEXArgumentInputView *inputView = [self.argumentInputViews objectAtIndex:fieldIndex];
-        
-        if (fieldTypeEncoding[0] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
-            // Object fields
-            memcpy(fieldPointer, (__bridge void *)inputView.inputValue, sizeof(id));
-        } else {
-            // Boxed primitive/struct fields
-            id inputValue = inputView.inputValue;
-            if ([inputValue isKindOfClass:[NSValue class]] && strcmp([inputValue objCType], fieldTypeEncoding) == 0) {
-                [inputValue getValue:fieldPointer];
+    if (structSize > 0) {
+        void *unboxedStruct = malloc(structSize);
+        [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName, const char *fieldTypeEncoding, NSString *prettyTypeEncoding, NSUInteger fieldIndex, NSUInteger fieldOffset) {
+            
+            void *fieldPointer = unboxedStruct + fieldOffset;
+            FLEXArgumentInputView *inputView = [self.argumentInputViews objectAtIndex:fieldIndex];
+            
+            if (fieldTypeEncoding[0] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
+                // Object fields
+                memcpy(fieldPointer, (__bridge void *)inputView.inputValue, sizeof(id));
+            } else {
+                // Boxed primitive/struct fields
+                id inputValue = inputView.inputValue;
+                if ([inputValue isKindOfClass:[NSValue class]] && strcmp([inputValue objCType], fieldTypeEncoding) == 0) {
+                    [inputValue getValue:fieldPointer];
+                }
             }
-        }
-    }];
-    
-    NSValue *boxedStruct = [NSValue value:unboxedStruct withObjCType:structTypeEncoding];
-    free(unboxedStruct);
+        }];
+        
+        boxedStruct = [NSValue value:unboxedStruct withObjCType:structTypeEncoding];
+        free(unboxedStruct);
+    }
     
     return boxedStruct;
 }

+ 47 - 28
Classes/Utility/FLEXRuntimeUtility.m

@@ -218,13 +218,18 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
         NSAssert(strcmp([valueValue objCType], typeEncodingCString) == 0, @"Type encoding mismatch (value: %s; ivar: %s) in setting ivar named: %s on object: %@", [valueValue objCType], typeEncodingCString, ivar_getName(ivar), object);
         
         NSUInteger bufferSize = 0;
-        NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
-        void *buffer = calloc(bufferSize, 1);
-        [valueValue getValue:buffer];
-        ptrdiff_t offset = ivar_getOffset(ivar);
-        void *pointer = (__bridge void *)object + offset;
-        memcpy(pointer, buffer, bufferSize);
-        free(buffer);
+        @try {
+            // NSGetSizeAndAlignment barfs on type encoding for bitfields.
+            NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
+        } @catch (NSException *exception) { }
+        if (bufferSize > 0) {
+            void *buffer = calloc(bufferSize, 1);
+            [valueValue getValue:buffer];
+            ptrdiff_t offset = ivar_getOffset(ivar);
+            void *pointer = (__bridge void *)object + offset;
+            memcpy(pointer, buffer, bufferSize);
+            free(buffer);
+        }
     }
 }
 
@@ -315,11 +320,17 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
                 }
                 
                 NSUInteger bufferSize = 0;
-                NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
-                void *buffer = calloc(bufferSize, 1);
-                [argumentValue getValue:buffer];
-                [invocation setArgument:buffer atIndex:argumentIndex];
-                free(buffer);
+                @try {
+                    // NSGetSizeAndAlignment barfs on type encoding for bitfields.
+                    NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
+                } @catch (NSException *exception) { }
+                
+                if (bufferSize > 0) {
+                    void *buffer = calloc(bufferSize, 1);
+                    [argumentValue getValue:buffer];
+                    [invocation setArgument:buffer atIndex:argumentIndex];
+                    free(buffer);
+                }
             }
         }
     }
@@ -446,23 +457,31 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
             NSString *structName = [@(structEncoding) substringWithRange:NSMakeRange(nameStart - structEncoding, equals - nameStart)];
             
             NSUInteger fieldAlignment = 0;
-            NSGetSizeAndAlignment(structEncoding, NULL, &fieldAlignment);
-            NSUInteger runningFieldIndex = 0;
-            NSUInteger runningFieldOffset = 0;
-            const char *typeStart = equals + 1;
-            while (*typeStart != '}') {
-                NSUInteger fieldSize = 0;
-                const char *nextTypeStart = NSGetSizeAndAlignment(typeStart, &fieldSize, NULL);
-                NSString *typeEncoding = [@(structEncoding) substringWithRange:NSMakeRange(typeStart - structEncoding, nextTypeStart - typeStart)];
-                typeBlock(structName, [typeEncoding UTF8String], [self readableTypeForEncoding:typeEncoding], runningFieldIndex, runningFieldOffset);
-                runningFieldOffset += fieldSize;
-                // Padding to keep propper alignment. __attribute((packed)) structs will break here.
-                // The type encoding is no different for packed structs, so it's not clear there's anything we can do for those.
-                if (runningFieldOffset % fieldAlignment != 0) {
-                    runningFieldOffset += fieldAlignment - runningFieldOffset % fieldAlignment;
+            NSUInteger structSize = 0;
+            @try {
+                // NSGetSizeAndAlignment barfs on type encoding for bitfields.
+                NSGetSizeAndAlignment(structEncoding, &structSize, &fieldAlignment);
+            } @catch (NSException *exception) { }
+            
+            if (structSize > 0) {
+                NSUInteger runningFieldIndex = 0;
+                NSUInteger runningFieldOffset = 0;
+                const char *typeStart = equals + 1;
+                while (*typeStart != '}') {
+                    NSUInteger fieldSize = 0;
+                    // If the struct type encoding was successfully handled by NSGetSizeAndAlignment above, we *should* be ok with the field here.
+                    const char *nextTypeStart = NSGetSizeAndAlignment(typeStart, &fieldSize, NULL);
+                    NSString *typeEncoding = [@(structEncoding) substringWithRange:NSMakeRange(typeStart - structEncoding, nextTypeStart - typeStart)];
+                    typeBlock(structName, [typeEncoding UTF8String], [self readableTypeForEncoding:typeEncoding], runningFieldIndex, runningFieldOffset);
+                    runningFieldOffset += fieldSize;
+                    // Padding to keep propper alignment. __attribute((packed)) structs will break here.
+                    // The type encoding is no different for packed structs, so it's not clear there's anything we can do for those.
+                    if (runningFieldOffset % fieldAlignment != 0) {
+                        runningFieldOffset += fieldAlignment - runningFieldOffset % fieldAlignment;
+                    }
+                    runningFieldIndex++;
+                    typeStart = nextTypeStart;
                 }
-                runningFieldIndex++;
-                typeStart = nextTypeStart;
             }
         }
     }