背景
前一段时间赶工修一个段错误
的BUG,修复后代码不再有段错误,但却会导致板子软件与上位机断链,而且还是概率性的。
经过一周的排查,原来是修BUG时引入一个传参错误,给期待struct *
形参的函数传了个struct **
的实参,导致踩内存
,又因为赶工,没仔细看编译告警,于是坑了自己。
复现过程
复现代码:
#include<stdio.h>
void change_info(int *p) // 形参期待一级指针
{
*p = 42;
}
int main() {
int a = 0;
int *pa = &a;
printf("a == %d\n", a);
change_info(&pa); // 实参传递二级指针,会导致内存访问越界,即踩内存!
printf("a == %d\n", a);
return 0;
}
上面代码gcc编译通过,但有告警,说指针类型不匹配:
isp@ax:~/demo$ gcc test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘main’:
test_2nd_ptr2.c:13:17: warning: passing argument 1 of ‘change_info’ from incompatible pointer type [-Wincompatible-pointer-types]
change_info(&pa);
^
test_2nd_ptr2.c:3:6: note: expected ‘int *’ but argument is of type ‘int **’
void change_info(int *p)
^~~~~~~~~~~
如果编译的文件很多,很容易忽略这些告警
上面问题代码的运行效果:
isp@ax:~/demo$ ./a.out
a == 0
a == 0
如何规避
- 用g++编译器无此问题,直接报error
isp@ax:~/demo$ g++ test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘int main()’:
test_2nd_ptr2.c:13:18: error: invalid conversion from ‘long long int’ to ‘int*’ [-fpermissive]
change_info(l);
^
test_2nd_ptr2.c:3:6: note: initializing argument 1 of ‘void change_info(int*)’
void change_info(int *p)
^~~~~~~~~~~
test_2nd_ptr2.c:15:20: error: cannot convert ‘int**’ to ‘int*’ for argument ‘1’ to ‘void change_info(int*)’
change_info(&pa);
^
- 给gcc传递
-Werror
选项也能避免此问题
isp@ax:~/demo$ gcc -Werror test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘main’:
test_2nd_ptr2.c:13:17: error: passing argument 1 of ‘change_info’ from incompatible pointer type [-Werror=incompatible-pointer-types]
change_info(&pa);
^
test_2nd_ptr2.c:3:6: note: expected ‘int *’ but argument is of type ‘int **’
void change_info(int *p)
^~~~~~~~~~~
cc1: all warnings being treated as errors
- 给指针字段添加
p_
之类的前缀,便于提醒自己
后记
我试了好几种不兼容的指针类型传递,都能编译通过,可见只要参数size匹配就不会报错。
对于非指针类型的参数,一般情况下size不同,此时会报错,但如果是内置类型,则size不同也不会报错,因为会自动向上取整或截断。