Java: Introduce language specific file for model generator code.

This commit is contained in:
Michael Nebel
2022-03-03 15:01:33 +01:00
parent a1c642685a
commit a2d9f4f6f4
2 changed files with 196 additions and 195 deletions

View File

@@ -1,195 +1 @@
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.internal.DataFlowPrivate
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() = ""
}
predicate isRelevantForModels(Callable api) {
not isInTestFile(api.getCompilationUnit().getFile()) and
not isJdkInternal(api.getCompilationUnit()) and
not api instanceof MainMethod
}
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.
*/
private string asPartialModel(TargetApi api) {
result =
typeAsSummaryModel(api) + ";" //
+ isExtensible(bestTypeForModel(api)) + ";" //
+ api.getName() + ";" //
+ paramsString(api) + ";" //
+ /* ext + */ ";" //
}
bindingset[input, output]
string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
bindingset[input, output, kind]
string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
bindingset[input, output]
string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
bindingset[input, kind]
string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
bindingset[output, kind]
string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Character")
}
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())
)
}
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
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 | storeStep(node1, f, node2) |
f instanceof DataFlow::ArrayContent or
f instanceof DataFlow::CollectionContent or
f instanceof DataFlow::MapKeyContent or
f instanceof DataFlow::MapValueContent
)
}
predicate isRelevantContent(DataFlow::Content f) {
isRelevantType(f.(DataFlow::FieldContent).getField().getType()) or
f instanceof DataFlow::ArrayContent or
f instanceof DataFlow::CollectionContent or
f instanceof DataFlow::MapKeyContent or
f instanceof DataFlow::MapValueContent
}
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() + "]"
}
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
}
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
)
}
import ModelGeneratorUtilsSpecific

View File

@@ -0,0 +1,195 @@
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.internal.DataFlowPrivate
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() = ""
}
predicate isRelevantForModels(Callable api) {
not isInTestFile(api.getCompilationUnit().getFile()) and
not isJdkInternal(api.getCompilationUnit()) and
not api instanceof MainMethod
}
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.
*/
private string asPartialModel(TargetApi api) {
result =
typeAsSummaryModel(api) + ";" //
+ isExtensible(bestTypeForModel(api)) + ";" //
+ api.getName() + ";" //
+ paramsString(api) + ";" //
+ /* ext + */ ";" //
}
bindingset[input, output]
string asValueModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
bindingset[input, output, kind]
string asSummaryModel(TargetApi api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
bindingset[input, output]
string asTaintModel(TargetApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
bindingset[input, kind]
string asSinkModel(TargetApi api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
bindingset[output, kind]
string asSourceModel(TargetApi api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Character")
}
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())
)
}
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
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 | storeStep(node1, f, node2) |
f instanceof DataFlow::ArrayContent or
f instanceof DataFlow::CollectionContent or
f instanceof DataFlow::MapKeyContent or
f instanceof DataFlow::MapValueContent
)
}
predicate isRelevantContent(DataFlow::Content f) {
isRelevantType(f.(DataFlow::FieldContent).getField().getType()) or
f instanceof DataFlow::ArrayContent or
f instanceof DataFlow::CollectionContent or
f instanceof DataFlow::MapKeyContent or
f instanceof DataFlow::MapValueContent
}
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() + "]"
}
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
}
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
)
}