@@ -18,32 +18,44 @@ import javascript
1818 * A call that checks a property of some file.
1919 */
2020class FileCheck extends DataFlow:: CallNode {
21+ string member ;
22+
2123 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 ( )
2730 }
2831
2932 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" ] }
3036}
3137
3238/**
3339 * A call that modifies or otherwise interacts with a file.
3440 */
3541class FileUse extends DataFlow:: CallNode {
42+ string member ;
43+
3644 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 ( )
4453 }
4554
4655 DataFlow:: Node getPathArgument ( ) { result = this .getArgument ( 0 ) }
56+
57+ /** Holds if this call reads from a file. */
58+ predicate isFileRead ( ) { member = [ "readFile" , "readFileSync" ] }
4759}
4860
4961/**
@@ -101,5 +113,6 @@ from FileCheck check, FileUse use
101113where
102114 checkAndUseOnSame ( check , use ) and
103115 useAfterCheck ( check , use ) and
116+ not ( check .isExistsCheck ( ) and use .isFileRead ( ) ) and // a read after an exists check is fine
104117 not getAFileHandle ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( use .getPathArgument ( ) )
105118select use , "The file may have changed since it $@." , check , "was checked"
0 commit comments