iPhone 6 上的 KERN_INVALID_ADDRESS 异常

Posted

技术标签:

【中文标题】iPhone 6 上的 KERN_INVALID_ADDRESS 异常【英文标题】:KERN_INVALID_ADDRESS exception on iPhone 6 【发布时间】:2015-08-19 20:15:28 【问题描述】:

我们的ios 应用程序中抛出了一个KERN_INVALID_ADDRESS 异常。该应用程序实际上是一个Tamarin 应用程序,但异常发生在我们的PhoneGap 库中,该库基于PhoneGap 2.1 版的代码。该异常仅在iPhone 6iPad Air 2 设备上报告,而不在其他Apple 设备上报告。

这是符号化的崩溃报告:

Exception Type:  EXC_BAD_ACCESS (SIGABRT)
Exception Subtype: KERN_INVALID_ADDRESS at 0x004c004900000072
Triggered by Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib               0x000000019853b270 0x198520000 + 111216
1   libsystem_pthread.dylib              0x00000001985d916c 0x1985d4000 + 20844
2   libsystem_c.dylib                    0x00000001984b2b14 0x198450000 + 404244
3   Mobileforms                          0x0000000100799384 mono_handle_native_sigsegv (mini-exceptions.c:2386)
4   Mobileforms                          0x00000001007a61b0 mono_sigsegv_signal_handler (mini.c:6818)
5   libsystem_platform.dylib             0x00000001985d0958 0x1985cc000 + 18776
6   Mobileforms                          0x0000000100155104 -[CDVConnection getConnectionInfo:] (CDVConnection.m:36)
7   Mobileforms                          0x000000010014e948 -[NativeGapViewController execute:] (NativeGap.mm:205)
8   Mobileforms                          0x000000010014e6d4 -[NativeGapViewController executeCommandsFromJson:] (NativeGap.mm:158)
9   Mobileforms                          0x000000010014e58c -[NativeGapViewController flushCommandQueue] (NativeGap.mm:136)
10  Mobileforms                          0x000000010014e2c4 -[NativeGapViewController handleRequest:] (NativeGap.mm:78)

在这里,我正在跟踪flushCommandQueue 方法中从第 136 行开始的代码。

NativeGap.mm: 136

/**
 * Repeatedly fetches and executes the command queue until it is empty.
 */
- (void) flushCommandQueue

    UIWebView* webView = (UIWebView*)self.view ;
    [webView stringByEvaluatingjavascriptFromString:
     @"cordova.commandQueueFlushing = true"];

    // Keep executing the command queue until no commands get executed.
    // This ensures that commands that are queued while executing other
    // commands are executed as well.
    int numExecutedCommands = 0;
    do 
        // Grab all the queued commands from the JS side.
        NSString* queuedCommandsJSON = [webView stringByEvaluatingJavaScriptFromString:
                                        @"cordova.require('cordova/plugin/ios/nativecomm')()"];
        numExecutedCommands = [self executeCommandsFromJson:queuedCommandsJSON]; // LINE 136
     while (numExecutedCommands != 0);

    [webView stringByEvaluatingJavaScriptFromString:
     @"cordova.commandQueueFlushing = false"];

NativeGap.mm:158

/**
 * Fetches the command queue and executes each command. It is possible that the
 * queue will not be empty after this function has completed since the executed
 * commands may have run callbacks which queued more commands.
 *
 * Returns the number of executed commands.
 */
- (int) executeCommandsFromJson:(NSString*)queuedCommandsJSON

    // Parse the returned JSON array.
    NSArray* queuedCommands = [queuedCommandsJSON cdvjk_mutableObjectFromJSONString];

    // Iterate over and execute all of the commands.
    for (NSArray* jsonEntry in queuedCommands) 
        CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand commandFromJson:jsonEntry] retain];
        if(![self.commandDelegate execute:command])  // LINE 158
            DLog(@"FAILED pluginJSON = %@", commandString);
        
        [command release];
    
    return [queuedCommands count];

NativeGap.mm: 205

- (BOOL) execute:(CDVInvokedUrlCommand*)command

    ...

    // Find the proper selector to call.
    NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName];
    NSString* methodNameWithDict = [NSString stringWithFormat:@"%@:withDict:", command.methodName];
    SEL normalSelector = NSSelectorFromString(methodName);
    SEL legacySelector = NSSelectorFromString(methodNameWithDict);
    // Test for the legacy selector first in case they both exist.
    if ([obj respondsToSelector:legacySelector]) 
        NSMutableArray* arguments = nil;
        NSMutableDictionary* dict = nil;
        [command legacyArguments:&arguments andDict:&dict];
        //[obj performSelector:legacySelector withObject:arguments withObject:dict];
        objc_msgSend(obj,legacySelector,arguments,dict);
     else if ([obj respondsToSelector:normalSelector]) 
        //[obj performSelector:normalSelector withObject:command];
        objc_msgSend(obj,normalSelector,command); // LINE 205

     else 
        // There's no method to call, so throw an error.
        NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className);
        retVal = NO;
    

    return retVal;

CSVConnection.m: 36

- (void) getConnectionInfo:(CDVInvokedUrlCommand*)command

    CDVPluginResult* result = nil;
    NSString* jsString = nil;
    NSString* callbackId = command.callbackId; // LINE 36 << Exception 

    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.connectionType];
    jsString = [result toSuccessCallbackString:callbackId];
    [self writeJavascript:jsString];

在我看来,问题的根源在于方法executeCommandsFromJson (NativeGap.mm: 158),特别是这段代码:

CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand commandFromJson:jsonEntry] retain];
if(![self.commandDelegate execute:command])  // LINE 158
    DLog(@"FAILED pluginJSON = %@", commandString);

[command release];

在我看来,创建的这个 CDVInvokedUrlCommand 实例不知何故被提前释放,并且在到达 CSVConnection 中的这一行时已经被释放:

NSString* callbackId = command.callbackId; // LINE 36

这里是创建CDVInvokedUrlCommand 实例的相关部分:

+ (CDVInvokedUrlCommand*) commandFromJson:(NSArray*)jsonEntry

    return [[[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry] autorelease];


- (id) initFromJson:(NSArray*)jsonEntry

    id tmp = [jsonEntry objectAtIndex:0];
    NSString* callbackId = tmp == [NSNull null] ? nil : tmp;
    NSString* className = [jsonEntry objectAtIndex:1];
    NSString* methodName = [jsonEntry objectAtIndex:2];
    NSMutableArray* arguments = [jsonEntry objectAtIndex:3];

    return [self initWithArguments:arguments
                        callbackId:callbackId
                         className:className
                        methodName:methodName];

有谁知道为什么iPhone 6 会出现此异常以及我们如何解决它?

【问题讨论】:

【参考方案1】:

如果它对其他人有帮助,这里是我花了几天时间寻找的这个问题的解决方案。崩溃仅发生在具有 64 位架构的设备上。 NativeGap.mm 中的这一行:

objc_msgSend(obj,normalSelector,command); // LINE 205

需要改成如下:

((void(*)(id, SEL, id))objc_msgSend)(obj,normalSelector,command); // LINE 205

关于这个问题的更多信息可以在over here找到。

【讨论】:

以上是关于iPhone 6 上的 KERN_INVALID_ADDRESS 异常的主要内容,如果未能解决你的问题,请参考以下文章

iPhone 5/6 上的窗口尺寸小

iPhone 6 上的状态栏太大

iPhone 3GS 上的 iOS 6.0 上的 UICollectionView 崩溃

iPhone 6 Plus 上的 UISplitViewController 旋转大师大师

iPhone 6 Plus 上的方向不正确?

iPhone 6 设备和模拟器上的快照方法损坏