• C安全编码--数组


    建议和规则

    建议:

    • 理解数组的工作方式

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

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

    规则:

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

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

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

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

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

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

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

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

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

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

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

    代码:

    void clear(int array[]) {
        for(size_t i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
            array[i] = 0;
        }
    }
    void dowork(void) {
        int dis[12];
        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 = 0; i < len; i++) {
            array[i] = 0;
        }
    }
    
    void dowork(void) {
        int dis[12];
        clear(dis, sizeof(dis) / sizeof(dis[0]));
        /*...*/
    }

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

    代码:

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

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

    解决方案:

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

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

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

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

    代码:

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

    解决方案:

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

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

    代码:

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

    解决方案:

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

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

    代码:

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

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

    代码:

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

    解决方案:

    enum {a = 10, b = 10, c = 20};
    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 = 0;
        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 = {1,2,3,4,5,6,7,8,9};
        sum_numbers(&my_numbers);
        return 0;
    }

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

    解决方案(使用数组):

    struct numbers {
        short num1;
        short num2;
        /*...*/
        short num9;
    };
    int sum_numbers(const short *numb, size_t dim) {
        int total = 0;
        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[9] = {1,2,3,4,5,6,7,8,9};
        sum_numbers(my_numbers, sizeof(my_numbers) / sizeof(my_numbers[0]));
        return 0;
    }

    参考资料

    《C安全编码标准》

  • 相关阅读:
    我喜欢的乐队-Descending
    SQL合并时间段的问题
    基本字符串相关函数,基本宏,内存相关函数,类型转换函数实现合集
    centos7.4 安装 .net core 2.2
    在Global.asax中 注册Application_Error事件 捕获全局异常
    一般后台系统数据库 用户权限设计
    API接口利用ActionFilterAttribute实现接口耗时检测
    Git 一般性操作
    tasks.json 配置 解决vscode控制台乱码问题
    iview发布到IIS 路由问题
  • 原文地址:https://www.cnblogs.com/wuyudong/p/c-security-array.html
Copyright © 2020-2023  润新知