2011-08-11 61 views
7

Cppcheck顯示scanf函數如下警告:scanf函數Cppcheck警告

 
Message: scanf without field width limits can crash with huge input data. To fix this error message add a field width specifier: 
    %s => %20s 
    %i => %3i 

Sample program that can crash: 

#include 
int main() 
{ 
    int a; 
    scanf("%i", &a); 
    return 0; 
} 

To make it crash: 
perl -e 'print "5"x2100000' | ./a.out 

我不能崩潰這個程序輸入「巨大的輸入數據」。我應該輸入什麼來獲得這次崩潰?我也弄不明白這個警告的最後一行的含義是:

的perl -e ...

+6

「按任意鍵繼續。」 「任何鑰匙在哪裏?」 – Dave

+0

@Dave:?????你的評論看起來像垃圾郵件:( –

+1

什麼?不是。按照你的問題的措辭,看起來你錯誤地理解了「巨大的輸入數據」這個短語 - 這不是你輸入的內容,而是輸入的屬性。與經典的任何關鍵笑話都是一樣的,我用這個笑話來比喻你的問題。 – Dave

回答

5

最後一行是一個示例命令,用於演示示例程序的崩潰。它本質上導致perl打印2.100.000次「5」,然後將其傳遞給程序「a.out」(這是編譯的示例程序)的stdin。

首先,scanf()應該僅用於測試,而不是在現實世界中的方案由於幾個問題就不能適當地處理(例如,要求「%I」,但用戶輸入「12345ABC」(以下簡稱「ABC」將停留在stdin中,並可能導致下面的輸入被填充而沒有用戶改變它們的機會)

關於這個問題:scanf()會知道它應該讀取一個整數值,但它不知道它會持續多久可以是指針可以指向一個16位整數,32位整數或64位整數或者甚至更大的東西(它不知道關閉)具有可變參數數量的函數(用...定義) t知道傳遞的元素的確切數據類型,所以必須重新考慮在格式字符串上(原因是格式標籤不像C#中那樣只是編號,例如, "{0} {1} {2}")。如果沒有給定的長度,它必須假設一些長度,這也可能與平臺有關(使得該功能甚至更難以使用)。

通常,考慮它可能有害並且是緩衝區溢出攻擊的起點。如果您想要保護和優化您的程序,請首先將其替換爲替代方案。

+3

Scanf確切知道指針可以有多大:'%d'是'sizeof(int)* 8'位,'%ld'是'sizeof(long)* 8'-bit等等。所有這些在編譯時都是已知的。 – Dave

+0

@Dave:int n [SIZE]; memset(n,0,sizeof(n)* sizeof(int)); –

+0

我不明白爲什麼這個答案被接受。它不回答這個問題。 scanf()假設輸入字符串數字的數量定義了它正在讀入的整數的位寬(cppreference會不同意這個答案)?還是一些scanf()實現有內部溢出? – Arvid

0

我試圖運行鍼對C程序perl的表達,它在Linux上做了這裏碰撞(分段錯誤)。

0

在實際應用中使用'scanf'(或fscanf和sscanf)函數通常不被推薦,因爲它不安全,如果提供了一些不正確的輸入數據,它通常是一個緩衝區溢出的漏洞。 在許多常用的C++庫(QT,用於Microsoft Visual C++的運行時庫等)中,有許多更安全的方法來輸入數字。也許你可以找到「純」C語言的安全選擇。