一 概述
二 类型
三 语句
四 函数
五 数据
六 内存
七 代码
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
安全
安全编程也称作 防御性编程 (defensive programming),核心理念是不对函数调用和库使用做任何假设。
断言
用断言对输入输出数据进行检查,尽可能在调试或测试阶段找出自己或调用方潜在问题。以 NDEBUG 宏控制,不会影响发行版(release)性能。
#ifdef NDEBUG #define assert(condition) ((void)0) #else #define assert(condition) /*implementation defined*/ #endif
$ gcc -DNDEBUG -g -o test main.c
还可用 static_assert
进行编译期检查,比如某些结构体字段位置(offset)不能改变等。不会生成指令。
建议
编码常见安全问题清单。
- 使用常量代替字面量。(
MIN = 10, MAX = MIN + 90
) - 尝试用 typedef 提高可读性。(函数类型)
- 用括号保证优先级。
- 不要依赖跨单元的初始化顺序。
- 不要在子作用域中复用变量名。(尤其是全局变量名命名)
- 不要在一个声明中超过一个变量。(
int *p, x
) - 不要引用未初始化内存。
- 不被导出的对象声明为 static。
- 不被修改的参数声明为 const。
- 不要忽略函数返回值。
- 打开高警告级别,尝试通过代码修改消除警告。
- 断言的副作用。(不要在 assert 表达式执行
++
等操作,断言可被忽略) - 指针长度和指针目标长度的差别。(
sizeof(ptr)
,sizeof(*ptr)
) - 不要在另一个线程中解锁。
- 结构长度和结构成员长度总和的差别。(对齐)
- 不要通过字节对比来判断结构是否相同,因为填充字节内容未定。
- 获取数组长度时,需要知道当前是数组名还是指针。
- 避免数组越界。
- 函数签名区别指针和数组。(
int *d
vsint d[]
)
- 字符串结束方式,是有长度计数,还是结束标记。
- 字符串是否可被修改,子串如何返回?是否共享内存?
- 如果引用字符串常量,建议使用 const 表示不能修改(编译器检查)。
- 在相同单元里处理内存申请和分配。(malloc, free)
- 调用 free 后,将指针赋值为 NULL。
- 内存敏感信息处理。
(释放前覆盖 memset,避免被交换 mlock,避免 realloc 异地分配留下副本) - 警惕编译器优化掉安全措施。
(比如认为 memset 覆盖清除无意义,被忽略,可在后面继续引用) - 禁止被 core dump。(setrlimit CORE, 0)
- 小心使用伪随机数。(安全攻击)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论