@@ -349,22 +349,95 @@ module API {
349
349
)
350
350
}
351
351
352
- private import semmle.python.types.Builtins as Builtins
352
+ /** Gets the name of a known built-in. */
353
+ private string getBuiltInName ( ) {
354
+ // These lists were created by inspecting the `builtins` and `__builtin__` modules in
355
+ // Python 3 and 2 respectively, using the `dir` built-in.
356
+ // Built-in functions and exceptions shared between Python 2 and 3
357
+ result in [
358
+ "abs" , "all" , "any" , "bin" , "bool" , "bytearray" , "callable" , "chr" , "classmethod" ,
359
+ "compile" , "complex" , "delattr" , "dict" , "dir" , "divmod" , "enumerate" , "eval" , "filter" ,
360
+ "float" , "format" , "frozenset" , "getattr" , "globals" , "hasattr" , "hash" , "help" , "hex" ,
361
+ "id" , "input" , "int" , "isinstance" , "issubclass" , "iter" , "len" , "list" , "locals" , "map" ,
362
+ "max" , "memoryview" , "min" , "next" , "object" , "oct" , "open" , "ord" , "pow" , "print" ,
363
+ "property" , "range" , "repr" , "reversed" , "round" , "set" , "setattr" , "slice" , "sorted" ,
364
+ "staticmethod" , "str" , "sum" , "super" , "tuple" , "type" , "vars" , "zip" , "__import__" ,
365
+ // Exceptions
366
+ "ArithmeticError" , "AssertionError" , "AttributeError" , "BaseException" , "BufferError" ,
367
+ "BytesWarning" , "DeprecationWarning" , "EOFError" , "EnvironmentError" , "Exception" ,
368
+ "FloatingPointError" , "FutureWarning" , "GeneratorExit" , "IOError" , "ImportError" ,
369
+ "ImportWarning" , "IndentationError" , "IndexError" , "KeyError" , "KeyboardInterrupt" ,
370
+ "LookupError" , "MemoryError" , "NameError" , "NotImplemented" , "NotImplementedError" ,
371
+ "OSError" , "OverflowError" , "PendingDeprecationWarning" , "ReferenceError" , "RuntimeError" ,
372
+ "RuntimeWarning" , "StandardError" , "StopIteration" , "SyntaxError" , "SyntaxWarning" ,
373
+ "SystemError" , "SystemExit" , "TabError" , "TypeError" , "UnboundLocalError" ,
374
+ "UnicodeDecodeError" , "UnicodeEncodeError" , "UnicodeError" , "UnicodeTranslateError" ,
375
+ "UnicodeWarning" , "UserWarning" , "ValueError" , "Warning" , "ZeroDivisionError" ,
376
+ // Added for compatibility
377
+ "exec"
378
+ ]
379
+ or
380
+ // Built-in constants shared between Python 2 and 3
381
+ result in [ "False" , "True" , "None" , "NotImplemented" , "Ellipsis" , "__debug__" ]
382
+ or
383
+ // Python 3 only
384
+ result in [
385
+ "ascii" , "breakpoint" , "bytes" , "exec" ,
386
+ // Exceptions
387
+ "BlockingIOError" , "BrokenPipeError" , "ChildProcessError" , "ConnectionAbortedError" ,
388
+ "ConnectionError" , "ConnectionRefusedError" , "ConnectionResetError" , "FileExistsError" ,
389
+ "FileNotFoundError" , "InterruptedError" , "IsADirectoryError" , "ModuleNotFoundError" ,
390
+ "NotADirectoryError" , "PermissionError" , "ProcessLookupError" , "RecursionError" ,
391
+ "ResourceWarning" , "StopAsyncIteration" , "TimeoutError"
392
+ ]
393
+ or
394
+ // Python 2 only
395
+ result in [
396
+ "basestring" , "cmp" , "execfile" , "file" , "long" , "raw_input" , "reduce" , "reload" ,
397
+ "unichr" , "unicode" , "xrange"
398
+ ]
399
+ }
353
400
354
401
/**
355
402
* Gets a data flow node that is likely to refer to a built-in with the name `name`.
356
403
*
357
- * Currently this is an over-approximation, and does not account for things like overwriting a
404
+ * Currently this is an over-approximation, and may not account for things like overwriting a
358
405
* built-in with a different value.
359
406
*/
360
407
private DataFlow:: Node likely_builtin ( string name ) {
361
- result .asCfgNode ( ) =
362
- any ( NameNode n |
363
- n .isGlobal ( ) and
364
- n .isLoad ( ) and
365
- name = n .getId ( ) and
366
- name in [ any ( Builtins:: Builtin b ) .getName ( ) , "None" , "True" , "False" ]
367
- )
408
+ exists ( Module m |
409
+ result .asCfgNode ( ) =
410
+ any ( NameNode n |
411
+ possible_builtin_accessed_in_module ( n , name , m ) and
412
+ not possible_builtin_defined_in_module ( name , m )
413
+ )
414
+ )
415
+ }
416
+
417
+ /**
418
+ * Holds if a global variable called `name` (which is also the name of a built-in) is assigned
419
+ * a value in the module `m`.
420
+ */
421
+ private predicate possible_builtin_defined_in_module ( string name , Module m ) {
422
+ exists ( NameNode n |
423
+ not exists ( LocalVariable v | n .defines ( v ) ) and
424
+ n .isStore ( ) and
425
+ name = n .getId ( ) and
426
+ name = getBuiltInName ( ) and
427
+ m = n .getEnclosingModule ( )
428
+ )
429
+ }
430
+
431
+ /**
432
+ * Holds if `n` is an access of a global variable called `name` (which is also the name of a
433
+ * built-in) inside the module `m`.
434
+ */
435
+ private predicate possible_builtin_accessed_in_module ( NameNode n , string name , Module m ) {
436
+ n .isGlobal ( ) and
437
+ n .isLoad ( ) and
438
+ name = n .getId ( ) and
439
+ name = getBuiltInName ( ) and
440
+ m = n .getEnclosingModule ( )
368
441
}
369
442
370
443
/**
0 commit comments