/** * Pass #21: resource-leak (CWE-772, category: reliability) * * Detects I/O resources (streams, connections, sockets) that are opened but * not closed on all exit paths. Unclosed resources exhaust file descriptors * or connection pools and cause subtle failures under load. * * Detection strategy: * 1. Find resource-opening calls: known constructors (FileInputStream, etc.) * or factory methods (open, createReadStream, etc.). * 2. Get the variable bound to the resource from DFG defs at the open line. * 3. Within the enclosing method, look for a close()/dispose() call whose * receiver matches the resource variable. * 4a. No close call found → definite leak (high, error). * 4b. Close found but no `finally` keyword in the method after the open * → potential leak (medium, warning): an exception skips the close. * * Note: Java try-with-resources generates no explicit close() in the source; * the pass treats the absence of both an explicit close AND a finally as a * definite leak. */ import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js'; export interface ResourceLeakResult { /** Resources that may not be properly closed. */ leaks: Array<{ line: number; resource: string; variable: string; kind: 'definite' | 'potential'; }>; } export declare class ResourceLeakPass implements AnalysisPass { readonly name = "resource-leak"; readonly category: "reliability"; run(ctx: PassContext): ResourceLeakResult; /** True if a `finally` keyword appears in the method body after the open line. */ private hasFinallyBlock; /** * True if a try-with-resources or Python `with` statement wraps the resource, * indicating implicit close. Detects `try (` or `with open(` patterns. */ private hasTryWithResources; /** * #158 — true if `variable` appears in a `return ...` expression within * the enclosing method's line range. Returning the handle transfers * ownership to the caller (caller is responsible for close). */ private isReturnedToCaller; /** * #158 — if `variable` is assigned to `this.` within the * enclosing method (scanning from the open line to method end), * returns the field name; otherwise null. */ private fieldStoredName; /** * #158 — true if the enclosing class declares any call of the form * `.(...)` where closeMethod is in * CLOSE_METHODS. Indicates a paired close method (e.g. `closeDriver`) * exists on the same class, so the field-stored resource is * eventually released. */ private classHasCloseMethodFor; /** * #158 — true if the enclosing method's name matches a factory-shape * prefix (`open` / `create` / `new` / `get` / `make` / `build` followed * by a capital letter) AND its return type is non-void / non-null. * Both conditions required: methods named `process()` or * `void openFoo()` continue to fire. */ private isFactoryMethod; /** * #226 — true if `variable` is passed as a constructor argument to a * known Closeable wrapper call within the enclosing method's line * range. Ownership of the inner stream transfers to the wrapper. * * The check is deliberately per-method: cross-method wrapping does * not apply because the inner reference has already escaped the * scope by then. */ private isWrappedByCloseableCtor; /** * #227 — true if `variable` refers to a field of the enclosing class * that is closed inside a worker-literal method (Runnable#run, * Callable#call, Consumer#accept, ...) declared in the same enclosing * method. Ownership transfers to the executor thread. * * The heuristic is intentionally conservative: it requires both * (a) the resource variable to match a declared field name on the * enclosing class (so a stray local named `selector` cannot * accidentally opt in to the suppression), AND * (b) a `.close()` (or CLOSE_METHODS) call to appear on a * line inside a method whose name is one of WORKER_METHODS and * whose start_line is strictly within the enclosing method's * body (nested literal indicator). */ private isClosedInNestedWorker; } //# sourceMappingURL=resource-leak-pass.d.ts.map