infer

672 阅读3分钟

安装

brew install infer && infer --version

brew install sqlite && STATIC_DEPS=true sudo pip3 install lxml

使用

- 分析并输出结果

对于大型项目可能出错,建议先输出编译日志再进行分析

  1. 分析xcodeproj项目: $infer -- xcodebuild -project 项目名.xcodeproj -scheme 项目名 -configuration Release -sdk iphoneos

  2. 分析workspace项目: $infer -- xcodebuild -workspace 项目名.xcworkspace -scheme 项目名 -configuration Release -sdk iphoneos

  3. 分析iOS文件: $infer -- clang -c -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk   *.m

  4. 分析c文件: $infer -- clang -c ac.m

- 分析并输出json文件

  1. 输出编译日志

    xcodebuild -project 项目名.xcodeproj -scheme 项目名 -configuration Release -sdk iphoneos COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" | tee xcodebuild.log

  2. 格式化编译日志

    xcpretty -r json-compilation-database -o compile_commands.json < xcodebuild.log > /dev/null

  3. 输出分析报告

    直接输出:infer run --keep-going --skip-analysis-in-path Pods --compilation-database-escaped compile_commands.json

    xml格式:infer  --pmd-xml --keep-going --skip-analysis-in-path Pods --compilation-database-escaped compile_commands.json

    html格式:infer  --html --keep-going --skip-analysis-in-path Pods --compilation-database-escaped compile_commands.json

- 跳过分析指定target

在工程根目录下添加.inferconfig:

{
    "skip-analysis-in-path":[

        "Pods/AFNetworking",

        "Pods/Bugly"
    ]
}
{
        "skip-analysis-in-path":["Pods"]
}

分析出的问题类型:

变量未使用(dead_store)

为空判断

  • 空指针异常(Null Dereference):当一个对象声明后,没有初始化,就被引用了,这个时候会报空指针错误。

      - 传参为0的情况。例如代码中,在调用showAlertViewA()时,将tag传参为0,infer检测此处传0,判断为一个NULL空指针,所以爆出警告。这里可以理解为误报,不会出现问题。
    
      -   通过malloc,calloc,realloc等函数申请内存,当内存不足时,有可能会在该函数中返回NULL,如果没有做NULL的判断,则警告
    
      -   在创建NSArray或者NSDictionary时,传入的参数有可能会nil。由于NSArrayNSDictionary不接受空指针,所以在对其addObject或者setObject:forKey: 时需要进行判断一下是否为nil
    
  • 参数未判空(parameter_not_null_checked): 例如block未判空就进行调用。

  • 本地变量不为空的检查(Ivar not null checked)

方法调用

  • 调用可选方法前未做实现判断(unsafe_call_to_optional_method):例如直接调用[error debugDescription],debugDescription不一定实现导致崩溃。

循环引用

  • 循环引用(Retain cycle):内存死锁只存在OC中,A 创造B,B也创造了A,然后你等我,我等你,都无法释放

  • deleate属性为strong(STRONG_DELEGATE_WARNING):

  • 指针类型为assign(ASSIGN_POINTER_WARNING):

  • block中使用了强引用self(captured_strong_self):在block中使用了self,如果block被self强引用,会构成循环引用。

  • block中弱引用对象多次出现(multiple_weakself):此种情况下有可能代码执行过程中self被释放,执行流程非闭环,出现脏数据或资源泄漏等问题。

  • 内存泄漏 (Memory leak):内存泄漏的问题只在C/OC中报告

  • 资源泄漏(RESOURCE_LEAK)

闭环处理

  • nstimer置为无效

  • 通知注册后未删除(REGISTERED_OBSERVER_BEING_DEALLOCATED):创建一个对象后,监听了某些通知,但是没有在dealloc中释放该通知。项目中出现这种问题的类,基本都是单例,不会被销毁。

内存泄漏误报的情况:

__bridge:

CF和OC对象转化时只涉及对象类型不涉及对象所有权的转化。

OC->CF:

CGImageSourceRef source = (__bridge CFURLRef)(NSURL * url);

CF->OC:

__bridge_transfer:

常用在CF对象转化成OC对象时,将CF对象的所有权交给OC对象,此时ARC就能自动管理该内存,作用同CFBridgingRelease()

id obj = (__bridge_transfer id)p;其中obj为OC类,p为CF指针

__bridge_retained:

与__bridge_transfer 相反,常用在将OC对象转化成CF对象,且OC对象的所有权也交给CF对象来管理,即OC对象转化成CF对象时,涉及到对象类型和对象所有权的转化,作用同CFBridgingRetain()

void *p = (__bridge_retained void *)obj;其中obj为OC类,p为CF指针

QA

  • 路径中不能有中文