Invalid number value (infinite) in JSON write

背景

線上崩潰排查中,發(fā)現(xiàn)一批model轉(zhuǎn)JSON時發(fā)生崩潰,描述如下:

崩潰信息

Invalid number value (infinite) in JSON write
XXXX -[NSObject(YYModel) modelToJSONData] (NSObject+YYModel.m:)

崩潰原因

INFINITY:無窮
NAN:不是數(shù)字
使用系統(tǒng)解析方法NSJSONSerialization解析JSON時,會發(fā)生崩潰(如上崩潰日志)。

為什么會產(chǎn)生NAN/INFINITY?

  1. App作圖記錄,是全平臺的互通的,JS或其它語言支持NAN數(shù)字
  2. 未知原因混進來或錯誤生成一些NAN,INFINITY數(shù)據(jù)

注:
浮點數(shù)類型除以0 產(chǎn)生 +inf
錯誤開方產(chǎn)生NaN

image.png

如何防護

ios提供了檢測無效數(shù)字的函數(shù)

  1. isnan(number)
  2. isinf(number)

在YYModel中,已經(jīng)添加了對無效數(shù)字的檢測(第6行),為什么還是崩了呢?

static id ModelToJSONObjectRecursive(NSObject *model) {
    if (!model || model == (id)kCFNull) return model;
    if ([model isKindOfClass:[NSString class]]) return model;
    if ([model isKindOfClass:[NSNumber class]]) {
        double doubleValue = ((NSNumber *)model).doubleValue;
        if (isnan(doubleValue) || isinf(doubleValue)) {
            return @(0);
        }
        return model;
    }
...
...
    // Set解析同樣
    // 數(shù)組解析
    if ([model isKindOfClass:[NSArray class]]) {
        if ([NSJSONSerialization isValidJSONObject:model]) return model;
        NSMutableArray *newArray = [NSMutableArray new];
        for (id obj in (NSArray *)model) {
            if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
                [newArray addObject:obj];
            } else {
                id jsonObj = ModelToJSONObjectRecursive(obj);
                if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
            }
        }
        return newArray;
    }
}

上面的解析,對于dict中value為Number類型,@{key: @(NAN)},確實已經(jīng)通過if (isnan(doubleValue) || isinf(doubleValue))返回0避免崩潰。
但當value為數(shù)組,數(shù)組內(nèi)包含無效數(shù)字時,@{@"v1": @[@(NAN),@(INFINITY)]},就直接繞過了isnan/isinf的檢測(走第19行),導致解析崩潰。

修復

去除NSSet/NSArray中的NSNumber判定(19行),讓其走isnan/isinf檢測。

static id ModelToJSONObjectRecursive(NSObject *model) {
    if (!model || model == (id)kCFNull) return model;
    if ([model isKindOfClass:[NSString class]]) return model;
    if ([model isKindOfClass:[NSNumber class]]) {
        double doubleValue = ((NSNumber *)model).doubleValue;
        if (isnan(doubleValue) || isinf(doubleValue)) {
            return @(0);
        }
        return model;
    }
...
...
    // Set解析同樣
    // 數(shù)組解析
    if ([model isKindOfClass:[NSArray class]]) {
        if ([NSJSONSerialization isValidJSONObject:model]) return model;
        NSMutableArray *newArray = [NSMutableArray new];
        for (id obj in (NSArray *)model) {
            if ([obj isKindOfClass:[NSString class]]) { // 去除NSNumber判定,讓其走isnan/isinf檢測
                [newArray addObject:obj];
            } else {
                id jsonObj = ModelToJSONObjectRecursive(obj);
                if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
            }
        }
        return newArray;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容