mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Address review comments
- changes `getReceiver` to `getObject` - fixes `calls` to avoid unwanted cross-talk - adds some more documentation to highlight the above issue
This commit is contained in:
@@ -42,7 +42,7 @@ API::Node sslContextInstance() {
|
||||
class WrapSocketCall extends ConnectionCreation, DataFlow::MethodCallNode {
|
||||
WrapSocketCall() { this = sslContextInstance().getMember("wrap_socket").getACall() }
|
||||
|
||||
override DataFlow::Node getContext() { result = this.getReceiver() }
|
||||
override DataFlow::Node getContext() { result = this.getObject() }
|
||||
}
|
||||
|
||||
class OptionsAugOr extends ProtocolRestriction, DataFlow::CfgNode {
|
||||
|
||||
@@ -70,7 +70,7 @@ private module Re {
|
||||
CompiledRegex() {
|
||||
exists(DataFlow::MethodCallNode patternCall |
|
||||
patternCall = API::moduleImport("re").getMember("compile").getACall() and
|
||||
patternCall.flowsTo(this.getReceiver()) and
|
||||
patternCall.flowsTo(this.getObject()) and
|
||||
this.getMethodName() instanceof RegexExecutionMethods and
|
||||
regexNode = patternCall.getArg(0)
|
||||
)
|
||||
|
||||
@@ -184,23 +184,38 @@ class CallCfgNode extends CfgNode, LocalSourceNode {
|
||||
* A data-flow node corresponding to a method call, that is `foo.bar(...)`.
|
||||
*
|
||||
* Also covers the case where the method lookup is done separately from the call itself, as in
|
||||
* `temp = foo.bar; temp(...)`.
|
||||
* `temp = foo.bar; temp(...)`. Note that this is only tracked through local scope.
|
||||
*/
|
||||
class MethodCallNode extends CallCfgNode {
|
||||
AttrRead method_lookup;
|
||||
|
||||
MethodCallNode() { method_lookup = this.getFunction().getALocalSource() }
|
||||
|
||||
/** Gets the name of the method being invoked (the `bar` in `foo.bar(...)`, if it can be determined. */
|
||||
/**
|
||||
* Gets the name of the method being invoked (the `bar` in `foo.bar(...)`) if it can be determined.
|
||||
*
|
||||
* Note that this method may have multiple results if a single call node represents calls to
|
||||
* multiple different objects and methods. If you want to link up objects and method names
|
||||
* accurately, use the `calls` method instead.
|
||||
*/
|
||||
string getMethodName() { result = method_lookup.getAttributeName() }
|
||||
|
||||
/** Gets the data-flow node corresponding to the receiver of this call. That is, the `foo` in `foo.bar(...)`. */
|
||||
Node getReceiver() { result = method_lookup.getObject() }
|
||||
/**
|
||||
* Gets the data-flow node corresponding to the object receiving this call. That is, the `foo` in
|
||||
* `foo.bar(...)`.
|
||||
*
|
||||
* Note that this method may have multiple results if a single call node represents calls to
|
||||
* multiple different objects and methods. If you want to link up objects and method names
|
||||
* accurately, use the `calls` method instead.
|
||||
*/
|
||||
Node getObject() { result = method_lookup.getObject() }
|
||||
|
||||
/** Holds if this data-flow node calls method `methodName` on receiver node `receiver`. */
|
||||
predicate calls(Node receiver, string methodName) {
|
||||
receiver = this.getReceiver() and
|
||||
methodName = this.getMethodName()
|
||||
/** Holds if this data-flow node calls method `methodName` on the object node `object`. */
|
||||
predicate calls(Node object, string methodName) {
|
||||
// As `getObject` and `getMethodName` may both have multiple results, we must look up the object
|
||||
// and method name directly on `method_lookup`.
|
||||
object = method_lookup.getObject() and
|
||||
methodName = method_lookup.getAttributeName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -267,8 +267,11 @@ private module CryptographyModel {
|
||||
string algorithmName;
|
||||
|
||||
CryptographyGenericCipherOperation() {
|
||||
this.getMethodName() in ["update", "update_into"] and
|
||||
this.getReceiver() in [cipherEncryptor(algorithmName), cipherDecryptor(algorithmName)]
|
||||
exists(DataFlow::Node object, string method |
|
||||
object in [cipherEncryptor(algorithmName), cipherDecryptor(algorithmName)] and
|
||||
method in ["update", "update_into"] and
|
||||
this.calls(object, method)
|
||||
)
|
||||
}
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
conjunctive_lookup
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | bar |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | foo |
|
||||
calls_lookup
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar |
|
||||
@@ -0,0 +1,6 @@
|
||||
if cond:
|
||||
meth = obj1.foo
|
||||
else:
|
||||
meth = obj2.bar
|
||||
|
||||
meth()
|
||||
18
python/ql/test/experimental/dataflow/method-calls/test.ql
Normal file
18
python/ql/test/experimental/dataflow/method-calls/test.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import experimental.dataflow.TestUtil.PrintNode
|
||||
|
||||
query predicate conjunctive_lookup(
|
||||
DataFlow::MethodCallNode methCall, string call, string object, string methodName
|
||||
) {
|
||||
call = prettyNode(methCall) and
|
||||
object = prettyNode(methCall.getObject()) and
|
||||
methodName = methCall.getMethodName()
|
||||
}
|
||||
|
||||
query predicate calls_lookup(
|
||||
DataFlow::MethodCallNode methCall, string call, string object, string methodName
|
||||
) {
|
||||
call = prettyNode(methCall) and
|
||||
exists(DataFlow::Node o | methCall.calls(o, methodName) and object = prettyNode(o))
|
||||
}
|
||||
Reference in New Issue
Block a user