1
1
/** Definitions for reasoning about whether files are closed. */
2
2
3
3
import python
4
- // import semmle.python.dataflow.DataFlow
4
+ import semmle.python.dataflow.new.internal.DataFlowDispatch
5
5
import semmle.python.ApiGraphs
6
6
7
7
abstract class FileOpen extends DataFlow:: CfgNode { }
8
8
9
9
class 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 }
11
22
}
12
23
13
- // todo: type tracking to find wrapping funcs
14
24
abstract class FileClose extends DataFlow:: CfgNode { }
15
25
16
26
class FileCloseCall extends FileClose {
17
27
FileCloseCall ( ) { exists ( DataFlow:: MethodCallNode mc | mc .calls ( this , "close" ) ) }
18
28
}
19
29
30
+ class OsCloseCall extends FileClose {
31
+ OsCloseCall ( ) { this = API:: moduleImport ( "os" ) .getMember ( "close" ) .getACall ( ) .getArg ( 0 ) }
32
+ }
33
+
20
34
class WithStatement extends FileClose {
21
35
WithStatement ( ) { exists ( With w | this .asExpr ( ) = w .getContextExpr ( ) ) }
22
36
}
@@ -34,6 +48,6 @@ predicate fileIsStoredInField(FileOpen fo) {
34
48
predicate fileNotAlwaysClosed ( FileOpen fo ) {
35
49
not fileIsClosed ( fo ) and
36
50
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 ( ) )
39
53
}
0 commit comments