FindBugs的作用就不多說(shuō)了,本文具體是使用FindBugs生成報(bào)告后,一些縮寫的解讀。
FindBugs是基于Bug Patterns概念,查找javabytecode(.class文件)中的潛在bug,主要檢查bytecode中的bug patterns,如NullPoint空指針檢查、沒(méi)有合理關(guān)閉資源、字符串相同判斷錯(cuò)(==,而不是equals)等。
一、Security 關(guān)于代碼安全性防護(hù)
1.Dm: Hardcoded constant database password (DMI_CONSTANT_DB_PASSWORD)
代碼中創(chuàng)建DB的密碼時(shí)采用了寫死的密碼。
2.Dm: Empty database password (DMI_EMPTY_DB_PASSWORD)
創(chuàng)建數(shù)據(jù)庫(kù)連接時(shí)沒(méi)有為數(shù)據(jù)庫(kù)設(shè)置密碼,這會(huì)使數(shù)據(jù)庫(kù)沒(méi)有必要的保護(hù)。
3.HRS: HTTP cookie formed from untrusted input (HRS_REQUEST_PARAMETER_TO_COOKIE)
此代碼使用不受信任的HTTP參數(shù)構(gòu)造一個(gè)HTTP Cookie。
4.HRS: HTTP Response splitting vulnerability (HRS_REQUEST_PARAMETER_TO_HTTP_HEADER)
在代碼中直接把一個(gè)HTTP的參數(shù)寫入一個(gè)HTTP頭文件中,它為HTTP的響應(yīng)暴露了漏洞。
5.SQL: Nonconstant string passed to execute method on an SQL statement (SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE)
該方法以字符串的形式來(lái)調(diào)用SQLstatement的execute方法,它似乎是動(dòng)態(tài)生成SQL語(yǔ)句的方法。這會(huì)更容易受到SQL注入攻擊。
6.XSS: JSP reflected cross site scripting vulnerability (XSS_REQUEST_PARAMETER_TO_JSP_WRITER)
在代碼中在JSP輸出中直接寫入一個(gè)HTTP參數(shù),這會(huì)造成一個(gè)跨站點(diǎn)的腳本漏洞。
二、Experimental
1.LG: Potential lost logger changes due to weak reference in OpenJDK (LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)
OpenJDK的引入了一種潛在的不兼容問(wèn)題,特別是,java.util.logging.Logger的行為改變時(shí)。它現(xiàn)在使用內(nèi)部弱引用,而不是強(qiáng)引用。–logger配置改變,它就是丟失對(duì)logger的引用,這本是一個(gè)合理的變化,但不幸的是一些代碼對(duì)舊的行為有依賴關(guān)系。這意味著,當(dāng)進(jìn)行垃圾收集時(shí)對(duì)logger配置將會(huì)丟失。例如:
public static void initLogging() throws Exception {
?Logger logger = Logger.getLogger("edu.umd.cs");
?logger.addHandler(new FileHandler()); // call to change logger configuration
?logger.setUseParentHandlers(false); // another call to change logger configuration
}
該方法結(jié)束時(shí)logger的引用就丟失了,如果你剛剛結(jié)束調(diào)用initLogging方法后進(jìn)行垃圾回收,logger的配置將會(huì)丟失(因?yàn)橹挥斜3钟涗浧魅跻茫?/p>
public static void main(String[] args) throws Exception {
?initLogging(); // adds a file handler to the logger
?System.gc(); // logger configuration lost
?Logger.getLogger("edu.umd.cs").info("Some message"); // this isn't logged to the file as expected
}
2.OBL: Method may fail to clean up stream or resource (OBL_UNSATISFIED_OBLIGATION)
這種方法可能無(wú)法清除(關(guān)閉,處置)一個(gè)流,數(shù)據(jù)庫(kù)對(duì)象,或其他資源需要一個(gè)明確的清理行動(dòng)。
一般來(lái)說(shuō),如果一個(gè)方法打開(kāi)一個(gè)流或其他資源,該方法應(yīng)該使用try / finally塊來(lái)確保在方法返回之前流或資源已經(jīng)被清除了。這種錯(cuò)誤模式基本上和OS_OPEN_STREAM和ODR_OPEN_DATABASE_RESOURCE錯(cuò)誤模式相同,但是是在不同在靜態(tài)分析技術(shù)。我們正為這個(gè)錯(cuò)誤模式的效用收集反饋意見(jiàn)。
三、Bad practice代碼實(shí)現(xiàn)中的一些壞習(xí)慣
1.AM: Creates an empty jar file entry (AM_CREATES_EMPTY_JAR_FILE_ENTRY)
調(diào)用putNextEntry()方法寫入新的 jar 文件條目時(shí)立即調(diào)用closeEntry()方法。這樣會(huì)造成JarFile條目為空。
2.AM: Creates an empty zip file entry (AM_CREATES_EMPTY_ZIP_FILE_ENTRY)
調(diào)用putNextEntry()方法寫入新的 zip 文件條目時(shí)立即調(diào)用closeEntry()方法。這樣會(huì)造成ZipFile條目為空。
3.BC: Equals method should not assume anything about the type of its argument (BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS)
equals(Object o)方法不能對(duì)參數(shù)o的類型做任何的假設(shè)。比較此對(duì)象與指定的對(duì)象。當(dāng)且僅當(dāng)該參數(shù)不為 null,并且是表示與此對(duì)象相同的類型的對(duì)象時(shí),結(jié)果才為 true。
4.BC: Random object created and used only once (DMI_RANDOM_USED_ONLY_ONCE)
隨機(jī)創(chuàng)建對(duì)象只使用過(guò)一次就拋棄
5.BIT: Check for sign of bitwise operation (BIT_SIGNED_CHECK)
檢查位操作符運(yùn)行是否合理
((event.detail & SWT.SELECTED) > 0)
If SWT.SELECTED is a negative number, this is a candidate for a bug. Even when SWT.SELECTED is not negative, it seems good practice to use '!= 0' instead of '> 0'.
6.CN: Class implements Cloneable but does not define or use clone method (CN_IDIOM)
按照慣例,實(shí)現(xiàn)此接口的類應(yīng)該使用公共方法重寫 Object.clone(它是受保護(hù)的),以獲得有關(guān)重寫此方法的詳細(xì)信息。此接口不 包含 clone 方法。因此,因?yàn)槟硞€(gè)對(duì)象實(shí)現(xiàn)了此接口就克隆它是不可能的,應(yīng)該實(shí)現(xiàn)此接口的類應(yīng)該使用公共方法重寫 Object.clone
7.CN: clone method does not call super.clone() (CN_IDIOM_NO_SUPER_CALL)
一個(gè)非final類型的類定義了clone()方法而沒(méi)有調(diào)用super.clone()方法。例如:B擴(kuò)展自A,如果B中clone方法調(diào)用了spuer.clone(),而A中的clone沒(méi)有調(diào)用spuer.clone(),就會(huì)造成結(jié)果類型不準(zhǔn)確。要求A的clone方法中調(diào)用spuer.clone()方法。
8.CN: Class defines clone() but doesn't implement Cloneable (CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE)
類中定義了clone方法但是它沒(méi)有實(shí)現(xiàn)Cloneable接口
9.Co: Abstract class defines covariant compareTo() method (CO_ABSTRACT_SELF)
抽象類中定義了多個(gè)compareTo()方法,正確的是覆寫Comparable中的compareTo方法,方法的參數(shù)為Object類型,如下例:
int compareTo(T o) ?比較此對(duì)象與指定對(duì)象的順序。
10.Co: Covariant compareTo() method defined (CO_SELF_NO_OBJECT)
類中定義了多個(gè)compareTo()方法,正確的是覆寫Comparable中的compareTo方法,方法的參數(shù)為Object類型
11.DE: Method might drop exception (DE_MIGHT_DROP)
方法可能拋出異常
12.DE: Method might ignore exception (DE_MIGHT_IGNORE)
方法可能忽略異常
13.DMI: Don't use removeAll to clear a collection (DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION)
不要用removeAll方法去clear一個(gè)集合
14.DP: Classloaders should only be created inside doPrivileged block (DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED)
類加載器只能建立在特殊的方法體內(nèi)
15.Dm: Method invokes System.exit(...) (DM_EXIT)
在方法中調(diào)用System.exit(...)語(yǔ)句,考慮用RuntimeException來(lái)代替
16.Dm: Method invokes dangerous method runFinalizersOnExit (DM_RUN_FINALIZERS_ON_EXIT)
在方法中調(diào)用了System.runFinalizersOnExit 或者Runtime.runFinalizersOnExit方法,因?yàn)檫@樣做是很危險(xiǎn)的。
17.ES: Comparison of String parameter using == or != (ES_COMPARING_PARAMETER_STRING_WITH_EQ)
用==或者!=方法去比較String類型的參數(shù)
18.ES: Comparison of String objects using == or != (ES_COMPARING_STRINGS_WITH_EQ)
用==或者!=去比較String類型的對(duì)象
19.Eq: Abstract class defines covariant equals() method (EQ_ABSTRACT_SELF)
20.Eq: Equals checks for noncompatible operand (EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS)
equals方法檢查不一致的操作。兩個(gè)類根本就是父子關(guān)系而去調(diào)用equals方法去判讀對(duì)象是否相等。
public boolean equals(Object o) {
? if (o instanceof Foo)
? ? return name.equals(((Foo)o).name);
? else if (o instanceof String)
? ? return name.equals(o);
? else return false;
21.Eq: Class defines compareTo(...) and uses Object.equals() (EQ_COMPARETO_USE_OBJECT_EQUALS)
類中定義了compareTo方法但是繼承了Object中的compareTo方法
22.Eq: equals method fails for subtypes (EQ_GETCLASS_AND_CLASS_CONSTANT)
類中的equals方法可能被子類中的方法所破壞,當(dāng)使用類似于Foo.class == o.getClass()的判斷時(shí)考慮用this.getClass() == o.getClass()來(lái)替換
23.Eq: Covariant equals() method defined (EQ_SELF_NO_OBJECT)
類中定義了多個(gè)equals方法。正確的做法是覆寫Object中的equals方法,它的參數(shù)為Object類型的對(duì)象。
24.FI: Empty finalizer should be deleted (FI_EMPTY)
為空的finalizer方法應(yīng)該刪除。一下關(guān)于finalizer的內(nèi)容省略
25.GC: Unchecked type in generic call (GC_UNCHECKED_TYPE_IN_GENERIC_CALL)
This call to a generic collection method passes an argument while compile type Object where a specific type from the generic type parameters is expected. Thus, neither the standard Java type system nor static analysis can provide useful information on whether the object being passed as a parameter is of an appropriate type.
26.HE: Class defines equals() but not hashCode() (HE_EQUALS_NO_HASHCODE)
方法定義了equals方法卻沒(méi)有定義hashCode方法
27.HE: Class defines hashCode() but not equals() (HE_HASHCODE_NO_EQUALS)
?類定義了hashCode方法去沒(méi)有定義equal方法
28.HE: Class defines equals() and uses Object.hashCode() (HE_EQUALS_USE_HASHCODE)
一個(gè)類覆寫了equals方法,沒(méi)有覆寫hashCode方法,使用了Object對(duì)象的hashCode方法
29.HE: Class inherits equals() and uses Object.hashCode() (HE_INHERITS_EQUALS_USE_HASHCODE)
子類繼承了父類的equals方法卻使用了Object的hashCode方法
30.IC: Superclass uses subclass during initialization (IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION)
子類在父類未初始化之前使用父類對(duì)象實(shí)例
public class CircularClassInitialization {
static class InnerClassSingleton extends CircularClassInitialization {
static InnerClassSingleton singleton = new InnerClassSingleton();
}
static CircularClassInitialization foo = InnerClassSingleton.singleton;
}
31.IMSE: Dubious catching of IllegalMonitorStateException (IMSE_DONT_CATCH_IMSE)
捕捉違法的監(jiān)控狀態(tài)異常,例如當(dāng)沒(méi)有獲取到對(duì)象鎖時(shí)使用其wait和notify方法
32.ISC: Needless instantiation of class that only supplies static methods (ISC_INSTANTIATE_STATIC_CLASS)
為使用靜態(tài)方法而創(chuàng)建一個(gè)實(shí)例對(duì)象。調(diào)用靜態(tài)方法時(shí)只需要使用類名+靜態(tài)方法名就可以了。
33.It: Iterator next() method can't throw NoSuchElementException (IT_NO_SUCH_ELEMENT)
迭代器的next方法不能夠拋出NoSuchElementException
34.J2EE: Store of non serializable object into HttpSession (J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION)
在HttpSession對(duì)象中保存非連續(xù)的對(duì)象
35.JCIP: Fields of immutable classes should be final (JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS)
?The class is annotated with net.jcip.annotations.Immutable, and the rules for that annotation require that all fields are final. .
36.NP: Method with Boolean return type returns explicit null (NP_BOOLEAN_RETURN_NULL)
返回值為boolean類型的方法直接返回null,這樣會(huì)導(dǎo)致空指針異常
37.NP: equals() method does not check for null argument (NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT)
變量調(diào)用equals方法時(shí)沒(méi)有進(jìn)行是否為null的判斷
38.NP: toString method may return null (NP_TOSTRING_COULD_RETURN_NULL)
toString方法可能返回null
39.Nm: Class names should start with an upper case letter (NM_CLASS_NAMING_CONVENTION)
類的名稱以大寫字母名稱開(kāi)頭
40.Nm: Class is not derived from an Exception, even though it is named as such (NM_CLASS_NOT_EXCEPTION)
類的名稱中含有Exception但是卻不是一個(gè)異常類的子類,這種名稱會(huì)造成混淆
41.Nm: Confusing method names (NM_CONFUSING)
令人迷惑的方面命名
42.Nm: Field names should start with a lower case letter (NM_FIELD_NAMING_CONVENTION)
非final類型的字段需要遵循駝峰命名原則
43.Nm: Use of identifier that is a keyword in later versions of Java (NM_FUTURE_KEYWORD_USED_AS_IDENTIFIER)
驗(yàn)證是否是java預(yù)留關(guān)鍵字
44.Nm: Use of identifier that is a keyword in later versions of Java (NM_FUTURE_KEYWORD_USED_AS_MEMBER_IDENTIFIER)
驗(yàn)證是否時(shí)java中的關(guān)鍵字
45.Nm: Method names should start with a lower case letter (NM_METHOD_NAMING_CONVENTION)
方法名稱以小寫字母開(kāi)頭
46.Nm: Class names shouldn't shadow simple name of implemented interface (NM_SAME_SIMPLE_NAME_AS_INTERFACE)
實(shí)現(xiàn)同一接口實(shí)現(xiàn)類不能使用相同的名稱,即使它們位于不同的包中
47.Nm: Class names shouldn't shadow simple name of superclass (NM_SAME_SIMPLE_NAME_AS_SUPERCLASS)
繼承同一父類的子類不能使用相同的名稱,即使它們位于不同的包中
48.Nm: Very confusing method names (but perhaps intentional) (NM_VERY_CONFUSING_INTENTIONAL)
很容易混淆的方法命名,例如方法的名稱名稱使用使用大小寫來(lái)區(qū)別兩個(gè)不同的方法。
49.Nm: Method doesn't override method in superclass due to wrong package for parameter (NM_WRONG_PACKAGE_INTENTIONAL)
由于錯(cuò)誤引用了不同包中相同類名的對(duì)象而不能夠正確的覆寫父類中的方法
import alpha.Foo;
public class A {
? public int f(Foo x) { return 17; }
}
import beta.Foo;
public class B extends A {
? public int f(Foo x) { return 42; }
? public int f(alpha.Foo x) { return 27; }
}
50.ODR: Method may fail to close database resource (ODR_OPEN_DATABASE_RESOURCE)
方法中可能存在關(guān)閉數(shù)據(jù)連接失敗的情況
51.OS: Method may fail to close stream (OS_OPEN_STREAM)
方法中可能存在關(guān)閉流失敗的情況
52.OS: Method may fail to close stream on exception (OS_OPEN_STREAM_EXCEPTION_PATH)
方法中可能存在關(guān)閉流時(shí)出現(xiàn)異常情況
53.RC: Suspicious reference comparison to constant (RC_REF_COMPARISON_BAD_PRACTICE)
當(dāng)兩者為不同類型的對(duì)象時(shí)使用equals方法來(lái)比較它們的值是否相等,而不是使用==方法。例如比較的兩者為java.lang.Integer, java.lang.Float
54.RC: Suspicious reference comparison of Boolean values (RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN)
使用== 或者 !=操作符來(lái)比較兩個(gè) Boolean類型的對(duì)象,建議使用equals方法。
55.RR: Method ignores results of InputStream.read() (RR_NOT_CHECKED)
InputStream.read方法忽略返回的多個(gè)字符,如果對(duì)結(jié)果沒(méi)有檢查就沒(méi)法正確處理用戶讀取少量字符請(qǐng)求的情況。
56.RR: Method ignores results of InputStream.skip() (SR_NOT_CHECKED)
InputStream.skip()方法忽略返回的多個(gè)字符,如果對(duì)結(jié)果沒(méi)有檢查就沒(méi)法正確處理用戶跳過(guò)少量字符請(qǐng)求的情況
57.RV: Method ignores exceptional return value (RV_RETURN_VALUE_IGNORED_BAD_PRACTICE)
方法忽略返回值的異常信息
58.SI: Static initializer creates instance before all static final fields assigned (SI_INSTANCE_BEFORE_FINALS_ASSIGNED)
在所有的static final字段賦值之前去使用靜態(tài)初始化的方法創(chuàng)建一個(gè)類的實(shí)例。
59.Se: Non-serializable value stored into instance field of a serializable class (SE_BAD_FIELD_STORE)
非序列化的值保存在聲明為序列化的的非序列化字段中
60.Se: Comparator doesn't implement Serializable (SE_COMPARATOR_SHOULD_BE_SERIALIZABLE)
Comparator接口沒(méi)有實(shí)現(xiàn)Serializable接口
61.Se: Serializable inner class (SE_INNER_CLASS)
序列化內(nèi)部類
62.Se: serialVersionUID isn't final (SE_NONFINAL_SERIALVERSIONID)
關(guān)于UID類的檢查內(nèi)容省略
63.Se: Class is Serializable but its superclass doesn't define a void constructor (SE_NO_SUITABLE_CONSTRUCTOR)
子類序列化時(shí)父類沒(méi)有提供一個(gè)void的構(gòu)造函數(shù)
64.Se: Class is Externalizable but doesn't define a void constructor (SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION)
Externalizable 實(shí)例類沒(méi)有定義一個(gè)void類型的構(gòu)造函數(shù)
65.Se: The readResolve method must be declared with a return type of Object. (SE_READ_RESOLVE_MUST_RETURN_OBJECT)
readResolve從流中讀取類的一個(gè)實(shí)例,此方法必須聲明返回一個(gè)Object類型的對(duì)象
66.Se: Transient field that isn't set by deserialization. (SE_TRANSIENT_FIELD_NOT_RESTORED)
This class contains a field that is updated at multiple places in the class, thus it seems to be part of the state of the class. However, since the field is marked as transient and not set in readObject or readResolve, it will contain the default value in any deserialized instance of the class.
67.SnVI: Class is Serializable, but doesn't define serialVersionUID (SE_NO_SERIALVERSIONID)
一個(gè)類實(shí)現(xiàn)了Serializable接口但是沒(méi)有定義serialVersionUID類型的變量。序列化運(yùn)行時(shí)使用一個(gè)稱為 serialVersionUID 的版本號(hào)與每個(gè)可序列化類相關(guān)聯(lián),該序列號(hào)在反序列化過(guò)程中用于驗(yàn)證序列化對(duì)象的發(fā)送者和接收者是否為該對(duì)象加載了與序列化兼容的類。如果接收者加載的該對(duì)象的類的 serialVersionUID 與對(duì)應(yīng)的發(fā)送者的類的版本號(hào)不同,則反序列化將會(huì)導(dǎo)致 InvalidClassException??尚蛄谢惪梢酝ㄟ^(guò)聲明名為 "serialVersionUID" 的字段(該字段必須是靜態(tài) (static)、最終 (final) 的 long 型字段)顯式聲明其自己的 serialVersionUID:?
?ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
68.UI: Usage of GetResource may be unsafe if class is extended (UI_INHERITANCE_UNSAFE_GETRESOURCE)
當(dāng)一個(gè)類被子類繼承后不要使用this.getClass().getResource(...)來(lái)獲取資源