Fortify Audit Workbench 筆記 Unreleased Resource: Database( 未釋放資源:數據庫)

Unreleased Resource: Database 未釋放資源:數據庫java

Abstract

程序可能沒法成功釋放某一項系統資源。數據庫

Explanation

程序可能沒法成功釋放某一項系統資源。 資源泄露至少有兩種常見的緣由:
- 錯誤情況及其餘異常狀況。
- 未明確程序的哪一部份負責釋放資源。
大部分 Unreleased Resource 問題只會致使通常的軟件可靠性問題, 但若是攻擊者可以故意觸發資源泄漏,該攻擊者就有可能經過耗盡資源池的方式發起 denial of service 攻
擊。
例 1: 下面的方法毫不會關閉它所打開的文件句柄。 FileInputStream 中的 finalize() 方法最終會調用 close(),但沒法保證它調用 finalize() 方法的時間。 在繁忙的環境中,這會致使 JVM 用盡它全部的文件句柄。網絡

private void processFile(String fName) throws FileNotFoundException,
IOException
{
FileInputStream fis = new FileInputStream(fName);
int sz;
byte[] byteArray = new byte[BLOCK_SIZE];
while ((sz = fis.read(byteArray)) != -1) {
processBytes(byteArray, sz);
}
}

例 2: 在正常條件下,如下代碼會執行數據庫查詢指令,處理數據庫返回的結果,並關閉已分配的指令對象。 但若是在執行 SQL 或是處理結果時發生異常,指令對象將不會關閉。 若是這種狀況頻繁出現,數據庫將用完全部可用的指針,且不能再執行任何 SQL 查詢。函數

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(CXN_SQL);
harvestResults(rs);
stmt.close();

Recommendation

1.毫不要依賴 finalize() 回收資源。 爲了使對象的 Finalize() 方法能被調用,垃圾收集器必須確認對象符合垃圾回收的條件。 可是垃圾收集器只有在 JVM 內存太小時纔會使用。所以,沒法保證什麼時候可以調用該對象的 finalize() 方法。 垃圾收集器最終運行時,可能出現這樣的狀況,即在短期內回收大量的資源,這種狀況會致使「突發」性能,並下降整體系統經過量。 隨着系統負載的增長,這種影響會愈來愈明顯。 最後, 若是某一資源回收操做被掛起(例如該操做須要經過網絡訪問數據庫),那麼執行 finalize() 方法的線程也將被掛起。 2. 在 finally 代碼段中釋放資源。 例 2 中的代碼可按如下方式改寫:性能

public void execCxnSql(Connection conn) {
    Statement stmt;
    try {
        stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(CXN_SQL);
        ...
    }
    finally {
        if (stmt != null) {
            safeClose(stmt);
        }
    }
}
public static void safeClose(Statement stmt) {
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
            log(e);
        }
    }
}

以上方案使用了一個助手函數,用以記錄在嘗試關閉指令時可能產生的異常。 該助手函數大約會在須要關閉指令時從新使用。 一樣, execCxnSql 方法不會將 stmt 對象預置爲空。 而是進行檢查,以確保調用safeClose() 以前, stmt 不是 null。 若是沒有檢查 null, Java 編譯器會報告 stmt 可能沒有進行初始化。 編譯器作出這一判斷源於 Java 能夠檢測未初始化的變量。 若是用一種更加複雜的方法將 stmt 初始化爲 null,那麼 Java 編譯器就沒法檢測 stmt 是否已被初始化。線程

相關文章
相關標籤/搜索