首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C 安全編碼:數組安全使用規範與常見漏洞防範

     編輯:C++ 入門

核心建議與規則

類別條目
建議理解數組工作機制(退化為指針、sizeof 行為)
獲取長度勿對指針用 sizeof
顯式指定數組邊界,即使有初始化列表
規則索引必須在合法範圍內
全項目統一數組記法(指針/數組聲明一致)
變長數組 (VLA) 長度參數合法性檢查
確保複製目標有足夠空間
表達式中數組類型兼容
循環不越界迭代
不比較/相減不同數組的指針
非數組對象指針不做整數加減
指針加減結果必須引用合法元素

經典錯誤案例與修正

1. sizeof(指針) 取代 sizeof(數組)

// 錯誤:形參退化為指針,sizeof 返回指針大小
void clear(int array[]) {
    for (size_t i = 0; i < sizeof(array)/sizeof(array[0]); i++) // 永遠只循環 1/2 次
        array[i] = 0;
}

// 正確:顯式傳長度
void clear(int array[], size_t len) {
    for (size_t i = 0; i < len; i++) array[i] = 0;
}
void dowork() {
    int dis[12];
    clear(dis, sizeof(dis)/sizeof(dis[0]));
}

2. 索引類型簽名不匹配導致負數越界

// 錯誤:pos 為 int,可能為負
int insert_in_table(int pos, int value) {
    if (pos >= TABLESIZE) return -1;
    table[pos] = value; // pos=-1 寫入 table[-1]
}

// 正確:用 size_t
int insert_in_table(size_t pos, int value) {
    if (pos >= TABLESIZE) return -1;
    table[pos] = value;
}

3. 跨文件數組聲明不一致

// main.c
char *a; // 指針

// insert_a.c
char a[]; // 數組 —— 鏈接時類型衝突,行為未定義

// 正確:統一用指針聲明
// insert_a.h
extern char *a;
void insert_a(void);

// insert_a.c
#include "insert_a.h"
char *a;
void insert_a() { a[0] = 'a'; }

4. VLA 長度未檢查

// 危險:size 過大導致棧溢出,或為 0
void func(size_t s) { int vla[s]; ... }

// 安全:限制上界
enum { MAX_ARRAY = 1024 };
void func(size_t s) {
    if (s != 0 && s < MAX_ARRAY) { int vla[s]; ... }
    else { /* 錯誤處理 */ }
}

5. 目標空間不足導致緩衝區溢出

void func(const int src[], size_t len) {
    int dest[WORKSPACE_SIZE];
    if (len > WORKSPACE_SIZE) { /* 錯誤 */ }
    memcpy(dest, src, sizeof(int) * len); // 安全
}

6. 多維數組指釖類型不兼容

enum { a=10, b=15, c=20 };
int arr1[c][b];        // int (*)[15]
int (*arr2)[a];        // int (*)[10]
arr2 = arr1;           // 錯誤:10 != 15

// 修正:維度一致
enum { a=10, b=10, c=20 };
int arr1[c][b];
int (*arr2)[a];
arr2 = arr1; // 正確

7. 結構體非數組字段用指針算術遍歷

// 危險:結構體字段內存不保證連續
struct numbers { short num1, num2, ..., num9; };
int sum_numbers(struct numbers *n) {
    for (int *p = &n->num1; p <= &n->num9; p++) // UB
        total += *p;
}

// 正確:改用數組
struct numbers { short nums[9]; };
int sum_numbers(short *n, size_t dim) {
    for (short *p = n; p < n + dim; p++) total += *p;
}

最佳實踐清單

  • 函數參數傳數組時,必須同步傳遞長度。
  • 索引變量優先用 size_t,避免符號擴展漏洞。
  • 跨文件共享數組,統一用指針聲明,頭文件 extern。
  • VLA 必須檢查長度上界與非零。
  • memcpy/memmove 前驗證目標空間 ≥ 源長度。
  • 多維數組指針賦值時,除第一維外所有維度必須完全一致。
  • 遍歷結構體字段用數組,不用指針算術。

總結

數組安全的核心是「知邊界、傳長度、統一聲明、查空間」。將規則落實到編碼規範與代碼審查中,可有效杜絕緩衝區溢出、越界訪問等高危漏洞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved