@@ -349,22 +349,95 @@ module API {
349349 )
350350 }
351351
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+ }
353400
354401 /**
355402 * Gets a data flow node that is likely to refer to a built-in with the name `name`.
356403 *
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
358405 * built-in with a different value.
359406 */
360407 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 ( )
368441 }
369442
370443 /**
0 commit comments