C 程式設計/stdio.h/gets
gets 是 C 標準庫中的一個函式,在標頭檔案 stdio.h 中宣告,它從標準輸入讀取一行並將其儲存在呼叫者提供的緩衝區中。
強烈建議不要使用 gets。 它保留在 C89 和 C99 標準中以實現向後相容性(但在 C99 的後期版本中正式棄用)。 它已從 C11 標準中刪除[1],取而代之的是引入了範圍檢查替代方法 gets_s。[2] 當連結使用 gets 的程式碼時,許多開發工具(例如 GNU ld)會發出警告。
它可以按如下方式實現(使用 getchar)
char *
gets (char *s)
{
char * ch = s;
int k;
/* until we read a newline */
while ((k = getchar ()) != '\n') {
if (k == EOF) {
/* EOF at start of line or errors other than EOF return NULL */
if (ch == s || !feof(stdin))
return NULL;
break;
}
/* character is stored at address, and pointer is incremented */
*ch++ = k;
}
/* Null-terminating character added */
*ch = '\0';
/* return original pointer */
return s;
}
程式設計師必須知道 gets 將讀取的字元數的最大限制,以便他可以確保緩衝區足夠大。 在沒有資料知識的情況下這是不可能的。 這種設計缺陷會導致錯誤,併為透過緩衝區溢位利用計算機安全打開了一個通道。 許多資料建議程式設計師在新的程式中永遠不要使用 gets。[3][4][5]
可以使用其他行輸入函式代替 gets,以避免緩衝區溢位錯誤。 一個簡單的替代方法是 fgets。 當用以下形式的程式碼替換程式碼時
char buffer[BUFFERSIZE];
gets(buffer);
用以下形式的程式碼
char buffer[BUFFERSIZE];
fgets(buffer, sizeof(buffer), stdin);
必須記住,fgets(buffer, sizeof(buffer), stdin) 呼叫不同於 gets(buffer),不僅在於緩衝區溢位保護,還在於 fgets(buffer, sizeof(buffer), stdin) 保留終止換行符(如果輸入行以換行符終止),而 gets(buffer) 會將其丟棄。
The C Programming Language 的第一版沒有使用 gets,而是描述了一個更安全的函式 getline(buffer, length),它不會溢位緩衝區,並且會返回有關讀取了多少位元組的有用資訊(這將允許輸入 NUL)或在錯誤或 EOF 時返回 -1。 不清楚為什麼gets最終出現在 C 標準庫中而不是這個函式。
POSIX-2008 定義了 getline(char **buffer, size_t *buffersize, FILE*),它根據需要重新分配緩衝區以容納輸入行(注意緩衝區和大小的額外間接級別)。[6]
C1X 提案有一個替換函式 gets_s(char* buffer, size_t n),如果該行不能容納在 n-1 個字元中,則返回空字串並消耗整個當前行。
安全使用 gets 需要程式設計師確保緩衝區溢位不會成為問題。 唯一可移植的方法是透過某種方式確保輸入檔案不能包含比緩衝區更長的行,例如透過確保該檔案是由不能寫入此類行的程式建立的。 還有許多其他相對複雜的方法可以防止緩衝區溢位,其可移植性程度各不相同。 一種可能性是使用保護頁面來保護記憶體。 單獨使用,這會將可利用的緩衝區溢位變成單純的崩潰。 與異常處理程式(例如涉及 SIGSEGV 和 sigaction 的處理程式)結合使用,保護頁面可以允許優雅的錯誤處理。
- ↑ n1548,xiv 頁
- ↑ n1548,K.3.5.4.1
- ↑ GNU. "行輸入". GNU C 庫. GNU. http://www.gnu.org/software/libc/manual/html_node/Line-Input.html#Line-Input. Retrieved 2008-08-02. "
gets函式非常危險,因為它不提供防止字串s溢位的保護。 GNU 庫僅出於相容性原因包含它。 你應該始終使用fgets或getline代替."(原文強調。) - ↑ "為什麼每個人都說不要使用
gets()?". comp.lang.c 常見問題解答. Retrieved 2008-08-02. - ↑ "
gets(3)".man. http://linux.die.net/man/3/gets. Retrieved 2008-08-02. "不要使用gets()。 由於在事先不知道資料的情況下無法確定gets()將讀取多少個字元,並且由於gets()會繼續將字元儲存到緩衝區的末尾,因此使用它非常危險。 它已被用於破壞計算機安全." - ↑ "getdelim". The Open Group.