Python move various theXXX() predicates into the appropriate module.

This commit is contained in:
Mark Shannon
2019-01-18 14:27:23 +00:00
parent 2dea0b4270
commit 35fa5d8f60
30 changed files with 211 additions and 126 deletions

View File

@@ -67,9 +67,9 @@ predicate subscript(Stmt s) {
predicate encode_decode(Expr ex, ClassObject type) {
exists(string name |
ex.(Call).getFunc().(Attribute).getName() = name |
name = "encode" and type = builtin_object("UnicodeEncodeError")
name = "encode" and type = Object::builtin("UnicodeEncodeError")
or
name = "decode" and type = builtin_object("UnicodeDecodeError")
name = "decode" and type = Object::builtin("UnicodeDecodeError")
)
}

View File

@@ -3,9 +3,9 @@ import python
/** Holds if `notimpl` refers to `NotImplemented` or `NotImplemented()` in the `raise` statement */
predicate use_of_not_implemented_in_raise(Raise raise, Expr notimpl) {
notimpl.refersTo(theNotImplementedObject()) and
notimpl.refersTo(Object::notImplemented()) and
(
notimpl = raise.getException() or
notimpl = raise.getException() or
notimpl = raise.getException().(Call).getFunc()
)
}

View File

@@ -13,11 +13,11 @@
import python
FunctionObject iter() {
result = builtin_object("iter")
result = Object::builtin("iter")
}
FunctionObject next() {
result = builtin_object("next")
result = Object::builtin("next")
}
predicate call_to_iter(CallNode call, EssaVariable sequence) {

View File

@@ -107,7 +107,7 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en
private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) {
exists(CallNode call |
call = format_expr.getAFlowNode() |
call.getFunction().refersTo(theFormatFunction()) and call.getArg(0).refersTo(_, fmt.getAFlowNode()) and
call.getFunction().refersTo(BuiltinFunctionObject::format()) and call.getArg(0).refersTo(_, fmt.getAFlowNode()) and
args = count(format_expr.getAnArg()) - 1
or
call.getFunction().(AttrNode).getObject("format").refersTo(_, fmt.getAFlowNode()) and

View File

@@ -13,5 +13,5 @@ import python
from CallNode call, ControlFlowNode func
where
major_version() = 2 and call.getFunction() = func and func.refersTo(theApplyFunction())
major_version() = 2 and call.getFunction() = func and func.refersTo(BuiltinFunctionObject::apply())
select call, "Call to the obsolete builtin function 'apply'."

View File

@@ -14,5 +14,5 @@ import python
from CallNode call, Context context, ControlFlowNode func
where
context.getAVersion().includes(2, _) and call.getFunction() = func and func.refersTo(context, theInputFunction(), _, _)
context.getAVersion().includes(2, _) and call.getFunction() = func and func.refersTo(context, BuiltinFunctionObject::input(), _, _)
select call, "The unsafe built-in function 'input' is used."

View File

@@ -70,11 +70,11 @@ predicate correct_raise(string name, ClassObject ex) {
predicate preferred_raise(string name, ClassObject ex) {
attribute_method(name) and ex = theAttributeErrorType()
or
indexing_method(name) and ex = builtin_object("LookupError")
indexing_method(name) and ex = Object::builtin("LookupError")
or
ordering_method(name) and ex = theTypeErrorType()
or
arithmetic_method(name) and ex = builtin_object("ArithmeticError")
arithmetic_method(name) and ex = Object::builtin("ArithmeticError")
}
predicate no_need_to_raise(string name, string message) {

View File

@@ -128,7 +128,7 @@ predicate function_should_close_parameter(Function func) {
}
predicate function_opens_file(FunctionObject f) {
f = theOpenFunction()
f = BuiltinFunctionObject::open()
or
exists(EssaVariable v, Return ret |
ret.getScope() = f.getFunction() |

View File

@@ -42,7 +42,7 @@ predicate possible_reflective_name(string name) {
or
any(ModuleObject m).getName() = name
or
exists(builtin_object(name))
exists(Object::builtin(name))
}
int char_count(StrConst str) {

View File

@@ -39,14 +39,14 @@ predicate maybe_defined_in_outer_scope(Name n) {
}
Variable relevant_var(Name n) {
n.getVariable() = result and
(corresponding(n, _) or corresponding(_, n))
n.getVariable() = result and
(corresponding(n, _) or corresponding(_, n))
}
predicate same_name(Name n1, Name n2) {
corresponding(n1, n2) and
relevant_var(n1) = relevant_var(n2) and
not exists(builtin_object(n1.getId())) and
not exists(Object::builtin(n1.getId())) and
not maybe_defined_in_outer_scope(n2)
}

View File

@@ -12,5 +12,5 @@
import python
from CallNode call, string name
where call.getFunction().refersTo(quitterObject(name))
where call.getFunction().refersTo(Object::quitter(name))
select call, "The '" + name + "' site.Quitter object may not exist if the 'site' module is not loaded or is modified."

View File

@@ -15,7 +15,7 @@ predicate monkey_patched_builtin(string name) {
bltn.refersTo(theBuiltinModuleObject()) and
call.getArg(1).getNode() = s and
s.getText() = name and
call.getFunction().refersTo(builtin_object("setattr"))
call.getFunction().refersTo(Object::builtin("setattr"))
)
or
exists(AttrNode attr |

View File

@@ -45,7 +45,7 @@ predicate white_list(string name) {
predicate shadows(Name d, string name, Scope scope, int line) {
exists(LocalVariable l | d.defines(l) and scope instanceof Function and
l.getId() = name and
exists(builtin_object(l.getId()))
exists(Object::builtin(l.getId()))
) and
d.getScope() = scope and
d.getLocation().getStartLine() = line and

View File

@@ -21,7 +21,7 @@ predicate shadows(Name d, GlobalVariable g, Scope scope, int line) {
not exists(Import il, Import ig, Name gd | il.contains(d) and gd.defines(g) and ig.contains(gd)) and
not exists(Assign a | a.getATarget() = d and a.getValue() = g.getAnAccess())
) and
not exists(builtin_object(g.getId())) and
not exists(Object::builtin(g.getId())) and
d.getScope() = scope and
d.getLocation().getStartLine() = line and
exists(Name defn | defn.defines(g) |

View File

@@ -47,8 +47,8 @@ predicate one_item_only(For f) {
predicate points_to_call_to_range(ControlFlowNode f) {
/* (x)range is a function in Py2 and a class in Py3, so we must treat it as a plain object */
exists(Object range, Object call |
range = builtin_object("range") or
range = builtin_object("xrange")
range = Object::builtin("range") or
range = Object::builtin("xrange")
|
f.refersTo(call) and
call.(CallNode).getFunction().refersTo(range)

View File

@@ -24,7 +24,7 @@ predicate declaredInAll(Module m, StrConst name)
predicate mutates_globals(PythonModuleObject m) {
exists(CallNode globals |
globals = theGlobalsFunction().(FunctionObject).getACall() and
globals = BuiltinFunctionObject::globals().getACall() and
globals.getScope() = m.getModule() |
exists(AttrNode attr | attr.getObject() = globals)
or

View File

@@ -90,8 +90,8 @@ predicate use_of_exec(Module m) {
or
exists(CallNode call, FunctionObject exec |
exec.getACall() = call and call.getScope() = m |
exec = builtin_object("exec") or
exec = builtin_object("execfile")
exec = Object::builtin("exec") or
exec = Object::builtin("execfile")
)
}

View File

@@ -396,7 +396,7 @@ private predicate attribute_assignment_jump_to_defn_attribute(AttributeAssignmen
private predicate sets_attribute(ArgumentRefinement def, string name) {
exists(CallNode call |
call = def.getDefiningNode() and
call.getFunction().refersTo(builtin_object("setattr")) and
call.getFunction().refersTo(Object::builtin("setattr")) and
def.getInput().getAUse() = call.getArg(0) and
call.getArg(1).getNode().(StrConst).getText() = name
)

View File

@@ -201,7 +201,7 @@ private predicate gettext_installed() {
}
private predicate builtin_constant(string name) {
exists(builtin_object(name))
exists(Object::builtin(name))
or
name = "WindowsError"
or

View File

@@ -196,7 +196,7 @@ predicate function_can_never_return(FunctionObject func) {
not exists(f.getAnExitNode())
)
or
func = theExitFunctionObject()
func = BuiltinFunctionObject::sysExit()
}
/** Python specific sub-class of generic EssaNodeDefinition */
@@ -570,13 +570,13 @@ predicate potential_builtin_points_to(NameNode f, Object value, ClassObject cls,
(
builtin_name_points_to(f.getId(), value, cls)
or
not exists(builtin_object(f.getId())) and value = unknownValue() and cls = theUnknownType()
not exists(Object::builtin(f.getId())) and value = unknownValue() and cls = theUnknownType()
)
}
pragma [noinline]
predicate builtin_name_points_to(string name, Object value, ClassObject cls) {
value = builtin_object(name) and py_cobjecttypes(value, cls)
value = Object::builtin(name) and py_cobjecttypes(value, cls)
}
module BaseFlow {

View File

@@ -322,7 +322,7 @@ module PointsTo {
/** Holds if `call` is of the form `getattr(arg, "name")`. */
cached predicate getattr(CallNode call, ControlFlowNode arg, string name) {
points_to(call.getFunction(), _, builtin_object("getattr"), _, _) and
points_to(call.getFunction(), _, Object::builtin("getattr"), _, _) and
call.getArg(1).getNode().(StrConst).getText() = name and
arg = call.getArg(0)
}
@@ -1110,9 +1110,9 @@ module PointsTo {
pragma [noinline]
predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
exists(BuiltinCallable b |
b != builtin_object("isinstance") and
b != builtin_object("issubclass") and
b != builtin_object("callable") and
b != Object::builtin("isinstance") and
b != Object::builtin("issubclass") and
b != Object::builtin("callable") and
f = get_a_call(b, context) and
cls = b.getAReturnType()
) and
@@ -2007,9 +2007,9 @@ module PointsTo {
exists(ControlFlowNode func, Object obj |
two_args_first_arg_string(def, func, name) and
points_to(func, _, obj, _, _) |
obj = builtin_object("setattr") and result = true
obj = Object::builtin("setattr") and result = true
or
obj != builtin_object("setattr") and result = false
obj != Object::builtin("setattr") and result = false
)
}
@@ -2349,7 +2349,7 @@ module PointsTo {
(
exists(CallNode call |
call = expr and
points_to(call.getFunction(), context, theLenFunction(), _, _) and
points_to(call.getFunction(), context, Object::builtin("len"), _, _) and
use = call.getArg(0) and
val.(SequenceObject).getLength() = result
)

View File

@@ -246,7 +246,7 @@ private predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
tonode.getArg(0) = fromnode
)
or
tonode.getFunction().refersTo(builtin_object("reversed")) and
tonode.getFunction().refersTo(Object::builtin("reversed")) and
tonode.getArg(0) = fromnode
}
@@ -937,7 +937,7 @@ library module TaintFlowImplementation {
pragma [noinline]
predicate getattr_step(TaintedNode fromnode, TrackedValue totaint, CallContext tocontext, CallNode tonode) {
exists(ControlFlowNode arg, string name |
tonode.getFunction().refersTo(builtin_object("getattr")) and
tonode.getFunction().refersTo(Object::builtin("getattr")) and
arg = tonode.getArg(0) and
name = tonode.getArg(1).getNode().(StrConst).getText() and
arg = fromnode.getNode() and

View File

@@ -12,9 +12,9 @@ import semmle.python.security.strings.Untrusted
private FunctionObject exec_or_eval() {
result = builtin_object("exec")
result = Object::builtin("exec")
or
result = builtin_object("eval")
result = Object::builtin("eval")
}
/** A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.

View File

@@ -84,7 +84,7 @@ class OpenNode extends TaintSink {
OpenNode() {
exists(CallNode call |
call.getFunction().refersTo(builtin_object("open")) and
call.getFunction().refersTo(Object::builtin("open")) and
call.getAnArg() = this
)
}

View File

@@ -11,6 +11,6 @@ predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
tonode.getArg(0) = fromnode
)
or
tonode.getFunction().refersTo(builtin_object("reversed")) and
tonode.getFunction().refersTo(Object::builtin("reversed")) and
tonode.getArg(0) = fromnode
}

View File

@@ -495,9 +495,9 @@ ClassObject theUnicodeType() {
/** The builtin class '(x)range' */
ClassObject theRangeType() {
result = builtin_object("xrange")
result = Object::builtin("xrange")
or
major_version() = 3 and result = builtin_object("range")
major_version() = 3 and result = Object::builtin("range")
}
/** The builtin class for bytes. str in Python2, bytes in Python3 */
@@ -590,20 +590,20 @@ ClassObject theBuiltinPropertyType() {
/** The builtin class 'IOError' */
ClassObject theIOErrorType() {
result = builtin_object("IOError")
result = Object::builtin("IOError")
}
/** The builtin class 'super' */
ClassObject theSuperType() {
result = builtin_object("super")
result = Object::builtin("super")
}
/** The builtin class 'StopIteration' */
ClassObject theStopIterationType() {
result = builtin_object("StopIteration")
result = Object::builtin("StopIteration")
}
/** The builtin class 'NotImplementedError' */
ClassObject theNotImplementedErrorType() {
result = builtin_object("NotImplementedError")
result = Object::builtin("NotImplementedError")
}

View File

@@ -31,7 +31,7 @@ class RaisingNode extends ControlFlowNode {
}
private predicate quits() {
this.(CallNode).getFunction().refersTo(quitterObject(_))
this.(CallNode).getFunction().refersTo(Object::quitter(_))
}
/** Gets the type of an exception that may be raised
@@ -49,7 +49,7 @@ class RaisingNode extends ControlFlowNode {
pragma[noinline]
private ClassObject systemExitRaise() {
this.quits() and result = builtin_object("SystemExit")
this.quits() and result = Object::builtin("SystemExit")
}
pragma [noinline, nomagic]
@@ -62,7 +62,7 @@ class RaisingNode extends ControlFlowNode {
(ex.refersTo(result) or ex.refersTo(_, result, _))
)
or
this.getNode() instanceof ImportExpr and result = builtin_object("ImportError")
this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError")
or
this.getNode() instanceof Print and result = theIOErrorType()
or

View File

@@ -348,21 +348,21 @@ class BuiltinFunctionObject extends BuiltinCallable {
override ClassObject getAReturnType() {
/* Enumerate the types of a few builtin functions, that the CPython analysis misses.
*/
this = builtin_object("hex") and result = theStrType()
this = Object::builtin("hex") and result = theStrType()
or
this = builtin_object("oct") and result = theStrType()
this = Object::builtin("oct") and result = theStrType()
or
this = builtin_object("intern") and result = theStrType()
this = Object::builtin("intern") and result = theStrType()
or
/* Fix a few minor inaccuracies in the CPython analysis */
ext_rettype(this, result) and not (
this = builtin_object("__import__") and result = theNoneType()
this = Object::builtin("__import__") and result = theNoneType()
or
this = builtin_object("compile") and result = theNoneType()
this = Object::builtin("compile") and result = theNoneType()
or
this = builtin_object("sum")
this = Object::builtin("sum")
or
this = builtin_object("filter")
this = Object::builtin("filter")
)
}
@@ -376,4 +376,107 @@ class BuiltinFunctionObject extends BuiltinCallable {
}
module BuiltinFunctionObject {
/** The builtin function apply (Python 2 only) */
BuiltinFunctionObject apply() {
result = Object::builtin("apply")
}
/** The builtin function `hasattr` */
BuiltinFunctionObject hasattr() {
result = Object::builtin("hasattr")
}
/** The builtin function `len` */
BuiltinFunctionObject len() {
result = Object::builtin("len")
}
BuiltinFunctionObject format() {
result = Object::builtin("format")
}
/** The builtin function open */
BuiltinFunctionObject open() {
result = Object::builtin("open")
}
/** The builtin function print (Python 2.7 upwards) */
BuiltinFunctionObject print() {
result = Object::builtin("print")
}
/** The builtin function input (Python 2 only) */
BuiltinFunctionObject input() {
result = Object::builtin("input")
}
/** The builtin function locals */
BuiltinFunctionObject locals() {
py_special_objects(result, "locals")
}
/** The builtin function globals */
BuiltinFunctionObject globals() {
py_special_objects(result, "globals")
}
/** The builtin function sys.exit */
BuiltinFunctionObject sysExit() {
py_cmembers_versioned(theSysModuleObject(), "exit", result, major_version().toString())
}
}
/** DEPRECATED -- Use `BuiltinFunctionObject::apply()` instead. */
Object theApplyFunction() {
result = BuiltinFunctionObject::apply()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::hasattr()` instead. */
Object theHasattrFunction() {
result = BuiltinFunctionObject::hasattr()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::len()` instead. */
Object theLenFunction() {
result = BuiltinFunctionObject::len()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::format()` instead. */
Object theFormatFunction() {
result = BuiltinFunctionObject::format()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::open()` instead. */
Object theOpenFunction() {
result = BuiltinFunctionObject::open()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::print()` instead. */
Object thePrintFunction() {
result = BuiltinFunctionObject::print()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::input()` instead. */
Object theInputFunction() {
result = BuiltinFunctionObject::input()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::locals()` instead. */
Object theLocalsFunction() {
result = BuiltinFunctionObject::locals()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::globals()` instead. */
Object theGlobalsFunction() {
result = BuiltinFunctionObject::globals()
}
/** DEPRECATED -- Use `BuiltinFunctionObject::sysExit()` instead. */
Object theExitFunctionObject() {
result = BuiltinFunctionObject::sysExit()
}

View File

@@ -354,6 +354,14 @@ class TupleObject extends SequenceObject {
}
module TupleObject {
TupleObject empty() {
py_cobjecttypes(result, theTupleType()) and not py_citems(result, _, _)
}
}
class NonEmptyTupleObject extends TupleObject {
NonEmptyTupleObject() {
@@ -389,108 +397,82 @@ BuiltinModuleObject theSysModuleObject() {
py_special_objects(result, "sys")
}
/** DEPRECATED -- Use `Object::builtin(name)` instead. */
deprecated
Object builtin_object(string name) {
py_cmembers_versioned(theBuiltinModuleObject(), name, result, major_version().toString())
result = Object::builtin(name)
}
/** The built-in object None */
Object theNoneObject() {
Object theNoneObject() {
py_special_objects(result, "None")
}
/** The built-in object True */
Object theTrueObject() {
Object theTrueObject() {
py_special_objects(result, "True")
}
/** The built-in object False */
Object theFalseObject() {
Object theFalseObject() {
py_special_objects(result, "False")
}
/** The builtin function apply (Python 2 only) */
Object theApplyFunction() {
result = builtin_object("apply")
}
/** The builtin function hasattr */
Object theHasattrFunction() {
result = builtin_object("hasattr")
}
/** The builtin function len */
Object theLenFunction() {
result = builtin_object("len")
}
/** The builtin function format */
Object theFormatFunction() {
result = builtin_object("format")
}
/** The builtin function open */
Object theOpenFunction() {
result = builtin_object("open")
}
/** The builtin function print (Python 2.7 upwards) */
Object thePrintFunction() {
result = builtin_object("print")
}
/** The builtin function input (Python 2 only) */
Object theInputFunction() {
result = builtin_object("input")
}
/** The builtin function locals */
Object theLocalsFunction() {
py_special_objects(result, "locals")
}
/** The builtin function globals */
Object theGlobalsFunction() {
py_special_objects(result, "globals")
}
/** The builtin function sys.exit */
Object theExitFunctionObject() {
py_cmembers_versioned(theSysModuleObject(), "exit", result, major_version().toString())
}
/** The NameError class */
Object theNameErrorType() {
result = builtin_object("NameError")
result = Object::builtin("NameError")
}
/** The StandardError class */
Object theStandardErrorType() {
result = builtin_object("StandardError")
result = Object::builtin("StandardError")
}
/** The IndexError class */
Object theIndexErrorType() {
result = builtin_object("IndexError")
result = Object::builtin("IndexError")
}
/** The LookupError class */
Object theLookupErrorType() {
result = builtin_object("LookupError")
result = Object::builtin("LookupError")
}
/** The named quitter object (quit or exit) in the builtin namespace */
/** DEPRECATED -- Use `Object::quitter(name)` instead. */
deprecated
Object quitterObject(string name) {
(name = "quit" or name = "exit") and
result = builtin_object(name)
result = Object::quitter(name)
}
/** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */
/** DEPRECATED -- Use `Object::notImplemented()` instead. */
deprecated
Object theNotImplementedObject() {
result = builtin_object("NotImplemented")
result = Object::builtin("NotImplemented")
}
/** DEPRECATED -- Use `TupleObject::empty()` instead. */
deprecated
Object theEmptyTupleObject() {
py_cobjecttypes(result, theTupleType()) and not py_citems(result, _, _)
result = TupleObject::empty()
}
module Object {
Object builtin(string name) {
py_cmembers_versioned(theBuiltinModuleObject(), name, result, major_version().toString())
}
/** The named quitter object (quit or exit) in the builtin namespace */
Object quitter(string name) {
(name = "quit" or name = "exit") and
result = builtin(name)
}
/** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */
Object notImplemented() {
result = builtin("NotImplemented")
}
}

View File

@@ -18,7 +18,7 @@ predicate tracked_object(ControlFlowNode obj, string attr) {
}
predicate open_file(Object obj) {
obj.(CallNode).getFunction().refersTo(theOpenFunction())
obj.(CallNode).getFunction().refersTo(BuiltinFunctionObject::open())
}
predicate string_attribute_any(ControlFlowNode n, string attr) {
@@ -26,9 +26,9 @@ predicate string_attribute_any(ControlFlowNode n, string attr) {
exists(Object input |
n.(CallNode).getFunction().refersTo(input) |
if major_version() = 2 then
input = builtin_object("raw_input")
input = Object::builtin("raw_input")
else
input = theInputFunction()
input = BuiltinFunctionObject::input()
)
or
attr = "file-input" and