【学习】安全编程之“变量”篇

规则1:指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值

变量声明赋予初值,可以避免由于编程人员的疏忽导致的变量未初始化引用。
示例:

1. SOCKET s = INVALID_SOCKET;
2. unsigned char *msg = NULL;
3. BOOL success = FALSE;
4. int fd = -1;

以下代码,由于变量声明未赋予初值,在最后free的时候出错。(ps:相当于释放野指针了)

1. char *message; // 错误!必须声明为 char *message = NULL;
2. ...
3. if (condition) {
4. message = (char *)malloc(len);
5. ...
6. }
7. ...
8. if (message != NULL) {
9. free(message); //如果condition未满足,会造成free未初始化的内存。
10. }

例外1: 对全局变量,静态变量,在编译阶段自动初始化为0或者等于NULL,不用在定义时强制初始化。 例如:

1. OS_SEC_BSS TICK_ENTRY_FUNC g_pfnTickTaskEntry;
2. OS_SEC_BSS volatile UINT64 g_ullSleepTime;
3. OS_SEC_BSS volatile UINT64 g_ullSleepBegin;
4. OS_SEC_BSS volatile UINT64 g_ullSleepEnd;
规则2:指向资源句柄或描述符的变量,在资源释放后立即赋予新值

资源释放后,对应的变量应该立即赋予新值,防止后续又被重新引用。如果释放语句刚好在变量作用域的最后一句,可以不进行赋值。
示例:

1. SOCKET s = INVALID_SOCKET;
2. unsigned char *msg = NULL;
3. int fd = -1;
4. ...
5. closesocket(s);
6. s = INVALID_SOCKET;
7. ...
8. free(msg);
9. msg = (unsigned char *)malloc(...); //msg变量又被赋予新值
10. ...
11. close(fd);
12. fd = -1;
13. ...
规则3:类的成员变量必须在构造函数中赋予初值

如果类中声明了变量,则必须在构造函数中对变量进行赋值。
示例:

1. class CMsg {
2. public:
3.     CMsg();
4.     ~CMsg();
5. protected:
6.     int size;
7.     unsigned char *msg;
8. };
9.
10. CMsg::CMsg()
11. {
12.     size = 0;
13.     msg = NULL;
14. }
规则4:严禁对指针变量进行sizeof操作

编码人员往往由于粗心,将指针当做数组进行sizeof操作,导致实际的执行结果与预期不符。 下面的代码,buffer和path分别是指针和数组,编码人员想对这2个内存进行清0操作,但由于编码人员的疏忽,第5行代码,将内存大小误写成了sizeof,与预期不符。

1. char *buffer = (char *)malloc(size);
2. char path[MAX_PATH] = {0};
3. ...
4. memset(path, 0, sizeof(path));
5. memset(buffer, 0, sizeof(buffer));

如果要判断当前的指针类型大小,请使用sizeof(char *)的方式。

建议1:尽量使用const

在变量声明前加const关键字,表示该变量不可被修改,这样就可以利用编译器进行类型检查,将代码的权限降到更低。 例如下面是不好的定义:

1. float pi = 3.14159f;

应当这样定义:

1. const float PI = 3.14159f;
建议2:全局变量的访问如果涉及多个线程,需要考虑多线程竞争条件问题

应该尽可能减少全局变量的使用,如果多个线程会访问到该全局变量,则访问过程必须加锁。 以下代码中,g_list是全局变量,对链表进行搜索操作时,在while循环语句的前后加锁。

1. ItemList *g_list = NULL;
2.
3. ItemList *SearchList(const char *name)
4. {
5.     Lock();
6.
7.     ItemList *p = g_list;
8.
9.     while (p != NULL) {
10.     if (strcmp(p->name, name) == 0) {
11.         break;
12.     }
13.     p = p->next;
14.     }
15.
16.     UnLock();
17.
18.     return p;
19. }

性能敏感的代码,请考虑采用原子操作或者无锁算法。

建议3:同一个函数内,局部变量所占用的空间不要过大

程序在运行期间,函数内的局部变量保存在栈中,栈的大小是有限的。如果申请过大的静态数组,可能导致出现运行出错。 建议在申请静态数组的时候,大小不超过0x1000。 下面的代码,buff申请过大,导致栈空间不够,程序发生stackoverflow异常。

1. #define MAX_BUFF 0x1000000
2. int Foo()
3. {
4. char buff[MAX_BUFF] = {0};
5. ...
6. }

参考:gitcode社区-开源文档-菊厂C&C++安全编程规范

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容