Java: Re-factor NeutralCallable to include all neutrals and introduce NeutralSummaryCallable.

This commit is contained in:
Michael Nebel 2023-06-12 13:50:05 +02:00
Родитель 6deeb36a97
Коммит 5623ccf4a0
8 изменённых файлов: 51 добавлений и 24 удалений

Просмотреть файл

@ -175,8 +175,6 @@ class Provenance = Impl::Public::Provenance;
class SummarizedCallable = Impl::Public::SummarizedCallable;
class NeutralCallable = Impl::Public::NeutralCallable;
/**
* An adapter class to add the flow summaries specified on `SyntheticCallable`
* to `SummarizedCallable`.

Просмотреть файл

@ -2,16 +2,16 @@ private import java
private import DataFlowPrivate
private import DataFlowUtil
private import semmle.code.java.dataflow.InstanceAccess
private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as Impl
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
private import semmle.code.java.dataflow.TypeFlow
private import semmle.code.java.dispatch.internal.Unification
private module DispatchImpl {
private predicate hasHighConfidenceTarget(Call c) {
exists(SummarizedCallable sc | sc.getACall() = c and not sc.applyGeneratedModel())
exists(Impl::Public::SummarizedCallable sc | sc.getACall() = c and not sc.applyGeneratedModel())
or
exists(NeutralCallable nc | nc.getACall() = c and nc.hasManualModel())
exists(Impl::Public::NeutralSummaryCallable nc | nc.getACall() = c and nc.hasManualModel())
or
exists(Callable srcTgt |
srcTgt = VirtualDispatch::viableCallable(c) and

Просмотреть файл

@ -296,11 +296,21 @@ module Public {
predicate hasProvenance(Provenance provenance) { provenance = "manual" }
}
/** A callable where there is no flow via the callable. */
class NeutralCallable extends SummarizedCallableBase {
/**
* A callable where there is no flow via the callable.
*/
class NeutralSummaryCallable extends NeutralCallable {
NeutralSummaryCallable() { this.getKind() = "summary" }
}
/**
* A callable that has a neutral model.
*/
class NeutralCallable extends NeutralCallableBase {
private string kind;
private Provenance provenance;
NeutralCallable() { neutralSummaryElement(this, provenance) }
NeutralCallable() { neutralElement(this, kind, provenance) }
/**
* Holds if the neutral is auto generated.
@ -316,6 +326,11 @@ module Public {
* Holds if the neutral has provenance `p`.
*/
predicate hasProvenance(Provenance p) { p = provenance }
/**
* Gets the kind of the neutral.
*/
string getKind() { result = kind }
}
}
@ -1318,6 +1333,8 @@ module Private {
/** Gets the string representation of this callable used by `neutral/1`. */
abstract string getCallableCsv();
string getKind() { result = super.getKind() }
string toString() { result = super.toString() }
}
@ -1364,6 +1381,7 @@ module Private {
exists(RelevantNeutralCallable c |
csv =
c.getCallableCsv() // Callable information
+ c.getKind() + ";" // kind
+ renderProvenanceNeutral(c) // provenance
)
}

Просмотреть файл

@ -14,6 +14,16 @@ private import semmle.code.java.dataflow.internal.AccessPathSyntax as AccessPath
class SummarizedCallableBase = FlowSummary::SummarizedCallableBase;
/**
* A class of callables that are candidates for neutral modeling.
*/
class NeutralCallableBase extends Callable {
NeutralCallableBase() { this.isSourceDeclaration() }
/** Gets a call that targets this neutral. */
Call getACall() { result.getCallee().getSourceDeclaration() = this }
}
/**
* A module for importing frameworks that define synthetic globals.
*/
@ -156,13 +166,13 @@ predicate summaryElement(
}
/**
* Holds if a neutral summary model exists for `c` with provenance `provenance`,
* which means that there is no flow through `c`.
* Holds if a neutral model exists for `c` of kind `kind`
* and with provenance `provenance`.
*/
predicate neutralSummaryElement(SummarizedCallableBase c, string provenance) {
predicate neutralElement(NeutralCallableBase c, string kind, string provenance) {
exists(string namespace, string type, string name, string signature |
neutralModel(namespace, type, name, signature, "summary", provenance) and
c.asCallable() = interpretElement(namespace, type, false, name, signature, "")
neutralModel(namespace, type, name, signature, kind, provenance) and
c = interpretElement(namespace, type, false, name, signature, "")
)
}

Просмотреть файл

@ -45,12 +45,10 @@ private int getNumApis(string package, string apiSubset) {
/** Holds if the given `callable` belongs to the specified `apiSubset`. */
private predicate callableSubset(Callable callable, string apiSubset) {
apiSubset in ["topJdkApis", "allApis"] and
(
if apiSubset = "topJdkApis"
then exists(TopJdkApi topJdkApi | callable = topJdkApi.asCallable())
else apiSubset = "allApis"
)
apiSubset = "topJdkApis" and
callable instanceof TopJdkApi
or
apiSubset = "allApis"
}
/**

Просмотреть файл

@ -287,16 +287,19 @@ predicate hasApiName(Callable c, string apiName) {
}
/** A top JDK API. */
class TopJdkApi extends SummarizedCallableBase {
class TopJdkApi extends Callable {
TopJdkApi() {
this.isSourceDeclaration() and
exists(string apiName |
hasApiName(this.asCallable(), apiName) and
hasApiName(this, apiName) and
topJdkApiName(apiName)
)
}
/** Holds if this API has a manual summary model. */
private predicate hasManualSummary() { this.(SummarizedCallable).hasManualModel() }
private predicate hasManualSummary() {
exists(SummarizedCallable sc | sc.asCallable() = this and sc.hasManualModel())
}
/** Holds if this API has a manual neutral model. */
private predicate hasManualNeutral() {

Просмотреть файл

@ -79,7 +79,7 @@ class ExternalApi extends Callable {
/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() { this = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() }
predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a

Просмотреть файл

@ -11,7 +11,7 @@ where
// top jdk api names for which there isn't a manual model
exists(TopJdkApi topApi |
not topApi.hasManualMadModel() and
hasApiName(topApi.asCallable(), apiName) and
hasApiName(topApi, apiName) and
message = "no manual model"
)
select apiName, message order by apiName