• Fortify Audit Workbench 笔记 Unreleased Resource: Database( 未释放资源:数据库)


    Unreleased Resource: Database 未释放资源:数据库

    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 是否已被初始化。

  • 相关阅读:
    古人诗词之王安石
    关于周期函数的命题
    Strum—Lioville问题
    计算反常积分
    【面积原理】计算级数和
    【洛谷P6046】纯粹容器
    【洛谷P3631】方格染色
    【牛客挑战赛48 E】速度即转发
    【CF103D】Time to Raid Cowavans
    【洛谷P4280】逆序对
  • 原文地址:https://www.cnblogs.com/mahongbiao/p/12494278.html
Copyright © 2020-2023  润新知