建议和规则
建议:
理解数组的工作方式
获取数组的长度时不要对指针应用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安全编码标准》
C安全编码--数组的更多相关文章
-
php从接口获取数据转成可以用的数组或其他(含转换编码)
程序开发,时常会用到将接口的json数据转换成程序可以用的,因为今天看到一个比较好的程序,贴上来,以备随时查看: /** * 将对象转成数组,并按要求转换编码 * * @param array $ar ...
-
YTU 3027: 哈夫曼编码
原文链接:https://www.dreamwings.cn/ytu3027/2899.html 3027: 哈夫曼编码 时间限制: 1 Sec 内存限制: 128 MB 提交: 2 解决: 2 ...
-
将汉字转化为拼音,正则表达式和得到汉字的Unicode编码
一:上图,不清楚的看代码注解,很详细了 二:具体代码 窗体代码 using System; using System.Collections.Generic; using System.Compone ...
-
IO流(随机流,数组内存流
File file1=new File("test1.txt"); RandomAccessFile in2=new RandomAccessFile(file1,"rw ...
-
Base64编码的java实现
Java本身是提供了Base64编码的工具包的,做项目的时候自己实现了个,在这里记录一下: /** Base64编码数组 */ private static final String base64En ...
-
Asterisk1.8 sip编码协商分析
在开始分析之前,先对编码协商中可能涉及的asterisk数据结构和变量作些说明.ast_channel:定义一个通用的通道数据结构 struct ast_channel { const struct ...
-
PHP保存数组到数据库
数组是 PHP 开发中使用最多的数据类型之一,对于结构化的数据尤为重要. 很多时候我们需要把数组保存到数据库中,实现对结构化数据的直接存储和读取. 其中一个案例就是,对于 Form 提交的多选 che ...
-
图论:Prufer编码
BZOJ1211:使用prufer编码解决限定结点度数的树的计数问题 首先学习一下prufer编码是干什么用的 prufer编码可以与无根树形成一一对应的关系 一种无根树就对应了一种prufer编码 ...
-
c# 自定义Base16编码解码
一.自定义Base16编码原理 Base16编码跟Base64编码原理上有点不同,当然前面转换是一样的,都是是将输入的字符串根据默认编码转换成一 ...
随机推荐
-
ajax post提交form表单 报400错误 解决方法
昨天晚上做项目遇到了一个奇怪的问题,我用ajax提交一个form表单,后台Java方法用的是一个实体接,但是他根本不进方法体中,直接给我一个400的错误,一开始我以为是我路径的问题(尴尬),结果直接访 ...
-
Less环境搭建
1.在页面中加入 .less 样式表的链接,并将 rel 属性设置为 "stylesheet/less": <link rel="stylesheet/less&q ...
-
C# Reflection BindingFlags
定义包含在搜索中的成员 下列 BindingFlags 筛选标志可用于定义包含在搜索中的成员: 为了获取返回值,必须指定 BindingFlags.Instance 或 BindingFlags.St ...
-
zoj 3962 Seven Segment Display 数位dp
非常好的一个题,可以比赛时想到的状态太奇葩,不方便转移,就一直没能AC. 思路:dp(i, j)表示已经考虑了前i位,前i位的和为j的贡献.如果当前的选择一直是最大的选择,那么就必须从0~下一位的最大 ...
-
mysql数据库字段内容替换
UPDATE 表名 SET 字段名= replace(字段名, '查找内容', '替换成内容') ; UPDATE car_articles SET article_title = replace(a ...
-
(转)Spring &; SpringMVC学习
https://shimo.im/docs/CzXTpHe7DlYbknEn/ 掌握过程: 业务逻辑(漏洞.合理性处理).设计-->技术流程.原理.搭建.整体架设-->源码分析.断 ...
-
使用 jekyll + github pages 搭建个人博客
1. 新建 github.io 项目 其实 github pages 有两个用途,大家可以在官方网页看到.其中一个是作为个人/组织的主页(每个账号只能有一个),另一个是作为 github 项目的项目主 ...
-
Eclipse安装教程
Eclipse安装教程 (Win7_64bit + Eclipse_64bit + JDK_8u131_64bit + python2.7.8 + PyDev5.7.0插件) 适用操作系统:W ...
-
WINDOWS操作系统中可以允许最大的线程数
默认情况下,一个线程的栈要预留1M的内存空间 而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程 但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小. ...
-
Squid 反向代理服务器配置
简介: Squid 反向代理常用于服务器端,客户端访问 Squid 代理服务器的 80 端口,Squid 代理服务器根据配置去请求后端的 web 服务器, 然后将请求到的信息保存在本地并回传给客户端, ...