Skip to content

Commit

Permalink
C#/Java/Go: Neutrals are split into seperate classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelnebel committed Jul 18, 2024
1 parent bf69c76 commit 630ece6
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 145 deletions.
18 changes: 0 additions & 18 deletions cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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_ }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, "")
Expand Down Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ private import semmle.code.csharp.dataflow.internal.ExternalFlow
module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow> {
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 }
Expand Down
10 changes: 5 additions & 5 deletions csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql
Original file line number Diff line number Diff line change
@@ -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<NeutralSummaryCallable> {
class RelevantNeutralCallable extends NeutralSummaryCallable {
final string getCallableCsv() { result = getSignature(this) }
}
}

class RelevantSourceCallable extends SourceCallable {
Expand All @@ -16,5 +16,5 @@ class RelevantSinkCallable extends SinkCallable {
}

import TestSummaryOutput<IncludeSummarizedCallable>
import TestNeutralOutput<RelevantNeutralCallable>
import TestNeutralOutput<NeutralSummaryCallable, R>
import External::TestSourceSinkOutput<RelevantSourceCallable, RelevantSinkCallable>
12 changes: 0 additions & 12 deletions go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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_ }
}
16 changes: 12 additions & 4 deletions go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ private string positionToString(int pos) {
module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
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) }
Expand Down Expand Up @@ -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)
}
}

Expand Down
15 changes: 0 additions & 15 deletions java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
22 changes: 10 additions & 12 deletions java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ private string positionToString(int pos) {
module Input implements InputSig<Location, DataFlowImplSpecific::JavaDataFlow> {
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() }
Expand Down Expand Up @@ -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. */
Expand Down
156 changes: 108 additions & 48 deletions shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> 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() }

Expand Down Expand Up @@ -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<hasKindSig/1 hasKind> {
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<neutralSummaryKind/1>::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<neutralSourceKind/1>::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<neutralSinkKind/1>::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
}
}
}

Expand Down Expand Up @@ -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<NeutralCallableSig NeutralCallableInput> {
class RelevantNeutralCallable extends NeutralCallableInput {
/** Gets the string representation of this callable used by `neutral/1`. */
string getCallableCsv();
}
}

module TestNeutralOutput<RelevantNeutralCallableSig RelevantNeutralCallable> {
private string renderProvenance(NeutralCallable c) {
module TestNeutralOutput<
NeutralCallableSig NeutralCallableInput,
RelevantNeutralCallableSig<NeutralCallableInput> 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
Expand Down
Loading

0 comments on commit 630ece6

Please sign in to comment.