CodeQL 文档

如果在执行过程中抛出异常,则可能不会调用 Dispose

ID: cs/dispose-not-called-on-throw
Kind: problem
Security severity: 
Severity: warning
Precision: medium
Tags:
   - efficiency
   - maintainability
   - external/cwe/cwe-404
   - external/cwe/cwe-459
   - external/cwe/cwe-460
Query suites:
   - csharp-security-and-quality.qls

单击以在 CodeQL 代码库中查看查询

如果在分配 IDisposable 对象与对该对象进行 Dispose() 调用之间抛出异常,并且 Dispose() 调用不在 catchfinally 块内,则 Dispose() 调用可能不会执行。

建议

如果可能,请将对象的分配包装在 using 块中,以便在 using 块完成后自动释放对象。

如果无法做到这一点,请确保对对象调用了 Dispose()。通常建议在 finally 块中调用 Dispose(),以确保即使抛出异常也能释放对象。

示例

在此示例中,创建了一个 SqlConnection,然后使用 SqlCommand 运行 SQL 查询。创建并释放了对象,但如果抛出异常(例如,通过调用 ExecuteReader),该方法将立即终止,并且永远不会对 cmdconn 调用 Dispose()。对于 SqlConnection,这可能会导致与连接关联的非托管资源被保留,并可能在尝试创建其他未来连接时导致资源耗尽。

using System;
using System.Data.SqlClient;

class Bad
{
    public SqlDataReader GetAllCustomers()
    {
        var conn = new SqlConnection("connection string");
        conn.Open();

        var cmd = new SqlCommand("SELECT * FROM Customers", conn);
        var ret = cmd.ExecuteReader();

        cmd.Dispose();
        conn.Dispose();

        return ret;
    }
}

在修改后的示例中,使用了一对 using 语句来确保在语句完成后释放连接和命令。

using System;
using System.Data.SqlClient;

class Good
{
    public SqlDataReader GetAllCustomers()
    {
        using (var conn = new SqlConnection("connection string"))
        {
            conn.Open();
            using (var cmd = new SqlCommand("SELECT * FROM Customers", conn))
            {
                return cmd.ExecuteReader();
            }
        }
    }
}

参考

  • ©GitHub 公司
  • 条款
  • 隐私