iOS静态分析

  • Analyzer
  • Infer
  • OCLint

Analyzer:

Clang Static Analyzer是一款静态代码扫描工具,专门用于针对C,C++和Objective-C的程序进行分析。已经被Xcode集成,可以直接使用Xcode进行静态代码扫描分析,也可以单独在命令行下使用并提供html格式的输出报吿和xml格式的结果文件方便集成到Jenkins上进行展示

Analyze主要分析以下四种问题:
1、逻辑错误:访问空指针或未初始化的变量等;
2、内存管理错误:如内存泄漏等;
3、声明错误:从未使用过的变量;
4、Api调用错误:未包含使用的库和框架。

分析车码头项目:

image.png

1.Dead store:

  • Value stored to 'stackTrace' is never read**
    如下,只是被赋值,没有被使用:
+(void)exception:(NSString *)eventCode extra:(NSDictionary *)param {
    NSString* stackTrace = [param objectForKey:MONITOR_CODE_STACK_TRACE];
    if (!stackTrace) {
        stackTrace = @"";
    }
    [[UCARMonitorNewStore sharedStore] storeException:eventCode stack:param remark:param];
}

2.Memory error:

  • nil assigned to a pointer which is expected to have non-null value
    nil 赋值给了一个期望非空值的指针
- (void)saveUserInfoModel:(id)model {
    _userInfo = nil;
    [[CMTCacheService sharedInstance] saveObject:model forKey:cmtLoginKey];
}
  • nil returned from a method that is expected to return a non-null value
    返回了 nil 值,期望返回一个非空值
- (NSArray *)getCurrentUploadModelArrWithSectionTag:(NSInteger)secTag {
    NSArray *arr;
    switch (secTag) {
        case Section2InvoiceTitle:
            arr = self.invoiceUpLoadArray;
            break;
        case Section3InputAndOutgoingVoucherTitle:
            arr = self.reciptUpLoadArray;
            break;
        case Section4OtherResources:
            arr = self.otherUpLoadArray;
            break;
    }    
    return arr;
}
  • nil passed to a callee that requires a non-null 1st parameter
    Null赋值给非空对象
        imageViewLabel.image = [UIImage imageNamed:lastImageLabel];

由于疏忽,判断语句的else里面并没有给filePath赋值,所以才会出现Null。只需进行非空判断或赋值给filePath就好了

3.Memory (Core Foundation/Objective-C)

  • Potential leak of an object stored into 'scaledImage
    存在潜在的内存泄露
- (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat)size {
    CGRect extent = CGRectIntegral(image.extent);
    CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
    
    // 1.创建bitmap;
    size_t width = CGRectGetWidth(extent) * scale;
    size_t height = CGRectGetHeight(extent) * scale;
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
    CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
    CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
    CGContextScaleCTM(bitmapRef, scale, scale);
    CGContextDrawImage(bitmapRef, extent, bitmapImage);
    
    // 2.保存bitmap到图片
    CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
    CGContextRelease(bitmapRef);
    CGImageRelease(bitmapImage);
    return [UIImage imageWithCGImage:scaledImage];
}

虽然是在ARC模式下,但不是什么东西都可以释放,例如上述的C-types对象,都需要手动来进行释放,所以上面的问题只需手动释放就可以了:CGImageRelease(scaledImage);
其它的如CoreFoundation对象有时候需要CFRelease,malloc/calloc等有时候需要free,还有标准IO fopen之类的需要fclose。

Infer

Facebook 的 [Infer] 是一个静态分析工具。Infer 可以分析 Objective-C, Java 或者 C 代码,报告潜在的问题。
可检测的 bug 类型:
C/OC中捕捉的bug类型

  • Resource leak
  • Memory leak
  • Null dereference
  • Premature nil termination argument

只在 OC中捕捉的bug类型

  • Retain cycle
  • Parameter not null checked
  • Ivar not null checked

工作机制

image.png

运行的两个阶段:

  1. 捕获阶段
    infer 捕获编译命令,将文件翻译成 Infer 内部的中间语言。

这种翻译和编译类似,Infer 从编译过程获取信息,并进行翻译。这就是我们调用 Infer 时带上一个编译命令的原因了,比如: infer -- clang -c file.c, infer -- javac File.java。结果就是文件照常编译,同时被 Infer 翻译成中间语言,留作第二阶段处理。特别注意的就是,如果没有文件被编译,那么也没有任何文件会被分析。

Infer 把中间文件存储在结果文件夹中,一般来说,这个文件夹会在运行 infer 的目录下创建,命名是 infer-out/。当然,你也可以通过 -o 选项来自定义文件夹名字:
infer -o /tmp/out -- javac Test.java
2.分析阶段
在分析阶段,Infer 分析 infer-out/ 下的所有文件。分析时,会单独分析每个方法和函数。

在分析一个函数的时候,如果发现错误,将会停止分析,但这不影响其他函数的继续分析。
所以你在检查问题的时候,修复输出的错误之后,需要继续运行 Infer 进行检查,知道确认所有问题都已经修复。
错误除了会显示在标准输出之外,还会输出到文件 infer-out/bug.txt 中,我们过滤这些问题,仅显示最有可能存在的。
在结果文件夹中(infer-out),同时还有一个 csv 文件 report.csv,这里包含了所有 Infer 产生的信息,包括:错误,警告和信息。

info优点
1:效率高,规模大,几分钟能扫描数千行代码;
2:支持增量及非增量分析(后边会解释)
3:分解分析,整合输出结果。(infer能将代码分解,小范围分析后再将结果整合在一起,兼顾分析的深度和速度)

安装
brew install infer
配置环境变量:
cd 你的代码文件路径//建议放到一个不常改动的位置
echo “export PATH=”$PATH:pwd/infer/infer/bin”” >> ~/.bash_profile &&source ~/.bash_profile
使用:
demo
下载后,找到 ios demo,cd命令进入ios_hello目录,然后运行以下命令进行编译
infer -- xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator
参考:more...,infer 中文网

OCLint

略.

你可能感兴趣的:(iOS静态分析)