作者介绍:王竞原,负责网游刀锋铁骑项目,使用C++10年左右,非常喜欢使用C++,特别是C++11。希望能与广大的C++爱好者多交流。

一、什么是Android的C/C++ NativeCrash

Android上的Crash可以分两种:

1、Java Crash
Java代码导致jvm退出,弹出“程序已经崩溃”的对话框,最终用户点击关闭后进程退出。
Logcat 会在“AndroidRuntime”tag下输出Java的调用栈。

2、Native Crash
通过NDK,使用C/C++开发,导致进程收到错误信号,发生Crash,Android 5.0之前进程直接退出(闪退) , Android 5.0之后会弹“程序已崩溃”的对话框。

Logcat 会在“debug”tag下输出dump信息:

  • 错误信号:11是信号量sigNum,SIGSEGV是信号的名字,SEGV_MAPERR是SIGSEGV下的一种类型。
  • 寄存器快照:进程收到错误信号时保存下来的寄存器快照,其中PC寄存器存储的就是下个要运行的指令(出错的位置)。
  • 调用栈:#00是栈顶,#02是栈底,#02调用#01调用#00方法,#00的方法时libspirit.so中的Spirit类下的testCrash方法,出错的地方是testCrash方法内汇编偏移17(不是行号哦!)

二、什么是错误信号

Android本质就是一个Linux,信号跟Linux信号是同一个东西,信号本身是用于进程间通信的没有正确错误之分,但官方给一些信号赋予了特定的含义及特定处理动作,

通常我们说的错误信号有5个(Bugly全部都能上报),系统默认处理就是dump出堆栈,并退出进程:

通常的来源有三个:
1、硬件发生异常,即硬件(通常是CPU)检测到一个错误条件并通知Linux内核,内核处理该异常,给相应的进程发送信号。硬件异常的例子包括执行一条异常的机器语言指令,诸如,被0除,或者引用了无法访问的内存区域。大部分信号如果没有被进程处理,默认的操作就是杀死进程。在本文中,SIGSEGV(段错误),SIGBUS(内存访问错误),SIGFPE(算数异常)属于这种信号。

2、进程调用的库发现错误,给自己发送中止信号,默认情况下,该信号会终止进程。在本文中,SIGABRT(中止进程)属于这种信号。

3、用户(手贱)或第三方App(恶意)通过kill-信号 pid的方式给错误进程发送,这时signal中的si_code会小于0。

三、抖几个常见错误

1. 空指针

代码示例

int* p = 0; //空指针
*p = 1; //写空指针指向的内存,产生SIGSEGV信号,造成Crash

原因分析

在进程的地址空间中,从0开始的第一个页面的权限被设置为不可读也不可写,当进程的指令试图访问该页面中的地址时(如读取空指针指向的内存),处理器就会产生一个异常,然后Linux内核会给该进程发送一个段错误信号(SIGSEGV),默认的操作就是杀死进程,并产生core文件。

解决方法

在使用指针前加以判断,如果为空,则是不可访问的。

Bug评述

空指针是很容易出现的一种bug,在代码量大,赶开发进度时很容易出现,但是它也很容易被发现和修复。

2. 野指针

代码示例

int* p; //野指针,未初始化,其指向的地址通常是随机的
*p = 1; //写野指针指向的内存,有可能不会马上Crash,而是破坏了别处的内存

原因分析

野指针指向的是一个无效的地址,该地址如果是不可读不可写的,那么会马上Crash(内核给进程发送段错误信号SIGSEGV),这时bug会很快被发现。
如果访问的地址为可写,而且通过野指针修改了该处的内存,那么很有可能会等一段时间(其它的代码使用了该处的内存后)才发生Crash。这时查看Crash时显示的调用栈,和野指针所在的代码部分,有可能基本上没有任何关联。

解决方法

  1. 在指针变量定义时,一定要初始化,特别是在结构体或类中的成员指针变量。
  2. 在释放了指针指向的内存后,要把该指针置为NULL(但是如果在别的地方也有指针指向该处内存的话,这种方式就不好解决了)。
  3. 野指针造成的内存破坏的问题,有时候光看代码很难查找,通过代码分析工具也很难找出,只有通过专业的内存检测工具,才能发现这类bug。

Bug评述

野指针的bug,特别是内存破坏的问题,有时候查起来毫无头绪,没有一点线索,让开发者感觉到很茫然和无助( Bugly上报的堆栈看不出任何问题)。可以说内存破坏bug是服务器稳定性最大的杀手,也是C/C++在开发应用方面相比于其它语言(如Java, C#)的最大劣势之一。

3. 数组越界

代码示例

int arr[10];
arr[10] = 1; //数组越界,有可能不会马上Crash,而是破坏了别处的内存

原因分析

数组越界和野指针类似,访问了无效的地址,如果该地址不可读写,则会马上Crash(内核给进程发送段错误信号SIGSEGV),如果修改了该处的内存,造成内存破坏,那么有可能会等一段时间才在别处发生Crash。

解决方法

  1. 所有数组遍历的循环,都要加上越界判断。
  2. 用下标访问数组时,要判断是否越界。
  3. 通过代码分析工具可以发现绝大部分的数组越界问题。

Bug评述

数组越界也是一种内存破坏的bug,有时候与野指针一样也是很难查找的。

4. 整数除以零

代码示例

int a = 1;
int b = a / 0; //整数除以0,产生SIGFPE信号,导致Crash

原因分析

整数除以零总是产生SIGFPE(浮点异常,产生SIGFPE信号时并非一定要涉及浮点算术,整数运算异常也用浮点异常信号是为了保持向下兼容性)信号,默认的处理方式是终止进程,并生成core文件。

解决方法

在做整数除法时,要判断被除数是否为0的情况。

Bug评述

整数被0除的bug很容易被开发者忽视,因为通常被除数为0的情况在开发环境下很难出现,但是到了生产环境,庞大的用户量和复杂的用户输入,就很容易导致被除数为0的情况出现了。

5. 格式化输出参数错误

代码示例

//格式化参数错误,可能会导致非法的内存访问,从而造成宕机
char text[200];
snprintf(text,200,"Valid %u, Invalid %u %s", 1);//format格式不匹配

原因分析

格式化参数错误也和野指针类似,但是只会读取无效地址的内存,而不会造成内存破坏,因此其结果是要么打印出错乱的数据,要么访问了无读写权限的内存(收到段错误信号SIGSEGV)而立即宕机。

解决方法

  1. 在书写输出格式和参数时,要做到参数个数和类型都要与输出格式一致。
  2. 在GCC的编译选项中加入-wformat,让GCC在编译时检测出此类错误。

6、缓冲区溢出

代码示例

char szBuffer[10];
//由于函数栈是从高地址往低地址创建,而sprintf是从低地址往高地址打印字符,
//如果超出了缓冲区的大小,函数的栈帧会被破坏,在函数返回时会跳转到未知的地址上,
//基本上都会造成访问异常,从而产生SIGABRT或SIGSEGV,造成Crashsprintf(szBuffer, "Stack Buffer Overrun!111111111111111"  "111111111111111111111");

原因分析

通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏函数调用的堆栈,修改函数调用的返回地址。如果不是黑客故意攻击,那么最终函数调用很可能会跳转到无法读写的内存区域,产生段错误信号SIGSEGV或SIGABRT,造成程序崩溃,并生成core文件。

解决方法

  1. 检查所有容易产生漏洞的库调用,比如sprintf,strcpy等,它们都没有检查输入参数的长度。
  2. 使用带有长度检查的库调用,如用snprintf来代替sprintf,或者自己在sprintf上封装一个带长度检查的函数。
  3. 在GCC编译时,在-O1以上的优化行为下,使用-D_FORTIFY_SOURCE=level进行编译(其中level=1或2,level代表的是检测级别的不同,数值越大越严格)。这样GCC会在编译时报告缓冲区溢出的错误。
  4. 在GCC编译时加上-fstack-protector或-fstack-protector-all选项,使得堆栈保护(stack-smashingprotector, SSP)功能生效。该功能会在编译后的汇编代码中插入堆栈检测的代码,并在运行时能够检测到栈破坏并输出报告。

Bug评述

缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。黑客在进行攻击时,输入的字符串一般不会让程序崩溃,而是修改函数的返回地址,使程序跳转到别的地方,转而执行黑客安排好的指令,以达到攻击的目的。
缓冲区溢出后,调试生成的core,可以看见调用栈是混乱的,因为函数的返回地址已经被修改到随机的地址上去了。
服务器宕机后,如果core文件和可执行文件是匹配的,但是调用栈是错乱的,那么很大的可能性是发生了缓冲区溢出。

7、主动抛出异常

代码示例

  if ((*env)->ExceptionOccurred(env) != 0) {//动态库在内部运行出现错误时,大都会主动abort,终止运行abort(); //给当前进程发送信号SIGABRT}

解决方法

查看堆栈找出abort的原因

Bug评述

如果是程序主动abort的,通过堆栈加源码还是很好定位的,但往往abort的位置是在系统库中,就不好定位了,需要多查看系统API的使用方法,检查是否使用不当。

转载于:https://www.cnblogs.com/chenliyang/p/6558838.html

常见Android Native崩溃及错误原因相关推荐

  1. Android应用解析包错误原因的总结(不定时更新)

    Android应用解析包错误的原因 导致这个问题的原因目前就我所知道的而言大致有三种(其他原因请看文章末尾): 一.使用v1.v2方式签名带来的问题 二.Android7.0新特性导致的原因 三.应用 ...

  2. Android Native Crash崩溃及错误原因分析二-实战解决

    一. 简述 之前有一篇文章讲诉了Android实际开发过程中一些崩溃的原因,以及对崩溃类型做了详细的介绍,简单回顾一下:Crash类型:Java和Native,JavaCrash中明显会打印出Andr ...

  3. android ndk 段错误,android crash之段错误原因及分析方法

    在解决app/frameworks客户问题的过程中经常碰到段错误的问题,在Aplog中搜索fatal关键字会碰到类似F/libc    ( 6721): Fatal signal 11 (SIGSEG ...

  4. 爬虫:常见的HTTP错误代码及错误原因

    状态码 含义 解释 100 继续 请求者应当继续提出请求 服务器已收到请求的一部分,正在等待其余部分 101 切换协议 请求者已要求服务器切换协议,服务器已确认并准备切换 200 成功 服务然已成功处 ...

  5. android r文件错误,Android R文件丢失异常原因汇总

    Console报错:R.java was modified manually! Reverting to generated version! 引言: R文件丢失异常在java开发中是个比较常见的异常 ...

  6. android+程序崩溃,Android平台程序崩溃的类型及原因列举

    Android平台程序崩溃大家都应该遇到过,force close和ANR应该是大家遇到较多的. 这里把Android平台程序崩溃的各种类型做一个简述和原因列举. 1.ANR(可见ANR): 发生场景 ...

  7. Android APP native 崩溃分析之 linker SIGBUS 崩溃

    原文地址:https://caikelun.io/post/2019-05-31-android-app-native-crash-linker-sigbus/ 这是 Android APP nati ...

  8. ASP.NET常见错误,原因及解决方法(2003版)_不断更新.....

    [标题]             ASP.NET常见错误,原因及解决方法[错误提示]    异常详细信息: System.Net.WebException: 请求因 HTTP 状态 401 失败:Un ...

  9. TCP/IP 某些最常见的错误原因码 (errno)列表

    TCP/IP 某些最常见的错误原因码 (errno)列表 对于在基于 UNIX 的环境中的 TCP/IP 用户,下表列出了某些最常见的错误原因码 (errno).它不是完整的错误列表.可以在文件 /u ...

最新文章

  1. 女子质疑无限极产品致女儿心肌损害:将继续维权讨说法
  2. Google研究员Ilya Sutskever:成功训练LDNN的13点建议
  3. CentOS 编译安装 Nodejs (实测 笔记 Centos 7.3 + node 6.9.5)
  4. matlab机器人自动分拣_极智嘉分拣系统落地 助力打造智慧物流引擎
  5. QT 应用程序关闭某个窗口时,关闭打开的所有其他窗口并退出程序 【转】
  6. 时间处理:计算下一天日期,如输入2004/12/31(注释2014年12月31日),则输出2005/1/1....
  7. 协议 - 收藏集 - 掘金
  8. 当产品部署出现问题时
  9. 关于STM32没有硬件浮点单元的纯经验之谈,是否可以在stm32上用float运算?
  10. 数据看板是什么,怎么做?
  11. springmvc GET POST 接受参数方式
  12. android调用截屏功能,调用安卓原生的截图功能
  13. 跨平台开发 uni-app
  14. 锅炉软化水不合格是怎么回事?该如何解决?
  15. oracle 中处理标准差的问题
  16. 协同数据交换平台详细设计方案(word)
  17. 喜报 | 冠骋信息获2022年苏州市工程技术研究中心认定
  18. 【飞郁2022新课程】31 - OD更多技巧
  19. 子线程更新UI,牵扯activity的启动过程
  20. 腾讯、阿里、小米...互联网企业进入组织架构调整期

热门文章

  1. HDOJ 1098 Ignatius's puzzle
  2. 解决“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”(转贴)...
  3. EPSON机器人_SPEL+语言
  4. python程序设计梁勇 百度网盘_20194220 2019-2020-2 《Python程序设计》实验二报告
  5. java播放器使用教程_java 实现音乐播放器的简单实例
  6. 特征值与特征向量_矩阵的特征值和特征向量
  7. 任意的android程序,Android任意位置获取应用Context
  8. 14.Python抠图脚本
  9. weblogic部署静态资源文件html,如何使用Spring的mvc提供静态资源:WebLogic上的资源?...
  10. suse linux c 编译环境,SUSE 11中安装GCC开发环境