Invalid number value (infinite) in JSON write

背景

线上崩溃排查中,发现一批model转JSON时发生崩溃,描述如下:

崩溃信息

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

崩溃原因

INFINITY:无穷
NAN:不是数字
使用系统解析方法NSJSONSerialization解析JSON时,会发生崩溃(如上崩溃日志)。

为什么会产生NAN/INFINITY?

  1. App作图记录,是全平台的互通的,JS或其它语言支持NAN数字
  2. 未知原因混进来或错误生成一些NAN,INFINITY数据

注:
浮点数类型除以0 产生 +inf
错误开方产生NaN

image.png

如何防护

ios提供了检测无效数字的函数

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

在YYModel中,已经添加了对无效数字的检测(第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解析同样
    // 数组解析
    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)},确实已经通过if (isnan(doubleValue) || isinf(doubleValue))返回0避免崩溃。
但当value为数组,数组内包含无效数字时,@{@"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解析同样
    // 数组解析
    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;
    }
}

你可能感兴趣的:(Invalid number value (infinite) in JSON write)