From fa2da2f3ecff346af41a425f496649952db0fd9a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Sun, 11 Sep 2022 22:25:29 +0200 Subject: [PATCH] Python: remove `NonLibraryNormalCall` it is not necessary to distinguish these calls, so we remove the class from the hierarchy. --- .../new/internal/DataFlowDispatchPointsTo.qll | 49 ++++++------------- .../dataflow/new/internal/DataFlowPrivate.qll | 6 +-- .../new/internal/FlowSummaryImplSpecific.qll | 13 +++-- 3 files changed, 27 insertions(+), 41 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll index f87631372d8..7e20307ff5f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll @@ -103,10 +103,10 @@ module ArgumentPassing { * Used to limit the size of predicates. */ predicate connects(CallNode call, CallableValue callable) { - exists(NonLibraryNormalCall c, NonLibraryDataFlowCallable k | + exists(NormalCall c, NonLibraryDataFlowCallable k | call = c.getNode() and callable = k.getCallableValue() and - k = c.getNonLibraryCallable() + k = c.getCallable() ) } @@ -511,31 +511,20 @@ class NormalCall extends DataFlowSourceCall, TNormalCall { abstract override Node getArg(int n); - override ControlFlowNode getNode() { result = call } + override CallNode getNode() { result = call } abstract override DataFlowCallable getCallable(); override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() } } -/** A (non-special) call that does not go to a library callable. */ -abstract class NonLibraryNormalCall extends NormalCall { - abstract Node getNonLibraryArg(int n); - - final override Node getArg(int n) { result = this.getNonLibraryArg(n) } - - abstract DataFlowCallable getNonLibraryCallable(); - - final override DataFlowCallable getCallable() { result = this.getNonLibraryCallable() } -} - /** * A call to a function. * This excludes calls to bound methods, classes, and special methods. * Bound method calls and class calls insert an argument for the explicit * `self` parameter, and special method calls have special argument passing. */ -class FunctionCall extends NonLibraryNormalCall { +class FunctionCall extends NormalCall { NonLibraryDataFlowCallable callable; FunctionCall() { @@ -543,15 +532,13 @@ class FunctionCall extends NonLibraryNormalCall { call = callable.getACall() } - override Node getNonLibraryArg(int n) { - result = getArg(call, TNoShift(), callable.getCallableValue(), n) - } + override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) } - override DataFlowCallable getNonLibraryCallable() { result = callable } + override DataFlowCallable getCallable() { result = callable } } /** A call to a lambda. */ -class LambdaCall extends NonLibraryNormalCall { +class LambdaCall extends NormalCall { NonLibraryDataFlowCallable callable; LambdaCall() { @@ -559,33 +546,29 @@ class LambdaCall extends NonLibraryNormalCall { callable = TLambda(any(Function f)) } - override Node getNonLibraryArg(int n) { - result = getArg(call, TNoShift(), callable.getCallableValue(), n) - } + override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) } - override DataFlowCallable getNonLibraryCallable() { result = callable } + override DataFlowCallable getCallable() { result = callable } } /** * Represents a call to a bound method call. * The node representing the instance is inserted as argument to the `self` parameter. */ -class MethodCall extends NonLibraryNormalCall { +class MethodCall extends NormalCall { FunctionValue bm; MethodCall() { call = bm.getAMethodCall() } private CallableValue getCallableValue() { result = bm } - override Node getNonLibraryArg(int n) { + override Node getArg(int n) { n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n) or n = 0 and result = TCfgNode(call.getFunction().(AttrNode).getObject()) } - override DataFlowCallable getNonLibraryCallable() { - result = TCallableValue(this.getCallableValue()) - } + override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) } } /** @@ -594,7 +577,7 @@ class MethodCall extends NonLibraryNormalCall { * That makes the call node be the post-update node holding the value of the object * after the constructor has run. */ -class ClassCall extends NonLibraryNormalCall { +class ClassCall extends NormalCall { ClassValue c; ClassCall() { @@ -604,15 +587,13 @@ class ClassCall extends NonLibraryNormalCall { private CallableValue getCallableValue() { c.getScope().getInitMethod() = result.getScope() } - override Node getNonLibraryArg(int n) { + override Node getArg(int n) { n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n) or n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call)) } - override DataFlowCallable getNonLibraryCallable() { - result = TCallableValue(this.getCallableValue()) - } + override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) } } /** A call to a special method. */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index ba7336378ad..a45ace62ae9 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -137,15 +137,15 @@ module SyntheticPostUpdateNode { * and should not have an extra node synthesised. */ Node argumentPreUpdateNode() { - result = any(FunctionCall c).getNonLibraryArg(_) + result = any(FunctionCall c).getArg(_) or // Avoid argument 0 of method calls as those have read post-update nodes. - exists(MethodCall c, int n | n > 0 | result = c.getNonLibraryArg(n)) + exists(MethodCall c, int n | n > 0 | result = c.getArg(n)) or result = any(SpecialCall c).getArg(_) or // Avoid argument 0 of class calls as those have non-synthetic post-update nodes. - exists(ClassCall c, int n | n > 0 | result = c.getNonLibraryArg(n)) + exists(ClassCall c, int n | n > 0 | result = c.getArg(n)) or // any argument of any call that we have not been able to resolve exists(CallNode call | not resolvedCall(call) | diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll index 3aa01a0a39e..d4cd71934ce 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll @@ -11,15 +11,20 @@ * These are identified by strings and has predicates for finding calls to them. * * Having both extracted and non-extracted callables means that we now have three types of calls: - * - Extracted calls to extracted callables, either `NonLibraryNormalCall` or `SpecialCall`. These are handled by standard data flow. - * - Extracted calls to non-extracted callables, `LibraryCall`. These are handled by summaries. + * - Extracted calls to extracted callables, either `NormalCall` or `SpecialCall`. These are handled by standard data flow. + * - Extracted calls to non-extracted callables, `LibraryCall`. These are handled by loking up the relevant summary when the + * global data flwo graph is connected up via `getViableCallable`. * - Non-extracted calls, `SummaryCall`. These are synthesised by the flow summary framework. * - * The first two can be referred to as `DataFlowSourceCall`. They have been split up for the benefit of call resolutiuon. + * The first two can be referred to as `DataFlowSourceCall`. In fact, `LibraryCall` is a subclass of `NormalCall`, where + * `getCallable` is set to `none()`. The member predicate `DataFlowSourceCall::getCallable` is _not_ the mechanism for + * call resolution in global data flow. That mechanism is `getViableCallable`. * Resolving a call to a non-extracted callable goes via `LibraryCallable::getACall`, which may involve type tracking. * To avoid that type tracking becomes mutualy recursive with data flow, type tracking must use a call graph not including summaries. + * Type tracking sees the callgraph given by `DataFlowSourceCall::getACallable`. * - * We do not support summaries of special methods. + * We do not support summaries of special methods via the special methods framework, + * the summary would have to identify the call. */ private import python