Python points-to: Fix up neverReturns() and return value of __import__().

This commit is contained in:
Mark Shannon
2019-04-12 15:42:56 +01:00
parent 62e05187af
commit 46b9ef79b4
4 changed files with 37 additions and 4 deletions

View File

@@ -52,6 +52,7 @@ abstract class CallableObjectInternal extends ObjectInternal {
override int length() { none() }
abstract predicate neverReturns();
}
@@ -146,6 +147,10 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
result.getNode() = this.getScope().getArgByName(name)
}
override predicate neverReturns() {
InterProceduralPointsTo::neverReturns(this.getScope())
}
}
@@ -220,9 +225,11 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
or
func = Builtin::builtin("intern") and result = Builtin::special("str")
or
func = Builtin::builtin("__import__") and result = Builtin::special("ModuleType")
or
/* Fix a few minor inaccuracies in the CPython analysis */
ext_rettype(func, result) and not (
func = Builtin::builtin("__import__") and result = Builtin::special("NoneType")
func = Builtin::builtin("__import__")
or
func = Builtin::builtin("compile") and result = Builtin::special("NoneType")
or
@@ -251,6 +258,10 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
none()
}
override predicate neverReturns() {
this = Module::named("sys").attr("exit")
}
}
@@ -334,6 +345,8 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
none()
}
override predicate neverReturns() { none() }
}
class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
@@ -405,6 +418,10 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
result = this.getFunction().getParameterByName(name)
}
override predicate neverReturns() {
this.getFunction().neverReturns()
}
}

View File

@@ -103,8 +103,7 @@ class CallableValue extends Value {
}
predicate neverReturns() {
// TO DO..
none()
this.(CallableObjectInternal).neverReturns()
}
Function getScope() {

View File

@@ -1022,6 +1022,23 @@ module InterProceduralPointsTo {
BaseFlow::reaches_exit(evar)
}
/** INTERNAL -- Use `FunctionObject.neverReturns()` instead.
* Whether function `func` never returns. Slightly conservative approximation, this predicate may be false
* for a function that can never return. */
cached predicate neverReturns(Function f) {
/* A Python function never returns if it has no normal exits that are not dominated by a
* call to a function which itself never returns.
*/
forall(BasicBlock exit |
exit = f.getANormalExit().getBasicBlock() |
exists(FunctionObject callee, BasicBlock call |
callee.getACall().getBasicBlock() = call and
callee.neverReturns() and
call.dominates(exit)
)
)
}
}
/** Gets the `value, origin` that `f` would refer to if it has not been assigned some other value */

View File

@@ -1268,7 +1268,7 @@ library module TaintFlowImplementation {
|
test.getSense() = true and not exists(kind.getClass())
or
test.getSense() = true and kind.getClass().getASuperType() = cls
test.getSense() = true and kind.getType().getASuperType() = cls
or
test.getSense() = false and not kind.getType().getASuperType() = cls
)