建议和规则

建议:

  • 理解数组的工作方式

  • 获取数组的长度时不要对指针应用sizeof操作符

  • 显示地指定数组的边界,即使它已经由初始化值列表隐式地指定

规则:

  • 保证数组索引位于合法的范围内

  • 在所有源文件中使用一致的数组记法

  • 保证变长数组的长度参数位于合法范围之内

  • 保证复制的目标具有足够的存储空间

  • 保证表达式中的数组类型是兼容的

  • 不允许循环迭代到数组尾部之后

  • 不要对两个并不指向同一个数组的指针进行相减或比较

  • 不要把一个指向非数组对象的指针加上或减去一个整数

  • 如果结果值并不引用合法的数组元素,不要把指针加上或减去一个整数

本文地址:http://www.cnblogs.com/archimedes/p/c-security-array.html,转载请注明源地址。

获取数组的长度时不要对指针应用sizeof操作符

代码:

void clear(int array[]) {
for(size_t i = ; i < sizeof(array) / sizeof(array[]); i++) {
array[i] = ;
}
}
void dowork(void) {
int dis[];
clear(dis);
/*...*/
}

clear()使用sizeof(array) / sizeof(array[0])这种用法确定这个数组的元素数量,但由于array是一个形参,因此它是指针类型,sizeof(array) = sizeof(int *) = 4  (32位OS)

当sizeof操作符应用于声明为数组或函数类型的形参时,它产生经过调整的(指针)类型的长度

解决方案:

void clear(int array[], size_t len) {
for(size_t i = ; i < len; i++) {
array[i] = ;
}
} void dowork(void) {
int dis[];
clear(dis, sizeof(dis) / sizeof(dis[]));
/*...*/
}

保证数组索引位于合法的范围内:

代码:

enum {TABLESIZE = };
int *table = NULL;
int insert_in_table(int pos, int value) {
if(!table) {
table = (int *)malloc(sizeof(int) *TABLESIZE);
}
if(pos >= TABLESIZE) {
return -;
}
table[pos] = value;
return ;
}

pos为int类型,可能为负数,导致在数组所引用的内存边界之外进行写入

解决方案:

enum {TABLESIZE = };
int *table = NULL;
int insert_in_table(size_t pos, int value) {
if(!table) {
table = (int *)malloc(sizeof(int) *TABLESIZE);
}
if(pos >= TABLESIZE) {
return -;
}
table[pos] = value;
return ;
}

在所有源文件中使用一致的数组记法

当在同一文件中时,void func(char *a);  和  void func(char a[]); 完全等价

但在函数原型之外,如果一个数组在一个文件中声明为指针,在另一个不同的文件中声明为数组,它们是不等价的

代码:

//main.c
#include<stdlib.h>
enum {ARRAYSIZE = };
char *a;
void insert_a(void);
int main(void) {
a = (char*)malloc(ARRAYSIZE);
if(a == NULL) {
//处理分配错误
}
insert_a();
return ;
}
//insert_a.c
char a[];
void insert_a(void) {
a[] = 'a';
}

解决方案:

//insert_a.h
enum {ARRAYSIZE = };
extern char *a;
void insert_a(void); //insert_a.c
#include "insert_a.h"
char *a;
void insert_a(void) {
a[] = 'a';
} //main.c
#include<stdlib.h>
#include"insert_a.h"
int main(void){
a = (char*)malloc(ARRAYSIZE);
if(a == NULL) {
//处理分配错误
}
insert_a();
return ;
}

保证变长数组的长度参数位于合法范围之内

代码:

void func(size_t s) {
int vla[s];
/*...*/
}
/*...*/
func(size);
/*...*/

解决方案:

enum {MAX_ARRAY = };
void func(size_t s) {
if(s < MAX_ARRAY && s != ) {
int vla[s];
/*...*/
} else {
//错误处理
}
}
/*...*/
func(size);
/*...*/

保证复制的目标具有足够的存储空间

代码:

enum {WORKSPACE_SIZE = };
void func(const int src[], size_t len) {
int dest[WORKSPACE_SIZE];
if(len > WORKSPACE_SIZE) {
//错误处理
}
memcpy(dest, src, sizeof(int) * len);
/*...*/
}

保证表达式中的数组类型是兼容的

代码:

enum {a = , b = , c = };
int arr1[c][b];
int (*arr2)[a];
arr2 = arr1; //不匹配 a != b

解决方案:

enum {a = , b = , c = };
int arr1[c][b];
int (*arr2)[a];
arr2 = arr1; //匹配 a == b

不要把一个指向非数组对象的指针加上或减去一个整数

代码:

struct numbers {
short num1;
short num2;
/*...*/
short num9;
};
int sum_numbers(const struct numbers *numb) {
int total = ;
const int *numb_ptr;
for(numb_ptr = &numb->num1; numb_ptr <= &numb->num9; numb_ptr++) {
total += *(numb_ptr);
}
return total;
}
int main(void) {
struct numbers my_numbers = {,,,,,,,,};
sum_numbers(&my_numbers);
return ;
}

上面的代码试图用指针运算访问结构的元素,这是危险的,因为结构中的字段并不保证在内存中是连续的

解决方案(使用数组):

struct numbers {
short num1;
short num2;
/*...*/
short num9;
};
int sum_numbers(const short *numb, size_t dim) {
int total = ;
const int *numb_ptr;
for(numb_ptr = numb; numb_ptr < numb + dim; numb_ptr++) {
total += *(numb_ptr);
}
return total;
}
int main(void) {
short my_numbers[] = {,,,,,,,,};
sum_numbers(my_numbers, sizeof(my_numbers) / sizeof(my_numbers[]));
return ;
}

参考资料

《C安全编码标准》

最新文章

  1. Nginx编译安装(Centos)
  2. 线性表-双向链表(LinkedList)
  3. VBS数组
  4. POJ 1552
  5. 【开源项目之路】jquery的build问题
  6. asp.net 通过ajax方式调用webmethod方法使用自定义类传参及获取返回参数
  7. QSettings介绍
  8. file is missing from source location:c\temp\batang.ttc
  9. UIApplication 常用方法
  10. linux共享windows资料
  11. jsxtransformer.js 和browser.js有什么关系?
  12. theOS环境搭建
  13. 数据库之Oracle——初级
  14. Java之泛型编程
  15. solr 学习笔记1
  16. 谈lisp
  17. 洛谷P3919 【模板】可持久化数组(可持久化线段树/平衡树)
  18. http指南(2)--代理
  19. luogu P2596 [ZJOI2006]书架
  20. 2018/04/14 理解oAuth2.0

热门文章

  1. ListView具有多种item布局——实现微信对话列
  2. JavaScript备忘录(1)——内置类型
  3. 【转】Linux下svn常用指令
  4. php分享三十三:用php中的register_shutdown_function和fastcgi_finish_request
  5. [Design Patterns] 1. Primary concept &amp; term - UML
  6. MySQL安全问题(防范必知)
  7. CentOS6.5菜鸟之旅:安装SUN JDK1.7和Tomcat7
  8. angular设置title
  9. P6 Enterprise Project Portfolio Contract Management
  10. Dev gridView中设置自适应列宽和日期显示格式、金额的显示格式