C安全編碼--預先處理

來源:互聯網
上載者:User

標籤:des   style   blog   http   color   使用   

建議和規則

建議:

  • 用內嵌函式或靜態函數代替與函數相似的宏

  • 在宏參數名兩邊加上括弧

  • 宏其他清單應該加上括弧

  • 應該使用typedef定義編碼類別型

  • 不要複用標準標頭檔名

  • 理解串連標記或執行字串化時的宏替換

  • 把標頭檔放在包含防護條件中

  • 避免使用連續的問號

  • 保證標頭檔名唯一

  • 不要用不安全的函數替換安全函數

  • 在一個do-while迴圈中封裝多條語句的宏

規則:

  • 不要通過串連建立統一字元名稱

  • 不要在不安全宏的參數中包含賦值、增值、減值、volatile訪問或函數調用

本文地址:http://www.cnblogs.com/archimedes/p/c-security-pretreatment-.html,轉載請註明源地址。

用內嵌函式或靜態函數代替與函數相似的宏

  宏是危險的,用法與真正的函數相似,但是具有不同的語義。C99在C中增加了內嵌函式,當內嵌函式和宏可以互換使用時,應該優先選擇內嵌函式,內聯替換並不是文本替換,也沒有建立函數,決定一個函數是否為內嵌函式是一個底層的最佳化細節,編譯器應該不依賴程式換做出這個決定,是否使用內嵌函式取決於目標編譯器對它們的支援,它們對系統效能特徵所產生的影響以及可移植性問題,靜態函數常常具有與內嵌函式相同的優點。

下面的例子中,當傳遞給CUBE宏的參數是一個具有副作用的運算式時,這個宏就具有未定義的行為。

代碼1:

#define CUBE(x) ((x) * (x) * (x))/*...*/int i = 2;int a = 81 / CUBE(++i);

在這個例子中,a的初始設定式展開為: int a = 81/((++i) * (++i) * (++i));

解決方案:

inline int cube(int x){    return x * x *x;}/*...*/int i = 2;int a = 81 / cube(++i);

代碼2:

#include<stdio.h>size_t count = 0;#define EXEC_BUMP(func) (func(), ++count)void g(void) {    printf("Called g, count = %zu.\n", count);}void aFunc(void) {    size_t count = 0;    while(count++ <10) {        EXEC_BUMP(g);    }}int main(void){    aFunc();    return 0;}

運行結果:

 解決方案:

#include<stdio.h>size_t count = 0;void g(void) {    printf("Called g, count = %zu.\n", count);}typedef void(*exec_func)(void);inline void exec_bump(exec_func f) {    f();    ++count;}void aFunc(void) {    size_t count = 0;    while(count++ <10) {        exec_bump(g);    }}int main(void){    aFunc();    return 0;}

運行結果:

和函數不同,宏的執行可以是交錯的,兩個宏單獨執行時無害,但是它們在同一個運算式中組合在一起時可能導致未定義的行為:

代碼3:

#define F(x) (++operations, ++calls_to_F, 2 * x)#define G(x) (++operations, ++calls_to_G, x + 1)/*...*/y = F(x) + G(x);

operations變數在同一個運算式中讀取並修改了2次,因此按照某種順序,可能會接收到錯誤的值

解決方案:

inline int f(int x) {    ++operations;    ++calls_to_f;    return 2 * x;}inline int g(int x) {    ++operations;    ++calls_to_f;    return 1 + x;}/*...*/y = f(x) + g(x);
在宏參數名兩邊加上括弧

代碼1:

#define CUBE(I) (I * I * I)int a = 81 / CUBE(2 + 1)

被展開為: int a = 81 / (2 + 1 * 2 + 1 * 2 + 1);

解決方案:

#define CUBE(I) ((I) * (I) * (I))int a = 81 / CUBE(2 + 1)

例外:當替換文本中的參數名由逗號分隔時,不管實際參數如何複雜,不需要對宏參數加上括弧,因為逗號操作符的優先順序低於其他任何操作符

#define FOO(a, b, c)   bar(a, b, c)/*...*/FOO(arg1, arg2, arg3);
宏其他清單應該加上括弧

宏其他清單應該加上括弧,以保護運算式中所有優先順序較低的操作符

代碼1:

#define CUBE(X) (X) * (X) * (X)int i = 3;int a = 81 / CUBE(i);//被展開為: int a = 81 / i * i * i

解決方案:

#define CUBE(X) ((X) * (X) * (X))int i = 3;int a = 81 / CUBE(i);

這個方案最好實現為內嵌函式

應該使用typedef定義編碼類別型

如果需要對類型進行編碼,應該使用類型定義(typedef)而不是宏定義(#define)。類型定義遵循範圍規則,而宏定義卻不遵循

代碼1:

#define cstring char *cstring s1, s2;

其中s1聲明為char *,s2聲明為char

解決方案:

typedef char * cstring;cstring s1, s2;
 不要複用標準標頭檔名

如果一個檔案與標準標頭檔同名。並且位於包含源檔案的搜尋路徑中,其行為是未定義的

建議:不要複用標準標頭檔名、系統特定的標頭檔名或其他的標頭檔名

把標頭檔放在包含防護條件中

防止標頭檔沒多次包含或是忘記包含,通過一種簡單的技巧:每個標頭檔應該用#define指令定義一個符號,表示已經被包含,然後整個標頭檔出現在一個包含防護條件中:

#ifndef HEADER_H#define HEADER_H/*....header的內容*/#endif
避免使用連續的問號

兩個連續的問號表示一個三字元序列,據C99標準,在一個源檔案中,下列這些3個字元的連續出現被對應的單個字元所替換

??= # ??) ] ??! |
??( [ ??‘ ^ ??> }
??/ \ ??< { ??- ~

代碼1:

//what is the value of a now ??/a++;

由於??/等價於\,a++相當於被注釋掉

解決方案:

//what is the value of a now? ?/a++;
保證標頭檔名唯一
  • 檔案名稱中只有前8個字元保證是唯一的

  • 檔案名稱中的點號後面只有1個非數字字元

  • 檔案名稱中字元的大小寫並不保證是區分的

代碼1:

#include<stdio.h>#include “Library.h”#include "library.h"#include "utilities_math.h"#include "utilities_physics.h"#include "my_library.h"

Library.h和library.h可能表示同一個檔案,並不清楚utilities_math和utilities_physics能否進行區分

解決方案:

#include<stdio.h>#include “Lib_main.h”#include "lib_2.h"#include "util_math.h"#include "util_physics.h"#include "my_library.h"
不要用不安全的函數替換安全函數

宏經常用於修補現有的代碼,用一個標識符對另一個標識符進行全域替換,但是這種做法存在一些風險,當一個函數被一個不夠安全的函數替換時,這種做法就顯得特別的危險

代碼:

#define vsnprintf(buf, size, fmt, list) \    vsprintf(buf, fmt, list)

vsprintf函數並不會檢查邊界,因此size參數將被丟棄,在使用不信任的資料的時候可能會導致潛在的緩衝區溢位問題

解決方案:

#include<stdio.h>#ifndef __USE_ISOC99    /* 重新實現 vsnprintf()*/    #include "my_stdio.h"#endif
在一個do-while迴圈中封裝多條語句的宏

參見《C語言中do...while(0)用法小結

參考資料

《C安全編碼通訊協定》

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.