解决FORTIFY错误 --- FORTIFY: strchr: prevented read past end of buffer
导致bug的原因:在android中通过log输出发现char默认是无符号的(unsigned),所以在读取到文件结尾的时候,char c获取到的值转换成十进制的值应该是-1(EOF),由于char默认是无符号的,导致转换成十进制的值是255,所以一直没有读取到文件的结尾。FORTIFY是GCC和Clang编译器提供的一套安全扩展,通过替换标准库函数(如memcpy、strcpy、printf等)
报错信息:FORTIFY: strchr: prevented read past end of buffer
报错原因:表示编译器的FORTIFY_SOURCE安全机制检测到了潜在的缓冲区越界读取,并阻止了该操作
FORTIFY是GCC和Clang编译器提供的一套安全扩展,通过替换标准库函数(如memcpy、strcpy、printf等)为更安全的版本,在编译时和运行时插入边界检查,防止缓冲区溢出、格式化字符串漏洞、内存越界访问等错误
具体可以参考:https://source.android.google.cn/docs/core/tests/debug/native-crash?hl=zh-cn#fority
解决方法:在Android.mk中添加 LOCAL_CFLAGS += -D_FORTIFY_SOURCE = 0即可解决问题
① 当_FORTIFY_SOURCE=1时(默认值,编译时需配合 -O 优化选项),编译器会对 memcpy、strcpy 等危险函数进行替换,在运行时检查缓冲区长度,若发现溢出则触发错误。
② 当_FORTIFY_SOURCE=2时,检测更严格,甚至会主动崩溃以阻止潜在漏洞利用。
③ 当_FORTIFY_SOURCE=0时,完全关闭该安全特性,编译器不进行任何额外的缓冲区检查。
进一步解析:
在mk中指定C编译器额外参数的变量虽然能解决问题,但是是治标不治本,没有解决根本问题,只是将问题绕开而已
接下来带大家具体再解析一下,以后再遇到FORTIFY错误,可以套用此思路来解决
① 首先从报错信息来看是strchr()函数抛出的错误,先找到代码调用这个函数的位置
char *commit = strchr(buff, '#');
调用strchr()函数来查找字符'#'的位置
② 查看一下strchr()函数在android中的定义
/bionic/libc/bionic/strchr.cpp#strchr()
char* strchr(const char* p, int ch) {
return __strchr_chk(p, ch, __BIONIC_FORTIFY_UNKNOWN_SIZE);
}
/bionic/libc/bionic/fortify.cpp#__strchr_chk()
char* __strchr_chk(const char* p, int ch, size_t s_len) {
for (;; ++p, s_len--) {
if (__predict_false(s_len == 0)) {
__fortify_fatal("strchr: prevented read past end of buffer");
}
if (*p == static_cast<char>(ch)) {
return const_cast<char*>(p);
}
if (*p == '\0') {
return NULL;
}
}
}
传入的第二个参数,要查找的字符,如果在字符串中存在则返回指向这个字符的指针;如果不存在,则返回NULL
第三个参数,是当前检查位之后的buff大小,在下面的逻辑中递减(FORTIFY 安全拓展,防止越界访问)
③ 通过查看strchr()函数的定义可以明确是由于buff所指向的字符串可能没有以\0结尾(C 字符串必须以 \0 作为结束标志)
④ 所以查看一下buffer的赋值位置即可
具体代码的实现过程就不展示了,buffer实际上是由char c = fgetc(_this->fd);(挨个读取文件的字符)来构建的
⑤ 查看一下fgetc()函数的定义
/bionic/libc/stdio/stdio.cpp#fgetc()
int fgetc(FILE* fp) {
CHECK_FP(fp);
return getc(fp);
}
注意fgetc()的返回值类型是int类型
⑥ 在这里打印一下c的值
发现没有读取到data.yml文件的结尾(EOF文件结束符,值为-1),循环读取ASCII码值为255,并填充至buff的大小为止(问题就在这里了!)
导致bug的原因:在android中通过log输出发现char默认是无符号的(unsigned),所以在读取到文件结尾的时候,char c获取到的值转换成十进制的值应该是-1(EOF),由于char默认是无符号的,导致转换成十进制的值是255,所以一直没有读取到文件的结尾
⑦ bug对策方案:将char c定义成有符号的signed即可
signed char c = fgetc(_this->fd);
更多推荐



所有评论(0)