C#/Java: Initial merge ModelGeneratorUtils into CaptureModels.

This commit is contained in:
Michael Nebel
2022-03-28 16:20:43 +02:00
parent 9b7691a5fc
commit 26d5eb64b3
15 changed files with 383 additions and 394 deletions

View File

@@ -75,10 +75,6 @@
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
],
"Model as Data Generation Java/C# - Utils": [
"java/ql/src/utils/model-generator/internal/ModelGeneratorUtils.qll",
"csharp/ql/src/utils/model-generator/internal/ModelGeneratorUtils.qll"
],
"Model as Data Generation Java/C# - CaptureModels": [
"java/ql/src/utils/model-generator/internal/CaptureModels.qll",
"csharp/ql/src/utils/model-generator/internal/CaptureModels.qll"
@@ -549,4 +545,4 @@
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
]
}
}

View File

@@ -4,7 +4,6 @@
* @id csharp/utils/model-generator/sink-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
from TargetApi api, string sink

View File

@@ -4,7 +4,6 @@
* @id csharp/utils/model-generator/sink-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
from TargetApi api, string source

View File

@@ -4,7 +4,6 @@
* @id csharp/utils/model-generator/summary-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
/**

View File

@@ -3,9 +3,82 @@
* and sink models of the Standard or a 3rd party library.
*/
private import ModelGeneratorUtils
private import CaptureModelsSpecific
class TargetApi = TargetApiSpecific;
/**
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
*/
private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and
if f instanceof DataFlow::FieldContent
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
else
if f instanceof DataFlow::SyntheticFieldContent
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
else any()
)
or
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
DataFlowPrivate::containerContent(f)
)
}
/**
* Holds if content `c` is either a field or synthetic field of a relevant type
* or a container like content.
*/
private predicate isRelevantContent(DataFlow::Content c) {
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
DataFlowPrivate::containerContent(c)
}
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
bindingset[input, output, kind]
private string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
/**
* Gets the value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
private string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
private string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/
bindingset[input, kind]
private string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
/**
* Gets the source model for `api` with `output` and `kind`.
*/
bindingset[output, kind]
private string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}
/**
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
*/

View File

@@ -4,10 +4,78 @@
import csharp
private import semmle.code.csharp.dataflow.TaintTracking
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import ModelGeneratorUtils
private import semmle.code.csharp.commons.Util as Util
private import semmle.code.csharp.commons.Collections
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
/**
* Holds if it is relevant to generate models for `api`.
*/
private predicate isRelevantForModels(Callable api) {
[api.(Modifiable), api.(Accessor).getDeclaration()].isEffectivelyPublic() and
not api instanceof Util::MainMethod
}
/**
* A class of callables that are relevant generating summary, source and sinks models for.
*
* In the Standard library and 3rd party libraries it the callables that can be called
* from outside the library itself.
*/
class TargetApiSpecific extends DataFlowCallable {
TargetApiSpecific() {
this.fromSource() and
isRelevantForModels(this)
}
}
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
/**
* Holds for type `t` for fields that are relevant as an intermediate
* read or write step in the data flow analysis.
*/
predicate isRelevantType(Type t) { not t instanceof Enum }
private string parameterAccess(Parameter p) {
if isCollectionType(p.getType())
then result = "Argument[" + p.getPosition() + "].Element"
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the CSV string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[Qualifier]" and p instanceof DataFlowPrivate::InstanceParameterNode
}
pragma[nomagic]
private Parameter getParameter(DataFlowImplCommon::ReturnNodeExt node, ParameterPosition pos) {
result = node.getEnclosingCallable().getParameter(pos.getPosition())
}
/**
* Gets the CSV string represention of the the return node `node`.
*/
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
then result = "ReturnValue"
else
exists(ParameterPosition pos |
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
result = parameterAccess(getParameter(node, pos))
or
pos.isThisParameter() and
result = "Argument[Qualifier]"
)
}
/**
* Gets the enclosing callable of `ret`.
@@ -19,7 +87,9 @@ Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
/**
* Holds if `node` is an own instance access.
*/
predicate isOwnInstanceAccessNode(ReturnNode node) { node.asExpr() instanceof ThisAccess }
predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) {
node.asExpr() instanceof ThisAccess
}
/**
* Gets the CSV string representation of the qualifier.
@@ -65,6 +135,6 @@ string asInputArgument(DataFlow::Node source) {
result = "Argument[" + pos + "]"
)
or
source.asExpr() instanceof FieldOrPropertyAccess and
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
result = qualifierString()
}

View File

@@ -1,73 +0,0 @@
import ModelGeneratorUtilsSpecific
/**
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
*/
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and
if f instanceof DataFlow::FieldContent
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
else
if f instanceof DataFlow::SyntheticFieldContent
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
else any()
)
or
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
DataFlowPrivate::containerContent(f)
)
}
/**
* Holds if content `c` is either a field or synthetic field of a relevant type
* or a container like content.
*/
predicate isRelevantContent(DataFlow::Content c) {
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
DataFlowPrivate::containerContent(c)
}
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
bindingset[input, output, kind]
string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
/**
* Gets the value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/
bindingset[input, kind]
string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
/**
* Gets the source model for `api` with `output` and `kind`.
*/
bindingset[output, kind]
string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}

View File

@@ -1,70 +0,0 @@
import csharp
private import semmle.code.csharp.commons.Util as Util
private import semmle.code.csharp.commons.Collections
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
/**
* Holds if it is relevant to generate models for `api`.
*/
predicate isRelevantForModels(Callable api) {
[api.(Modifiable), api.(Accessor).getDeclaration()].isEffectivelyPublic() and
not api instanceof Util::MainMethod
}
/**
* A class of callables that are relevant generating summary, source and sinks models for.
*
* In the Standard library and 3rd party libraries it the callables that can be called
* from outside the library itself.
*/
class TargetApi extends DataFlowCallable {
TargetApi() {
this.fromSource() and
isRelevantForModels(this)
}
}
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
/**
* Holds for type `t` for fields that are relevant as an intermediate
* read or write step in the data flow analysis.
*/
predicate isRelevantType(Type t) { not t instanceof Enum }
private string parameterAccess(Parameter p) {
if isCollectionType(p.getType())
then result = "Argument[" + p.getPosition() + "].Element"
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the CSV string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[Qualifier]" and p instanceof DataFlowPrivate::InstanceParameterNode
}
pragma[nomagic]
private Parameter getParameter(ReturnNodeExt node, ParameterPosition pos) {
result = node.getEnclosingCallable().getParameter(pos.getPosition())
}
/**
* Gets the CSV string represention of the the return node `node`.
*/
string returnNodeAsOutput(ReturnNodeExt node) {
if node.getKind() instanceof ValueReturnKind
then result = "ReturnValue"
else
exists(ParameterPosition pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
result = parameterAccess(getParameter(node, pos))
or
pos.isThisParameter() and
result = "Argument[Qualifier]"
)
}

View File

@@ -4,7 +4,6 @@
* @id java/utils/model-generator/sink-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
from TargetApi api, string sink

View File

@@ -4,7 +4,6 @@
* @id java/utils/model-generator/sink-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
from TargetApi api, string source

View File

@@ -4,7 +4,6 @@
* @id java/utils/model-generator/summary-models
*/
private import internal.ModelGeneratorUtils
private import internal.CaptureModels
/**

View File

@@ -3,9 +3,82 @@
* and sink models of the Standard or a 3rd party library.
*/
private import ModelGeneratorUtils
private import CaptureModelsSpecific
class TargetApi = TargetApiSpecific;
/**
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
*/
private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and
if f instanceof DataFlow::FieldContent
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
else
if f instanceof DataFlow::SyntheticFieldContent
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
else any()
)
or
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
DataFlowPrivate::containerContent(f)
)
}
/**
* Holds if content `c` is either a field or synthetic field of a relevant type
* or a container like content.
*/
private predicate isRelevantContent(DataFlow::Content c) {
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
DataFlowPrivate::containerContent(c)
}
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
bindingset[input, output, kind]
private string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
/**
* Gets the value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
private string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
private string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/
bindingset[input, kind]
private string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
/**
* Gets the source model for `api` with `output` and `kind`.
*/
bindingset[output, kind]
private string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}
/**
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
*/

View File

@@ -3,13 +3,171 @@
*/
import java
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.internal.DataFlowNodes
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.InstanceAccess
private import ModelGeneratorUtils
private import semmle.code.java.dataflow.internal.ContainerFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private Method superImpl(Method m) {
result = m.getAnOverride() and
not exists(result.getAnOverride()) and
not m instanceof ToStringMethod
}
private predicate isInTestFile(File file) {
file.getAbsolutePath().matches("%src/test/%") or
file.getAbsolutePath().matches("%/guava-tests/%") or
file.getAbsolutePath().matches("%/guava-testlib/%")
}
private predicate isJdkInternal(CompilationUnit cu) {
cu.getPackage().getName().matches("org.graalvm%") or
cu.getPackage().getName().matches("com.sun%") or
cu.getPackage().getName().matches("javax.swing%") or
cu.getPackage().getName().matches("java.awt%") or
cu.getPackage().getName().matches("sun%") or
cu.getPackage().getName().matches("jdk.%") or
cu.getPackage().getName().matches("java2d.%") or
cu.getPackage().getName().matches("build.tools.%") or
cu.getPackage().getName().matches("propertiesparser.%") or
cu.getPackage().getName().matches("org.jcp.%") or
cu.getPackage().getName().matches("org.w3c.%") or
cu.getPackage().getName().matches("org.ietf.jgss.%") or
cu.getPackage().getName().matches("org.xml.sax%") or
cu.getPackage().getName() = "compileproperties" or
cu.getPackage().getName() = "netscape.javascript" or
cu.getPackage().getName() = ""
}
/**
* Holds if it is relevant to generate models for `api`.
*/
private predicate isRelevantForModels(Callable api) {
not isInTestFile(api.getCompilationUnit().getFile()) and
not isJdkInternal(api.getCompilationUnit()) and
not api instanceof MainMethod
}
/**
* A class of Callables that are relevant for generating summary, source and sinks models for.
*
* In the Standard library and 3rd party libraries it the Callables that can be called
* from outside the library itself.
*/
class TargetApiSpecific extends Callable {
TargetApiSpecific() {
this.isPublic() and
this.fromSource() and
(
this.getDeclaringType().isPublic() or
superImpl(this).getDeclaringType().isPublic()
) and
isRelevantForModels(this)
}
}
private string isExtensible(RefType ref) {
if ref.isFinal() then result = "false" else result = "true"
}
private string typeAsModel(RefType type) {
result = type.getCompilationUnit().getPackage().getName() + ";" + type.nestedName()
}
private RefType bestTypeForModel(TargetApiSpecific api) {
if exists(superImpl(api))
then superImpl(api).fromSource() and result = superImpl(api).getDeclaringType()
else result = api.getDeclaringType()
}
/**
* Returns the appropriate type name for the model. Either the type
* declaring the method or the supertype introducing the method.
*/
private string typeAsSummaryModel(TargetApiSpecific api) {
result = typeAsModel(bestTypeForModel(api))
}
/**
* Computes the first 6 columns for CSV rows.
*/
string asPartialModel(TargetApiSpecific api) {
result =
typeAsSummaryModel(api) + ";" //
+ isExtensible(bestTypeForModel(api)) + ";" //
+ api.getName() + ";" //
+ ExternalFlow::paramsString(api) + ";" //
+ /* ext + */ ";" //
}
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Character")
}
/**
* Holds for type `t` for fields that are relevant as an intermediate
* read or write step in the data flow analysis.
*/
predicate isRelevantType(Type t) {
not t instanceof TypeClass and
not t instanceof EnumType and
not t instanceof PrimitiveType and
not t instanceof BoxedType and
not t.(RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and
not t.(RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and
(
not t.(Array).getElementType() instanceof PrimitiveType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(Array).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(CollectionType).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(CollectionType).getElementType())
)
}
private string parameterAccess(Parameter p) {
if
p.getType() instanceof Array and
not isPrimitiveTypeUsedForBulkData(p.getType().(Array).getElementType())
then result = "Argument[" + p.getPosition() + "].ArrayElement"
else
if p.getType() instanceof ContainerType
then result = "Argument[" + p.getPosition() + "].Element"
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the CSV string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
}
/**
* Gets the CSV string represention of the the return node `node`.
*/
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
then result = "ReturnValue"
else
exists(int pos |
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
result = parameterAccess(node.getEnclosingCallable().getParameter(pos))
or
result = "Argument[-1]" and pos = -1
)
}
/**
* Gets the enclosing callable of `ret`.

View File

@@ -1,73 +0,0 @@
import ModelGeneratorUtilsSpecific
/**
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
*/
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and
if f instanceof DataFlow::FieldContent
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
else
if f instanceof DataFlow::SyntheticFieldContent
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
else any()
)
or
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
DataFlowPrivate::containerContent(f)
)
}
/**
* Holds if content `c` is either a field or synthetic field of a relevant type
* or a container like content.
*/
predicate isRelevantContent(DataFlow::Content c) {
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
DataFlowPrivate::containerContent(c)
}
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
bindingset[input, output, kind]
string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
/**
* Gets the value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/
bindingset[input, kind]
string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
/**
* Gets the source model for `api` with `output` and `kind`.
*/
bindingset[output, kind]
string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}

View File

@@ -1,159 +0,0 @@
import java
import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private Method superImpl(Method m) {
result = m.getAnOverride() and
not exists(result.getAnOverride()) and
not m instanceof ToStringMethod
}
private predicate isInTestFile(File file) {
file.getAbsolutePath().matches("%src/test/%") or
file.getAbsolutePath().matches("%/guava-tests/%") or
file.getAbsolutePath().matches("%/guava-testlib/%")
}
private predicate isJdkInternal(CompilationUnit cu) {
cu.getPackage().getName().matches("org.graalvm%") or
cu.getPackage().getName().matches("com.sun%") or
cu.getPackage().getName().matches("javax.swing%") or
cu.getPackage().getName().matches("java.awt%") or
cu.getPackage().getName().matches("sun%") or
cu.getPackage().getName().matches("jdk.%") or
cu.getPackage().getName().matches("java2d.%") or
cu.getPackage().getName().matches("build.tools.%") or
cu.getPackage().getName().matches("propertiesparser.%") or
cu.getPackage().getName().matches("org.jcp.%") or
cu.getPackage().getName().matches("org.w3c.%") or
cu.getPackage().getName().matches("org.ietf.jgss.%") or
cu.getPackage().getName().matches("org.xml.sax%") or
cu.getPackage().getName() = "compileproperties" or
cu.getPackage().getName() = "netscape.javascript" or
cu.getPackage().getName() = ""
}
/**
* Holds if it is relevant to generate models for `api`.
*/
predicate isRelevantForModels(Callable api) {
not isInTestFile(api.getCompilationUnit().getFile()) and
not isJdkInternal(api.getCompilationUnit()) and
not api instanceof MainMethod
}
/**
* A class of Callables that are relevant for generating summary, source and sinks models for.
*
* In the Standard library and 3rd party libraries it the Callables that can be called
* from outside the library itself.
*/
class TargetApi extends Callable {
TargetApi() {
this.isPublic() and
this.fromSource() and
(
this.getDeclaringType().isPublic() or
superImpl(this).getDeclaringType().isPublic()
) and
isRelevantForModels(this)
}
}
private string isExtensible(RefType ref) {
if ref.isFinal() then result = "false" else result = "true"
}
private string typeAsModel(RefType type) {
result = type.getCompilationUnit().getPackage().getName() + ";" + type.nestedName()
}
private RefType bestTypeForModel(TargetApi api) {
if exists(superImpl(api))
then superImpl(api).fromSource() and result = superImpl(api).getDeclaringType()
else result = api.getDeclaringType()
}
/**
* Returns the appropriate type name for the model. Either the type
* declaring the method or the supertype introducing the method.
*/
private string typeAsSummaryModel(TargetApi api) { result = typeAsModel(bestTypeForModel(api)) }
/**
* Computes the first 6 columns for CSV rows.
*/
string asPartialModel(TargetApi api) {
result =
typeAsSummaryModel(api) + ";" //
+ isExtensible(bestTypeForModel(api)) + ";" //
+ api.getName() + ";" //
+ paramsString(api) + ";" //
+ /* ext + */ ";" //
}
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Character")
}
/**
* Holds for type `t` for fields that are relevant as an intermediate
* read or write step in the data flow analysis.
*/
predicate isRelevantType(Type t) {
not t instanceof TypeClass and
not t instanceof EnumType and
not t instanceof PrimitiveType and
not t instanceof BoxedType and
not t.(RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and
not t.(RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and
(
not t.(Array).getElementType() instanceof PrimitiveType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(Array).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(CollectionType).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(CollectionType).getElementType())
)
}
private string parameterAccess(Parameter p) {
if
p.getType() instanceof Array and
not isPrimitiveTypeUsedForBulkData(p.getType().(Array).getElementType())
then result = "Argument[" + p.getPosition() + "].ArrayElement"
else
if p.getType() instanceof ContainerType
then result = "Argument[" + p.getPosition() + "].Element"
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the CSV string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
}
/**
* Gets the CSV string represention of the the return node `node`.
*/
string returnNodeAsOutput(ReturnNodeExt node) {
if node.getKind() instanceof ValueReturnKind
then result = "ReturnValue"
else
exists(int pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
result = parameterAccess(node.getEnclosingCallable().getParameter(pos))
or
result = "Argument[-1]" and pos = -1
)
}