我想知道這兩個選項是更安全的一個使用方法:哪個sprintf/snprintf更安全?
#define MAXLEN 255
char buff[MAXLEN + 1]
sprintf(buff, "%.*s", MAXLEN, name)
snprintf(buff, MAXLEN, "%s", name)
我的理解是,兩者都是相同。請建議。
我想知道這兩個選項是更安全的一個使用方法:哪個sprintf/snprintf更安全?
#define MAXLEN 255
char buff[MAXLEN + 1]
sprintf(buff, "%.*s", MAXLEN, name)
snprintf(buff, MAXLEN, "%s", name)
我的理解是,兩者都是相同。請建議。
兩個會給你想要的結果,但snprintf
是更通用的,並會保護你的字符串從超支無論格式字符串給出。
另外,由於snprintf
(或sprintf
對這個問題)增加了最終\0
,你應該做的字符串緩衝區一個字節大,char buff[MAXLEN + 1]
。
事實證明,情況並非如此。在snprintf文檔中:「函數snprintf()和vsnprintf()將大部分字節(包括終止空字節('\ 0'))寫入到str中。」 – Chriszuma
你給出的兩個表達式是而不是等價物:sprintf
沒有指定要寫入的最大字節數的參數;它只需要一個目標緩衝區,一個格式字符串和一堆參數。因此,它可能會寫入比緩衝區有更多空間的字節,並在此寫入任意代碼。該%.*s
是不令人滿意的解決方案,因爲:
strlen
相當於;這是字符串中字符數量的一種度量,而不是它在內存中的長度(即它不計算空終止符)。sprintf
版本的行爲相對於緩衝區溢出。使用snprintf
,無論格式字符串或輸入類型如何變化,都會設置固定的清除最大值。你的sprintf語句是正確的,但我不會有足夠的自信以用於安全目的(例如,缺少一個神祕的字符而你是無屏蔽的),同時有可用於snprintf的snprintf任何格式...哦,等等的snprintf是不是在ANSI C。它是(僅)?C99。這可能是一個偏好另一個的(弱)理由。
嘛。你也可以使用strncpy
,對不對?
例如
char buffer[MAX_LENGTH+1];
buffer[MAX_LENGTH]=0; // just be safe in case name is too long
strncpy(buffer,MAX_LENGTH,name); // strncpy will never overwrite last byte
你確定'%。* s'在ANSI C中有效嗎?我試圖找到規範,但只能找到一個(不可信的)引用,沒有指定'。*'。 –
@Eli:自從原始標準(1989/1990)以來,在ANSI C中指定精度(如此處)或字段寬度作爲星號。在C99標準中增加了'snprintf()'。 –
@Michael - 對於字符串('%s')也?很高興知道,謝謝。 –
對於問題中的簡單示例,兩個調用之間的安全性可能沒有太大差異。但是,在一般情況下,snprintf()
可能更安全。一旦你有一個更復雜的格式字符串與多個規格的轉換可能很難(或者幾乎是不可能的),以確保您的緩衝區長度佔準確跨越不同的轉換 - 尤其是因爲以前的轉換並不一定產生一個固定數量的輸出字符。
所以,我會用snprintf()
堅持。
snprintf()
(儘管與安全無關)的另一個小優點是它會告訴您需要多大的緩衝區。
最後需要說明的 - 你應該在指定的snprintf()
通話的實際緩衝區大小 - 這會處理佔比爲你空終止:
snprintf(buff, sizeof(buff), "%s", name);
我想說snprintf()
得多好,直到我讀這樣一段話:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html
簡短的總結是:從系統snprintf()
不便於攜帶其行爲變化的系統。 snprintf()
最嚴重的問題可能發生在snprintf()
簡單地通過調用sprintf()
實現。您可能認爲它可以保護您免受緩衝區溢出並讓您警惕,但它可能不會。
所以現在我仍然說snprintf()
更安全,但在使用它時也很謹慎。
最好也是最靈活的方法是使用snprintf
!
size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */
char *str = malloc(nbytes);
snprintf(str, nbytes, "%s", name);
在C99,snprintf
返回寫到不包括'\0'
串的字節數。如果少於必需的字節數,則snprintf
返回擴展格式所需的字節數(仍然不包括'\0'
)。通過傳遞snprintf
長度爲0的字符串,您可以提前發現擴展字符串已經存在多長時間,並使用它來分配必要的內存。
這兩者之間有一個重要區別 - snprintf
調用將掃描name
參數到最後(終止NUL)以便找出正確的返回值。另一方面,sprintf
調用將從name
讀取AT MOST 255個字符。
所以如果name
是一個指向非NUL終止緩衝與至少255個字符,則snprintf
呼叫可能流掉的緩衝區的末尾,並觸發未定義的行爲(如崩潰),而sprintf
版本將不會。
將#2更改爲'MAXLEN + 1',它們在所有情況下寫入「buff」的內容都相同(如果'strlen(name)> 255',返回值將會不同)。 –