diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index 3d9a648ea6ce5..060d724a1362c 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -934,21 +934,3 @@ private class SummarizedCallableAdapter extends SummarizedCallable { interpretSummary(this, _, _, _, provenance) } } - -// adapter class for converting Mad neutrals to `NeutralCallable`s -private class NeutralCallableAdapter extends NeutralCallable { - string kind; - string provenance_; - - NeutralCallableAdapter() { - // Neutral models have not been implemented for CPP. - none() and - exists(this) and - exists(kind) and - exists(provenance_) - } - - override string getKind() { result = kind } - - override predicate hasProvenance(Provenance provenance) { provenance = provenance_ } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll index c8d74360d2978..3dce45b7a500e 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll @@ -556,7 +556,7 @@ private predicate interpretSummary( ) } -private predicate interpretNeutral(UnboundCallable c, string kind, string provenance) { +predicate interpretNeutral(UnboundCallable c, string kind, string provenance) { exists(string namespace, string type, string name, string signature | neutralModel(namespace, type, name, signature, kind, provenance) and c = interpretElement(namespace, type, false, name, signature, "") @@ -613,18 +613,6 @@ private class SummarizedCallableAdapter extends SummarizedCallable { } } -// adapter class for converting Mad neutrals to `NeutralCallable`s -private class NeutralCallableAdapter extends NeutralCallable { - string kind; - string provenance_; - - NeutralCallableAdapter() { interpretNeutral(this, kind, provenance_) } - - override string getKind() { result = kind } - - override predicate hasProvenance(Provenance provenance) { provenance = provenance_ } -} - /** * A callable where there exists a MaD sink model that applies to it. */ diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 596654797ab1f..7691376203ecd 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -16,6 +16,12 @@ private import semmle.code.csharp.dataflow.internal.ExternalFlow module Input implements InputSig { class SummarizedCallableBase = UnboundCallable; + predicate neutralElement(SummarizedCallableBase c, string kind, string provenance, boolean isExact) { + interpretNeutral(c, kind, provenance) and + // isExact has not been implemented yet. + isExact = false + } + ArgumentPosition callbackSelfParameterPosition() { result.isDelegateSelf() } ReturnKind getStandardReturnValueKind() { result instanceof NormalReturnKind } diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql index ccdf691d0b23b..677e4071a94f3 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql @@ -1,10 +1,10 @@ import shared.FlowSummaries import semmle.code.csharp.dataflow.internal.ExternalFlow -final private class NeutralCallableFinal = NeutralCallable; - -class RelevantNeutralCallable extends NeutralCallableFinal { - final string getCallableCsv() { result = getSignature(this) } +module R implements RelevantNeutralCallableSig { + class RelevantNeutralCallable extends NeutralSummaryCallable { + final string getCallableCsv() { result = getSignature(this) } + } } class RelevantSourceCallable extends SourceCallable { @@ -16,5 +16,5 @@ class RelevantSinkCallable extends SinkCallable { } import TestSummaryOutput -import TestNeutralOutput +import TestNeutralOutput import External::TestSourceSinkOutput diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 94b5dd708b2c1..53a3defa75add 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -595,15 +595,3 @@ private class SummarizedCallableAdapter extends SummarizedCallable { summaryElement(this, _, _, _, provenance, _) } } - -// adapter class for converting Mad neutrals to `NeutralCallable`s -private class NeutralCallableAdapter extends NeutralCallable { - string kind; - string provenance_; - - NeutralCallableAdapter() { neutralElement(this, kind, provenance_) } - - override string getKind() { result = kind } - - override predicate hasProvenance(Provenance provenance) { provenance = provenance_ } -} diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll index df1b3093bc3b7..2dcfcca6b41f8 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll @@ -23,6 +23,17 @@ private string positionToString(int pos) { module Input implements InputSig { class SummarizedCallableBase = Callable; + predicate neutralElement( + Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact + ) { + exists(string namespace, string type, string name, string signature | + neutralModel(namespace, type, name, signature, kind, provenance) and + c.asFunction() = interpretElement(namespace, type, false, name, signature, "").asEntity() + ) and + // isExact has not been implemented yet. + isExact = false + } + ArgumentPosition callbackSelfParameterPosition() { result = -1 } ReturnKind getStandardReturnValueKind() { result = getReturnKind(0) } @@ -304,10 +315,7 @@ module Private { * and with provenance `provenance`. */ predicate neutralElement(Input::SummarizedCallableBase c, string kind, string provenance) { - exists(string namespace, string type, string name, string signature | - neutralModel(namespace, type, name, signature, kind, provenance) and - c.asFunction() = interpretElement(namespace, type, false, name, signature, "").asEntity() - ) + Input::neutralElement(c, kind, provenance, false) } } diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 234d6e5cf13b6..86ac30bdce4dc 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -627,21 +627,6 @@ private class SummarizedCallableAdapter extends SummarizedCallable { override predicate hasExactModel() { summaryElement(this, _, _, _, _, _, true) } } -// adapter class for converting Mad neutrals to `NeutralCallable`s -private class NeutralCallableAdapter extends NeutralCallable { - string kind; - string provenance_; - boolean exact; - - NeutralCallableAdapter() { neutralElement(this, kind, provenance_, exact) } - - override string getKind() { result = kind } - - override predicate hasProvenance(Provenance provenance) { provenance = provenance_ } - - override predicate hasExactModel() { exact = true } -} - /** * A callable where there exists a MaD sink model that applies to it. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll index 6f27ea5b4b564..28c3d9a3633cb 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -1,6 +1,7 @@ private import java private import DataFlowPrivate private import DataFlowUtil +private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow private import semmle.code.java.dataflow.InstanceAccess private import semmle.code.java.dataflow.internal.FlowSummaryImpl as Impl private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll index 0a994991e26b9..feab4b3cec78f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll @@ -29,6 +29,15 @@ private string positionToString(int pos) { module Input implements InputSig { class SummarizedCallableBase = FlowSummary::SummarizedCallableBase; + predicate neutralElement( + Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact + ) { + exists(string namespace, string type, string name, string signature | + neutralModel(namespace, type, name, signature, kind, provenance) and + c.asCallable() = interpretElement(namespace, type, false, name, signature, "", isExact) + ) + } + ArgumentPosition callbackSelfParameterPosition() { result = -1 } ReturnKind getStandardReturnValueKind() { any() } @@ -332,18 +341,7 @@ module Private { ) } - /** - * Holds if a neutral model exists for `c` of kind `kind` - * and with provenance `provenance`. - */ - predicate neutralElement( - Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact - ) { - exists(string namespace, string type, string name, string signature | - neutralModel(namespace, type, name, signature, kind, provenance) and - c.asCallable() = interpretElement(namespace, type, false, name, signature, "", isExact) - ) - } + predicate neutralElement = Input::neutralElement/4; } /** Provides predicates for constructing summary components. */ diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index 0fd1835dba7d7..ba14cff067e09 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -19,6 +19,17 @@ signature module InputSig Lang> { string toString(); } + /** + * Holds if a neutral (MaD) model exists for `c` of kind `kind` + * with provenance `provenance` and `isExact` is true if the model + * signature matches `c` exactly - otherwise false. + */ + default predicate neutralElement( + SummarizedCallableBase c, string kind, string provenance, boolean isExact + ) { + none() + } + /** Gets the parameter position representing a callback itself, if any. */ default Lang::ArgumentPosition callbackSelfParameterPosition() { none() } @@ -261,64 +272,106 @@ module Make< predicate hasExactModel() { none() } } - final private class NeutralCallableFinal = NeutralCallable; + private signature predicate hasKindSig(string kind); - /** - * A callable where there is no flow via the callable. - */ - class NeutralSummaryCallable extends NeutralCallableFinal { - NeutralSummaryCallable() { this.getKind() = "summary" } - } + signature class NeutralCallableSig extends SummarizedCallableBaseFinal { + /** + * Holds if the neutral has provenance `p`. + */ + predicate hasProvenance(Provenance p); - /** - * A callable that has a neutral source model. - */ - class NeutralSourceCallable extends NeutralCallableFinal { - NeutralSourceCallable() { this.getKind() = "source" } + /** + * Gets the kind of the neutral. + */ + string getKind(); + + /** + * Holds if the neutral is auto generated. + */ + predicate hasGeneratedModel(); + + /** + * Holds if there exists a manual neutral that applies to this callable. + */ + predicate hasManualModel(); } /** - * A callable that has a neutral sink model. + * A module for constructing classes of neutral callables. */ - class NeutralSinkCallable extends NeutralCallableFinal { - NeutralSinkCallable() { this.getKind() = "sink" } + private module MakeNeutralCallable { + class NeutralCallable extends SummarizedCallableBaseFinal { + private string kind; + private string provenance_; + private boolean exact; + + NeutralCallable() { + hasKind(kind) and + neutralElement(this, kind, provenance_, exact) + } + + /** + * Gets the kind of the neutral. + */ + string getKind() { result = kind } + + /** + * Holds if the neutral has provenance `p`. + */ + predicate hasProvenance(Provenance provenance) { provenance = provenance_ } + + /** + * Holds if the neutral is auto generated. + */ + final predicate hasGeneratedModel() { + any(Provenance p | this.hasProvenance(p)).isGenerated() + } + + /** + * Holds if there exists a manual neutral that applies to this callable. + */ + final predicate hasManualModel() { any(Provenance p | this.hasProvenance(p)).isManual() } + + /** + * Holds if there exists a model for which this callable is an exact + * match, that is, no overriding was used to identify this callable from + * the model. + */ + predicate hasExactModel() { exact = true } + } } + private predicate neutralSummaryKind(string kind) { kind = "summary" } + /** - * A callable that has a neutral model. + * A callable where there exists a MaD neutral summary model that applies to it. */ - abstract class NeutralCallable extends SummarizedCallableBaseFinal { - bindingset[this] - NeutralCallable() { exists(this) } + class NeutralSummaryCallable = MakeNeutralCallable::NeutralCallable; - /** - * Holds if the neutral is auto generated. - */ - final predicate hasGeneratedModel() { - any(Provenance p | this.hasProvenance(p)).isGenerated() - } + private predicate neutralSourceKind(string kind) { kind = "source" } - /** - * Holds if there exists a manual neutral that applies to this callable. - */ - final predicate hasManualModel() { any(Provenance p | this.hasProvenance(p)).isManual() } + /** + * A callable where there exists a MaD neutral source model that applies to it. + */ + class NeutralSourceCallable = MakeNeutralCallable::NeutralCallable; - /** - * Holds if the neutral has provenance `p`. - */ - abstract predicate hasProvenance(Provenance p); + private predicate neutralSinkKind(string kind) { kind = "sink" } - /** - * Gets the kind of the neutral. - */ - abstract string getKind(); + /** + * A callable where there exists a MaD neutral sink model that applies to it. + */ + class NeutralSinkCallable = MakeNeutralCallable::NeutralCallable; - /** - * Holds if there exists a model for which this callable is an exact - * match, that is, no overriding was used to identify this callable from - * the model. - */ - predicate hasExactModel() { none() } + /** + * A callable where there exist a MaD neutral (summary, source or sink) model + * that applies to it. + */ + class NeutralCallable extends SummarizedCallableBaseFinal { + NeutralCallable() { + this instanceof NeutralSummaryCallable or + this instanceof NeutralSourceCallable or + this instanceof NeutralSinkCallable + } } } @@ -1880,13 +1933,20 @@ module Make< } /** A summarized callable relevant for testing. */ - signature class RelevantNeutralCallableSig extends NeutralCallable { - /** Gets the string representation of this callable used by `neutral/1`. */ - string getCallableCsv(); + signature module RelevantNeutralCallableSig { + class RelevantNeutralCallable extends NeutralCallableInput { + /** Gets the string representation of this callable used by `neutral/1`. */ + string getCallableCsv(); + } } - module TestNeutralOutput { - private string renderProvenance(NeutralCallable c) { + module TestNeutralOutput< + NeutralCallableSig NeutralCallableInput, + RelevantNeutralCallableSig RelevantNeutralCallableInput> + { + class RelevantNeutralCallable = RelevantNeutralCallableInput::RelevantNeutralCallable; + + private string renderProvenance(NeutralCallableInput c) { exists(Provenance p | p.isManual() and c.hasProvenance(p) and result = p.toString()) or not c.hasManualModel() and diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 80f4b8a1bc6ca..f396f9536e828 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -574,21 +574,3 @@ private class SummarizedCallableAdapter extends SummarizedCallable { interpretSummary(this, _, _, _, provenance, _) } } - -// adapter class for converting Mad neutrals to `NeutralCallable`s -private class NeutralCallableAdapter extends NeutralCallable { - string kind; - string provenance_; - - NeutralCallableAdapter() { - // Neutral models have not been implemented for Swift. - none() and - exists(this) and - exists(kind) and - exists(provenance_) - } - - override string getKind() { result = kind } - - override predicate hasProvenance(Provenance provenance) { provenance = provenance_ } -}