Dispose Before Scope
ID |
csharp.dispose_before_scope |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
CSharp |
Tags |
CWE:772, idisposable, reliability, resource-leak |
Description
Reports local IDisposable variables that exit their enclosing method without a
matching Dispose() call. Leaking an unmanaged resource (file handles, sockets,
database connections) keeps it allocated until the finaliser runs, which on hot
paths is enough to exhaust the process handle table.
Rationale
The IDisposable contract is the .NET runtime’s only deterministic mechanism for
releasing native resources. Forgetting to call Dispose() defers the cleanup to
the GC, which may take seconds or minutes; under load, the leak is fast enough to
break the program before the GC notices.
public class Reader
{
public string Bad(string path)
{
var stream = new FileStream(path, FileMode.Open); // FLAW
return new StreamReader(stream).ReadToEnd();
}
public string OkUsing(string path)
{
using (var stream = new FileStream(path, FileMode.Open)) // OK
{
return new StreamReader(stream).ReadToEnd();
}
}
public string OkUsingDecl(string path)
{
using var stream = new FileStream(path, FileMode.Open); // OK
return new StreamReader(stream).ReadToEnd();
}
public string OkManual(string path)
{
var stream = new FileStream(path, FileMode.Open); // OK, explicit Dispose
try { return new StreamReader(stream).ReadToEnd(); }
finally { stream.Dispose(); }
}
}
Remediation
Wrap the declaration in a using statement or the using var declaration form so
the compiler emits the matching Dispose() call. When the disposable must outlive
the method, transfer ownership explicitly (assign to a field, return it, or pass
it to a registry that documents disposal responsibility).