mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge pull request #13432 from michaelnebel/updateissupported
Java/C#: Update telemetry queries to report callables with sink/source neutrals as being supported.
This commit is contained in:
@@ -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,11 @@ module Private {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
/**
|
||||
* Gets the kind of the neutral.
|
||||
*/
|
||||
string getKind() { result = super.getKind() }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
@@ -1358,12 +1378,13 @@ module Private {
|
||||
|
||||
/**
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
* The syntax is: "namespace;type;name;signature;kind;provenance"",
|
||||
*/
|
||||
query predicate neutral(string csv) {
|
||||
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"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** Provides classes and predicates for working with Top JDK APIs. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSummary
|
||||
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
@@ -287,24 +286,29 @@ 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(FlowSummaryImpl::Public::SummarizedCallable sc |
|
||||
sc.asCallable() = this and sc.hasManualModel()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this API has a manual neutral model. */
|
||||
private predicate hasManualNeutral() {
|
||||
this.(FlowSummaryImpl::Public::NeutralCallable).hasManualModel()
|
||||
/** Holds if this API has a manual neutral summary model. */
|
||||
private predicate hasManualNeutralSummary() {
|
||||
this.(FlowSummaryImpl::Public::NeutralSummaryCallable).hasManualModel()
|
||||
}
|
||||
|
||||
/** Holds if this API has a manual MaD model. */
|
||||
predicate hasManualMadModel() { this.hasManualSummary() or this.hasManualNeutral() }
|
||||
predicate hasManualMadModel() { this.hasManualSummary() or this.hasManualNeutralSummary() }
|
||||
/*
|
||||
* Note: the following top JDK APIs are not modeled with MaD:
|
||||
* `java.lang.Runnable#run()`: specialised lambda flow
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
| java.io.File#File(String) | 2 |
|
||||
| java.net.URL#URL(String) | 2 |
|
||||
| java.io.File#compareTo(File) | 1 |
|
||||
| java.io.FileWriter#FileWriter(File) | 1 |
|
||||
| java.lang.StringBuilder#append(String) | 1 |
|
||||
| java.lang.StringBuilder#toString() | 1 |
|
||||
|
||||
@@ -17,7 +17,7 @@ class SupportedExternalApis {
|
||||
map.put("foo", new Object()); // supported summary
|
||||
map.entrySet().iterator().next().getKey(); // nested class (Map.Entry), supported summaries (entrySet, iterator, next, getKey)
|
||||
|
||||
Duration d = java.time.Duration.ofMillis(1000); // supported neutral
|
||||
Duration d = java.time.Duration.ofMillis(1000); // supported neutral summary
|
||||
|
||||
URL github = new URL("https://www.github.com/"); // supported summary
|
||||
InputStream stream = github.openConnection().getInputStream(); // supported source (getInputStream), supported sink (openConnection)
|
||||
@@ -25,6 +25,9 @@ class SupportedExternalApis {
|
||||
new FileWriter(new File("foo")); // supported sink (FileWriter), supported summary (File)
|
||||
new URL("http://foo").openStream(); // supported sink (openStream), supported summary (URL)
|
||||
|
||||
FileUtils.deleteDirectory(new File("foo")); // supported neutral (deleteDirectory), supported summary (File)
|
||||
File file = new File("foo"); // supported summary (File)
|
||||
FileUtils.deleteDirectory(file); // supported neutral summary (deleteDirectory)
|
||||
|
||||
file.compareTo(file); // supported neutral sink (compareTo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,15 @@ class ExternalApiUsage {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("foo", new Object());
|
||||
|
||||
Duration d = java.time.Duration.ofMillis(1000); // supported as a neutral model
|
||||
Duration d = java.time.Duration.ofMillis(1000); // supported as a neutral summary model
|
||||
|
||||
long l = "foo".length(); // supported as a neutral model
|
||||
long l = "foo".length(); // supported as a neutral summary model
|
||||
|
||||
AtomicReference<String> ref = new AtomicReference<>(); // uninteresting (parameterless constructor)
|
||||
ref.set("foo"); // supported as a summary model
|
||||
ref.toString(); // not supported
|
||||
|
||||
String.class.isAssignableFrom(Object.class); // parameter with generic type, supported as a neutral model
|
||||
String.class.isAssignableFrom(Object.class); // parameter with generic type, supported as a neutral summary model
|
||||
|
||||
System.out.println(d);
|
||||
System.out.println(map);
|
||||
|
||||
Reference in New Issue
Block a user