一.splint介紹
splint是一個靜態檢查C語言程序安全弱點和編寫錯誤的工具。splint會進行多種常規檢查,包括未使用的變量,類型不一致,使用未定義變量,無法執行的代碼,忽略返回值,執行路徑未返回,無限循環等錯誤。同時通過在源碼中添加注記給出的附加信息,使其可以進行功能更加強大的檢查。而注記,則是對文件中的函數、變量、參數以及類型進行假定的一種的程式化的注釋。
二.splint的安裝
下載地址:
http://www.splint.org/downloads/splint-3.1.2.src.tgz源碼包安裝:# tar zxvf splint-3.1.2.src.tgz# cd splint-3.1.2# mkdir /usr/local/splint# ./configure --prefix=/usr/local/splint# make install# vi ~/.bashrc添加:export LARCH_PATH=/usr/local/splint/share/splint/libexport LCLIMPORTDIR=/usr/local/splint/share/splint/import# source ~/.bashrc# export PATH=/usr/local/splint/bin/splint:$PATH三.splint的使用
1.空引用錯誤
在引用沒有指向任何內存地址的指針時,會導致這種錯誤.也就是使用了一個沒有賦值的指針.
splint支持一種特別的注釋.這種注釋寫在C程序代碼中,用於對程序進行特殊說明.
如下面這段程序.使用了/*@null@*/進行了說明,表示說明*s的值可能會是NULL.
//null.cchar firstChar1 (/*@null@*/ char *s){return *s;}char firstChar2 (/*@null@*/ char *s){ if (s ==NULL) return '\0'; return *s;}//END使用splint掃描這個程序時,會輸出:
# splint null.cSplint 3.1.1 --- 28 Apr 2005null.c: (in function firstChar1)null.c:3:11: Dereference of possibly null pointer s: *s null.c:1:35: Storage s may become nullFinished checking --- 1 code warning found由於firstChar1和firstChar2都使用了null說明,表示指針s可能是個NULL值.所以,splint會對s值的使用情況進行檢查.因為firstChar2函數中,對s的值進行了NULL的判斷.所以,沒有對firstChar2函數的指針s輸出警告信息.2.未定義的變量錯誤
C語言中,要求先定義變量,而後才可使用.所以,當使用一個沒有定義的變量時,編譯就會出錯.
如下例,使用/*@in@*/說明的變量,表示必須進行定義.使用/*@out@*/說明的變量,表示在 執行過此函數後,這個變量就進行了定義.
// usedef.cextern void setVal (/*@out@*/ int *x);extern int getVal (/*@in@*/ int *x);extern int mysteryVal (int *x);int dumbfunc (/*@out@*/ int *x, int i) { if (i > 3) return *x; else if (i > 1) return getVal (x); else if (i == 0) return mysteryVal (x); else { setVal (x); return *x; } }// END使用splint檢查usedef.c
$ splint usedef.cSplint 3.1.1 --- 28 Apr 2005usedef.c: (in function dumbfunc)usedef.c:7:19: Value *x used before definition An rvalue is used that may not be initialized to a value on some execution path. (Use -usedef to inhibit warning)usedef.c:9:18: Passed storage x not completely defined (*x is undefined): getVal (x) Storage derivable from a parameter, return value or global is not defined. Use /*@out@*/ to denote passed or returned storage which need not be defined. (Use -compdef to inhibit warning)usedef.c:11:22: Passed storage x not completely defined (*x is undefined): mysteryVal (x)Finished checking --- 3 code warnings//錯誤原因: 由於程序中沒有對x進行定義,所以報未定義錯誤.但setVal()使用了/*@out@*/說明,所以在setVal(x);和return x;中,沒有報未定義錯誤.3.類型錯誤
C語言中的數據類型較多,各個之間有些細微差別.splint也可以對變量類型進行檢查.
示例1:
//bool.cint f (int i, char *s,bool b1, bool b2){if (i = 3) return b1;if (!i || s) return i;if (s) return 7;if (b1 == b2)return 3;return 2;}//END使用splint進行檢查:
$ splint bool.cSplint 3.1.1 --- 28 Apr 2005bool.c: (in function f)bool.c:4:5: Test expression for if is assignment expression: i = 3 The condition test is an assignment expression. Probably, you mean to use == instead of =. If an assignment is intended, add an extra parentheses nesting (e.g., if ((a = b)) ...) to suppress this message. (Use -predassign to inhibit warning)// 錯誤原因: if語句中的條件表達式是一個賦值語句.bool.c:4:5: Test expression for if not boolean, type int: i = 3 Test expression type is not boolean or int. (Use -predboolint to inhibit warning)// 錯誤原因: if語句中的條件表達式的返回值,不是布爾型,而是整型.bool.c:4:8: Return value type bool does not match declared type int: b1 Types are incompatible. (Use -type to inhibit warning)// 錯誤原因: 返回值是布爾型,而不是整型.bool.c:5:6: Operand of ! is non-boolean (int): !i The operand of a boolean operator is not a boolean. Use +ptrnegate to allow ! to be used on pointers. (Use -boolops to inhibit warning)// 錯誤原因: "!"操作符的操作數不是布爾型,而是整型i.bool.c:5:11: Right operand of || is non-boolean (char *): !i || s// 錯誤原因: "||"操作符的右操作數不是布爾型,而是字符指針.bool.c:7:5: Use of == with boolean variables (risks inconsistency because of multiple true values): b1 == b2 Two bool values are compared directly using a C primitive. This may produce unexpected results since all non-zero values are considered true, so different true values may not be equal. The file bool.h (included in splint/lib) provides bool_equal for safe bool comparisons. (Use -boolcompare to inhibit warning)// 錯誤原因: 使用"=="對兩個布爾型進行比較.應該使用"&&".Finished checking --- 6 code warnings示例2:
//malloc1.c#include <stdlib.h>#include <stdio.h>int main(void){char *some_mem;int size1=1048576;some_mem=(char *)malloc(size1);printf("Malloed 1M Memory!\n");free(some_mem);exit(EXIT_SUCCESS);}//END使用splint檢查malloc1.c