@@ -18,32 +18,44 @@ import javascript
18
18
* A call that checks a property of some file.
19
19
*/
20
20
class FileCheck extends DataFlow:: CallNode {
21
+ string member ;
22
+
21
23
FileCheck ( ) {
22
- this =
23
- NodeJSLib:: FS:: moduleMember ( [
24
- "open" , "openSync" , "exists" , "existsSync" , "stat" , "statSync" , "lstat" , "lstatSync" ,
25
- "fstat" , "fstatSync" , "access" , "accessSync"
26
- ] ) .getACall ( )
24
+ member =
25
+ [
26
+ "open" , "openSync" , "exists" , "existsSync" , "stat" , "statSync" , "lstat" , "lstatSync" ,
27
+ "fstat" , "fstatSync" , "access" , "accessSync"
28
+ ] and
29
+ this = NodeJSLib:: FS:: moduleMember ( member ) .getACall ( )
27
30
}
28
31
29
32
DataFlow:: Node getPathArgument ( ) { result = this .getArgument ( 0 ) }
33
+
34
+ /** Holds if this call is a simple existence check for a file. */
35
+ predicate isExistsCheck ( ) { member = [ "exists" , "existsSync" ] }
30
36
}
31
37
32
38
/**
33
39
* A call that modifies or otherwise interacts with a file.
34
40
*/
35
41
class FileUse extends DataFlow:: CallNode {
42
+ string member ;
43
+
36
44
FileUse ( ) {
37
- this =
38
- NodeJSLib:: FS:: moduleMember ( [
39
- // these are the six methods that accept file paths and file descriptors
40
- "readFile" , "readFileSync" , "writeFile" , "writeFileSync" , "appendFile" , "appendFileSync" ,
41
- // don't use "open" after e.g. "access"
42
- "open" , "openSync"
43
- ] ) .getACall ( )
45
+ member =
46
+ [
47
+ // these are the six methods that accept file paths and file descriptors
48
+ "readFile" , "readFileSync" , "writeFile" , "writeFileSync" , "appendFile" , "appendFileSync" ,
49
+ // don't use "open" after e.g. "access"
50
+ "open" , "openSync"
51
+ ] and
52
+ this = NodeJSLib:: FS:: moduleMember ( member ) .getACall ( )
44
53
}
45
54
46
55
DataFlow:: Node getPathArgument ( ) { result = this .getArgument ( 0 ) }
56
+
57
+ /** Holds if this call reads from a file. */
58
+ predicate isFileRead ( ) { member = [ "readFile" , "readFileSync" ] }
47
59
}
48
60
49
61
/**
@@ -101,5 +113,6 @@ from FileCheck check, FileUse use
101
113
where
102
114
checkAndUseOnSame ( check , use ) and
103
115
useAfterCheck ( check , use ) and
116
+ not ( check .isExistsCheck ( ) and use .isFileRead ( ) ) and // a read after an exists check is fine
104
117
not getAFileHandle ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( use .getPathArgument ( ) )
105
118
select use , "The file may have changed since it $@." , check , "was checked"
0 commit comments