C语言安全编码(1)
保证不同背景和经历的开发人员可以良好的协同开发
保证组织级的开发技能和经验得以共享和传承
1.对象的持续期
(1)例1.1:不同的生命周期
1// 例1.1
2char *p;
3void func()
4{
5 char str[] = "abcdefg";
6 p = str; // error
7}
8
9int main()
10{
11 func();
12 printf("%s\n",p)
13 return 0;
14}
1// 例1
2// p和str的持续时间是一致的
3void func()
4{
5 char str[] = "abcdefg";
6 char *p = str;
7}
1// 在str被销毁之前设置p为NULL,防止p取不确定值
2char *p;
3void func()
4{
5 char str[] = "abcdefg";
6 p = str; // error
7 /*...*/
8 p = NULL;
9}
(2)例1.2:返回值
1// 例1.2
2char* func()
3{
4 char arr[5];
5 /*.....*/
6 return arr;
7}
1// 需要修改arr的值,应该以地址的方式传递给函数
2// 这样才能让arr在函数外得以保持
3void func(char* arr, size_t len)
4{
5 /*......*/
6 return;
7}
(3)例1.3:输出参数
1// 例1.3
2void fun1(char **ptr)
3{
4 char arr[10];
5 /*...*/
6 *ptr = arr;
7}
8
9void fun2()
10{
11 char *p;
12 func1(&p);
13}
1// 将变量arr定义为全局变量
2char arr[10];
3void fun1(char **ptr)
4{
5 /*...*/
6 *ptr = arr;
7}
8
9void fun2()
10{
11 char *p;
12 func1(&p);
13}
2.禁止访问未初始化的内存
(1)例2.1:Return by Reference
1//例2.1
2void func(int n, int *p)
3{
4 if(p == NULL) {
5 return;
6 }
7
8 if(n > 0) {
9 *p = 1;
10 }
11 else if(n < 0) {
12 *p = 2;
13 }
14}
15
16int call(int num)
17{
18 int flag;
19 func(num, flag);
20 return num;
21}
1void func(int n, int *p)
2{
3 if(p == NULL) {
4 return;
5 }
6
7 if(n >= 0) { // 增加等于0的情况
8 *p = 1;
9 }
10 else if(n < 0) {
11 *p = 2;
12 }
13}
(2)例2.2:uninitialized local
1//例2.2
2#define BUF_SIZE 24
3void myprint(char *msg)
4{
5 const char *log = msg;
6 char buf[BUF_SIZE];
7
8 sprintf(buf,"%s\n", log);
9 printf("%s\n", buf);
10}
1#define BUF_SIZE 24
2void myprint(char *msg)
3{
4 char buf[BUF_SIZE];
5
6 // 调用snprintf()消除缓存区溢出
7 if(0 < snprintf(buf, BUF_SIZE,"%s\n", msg)) {
8 printf("%s\n", buf);
9 }
10 else {
11 printf("ERROR\n");
12 }
13}
1//例2.3
2#include <string.h>
3#include <wchar.h>
4
5void func(char *msg)
6{
7 size_t len;
8 mbstste_t state;
9 len = mbrlen(msg, strlen(msg), &state);
10}
对于上面的情况,合适的处理方法如下:
1void func(char *msg)
2{
3 size_t len;
4 mbstste_t state;
5 memset(&state, 0, sizeof(state)); // 将mbstate_t对象初始化为0
6 len = mbrlen(msg, strlen(msg), &state);
7}
1#define OLDSIZE 10
2#define NEWSIZE 20
3int func_array(int *arr, int count)
4{
5 if(count == 0) {
6 return 0;
7 }
8 int *res = (int *)realloc(arr, count * sizeof(int));
9 if(res == NULL) {
10 free(res);
11 return 0;
12 }
13 return res;
14}
15
16void func()
17{
18 int *array = (int *)malloc(OLDSIZE * sizeof(int));
19 if(array == NULL) {
20 /* error */
21 }
22
23 for(int i = 0; i < OLDSIZE; i++){
24 array[i]=i + 1;
25 }
26
27 array = func_array(array, NEWSIZE);
28 if(array == NULL) {
29 /* error */
30 }
31
32 for(int i = 0; i < NEWSIZE; i++){
33 printf("%d ",array[i]);
34 }
35}
这段代码中,realloc()函数改变动态分配的内存的大小,返回内存对象最初的size个字节没有变化,但新添加空间没有初始化,其值不确定。
对于上面的情况,合适的处理方法如下:
1#define OLDSIZE 10
2#define NEWSIZE 20
3// 第二个参数作为旧的长度
4int func_array(int *arr, int oldcount, int newcount)
5{
6 if(newcount == 0) {
7 return 0;
8 }
9 int *res = (int *)realloc(arr, newcount * sizeof(int));
10 if(res == NULL) {
11 free(res);
12 return 0;
13 }
14
15 if(newcount > oldcount) {
16 memset(res + oldcount, 0, (newcount - oldcount) * sizeof(int));
17 }
18
19 return res;
20}
1void func(char *str)
2{
3 int len = strlen(str) + 1;
4 char *c_str = (char *)malloc(len);
5 memcpy(c_str, str, len);
6 /*...*/
7}
这段代码中,str拷贝给c_str指向的动态分配内存,但如果malloc()失败,c_str=NULL,此时运行memcpy会出现未定义行为。
对于上面的情况,合适的处理方法如下:
1void func(char *str)
2{
3 if(str == NULL) { // 确保str指针不是NULL
4 /* error */
5 }
6
7 int len = strlen(str) + 1;
8 char *c_str = (char *)malloc(len);
9 if(c_str == NULL) { // 确保malloc返回值不是NULL
10 /* error */
11 }
12
13 memcpy(c_str, str, len);
14 /*...*/
15}