11/** Definitions for reasoning about whether files are closed. */
22
33import python
4- // import semmle.python.dataflow.DataFlow
4+ import semmle.python.dataflow.new.internal.DataFlowDispatch
55import semmle.python.ApiGraphs
66
77abstract class FileOpen extends DataFlow:: CfgNode { }
88
99class FileOpenCall extends FileOpen {
10- FileOpenCall ( ) { this = API:: builtin ( "open" ) .getACall ( ) }
10+ FileOpenCall ( ) { this = [ API:: builtin ( "open" ) .getACall ( ) ] }
11+ }
12+
13+ class FileWrapperClassCall extends FileOpen , DataFlow:: CallCfgNode {
14+ FileOpen wrapped ;
15+
16+ FileWrapperClassCall ( ) {
17+ wrapped = this .getArg ( _) .getALocalSource ( ) and
18+ this .getFunction ( ) = classTracker ( _)
19+ }
20+
21+ FileOpen getWrapped ( ) { result = wrapped }
1122}
1223
13- // todo: type tracking to find wrapping funcs
1424abstract class FileClose extends DataFlow:: CfgNode { }
1525
1626class FileCloseCall extends FileClose {
1727 FileCloseCall ( ) { exists ( DataFlow:: MethodCallNode mc | mc .calls ( this , "close" ) ) }
1828}
1929
30+ class OsCloseCall extends FileClose {
31+ OsCloseCall ( ) { this = API:: moduleImport ( "os" ) .getMember ( "close" ) .getACall ( ) .getArg ( 0 ) }
32+ }
33+
2034class WithStatement extends FileClose {
2135 WithStatement ( ) { exists ( With w | this .asExpr ( ) = w .getContextExpr ( ) ) }
2236}
@@ -34,6 +48,6 @@ predicate fileIsStoredInField(FileOpen fo) {
3448predicate fileNotAlwaysClosed ( FileOpen fo ) {
3549 not fileIsClosed ( fo ) and
3650 not fileIsReturned ( fo ) and
37- not fileIsStoredInField ( fo )
38- // TODO: exception cases
51+ not fileIsStoredInField ( fo ) and
52+ not exists ( FileWrapperClassCall fwc | fo = fwc . getWrapped ( ) )
3953}
0 commit comments