程式碼品質不佳,會導致無法預料的行為。從使用者的角度來看,這通常表現為可用性不佳。對於攻擊者而言,這提供了以意想不到的方式向系統施加壓力的機會。
getChunk == NULL
述詞會一直為 false,因為 getChunk
是定義於程式中的函數名稱。
if (getChunk == NULL)
return ERR;
char* getName() {
char name[STR_MAX];
fillInName(name);
return name;
}
class AccessLevel{
public static final int ROOT = 0;
//...
public static final int NONE = 9;
}
//...
class User {
private static int access;
public User(){
access = AccessLevel.ROOT;
}
public static int getAccessLevel(){
return access;
}
//...
}
class RegularUser extends User {
private static int access;
public RegularUser(){
access = AccessLevel.NONE;
}
public static int getAccessLevel(){
return access;
}
public static void escalatePrivilege(){
access = AccessLevel.ROOT;
}
//...
}
//...
class SecureArea {
//...
public static void doRestrictedOperation(User user){
if (user instanceof RegularUser){
if (user.getAccessLevel() == AccessLevel.ROOT){
System.out.println("doing a privileged operation");
}else{
throw new RuntimeException();
}
}
}
}
user
實例 (而不是針對 User
或 RegularUser
類別) 呼叫 getAccessLevel()
方法,因此這將意味著,此狀況一律會傳回 true
,並且會執行限制的操作,即使使用 instanceof
以進入 if/else
區塊的此部分也是如此。serialPersistentFields
,就必須將其宣告為private
、static
及 final
。serialPersistentFields
陣列中指定類別的可序列化欄位來手動定義這些欄位。這項功能只有在宣告 serialPersistentFields
為 private
、static
以及 final
時才有效。serialPersistentFields
的宣告來定義 Serializable
欄位,因為欄位不是 private
、static
以及 final
。
class List implements Serializable {
public ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("myField", List.class) };
...
}
Object.equals()
,而不是呼叫 java.util.Arrays.equals().
Object.equals()
是錯誤的,因為這將會檢查陣列的位址是否相等,而不是陣列的元素是否相等,所以通常應該由 java.util.Arrays.equals()
取而代之。 Object.equals()
函數嘗試檢查兩個陣列。
...
int[] arr1 = new int[10];
int[] arr2 = new int[10];
...
if (arr1.equals(arr2)){
//treat arrays as if identical elements
}
...
pthread_cleanup_push()
使 routine
函數呼叫執行緒清除堆疊並回傳結果。因為 pthread_cleanup_push()
和它的相鄰函數 pthread_cleanup_pop()
被視為巨集而在除了 IBM AIX 以外的平台上實作,所以之後呼叫 pthread_cleanup_pop()
時,不會存取由 pthread_cleanup_push()
建立的資料結構。在這些函數被視為巨集而實作的所有平台上執行此程式碼,將會無法進行編譯或無法正常操作。
void helper() {
...
pthread_cleanup_push (routine, arg);
}
void clean_up()
{
char tmp[256];
...
free(tmp);
return;
}
System.Object.Equals()
:
public boolean Equals(string obj) {
...
}
System.Object.Equals()
需要一個 object
類型的引數,因此將永遠不會呼叫此方法。Object.equals()
:
public boolean equals(Object obj1, Object obj2) {
...
}
Object.equals()
只需要一個引數,因此將永遠不會呼叫 Example 1
中的方法。ISerializable
介面但不聲明 [Serializable]
屬性的類別將不會序列化。[Serializable]
屬性的物件進行序列化。如果類別能夠透過由 .NET 框架定義的預設序列化方法來序列化,則物件也可正確地序列化。如果類別要求自訂的序列化方法,則它必須執行 ISerializable
介面。不過,類別仍然必須聲明 [Serializable]
屬性。CustomStorage
類別執行 ISerializable
介面。不過,因為它沒有聲明 [Serializable]
屬性,所以它不會序列化。
public class CustomStorage: ISerializable {
...
}
java.io.Serializable
的內部類別可能導致問題並從外部類別洩漏資訊。
...
class User implements Serializable {
private int accessLevel;
class Registrator implements Serializable {
...
}
}
Example 1
中,當序列化內部類別 Registrator
時,也會從 User
外部類別序列化 accessLevel
欄位。synchronized
,保證多個執行緒存取相同實例時可正確運作。也應該宣告所有的取代方法為 synchronized
,否則可能會發生意外行為。Foo
類別會取代 Bar
類別,但是不會宣告 synchronizedMethod
方法為 synchronized
:
public class Bar {
public synchronized void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
public class Foo extends Bar {
public void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
Foo
的實例轉換為 Bar
類型。若向兩個不同的執行緒提供同一實例,並重複執行 synchronizedMethod
,則行為將無法預測。obj.Equals(null)
將永遠為 false。Equals()
方法將物件與 null
做比較。Equals()
方法的約定將要求此比較永遠傳回 false。obj.equals(null)
將永遠為 false。equals()
方法將物件與 null
做比較。由於該物件不是 null
,因此,此比較將永遠傳回 false。(如果該物件為 null
,程式會拋出 NullPointerException
)。pthread_exit()
,就會先終止由主處理 main()
函數的 pthread_create()
所呼叫而洐生的執行緒。呼叫 pthread_exit()
保證主處理會持續進行,直到所有執行緒完成執運作方式止。或者,主處理可呼叫所有子執行緒上的 pthread_join
,並確定這些執行緒將在處理結束前完成。pthread_create()
來建立執行緒,然後正常結束。如果子執行緒在 main()
函數回傳時沒有完整執行,就會先被終止。
void *Simple(void *threadid)
{
...
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
int rc;
pthread_t pt;
rc = pthread_create(&pt, NULL, Simple, (void *)t);
if (rc){
exit(-1);
}
}
readObject()
方法所呼叫的函數可能被取代。readObject()
的作用類似建構函式,因此物件初始化會在此函數結束時才會完成。因此,當 Serializable
類別的 readObject()
函數呼叫可取代的函數時,此函數可在完全初始化物件之前,提供物件狀態的取代方法存取權。readObject()
函數所呼叫的方法可被取代。
...
private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
checkStream(ois);
ois.defaultReadObject();
}
public void checkStream(ObjectInputStream stream){
...
}
checkStream()
函數及其封裝類別不是 final
和公用的,這表示它們可以被取代,這可能意味著攻擊者可以取代 checkStream()
函數,以便在還原序列化期間取得對物件的存取權。private readonly
清單變數將會允許呼叫程式碼修改該清單的內容,如此可有效提供清單寫入存取權,並阻止程式設計師將它設為 private readonly
的計畫。private readonly
的 _item
清單。
class Order
{
private readonly List<string> _item = new List<string>();
public IEnumerable<string> Item { get { return _item; } }
public Order()
{
/*class initialize */
}
/*some important function......*/
}
Marker child = MarkerManager.getMarker("child");
Marker parent = MarkerManager.getMarker("parent");
child.addParents(parent);
parent.addParents(child);
String toInfinity = child.toString();
toString()
包括遞迴處理方法時,就會觸發堆疊溢位異常 (堆疊耗盡)。此異常起因於子項與父項之間的循環連結。String
物件並不可靠,所以不應該這樣做。String
物件,通常必須先透過 Double.toString()
之類的函數將浮點值變更為 String
物件。根據浮點變數的類型和值,在轉換為 String
物件時,它可能是「NaN」、「Infinity」、「-Infinity」,有特定含零的行尾小數位數,或是可能包含指數欄位。如果轉換為十六進位字串,表示法也會大為不同。String
。
...
int initialNum = 1;
...
String resultString = Double.valueOf(initialNum/10000.0).toString();
if (s.equals("0.0001")){
//do something
...
}
...
if
陳述式的條件將無法滿足。變數 s
不能為 Null,但只能將 s
設為非 Null 值的路徑卻存在 return
陳述式。
String s = null;
if (b) {
s = "Yes";
return;
}
if (s != null) {
Dead();
}