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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容