Annex K 是技術名稱。其他常見關鍵字是 __STDC_LIB_EXT1__ 和 __STDC_WANT_LIB_EXT1__。附件 K 定義了「安全性」_s 後綴,例如 sprintf_s() 和 scanf_s()。
也請參閱附錄 K (2015) 的現場經驗和邊界檢查 - cppreference.com 技術文件。
_s() 函數有什麼意義?他們檢查參數是否有更多不變量,例如「如果流為空、字串為空、bufsz 為零或緩衝區寫入超出指定長度的越界,則將呼叫約束處理程序」。這似乎是個好主意,對吧?是的!確實如此!
重點是你可以/可以這樣做:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
這與沒有 __STDC_WANT_LIB_EXT1__ 的正常做事方式相比如何?
幸福之路
FILE *file = fopen("hello.txt", "r"); // file is OK.
FILE *file; errno_t err = fopen_s(&file, "hello.txt", "r"); // file is OK
悲傷之路
FILE *file = fopen("notexist.txt", "r"); // file is NULL, errno is set.
FILE *file; errno_t err = fopen_s(&file, "notexist.txt", "r"); // file is NULL, err is set.
壞路
FILE *file = fopen(NULL, NULL); // idk.
FILE *file; errno_t err = fopen_s(&file, NULL, NULL); // Constraint violated. Abort with message.
是的,您可以自訂約束處理程序以僅登入檔案並繼續,就像什麼都沒發生一樣。
set_constraint_handler_s(ignore_handler_s); set_constraint_handler_s(abort_handler_s); set_constraint_handler_s(my_awesome_handler);
注意到普通的 fopen() 如何具有相同的回傳值(可能不同的 errno)來指示不同層級的錯誤嚴重程度?這就是 fopen_s() 試圖改進的地方。至少,這是我讀到的。我認為它就像 Rust 的panic!() 與返回的 Result
char* gets( char* str ); // (removed in C11) char* gets_s( char* str, rsize_t n ); // (since C11, annex K)登入後複製將 stdin 讀入 str 指向的字元陣列中,直到找到換行符號或發生檔案結尾。在讀入數組的最後一個字元之後立即寫入一個空字元。換行符被丟棄,但不儲存在緩衝區中。
gets() 函數不執行邊界檢查,因此此函數極易受到緩衝區溢位攻擊。它不能安全使用(除非程式運行在限制 stdin 上顯示內容的環境中)。因此,函數在 C99 標準的第三次勘誤中已被棄用,並在 C11 標準中完全刪除。 fgets() 和 gets_s() 是推薦的替代品。
警告:切勿使用 gets()。
// BAD char buffer[1000]; gets(buffer); // ⚠️ Could write >1000 chars to `buffer`!
// GOOD char buffer[1000]; gets_s(buffer, sizeof(buffer)); // This will stop at 1000 chars.
_s() 函數似乎非常適合阻止可能發生緩衝區溢位的常見位置。
它們並沒有在所有地方實現。 _s() 函數是一個擴充,在 GNU 的 glibc 等 libc 實作中不可用。還有其他一些小問題,例如它對於多執行緒來說不符合人體工學,以及對於strcpy_s() 之類的東西使用sizeof(src) 而不是sizeof(dest) 的常見錯誤,但與可用性問題相比,所有這些都顯得蒼白無力。
我能找到的大多數線上資訊似乎表明 MSVC 是唯一實作了附件 K 的主要編譯器/libc。
鑑於這些花哨的 _s() 函數並不存在於您的程式碼需要編譯的所有地方,您需要編寫以下程式碼:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
...對於您想要執行 strlen_s() 或 fopen_s() 或 strcpy_s() 的每個實例。這是發瘋的好方法。
很明顯,你不會寫依賴平台的程式碼只是為了執行基本的 printf() 和 strcpy() 但是將所有 #ifdef __STDC_LIB_EXT1__ #else 內容包裝在庫中怎麼樣?
我透過 Google 快速搜尋發現了兩個看起來很有前途的函式庫:
所以...如果您想(或安全人員要求)使用 _s() 函數,但又不想將自己限制為 MSVC,那麼您可以使用其中一個 ☝ 函式庫。
?如需了解更多信息,請參閱附錄 K (2015) 的現場經驗和邊界檢查 - cppreference.com 技術文件。
以上是TIL CANnex K 存在,但您不應該使用它的詳細內容。更多資訊請關注PHP中文網其他相關文章!