merge in main

This commit is contained in:
yoff
2022-06-23 09:05:32 +00:00
committed by GitHub
parent 8bf60301da
commit 140dc1a61e
4448 changed files with 340100 additions and 31408 deletions

View File

@@ -59,7 +59,7 @@ okhttp3,2,,47,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,22,25
org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,
org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783
org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783
org.apache.commons.io,93,2,565,,78,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,2,551,14
org.apache.commons.io,104,,561,,89,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,547,14
org.apache.commons.jexl2,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,
org.apache.commons.jexl3,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,
org.apache.commons.lang3,,,424,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,293,131
1 package sink source summary sink:bean-validation sink:create-file sink:groovy sink:header-splitting sink:information-leak sink:intent-start sink:jdbc-url sink:jexl sink:jndi-injection sink:ldap sink:logging sink:mvel sink:ognl-injection sink:open-url sink:pending-intent-sent sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:set-hostname-verifier sink:sql sink:url-open-stream sink:url-redirect sink:write-file sink:xpath sink:xslt sink:xss source:android-widget source:contentprovider source:remote summary:taint summary:value
59 org.apache.commons.codec 6 6
60 org.apache.commons.collections 800 17 783
61 org.apache.commons.collections4 800 17 783
62 org.apache.commons.io 93 104 2 565 561 78 89 15 2 551 547 14
63 org.apache.commons.jexl2 15 15
64 org.apache.commons.jexl3 15 15
65 org.apache.commons.lang3 424 293 131

View File

@@ -9,7 +9,7 @@ Java framework & library support
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE022` :sub:`Path injection`,`CWE036` :sub:`Path traversal`,`CWE079` :sub:`Cross-site scripting`,`CWE089` :sub:`SQL injection`,`CWE090` :sub:`LDAP injection`,`CWE094` :sub:`Code injection`,`CWE319` :sub:`Cleartext transmission`
Android,``android.*``,46,424,108,,,3,67,,,
`Apache Commons Collections <https://commons.apache.org/proper/commons-collections/>`_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,,,
`Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,2,565,93,78,,,,,,15
`Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,561,104,89,,,,,,15
`Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,424,,,,,,,,
`Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,,,
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25
@@ -19,5 +19,5 @@ Java framework & library support
Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2
`Spring <https://spring.io/>`_,``org.springframework.*``,29,476,101,,,,19,14,,29
Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin.jvm.internal``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,395,932,,,,14,18,,3
Totals,,213,6414,1463,106,6,10,107,33,1,84
Totals,,211,6410,1474,117,6,10,107,33,1,84

View File

@@ -30,8 +30,14 @@ sourceSets {
// change the excludes for building with other versions:
excludes = [
"utils/versions/v_1_4_32/*.kt",
"utils/versions/v_1_5_0/*.kt",
"utils/versions/v_1_5_10/*.kt",
"utils/versions/v_1_5_21/*.kt",
"utils/versions/v_1_5_31/*.kt",
"utils/versions/v_1_6_10/*.kt"]
"utils/versions/v_1_6_10/*.kt",
"utils/versions/v_1_7_0-RC/*.kt",
// "utils/versions/v_1_6_20/*.kt",
]
}
}
}

View File

@@ -21,6 +21,8 @@ def parse_args():
help='Build for all versions/kinds')
parser.add_argument('--single', action='store_false',
dest='many', help='Build for a single version/kind')
parser.add_argument('--single-version',
help='Build for a specific version/kind')
return parser.parse_args()
@@ -35,8 +37,12 @@ def is_windows():
return True
return False
# kotlinc might be kotlinc.bat or kotlinc.cmd on Windows, so we use `which` to find out what it is
kotlinc = shutil.which('kotlinc')
if kotlinc is None:
print("Cannot build the Kotlin extractor: no kotlinc found on your PATH", file = sys.stderr)
sys.exit(1)
kotlinc = 'kotlinc.bat' if is_windows() else 'kotlinc'
javac = 'javac'
kotlin_dependency_folder = args.dependencies
@@ -91,19 +97,19 @@ def compile_to_dir(srcs, classpath, java_classpath, output):
'-classpath', os.path.pathsep.join([output, classpath, java_classpath])] + [s for s in srcs if s.endswith(".java")])
def compile_to_jar(srcs, classpath, java_classpath, output):
builddir = 'build/classes'
def compile_to_jar(build_dir, srcs, classpath, java_classpath, output):
class_dir = build_dir + '/classes'
if os.path.exists(builddir):
shutil.rmtree(builddir)
os.makedirs(builddir)
if os.path.exists(class_dir):
shutil.rmtree(class_dir)
os.makedirs(class_dir)
compile_to_dir(srcs, classpath, java_classpath, builddir)
compile_to_dir(srcs, classpath, java_classpath, class_dir)
run_process(['jar', 'cf', output,
'-C', builddir, '.',
'-C', class_dir, '.',
'-C', 'src/main/resources', 'META-INF'])
shutil.rmtree(builddir)
shutil.rmtree(class_dir)
def find_sources(path):
@@ -160,26 +166,28 @@ def transform_to_embeddable(srcs):
f.write(content)
def compile(jars, java_jars, dependency_folder, transform_to_embeddable, output, tmp_dir, version):
def compile(jars, java_jars, dependency_folder, transform_to_embeddable, output, build_dir, version):
classpath = patterns_to_classpath(dependency_folder, jars)
java_classpath = patterns_to_classpath(dependency_folder, java_jars)
if os.path.exists(tmp_dir):
shutil.rmtree(tmp_dir)
shutil.copytree('src', tmp_dir)
tmp_src_dir = build_dir + '/temp_src'
if os.path.exists(tmp_src_dir):
shutil.rmtree(tmp_src_dir)
shutil.copytree('src', tmp_src_dir)
for v in kotlin_plugin_versions.many_versions:
if v != version:
shutil.rmtree(
tmp_dir + '/main/kotlin/utils/versions/v_' + v.replace('.', '_'))
d = tmp_src_dir + '/main/kotlin/utils/versions/v_' + v.replace('.', '_')
shutil.rmtree(d)
srcs = find_sources(tmp_dir)
srcs = find_sources(tmp_src_dir)
transform_to_embeddable(srcs)
compile_to_jar(srcs, classpath, java_classpath, output)
compile_to_jar(build_dir, srcs, classpath, java_classpath, output)
shutil.rmtree(tmp_dir)
shutil.rmtree(tmp_src_dir)
def compile_embeddable(version):
@@ -188,7 +196,7 @@ def compile_embeddable(version):
kotlin_dependency_folder,
transform_to_embeddable,
'codeql-extractor-kotlin-embeddable-%s.jar' % (version),
'build/temp_src',
'build_embeddable_' + version,
version)
@@ -198,10 +206,12 @@ def compile_standalone(version):
kotlin_dependency_folder,
lambda srcs: None,
'codeql-extractor-kotlin-standalone-%s.jar' % (version),
'build/temp_src',
'build_standalone_' + version,
version)
if args.many:
if args.single_version:
compile_standalone(args.single_version)
elif args.many:
for version in kotlin_plugin_versions.many_versions:
compile_standalone(version)
compile_embeddable(version)

View File

@@ -1,5 +1,8 @@
#!/usr/bin/python
import platform
import re
import shutil
import subprocess
import sys
@@ -12,19 +15,25 @@ def is_windows():
return False
def version_tuple_to_string(version):
return f'{version[0]}.{version[1]}.{version[2]}'
return f'{version[0]}.{version[1]}.{version[2]}{version[3]}'
def version_string_to_tuple(version):
m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', version)
return tuple([int(m.group(i)) for i in range(1, 4)])
m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)(.*)', version)
return tuple([int(m.group(i)) for i in range(1, 4)] + [m.group(4)])
many_versions = [ '1.4.32', '1.5.31', '1.6.10', '1.6.20' ]
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.21', '1.5.31', '1.6.10', '1.7.0-RC', '1.6.20' ]
many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]
class KotlincNotFoundException(Exception):
pass
def get_single_version(fakeVersionOutput = None):
# TODO: `shell=True` is a workaround to get CI working on Windows. It breaks the build on Linux.
versionOutput = subprocess.run(['kotlinc', '-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=is_windows()).stderr if fakeVersionOutput is None else fakeVersionOutput
# kotlinc might be kotlinc.bat or kotlinc.cmd on Windows, so we use `which` to find out what it is
kotlinc = shutil.which('kotlinc')
if kotlinc is None:
raise KotlincNotFoundException()
versionOutput = subprocess.run([kotlinc, '-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stderr if fakeVersionOutput is None else fakeVersionOutput
m = re.match(r'.* kotlinc-jvm ([0-9]+\.[0-9]+\.[0-9]+) .*', versionOutput)
if m is None:
raise Exception('Cannot detect version of kotlinc (got ' + str(versionOutput) + ')')

View File

@@ -4,10 +4,14 @@ import java.lang.reflect.*;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.github.codeql.Logger;
import static com.github.codeql.ClassNamesKt.getIrDeclBinaryName;
@@ -547,6 +551,51 @@ public class OdasaOutput {
(tcv.majorVersion == majorVersion && tcv.minorVersion == minorVersion &&
tcv.lastModified < lastModified);
}
private static Map<String, Map<String, Long>> jarFileEntryTimeStamps = new HashMap<>();
private static Map<String, Long> getZipFileEntryTimeStamps(String path, Logger log) {
try {
Map<String, Long> result = new HashMap<>();
ZipFile zf = new ZipFile(path);
Enumeration<? extends ZipEntry> entries = zf.entries();
while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
result.put(ze.getName(), ze.getLastModifiedTime().toMillis());
}
return result;
} catch(IOException e) {
log.warn("Failed to get entry timestamps from " + path, e);
return null;
}
}
private static long getVirtualFileTimeStamp(VirtualFile vf, Logger log) {
if (vf.getFileSystem().getProtocol().equals("jar")) {
String[] parts = vf.getPath().split("!/");
if (parts.length == 2) {
String jarFilePath = parts[0];
String entryPath = parts[1];
if (!jarFileEntryTimeStamps.containsKey(jarFilePath)) {
jarFileEntryTimeStamps.put(jarFilePath, getZipFileEntryTimeStamps(jarFilePath, log));
}
Map<String, Long> entryTimeStamps = jarFileEntryTimeStamps.get(jarFilePath);
if (entryTimeStamps != null) {
Long entryTimeStamp = entryTimeStamps.get(entryPath);
if (entryTimeStamp != null)
return entryTimeStamp;
else
log.warn("Couldn't find timestamp for jar file " + jarFilePath + " entry " + entryPath);
}
} else {
log.warn("Expected JAR-file path " + vf.getPath() + " to have exactly one '!/' separator");
}
}
// For all files except for jar files, and a fallback in case of I/O problems reading a jar file:
return vf.getTimeStamp();
}
private static TrapClassVersion fromSymbol(IrDeclaration sym, Logger log) {
VirtualFile vf = sym instanceof IrClass ? getIrClassVirtualFile((IrClass)sym) :
sym.getParent() instanceof IrClass ? getIrClassVirtualFile((IrClass)sym.getParent()) :
@@ -583,7 +632,7 @@ public class OdasaOutput {
};
(new ClassReader(vf.contentsToByteArray())).accept(versionGetter, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, vf.getTimeStamp(), "kotlin");
return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, getVirtualFileTimeStamp(vf, log), "kotlin");
}
catch(IllegalAccessException e) {
log.warn("Failed to read class file version information", e);

View File

@@ -19,22 +19,20 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
val externalDeclsDone = HashSet<IrDeclaration>()
val externalDeclWorkList = ArrayList<Pair<IrDeclaration, String>>()
val propertySignature = ";property"
val fieldSignature = ";field"
fun extractLater(d: IrDeclaration, signature: String): Boolean {
if (d !is IrClass && !isExternalFileClassMember(d)) {
logger.warnElement("External declaration is neither a class, nor a top-level declaration", d)
logger.errorElement("External declaration is neither a class, nor a top-level declaration", d)
return false
}
val ret = externalDeclsDone.add(d)
if (ret) externalDeclWorkList.add(Pair(d, signature))
return ret
}
val propertySignature = ";property"
val fieldSignature = ";field"
fun extractLater(p: IrProperty) = extractLater(p, propertySignature)
fun extractLater(f: IrField) = extractLater(f, fieldSignature)
fun extractLater(c: IrClass) = extractLater(c, "")
fun extractExternalClasses() {
@@ -64,7 +62,7 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
val containingClass = getContainingClassOrSelf(irDecl)
if (containingClass == null) {
logger.warnElement("Unable to get containing class", irDecl)
logger.errorElement("Unable to get containing class", irDecl)
return
}
val binaryPath = getIrClassBinaryPath(containingClass)

View File

@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.IrElement
import java.io.File
import java.io.FileOutputStream
import java.lang.management.*
import java.nio.file.Files
import java.nio.file.Paths
import com.semmle.util.files.FileUtil
@@ -108,6 +109,7 @@ class KotlinExtractorExtension(
logger.flush()
logger.info("Extraction for invocation TRAP file $invocationTrapFile")
logger.flush()
logPeakMemoryUsage(logger, "before extractor")
if (System.getenv("CODEQL_EXTRACTOR_JAVA_KOTLIN_DUMP") == "true") {
logger.info("moduleFragment:\n" + moduleFragment.dump())
}
@@ -127,6 +129,7 @@ class KotlinExtractorExtension(
fileTrapWriter.writeCompilation_compiling_files_completed(compilation, index, fileExtractionProblems.extractionResult())
}
loggerBase.printLimitedDiagnosticCounts(tw)
logPeakMemoryUsage(logger, "after extractor")
logger.info("Extraction completed")
logger.flush()
val compilationTimeMs = System.currentTimeMillis() - startTimeMs
@@ -135,16 +138,34 @@ class KotlinExtractorExtension(
loggerBase.close()
}
}
private fun logPeakMemoryUsage(logger: Logger, time: String) {
logger.info("Peak memory: Usage $time")
val beans = ManagementFactory.getMemoryPoolMXBeans()
var heap: Long = 0
var nonheap: Long = 0
for (bean in beans) {
val peak = bean.getPeakUsage().getUsed()
val kind = when (bean.getType()) {
MemoryType.HEAP -> { heap += peak; "heap" }
MemoryType.NON_HEAP -> { nonheap += peak; "non-heap" }
else -> "unknown"
}
logger.info("Peak memory: * Peak for $kind bean ${bean.getName()} is $peak")
}
logger.info("Peak memory: * Total heap peak: $heap")
logger.info("Peak memory: * Total non-heap peak: $nonheap")
}
}
class KotlinExtractorGlobalState {
val genericSpecialisationsExtracted = HashSet<String>()
// These three record mappings of classes, functions and fields that should be replaced wherever they are found.
// As of now these are only used to fix IR generated by the Gradle Android Extensions plugin, hence e.g. IrProperty
// doesn't have a map as that plugin doesn't generate them. If and when these are used more widely additional maps
// should be added here.
val syntheticToRealClassMap = HashMap<IrClass, IrClass?>()
val syntheticToRealFunctionMap = HashMap<IrSimpleFunction, IrSimpleFunction?>()
val syntheticToRealFunctionMap = HashMap<IrFunction, IrFunction?>()
val syntheticToRealFieldMap = HashMap<IrField, IrField?>()
}

View File

@@ -19,7 +19,13 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.io.Closeable
import java.util.*
@@ -135,7 +141,7 @@ open class KotlinFileExtractor(
Unit
}
is IrField -> {
val parentId = useDeclarationParent(declaration.parent, false)?.cast<DbReftype>()
val parentId = useDeclarationParent(getFieldParent(declaration), false)?.cast<DbReftype>()
if (parentId != null) {
extractField(declaration, parentId)
}
@@ -171,21 +177,9 @@ open class KotlinFileExtractor(
}
}
fun extractTypeParameter(tp: IrTypeParameter, apparentIndex: Int): Label<out DbTypevariable>? {
fun extractTypeParameter(tp: IrTypeParameter, apparentIndex: Int, javaTypeParameter: JavaTypeParameter?): Label<out DbTypevariable>? {
with("type parameter", tp) {
val parentId: Label<out DbClassorinterfaceorcallable>? = when (val parent = tp.parent) {
is IrFunction -> useFunction(parent)
is IrClass -> useClassSource(parent)
else -> {
logger.errorElement("Unexpected type parameter parent", tp)
null
}
}
if (parentId == null) {
return null
}
val parentId = getTypeParameterParentLabel(tp) ?: return null
val id = tw.getLabelFor<DbTypevariable>(getTypeParameterLabel(tp))
// Note apparentIndex does not necessarily equal `tp.index`, because at least constructor type parameters
@@ -195,10 +189,21 @@ open class KotlinFileExtractor(
val locId = tw.getLocation(tp)
tw.writeHasLocation(id, locId)
// Annoyingly, we have no obvious way to pair up the bounds of an IrTypeParameter and a JavaTypeParameter
// because JavaTypeParameter provides a Collection not an ordered list, so we can only do our best here:
fun tryGetJavaBound(idx: Int) =
when(tp.superTypes.size) {
1 -> javaTypeParameter?.upperBounds?.singleOrNull()
else -> (javaTypeParameter?.upperBounds as? List)?.getOrNull(idx)
}
tp.superTypes.forEachIndexed { boundIdx, bound ->
if(!(bound.isAny() || bound.isNullableAny())) {
tw.getLabelFor<DbTypebound>("@\"bound;$boundIdx;{$id}\"") {
tw.writeTypeBounds(it, useType(bound).javaResult.id.cast<DbReftype>(), boundIdx, id)
// Note we don't look for @JvmSuppressWildcards here because it doesn't seem to have any impact
// on kotlinc adding wildcards to type parameter bounds.
val boundWithWildcards = addJavaLoweringWildcards(bound, true, tryGetJavaBound(tp.index))
tw.writeTypeBounds(it, useType(boundWithWildcards).javaResult.id.cast<DbReftype>(), boundIdx, id)
}
}
}
@@ -282,7 +287,7 @@ open class KotlinFileExtractor(
if (kind == ClassKind.ENUM_CLASS) {
tw.writeIsEnumType(classId)
} else if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT) {
logger.warnElement("Unrecognised class kind $kind", c)
logger.errorElement("Unrecognised class kind $kind", c)
}
}
@@ -334,17 +339,7 @@ open class KotlinFileExtractor(
val typeParamSubstitution =
when (argsIncludingOuterClasses) {
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
else -> {
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
x.substituteTypeAndArguments(
it,
useContext,
pluginContext
)
}
}
}
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
}
c.declarations.map {
@@ -404,7 +399,9 @@ open class KotlinFileExtractor(
extractEnclosingClass(c, id, locId, listOf())
c.typeParameters.mapIndexed { idx, param -> extractTypeParameter(param, idx) }
val javaClass = (c.source as? JavaSourceElement)?.javaElement as? JavaClass
c.typeParameters.mapIndexed { idx, param -> extractTypeParameter(param, idx, javaClass?.typeParameters?.getOrNull(idx)) }
if (extractDeclarations) {
c.declarations.map { extractDeclaration(it, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) }
if (extractStaticInitializer)
@@ -426,8 +423,7 @@ open class KotlinFileExtractor(
}
extractClassModifiers(c, id)
val forceExtractSupertypeMembers = !isExternalDeclaration(c)
extractClassSupertypes(c, id, inReceiverContext = forceExtractSupertypeMembers)
extractClassSupertypes(c, id, inReceiverContext = true) // inReceiverContext = true is specified to force extraction of member prototypes of base types
return id
}
@@ -511,24 +507,38 @@ open class KotlinFileExtractor(
return FieldResult(instanceId, instanceName)
}
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean): TypeResults {
@OptIn(ObsoleteDescriptorBasedAPI::class)
private fun hasSynthesizedParameterNames(f: IrFunction) = f.descriptor.hasSynthesizedParameterNames()
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
with("value parameter", vp) {
val location = getLocation(vp, classTypeArgsIncludingOuterClasses)
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
val maybeErasedType = (vp.parent as? IrFunction)?.let {
if (overridesCollectionsMethodWithAlteredParameterTypes(it))
eraseCollectionsMethodParameterType(vp.type, it.name.asString(), idx)
else
null
} ?: vp.type
val javaType = (vp.parent as? IrFunction)?.let { getJavaCallable(it)?.let { jCallable -> getJavaValueParameterType(jCallable, idx) } }
val typeWithWildcards = addJavaLoweringWildcards(maybeErasedType, !hasWildcardSuppressionAnnotation(vp), javaType)
val substitutedType = typeSubstitution?.let { it(typeWithWildcards, TypeContext.OTHER, pluginContext) } ?: typeWithWildcards
val id = useValueParameter(vp, parent)
if (extractTypeAccess) {
extractTypeAccessRecursive(vp.type, location, id, -1)
extractTypeAccessRecursive(substitutedType, location, id, -1)
}
return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
val syntheticParameterNames = (vp.parent as? IrFunction)?.let { hasSynthesizedParameterNames(it) } ?: true
return extractValueParameter(id, substitutedType, vp.name.asString(), location, parent, idx, useValueParameter(vp, parentSourceDeclaration), vp.isVararg, syntheticParameterNames)
}
}
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean): TypeResults {
val substitutedType = typeSubstitution?.let { it(t, TypeContext.OTHER, pluginContext) } ?: t
val type = useType(substitutedType)
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean, syntheticParameterNames: Boolean): TypeResults {
val type = useType(t)
tw.writeParams(id, type.javaResult.id, idx, parent, paramSourceDeclaration)
tw.writeParamsKotlinType(id, type.kotlinResult.id)
tw.writeHasLocation(id, locId)
tw.writeParamName(id, name)
if (!syntheticParameterNames) {
tw.writeParamName(id, name)
}
if (isVararg) {
tw.writeIsVarargsParam(id)
}
@@ -547,7 +557,10 @@ open class KotlinFileExtractor(
pluginContext.irBuiltIns.unitType,
extensionReceiverParameter = null,
functionTypeParameters = listOf(),
classTypeArgsIncludingOuterClasses = listOf()
classTypeArgsIncludingOuterClasses = listOf(),
overridesCollectionsMethod = false,
javaSignature = null,
addParameterWildcardsByDefault = false
)
val clinitId = tw.getLabelFor<DbMethod>(clinitLabel)
val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
@@ -571,7 +584,7 @@ open class KotlinFileExtractor(
val constructorId = useFunction<DbConstructor>(enclosingConstructor)
val enclosingClass = enclosingConstructor.parentClassOrNull
if (enclosingClass == null) {
logger.warnElement("Constructor's parent is not a class", enclosingConstructor)
logger.errorElement("Constructor's parent is not a class", enclosingConstructor)
return
}
@@ -676,13 +689,18 @@ open class KotlinFileExtractor(
}
}
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>? = null): Label<out DbCallable>? {
if (isFake(f)) return null
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
if (isFake(f))
null
else
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, null, null)
fun forceExtractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>?, locOverride: Label<DbLocation>?): Label<out DbCallable> {
with("function", f) {
DeclarationStackAdjuster(f).use {
getFunctionTypeParameters(f).mapIndexed { idx, tp -> extractTypeParameter(tp, idx) }
val javaCallable = getJavaCallable(f)
getFunctionTypeParameters(f).mapIndexed { idx, tp -> extractTypeParameter(tp, idx, (javaCallable as? JavaTypeParameterListOwner)?.typeParameters?.getOrNull(idx)) }
val id =
idOverride
@@ -694,7 +712,7 @@ open class KotlinFileExtractor(
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true)
val sourceDeclaration =
if (typeSubstitution != null)
if (typeSubstitution != null && idOverride == null)
useFunction(f)
else
id
@@ -702,13 +720,13 @@ open class KotlinFileExtractor(
val extReceiver = f.extensionReceiverParameter
val idxOffset = if (extReceiver != null) 1 else 0
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
}
val allParamTypes = if (extReceiver != null) {
val extendedType = useType(extReceiver.type)
tw.writeKtExtensionFunctions(id.cast<DbMethod>(), extendedType.javaResult.id, extendedType.kotlinResult.id)
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
listOf(t) + paramTypes
} else {
paramTypes
@@ -716,16 +734,17 @@ open class KotlinFileExtractor(
val paramsSignature = allParamTypes.joinToString(separator = ",", prefix = "(", postfix = ")") { it.javaResult.signature!! }
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
val adjustedReturnType = addJavaLoweringWildcards(getAdjustedReturnType(f), false, (javaCallable as? JavaMethod)?.returnType)
val substReturnType = typeSubstitution?.let { it(adjustedReturnType, TypeContext.RETURN, pluginContext) } ?: adjustedReturnType
val locId = getLocation(f, classTypeArgsIncludingOuterClasses)
val locId = locOverride ?: getLocation(f, classTypeArgsIncludingOuterClasses)
if (f.symbol is IrConstructorSymbol) {
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
val shortName = when {
f.returnType.isAnonymous -> ""
adjustedReturnType.isAnonymous -> ""
typeSubstitution != null -> useType(substReturnType).javaResult.shortName
else -> f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString()
else -> adjustedReturnType.classFqName?.shortName()?.asString() ?: f.name.asString()
}
val constrId = id.cast<DbConstructor>()
tw.writeConstrs(constrId, shortName, "$shortName$paramsSignature", unitType.javaResult.id, parentId, sourceDeclaration.cast<DbConstructor>())
@@ -738,7 +757,7 @@ open class KotlinFileExtractor(
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
if (extractMethodAndParameterTypeAccesses) {
extractTypeAccessRecursive(f.returnType, locId, id, -1)
extractTypeAccessRecursive(substReturnType, locId, id, -1)
}
if (shortName.nameInDB != shortName.kotlinName) {
@@ -778,7 +797,8 @@ open class KotlinFileExtractor(
with("field", f) {
DeclarationStackAdjuster(f).use {
declarationStack.push(f)
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(".", "$$") } ?: ""
return extractField(useField(f), "${f.name.asString()}$fNameSuffix", f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
}
}
}
@@ -829,13 +849,13 @@ open class KotlinFileExtractor(
}
} else {
if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) {
logger.errorElement("IrProperty without a getter", p)
logger.warnElement("IrProperty without a getter", p)
}
}
if (setter != null) {
if (!p.isVar) {
logger.errorElement("!isVar property with a setter", p)
logger.warnElement("!isVar property with a setter", p)
}
val setterId = extractFunction(setter, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution, classTypeArgsIncludingOuterClasses)?.cast<DbMethod>()
if (setterId != null) {
@@ -843,15 +863,18 @@ open class KotlinFileExtractor(
}
} else {
if (p.isVar && !isExternalDeclaration(p)) {
logger.errorElement("isVar property without a setter", p)
logger.warnElement("isVar property without a setter", p)
}
}
if (bf != null && extractBackingField) {
val fieldId = extractField(bf, parentId)
tw.writeKtPropertyBackingFields(id, fieldId)
if (p.isDelegated) {
tw.writeKtPropertyDelegates(id, fieldId)
val fieldParentId = useDeclarationParent(getFieldParent(bf), false)
if (fieldParentId != null) {
val fieldId = extractField(bf, fieldParentId.cast())
tw.writeKtPropertyBackingFields(id, fieldId)
if (p.isDelegated) {
tw.writeKtPropertyDelegates(id, fieldId)
}
}
}
@@ -1374,6 +1397,23 @@ open class KotlinFileExtractor(
return fn
}
private fun findTopLevelPropertyOrWarn(propertyFilter: String, type: String, warnAgainstElement: IrElement): IrProperty? {
val prop = pluginContext.referenceProperties(FqName(propertyFilter))
.firstOrNull { it.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type }
?.owner
if (prop != null) {
if (prop.parentClassOrNull != null) {
extractExternalClassLater(prop.parentAsClass)
}
} else {
logger.errorElement("Couldn't find JVM intrinsic property $propertyFilter in $type", warnAgainstElement)
}
return prop
}
val javaLangString by lazy {
val result = pluginContext.referenceClass(FqName("java.lang.String"))?.owner
result?.let { extractExternalClassLater(it) }
@@ -1393,12 +1433,6 @@ open class KotlinFileExtractor(
result
}
val javaLangObject by lazy {
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
val objectCloneMethod by lazy {
val result = javaLangObject?.declarations?.find {
it is IrFunction && it.name.asString() == "clone"
@@ -1504,7 +1538,7 @@ open class KotlinFileExtractor(
fun extractCall(c: IrCall, callable: Label<out DbCallable>, stmtExprParent: StmtExprParent) {
with("call", c) {
val target = tryReplaceAndroidSyntheticFunction(c.symbol.owner)
val target = tryReplaceSyntheticFunction(c.symbol.owner)
// The vast majority of types of call want an expr context, so make one available lazily:
val exprParent by lazy {
@@ -1662,7 +1696,7 @@ open class KotlinFileExtractor(
// as they can't be extracted as external dependencies.
isBuiltinCallInternal(c, "less") -> {
if(c.origin != IrStatementOrigin.LT) {
logger.errorElement("Unexpected origin for LT: ${c.origin}", c)
logger.warnElement("Unexpected origin for LT: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbLtexpr>()
val type = useType(c.type)
@@ -1672,7 +1706,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "lessOrEqual") -> {
if(c.origin != IrStatementOrigin.LTEQ) {
logger.errorElement("Unexpected origin for LTEQ: ${c.origin}", c)
logger.warnElement("Unexpected origin for LTEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbLeexpr>()
val type = useType(c.type)
@@ -1682,7 +1716,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "greater") -> {
if(c.origin != IrStatementOrigin.GT) {
logger.errorElement("Unexpected origin for GT: ${c.origin}", c)
logger.warnElement("Unexpected origin for GT: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbGtexpr>()
val type = useType(c.type)
@@ -1692,7 +1726,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "greaterOrEqual") -> {
if(c.origin != IrStatementOrigin.GTEQ) {
logger.errorElement("Unexpected origin for GTEQ: ${c.origin}", c)
logger.warnElement("Unexpected origin for GTEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbGeexpr>()
val type = useType(c.type)
@@ -1702,7 +1736,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "EQEQ") -> {
if(c.origin != IrStatementOrigin.EQEQ) {
logger.errorElement("Unexpected origin for EQEQ: ${c.origin}", c)
logger.warnElement("Unexpected origin for EQEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbValueeqexpr>()
val type = useType(c.type)
@@ -1712,7 +1746,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "EQEQEQ") -> {
if(c.origin != IrStatementOrigin.EQEQEQ) {
logger.errorElement("Unexpected origin for EQEQEQ: ${c.origin}", c)
logger.warnElement("Unexpected origin for EQEQEQ: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbEqexpr>()
val type = useType(c.type)
@@ -1722,7 +1756,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "ieee754equals") -> {
if(c.origin != IrStatementOrigin.EQEQ) {
logger.errorElement("Unexpected origin for ieee754equals: ${c.origin}", c)
logger.warnElement("Unexpected origin for ieee754equals: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbEqexpr>()
val type = useType(c.type)
@@ -1732,7 +1766,7 @@ open class KotlinFileExtractor(
}
isBuiltinCallInternal(c, "CHECK_NOT_NULL") -> {
if(c.origin != IrStatementOrigin.EXCLEXCL) {
logger.errorElement("Unexpected origin for CHECK_NOT_NULL: ${c.origin}", c)
logger.warnElement("Unexpected origin for CHECK_NOT_NULL: ${c.origin}", c)
}
val id = tw.getFreshIdLabel<DbNotnullexpr>()
@@ -1887,6 +1921,27 @@ open class KotlinFileExtractor(
}
}
}
isBuiltinCall(c, "<get-java>", "kotlin.jvm") -> {
// Special case for KClass<*>.java, which is used in the Parcelize plugin. In normal cases, this is already rewritten to the property referenced below:
findTopLevelPropertyOrWarn("kotlin.jvm.java", "kotlin.jvm.JvmClassMappingKt", c)?.let { javaProp ->
val getter = javaProp.getter
if (getter == null) {
logger.error("Couldn't find getter of `kotlin.jvm.JvmClassMappingKt::java`")
return
}
val ext = c.extensionReceiver
if (ext == null) {
logger.errorElement("No extension receiver found for `KClass::java` call", c)
return
}
val argType = (ext.type as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull
val typeArguments = if (argType == null) listOf() else listOf(argType)
extractRawMethodAccess(getter, c, callable, parent, idx, enclosingStmt, listOf(), null, ext, typeArguments)
}
}
isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "iterator") && c.origin == IrStatementOrigin.FOR_LOOP_ITERATOR -> {
findTopLevelFunctionOrWarn("kotlin.jvm.internal.iterator", "kotlin.jvm.internal.ArrayIteratorKt", c)?.let { iteratorFn ->
extractRawMethodAccess(iteratorFn, c, callable, parent, idx, enclosingStmt, listOf(c.dispatchReceiver), null, null, listOf((c.dispatchReceiver!!.type as IrSimpleType).arguments.first().typeOrNull!!))
@@ -2378,7 +2433,7 @@ open class KotlinFileExtractor(
val stmtParent = parent.stmt(e, callable)
val irConstructor = declarationStack.peek() as? IrConstructor
if (irConstructor == null) {
logger.warnElement("IrInstanceInitializerCall outside constructor", e)
logger.errorElement("IrInstanceInitializerCall outside constructor", e)
return
}
extractInstanceInitializerBlock(stmtParent, irConstructor)
@@ -2547,10 +2602,7 @@ open class KotlinFileExtractor(
tw.writeCallableEnclosingExpr(id, callable)
tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt)
val vId = if (owner is IrValueParameter && owner.isExtensionReceiver())
useValueParameter(owner, useFunction(owner.parent as IrFunction))
else
useValueDeclaration(owner)
val vId = useValueDeclaration(owner)
if (vId != null) {
tw.writeVariableBinding(id, vId)
}
@@ -2906,7 +2958,7 @@ open class KotlinFileExtractor(
stmtIdx: Int
) {
val paramId = tw.getFreshIdLabel<DbParam>()
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, null, paramId, false)
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, paramId, isVararg = false, syntheticParameterNames = false)
val assignmentStmtId = tw.getFreshIdLabel<DbExprstmt>()
tw.writeStmts_exprstmt(assignmentStmtId, ids.constructorBlock, stmtIdx, ids.constructor)
@@ -3187,7 +3239,7 @@ open class KotlinFileExtractor(
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
this.writeExpressionMetadataToTrapFile(callId, invokeLabels.methodId, retId)
tw.writeCallableBinding(callId as Label<out DbCaller>, getId)
tw.writeCallableBinding(callId, getId)
this.writeThisAccess(callId, invokeLabels.methodId, retId)
for ((pIdx, p) in invokeLabels.parameters.withIndex()) {
@@ -3352,7 +3404,7 @@ open class KotlinFileExtractor(
) {
with("function reference", functionReferenceExpr) {
val target = functionReferenceExpr.reflectionTarget ?: run {
logger.errorElement("Expected to find reflection target for function reference. Using underlying symbol instead.", functionReferenceExpr)
logger.warnElement("Expected to find reflection target for function reference. Using underlying symbol instead.", functionReferenceExpr)
functionReferenceExpr.symbol
}
@@ -3542,7 +3594,7 @@ open class KotlinFileExtractor(
val parameters = parameterTypes.mapIndexed { idx, p ->
val paramId = tw.getFreshIdLabel<DbParam>()
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, null, paramId, false)
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, paramId, isVararg = false, syntheticParameterNames = false)
Pair(paramId, paramType)
}
@@ -3719,6 +3771,17 @@ open class KotlinFileExtractor(
}
}
/**
* Extracts a single wildcard type access expression with no enclosing callable and statement.
*/
private fun extractWildcardTypeAccess(type: TypeResults, location: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int): Label<out DbExpr> {
val id = tw.getFreshIdLabel<DbWildcardtypeaccess>()
tw.writeExprs_wildcardtypeaccess(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
tw.writeHasLocation(id, location)
return id
}
/**
* Extracts a single type access expression with no enclosing callable and statement.
*/
@@ -3743,6 +3806,27 @@ open class KotlinFileExtractor(
return id
}
/**
* Extracts a type argument type access, introducing a wildcard type access if appropriate, or directly calling
* `extractTypeAccessRecursive` if the argument is invariant.
* No enclosing callable and statement is extracted, this is useful for type access extraction in field declarations.
*/
private fun extractWildcardTypeAccessRecursive(t: IrTypeArgument, location: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int) {
val typeLabels by lazy { TypeResults(getTypeArgumentLabel(t), TypeResult(fakeKotlinType(), "TODO", "TODO")) }
when (t) {
is IrStarProjection -> extractWildcardTypeAccess(typeLabels, location, parent, idx)
is IrTypeProjection -> when(t.variance) {
Variance.INVARIANT -> extractTypeAccessRecursive(t.type, location, parent, idx, TypeContext.GENERIC_ARGUMENT)
else -> {
val wildcardLabel = extractWildcardTypeAccess(typeLabels, location, parent, idx)
// Mimic a Java extractor oddity, that it uses the child index to indicate what kind of wildcard this is
val boundChildIdx = if (t.variance == Variance.OUT_VARIANCE) 0 else 1
extractTypeAccessRecursive(t.type, location, wildcardLabel, boundChildIdx, TypeContext.GENERIC_ARGUMENT)
}
}
}
}
/**
* Extracts a type access expression and its child type access expressions in case of a generic type. Nested generics are also handled.
* No enclosing callable and statement is extracted, this is useful for type access extraction in field declarations.
@@ -3750,8 +3834,8 @@ open class KotlinFileExtractor(
private fun extractTypeAccessRecursive(t: IrType, location: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, typeContext: TypeContext = TypeContext.OTHER): Label<out DbExpr> {
val typeAccessId = extractTypeAccess(useType(t, typeContext), location, parent, idx)
if (t is IrSimpleType) {
t.arguments.filterIsInstance<IrType>().forEachIndexed { argIdx, arg ->
extractTypeAccessRecursive(arg, location, typeAccessId, argIdx, TypeContext.GENERIC_ARGUMENT)
t.arguments.forEachIndexed { argIdx, arg ->
extractWildcardTypeAccessRecursive(arg, location, typeAccessId, argIdx)
}
}
return typeAccessId
@@ -3978,17 +4062,14 @@ open class KotlinFileExtractor(
}
val typeOwner = e.typeOperandClassifier.owner
val samMember = if (typeOwner !is IrClass) {
if (typeOwner !is IrClass) {
logger.errorElement("Expected to find SAM conversion to IrClass. Found '${typeOwner.javaClass}' instead. Can't implement SAM interface.", e)
return
} else {
val samMember = typeOwner.declarations.filterIsInstance<IrFunction>().find { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
if (samMember == null) {
logger.errorElement("Couldn't find SAM member in type '${typeOwner.kotlinFqName.asString()}'. Can't implement SAM interface.", e)
return
} else {
samMember
}
}
val samMember = typeOwner.declarations.filterIsInstance<IrFunction>().find { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
if (samMember == null) {
logger.errorElement("Couldn't find SAM member in type '${typeOwner.kotlinFqName.asString()}'. Can't implement SAM interface.", e)
return
}
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
@@ -4014,7 +4095,20 @@ open class KotlinFileExtractor(
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)
// add implementation function
extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, null, null, ids.function)
val classTypeArgs = (e.type as? IrSimpleType)?.arguments
val typeSub = classTypeArgs?.let { makeGenericSubstitutionFunction(typeOwner, it) }
fun trySub(t: IrType, context: TypeContext) = if (typeSub == null) t else typeSub(t, context, pluginContext)
// Force extraction of this function even if this is a fake override --
// This happens in the case where a functional interface inherits its only abstract member,
// which usually we wouldn't extract, but in this case we're effectively using it as a template
// for the real function we're extracting that will implement this interface, and it serves fine
// for that purpose. By contrast if we looked through the fake to the underlying abstract method
// we would need to compose generic type substitutions -- for example, if we're implementing
// T UnaryOperator<T>.apply(T t) here, we would need to compose substitutions so we can implement
// the real underlying R Function<T, R>.apply(T t).
forceExtractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, typeSub, classTypeArgs, ids.function, tw.getLocation(e))
//body
val blockId = tw.getFreshIdLabel<DbBlock>()
@@ -4037,7 +4131,7 @@ open class KotlinFileExtractor(
// Call to original `invoke`:
val callId = tw.getFreshIdLabel<DbMethodaccess>()
val callType = useType(samMember.returnType)
val callType = useType(trySub(samMember.returnType, TypeContext.RETURN))
tw.writeExprs_methodaccess(callId, callType.javaResult.id, returnId, 0)
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
extractCommonExpr(callId)
@@ -4061,7 +4155,7 @@ open class KotlinFileExtractor(
fun extractArgument(p: IrValueParameter, idx: Int, parent: Label<out DbExprparent>) {
val argsAccessId = tw.getFreshIdLabel<DbVaraccess>()
val paramType = useType(p.type)
val paramType = useType(trySub(p.type, TypeContext.OTHER))
tw.writeExprs_varaccess(argsAccessId, paramType.javaResult.id, parent, idx)
tw.writeExprsKotlinType(argsAccessId, paramType.kotlinResult.id)
extractCommonExpr(argsAccessId)

View File

@@ -1,20 +1,28 @@
package com.github.codeql
import com.github.codeql.utils.*
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import com.github.codeql.utils.versions.isRawType
import com.semmle.extractor.java.OdasaOutput
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.allOverridden
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
@@ -30,6 +38,17 @@ open class KotlinUsesExtractor(
val pluginContext: IrPluginContext,
val globalExtensionState: KotlinExtractorGlobalState
) {
val javaLangObject by lazy {
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
val javaLangObjectType by lazy {
javaLangObject?.typeWith()
}
fun usePackage(pkg: String): Label<out DbPackage> {
return extractPackage(pkg)
}
@@ -47,62 +66,6 @@ open class KotlinUsesExtractor(
TypeResult(fakeKotlinType(), "", "")
)
private data class MethodKey(val className: FqName, val functionName: Name)
private fun makeDescription(className: FqName, functionName: String) = MethodKey(className, Name.guessByFirstCharacter(functionName))
// This essentially mirrors SpecialBridgeMethods.kt, a backend pass which isn't easily available to our extractor.
private val specialFunctions = mapOf(
makeDescription(StandardNames.FqNames.collection, "<get-size>") to "size",
makeDescription(FqName("java.util.Collection"), "<get-size>") to "size",
makeDescription(StandardNames.FqNames.map, "<get-size>") to "size",
makeDescription(FqName("java.util.Map"), "<get-size>") to "size",
makeDescription(StandardNames.FqNames.charSequence.toSafe(), "<get-length>") to "length",
makeDescription(FqName("java.lang.CharSequence"), "<get-length>") to "length",
makeDescription(StandardNames.FqNames.map, "<get-keys>") to "keySet",
makeDescription(FqName("java.util.Map"), "<get-keys>") to "keySet",
makeDescription(StandardNames.FqNames.map, "<get-values>") to "values",
makeDescription(FqName("java.util.Map"), "<get-values>") to "values",
makeDescription(StandardNames.FqNames.map, "<get-entries>") to "entrySet",
makeDescription(FqName("java.util.Map"), "<get-entries>") to "entrySet"
)
private val specialFunctionShortNames = specialFunctions.keys.map { it.functionName }.toSet()
fun getSpecialJvmName(f: IrFunction): String? {
if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) {
f.allOverridden(true).forEach { overriddenFunc ->
overriddenFunc.parentAsClass.fqNameWhenAvailable?.let { parentFqName ->
specialFunctions[MethodKey(parentFqName, f.name)]?.let {
return it
}
}
}
}
return null
}
fun getJvmName(container: IrAnnotationContainer): String? {
for(a: IrConstructorCall in container.annotations) {
val t = a.type
if (t is IrSimpleType && a.valueArgumentsCount == 1) {
val owner = t.classifier.owner
val v = a.getValueArgument(0)
if (owner is IrClass) {
val aPkg = owner.packageFqName?.asString()
val name = owner.name.asString()
if(aPkg == "kotlin.jvm" && name == "JvmName" && v is IrConst<*>) {
val value = v.value
if (value is String) {
return value
}
}
}
}
}
return (container as? IrFunction)?.let { getSpecialJvmName(container) }
}
@OptIn(kotlin.ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5
fun extractFileClass(f: IrFile): Label<out DbClass> {
val fileName = f.fileEntry.name
@@ -215,6 +178,17 @@ open class KotlinUsesExtractor(
fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
getTypeParametersInScope(c).map({ it.symbol }).zip(argsIncludingOuterClasses.map { it.withQuestionMark(true) }).toMap()
fun makeGenericSubstitutionFunction(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
x.substituteTypeAndArguments(
it,
useContext,
pluginContext
)
}
}
// The Kotlin compiler internal representation of Outer<A, B>.Inner<C, D>.InnerInner<E, F>.someFunction<G, H>.LocalClass<I, J> is LocalClass<I, J, G, H, E, F, C, D, A, B>. This function returns [A, B, C, D, E, F, G, H, I, J].
fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): List<IrTypeArgument>? {
if(argsIncludingOuterClasses.isNullOrEmpty())
@@ -242,10 +216,12 @@ open class KotlinUsesExtractor(
val extractClass = substituteClass ?: c
// `KFunction1<T1,T2>` is substituted by `KFunction<T>`. The last type argument is the return type.
// Similarly Function23 and above get replaced by kotlin.jvm.functions.FunctionN with only one type arg, the result type.
// References to SomeGeneric<T1, T2, ...> where SomeGeneric is declared SomeGeneric<T1, T2, ...> are extracted
// as if they were references to the unbound type SomeGeneric.
val extractedTypeArgs = when {
c.symbol.isKFunction() && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last())
extractClass.symbol.isKFunction() && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last())
extractClass.fqNameWhenAvailable == FqName("kotlin.jvm.functions.FunctionN") && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last())
typeArgs != null && isUnspecialised(c, typeArgs) -> listOf()
else -> typeArgs
}
@@ -346,17 +322,17 @@ open class KotlinUsesExtractor(
} ?: c
}
fun tryReplaceAndroidSyntheticFunction(f: IrSimpleFunction): IrSimpleFunction {
private fun tryReplaceFunctionInSyntheticClass(f: IrFunction, getClassReplacement: (IrClass) -> IrClass): IrFunction {
val parentClass = f.parent as? IrClass ?: return f
val replacementClass = tryReplaceAndroidSyntheticClass(parentClass)
val replacementClass = getClassReplacement(parentClass)
if (replacementClass === parentClass)
return f
return globalExtensionState.syntheticToRealFunctionMap.getOrPut(f) {
val result = replacementClass.declarations.find { replacementDecl ->
replacementDecl is IrSimpleFunction && replacementDecl.name == f.name && replacementDecl.valueParameters.zip(f.valueParameters).all {
it.first.type == it.second.type
replacementDecl is IrSimpleFunction && replacementDecl.name == f.name && replacementDecl.valueParameters.size == f.valueParameters.size && replacementDecl.valueParameters.zip(f.valueParameters).all {
erase(it.first.type) == erase(it.second.type)
}
} as IrSimpleFunction?
} as IrFunction?
if (result == null) {
logger.warn("Failed to replace synthetic class function ${f.name}")
} else {
@@ -366,6 +342,11 @@ open class KotlinUsesExtractor(
} ?: f
}
fun tryReplaceSyntheticFunction(f: IrFunction): IrFunction {
val androidReplacement = tryReplaceFunctionInSyntheticClass(f) { tryReplaceAndroidSyntheticClass(it) }
return tryReplaceFunctionInSyntheticClass(androidReplacement) { tryReplaceParcelizeRawType(it)?.first ?: it }
}
fun tryReplaceAndroidSyntheticField(f: IrField): IrField {
val parentClass = f.parent as? IrClass ?: return f
val replacementClass = tryReplaceAndroidSyntheticClass(parentClass)
@@ -384,42 +365,83 @@ open class KotlinUsesExtractor(
} ?: f
}
private fun tryReplaceType(cBeforeReplacement: IrClass, argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?): Pair<IrClass, List<IrTypeArgument>?> {
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
val p = tryReplaceParcelizeRawType(c)
return Pair(
p?.first ?: c,
p?.second ?: argsIncludingOuterClassesBeforeReplacement
)
}
// `typeArgs` can be null to describe a raw generic type.
// For non-generic types it will be zero-length list.
fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
val classLabelResult = getClassLabel(c, argsIncludingOuterClasses)
private fun addClassLabel(cBeforeReplacement: IrClass, argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
val replaced = tryReplaceType(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
val replacedClass = replaced.first
val replacedArgsIncludingOuterClasses = replaced.second
val classLabelResult = getClassLabel(replacedClass, replacedArgsIncludingOuterClasses)
var instanceSeenBefore = true
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel, {
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel) {
instanceSeenBefore = false
extractClassLaterIfExternal(c)
})
extractClassLaterIfExternal(replacedClass)
}
if (argsIncludingOuterClasses == null || argsIncludingOuterClasses.isNotEmpty()) {
if (replacedArgsIncludingOuterClasses == null || replacedArgsIncludingOuterClasses.isNotEmpty()) {
// If this is a generic type instantiation or a raw type then it has no
// source entity, so we need to extract it here
val extractorWithCSource by lazy { this.withFileOfClass(c) }
val extractorWithCSource by lazy { this.withFileOfClass(replacedClass) }
if (!instanceSeenBefore) {
extractorWithCSource.extractClassInstance(c, argsIncludingOuterClasses)
extractorWithCSource.extractClassInstance(replacedClass, replacedArgsIncludingOuterClasses)
}
if (inReceiverContext && globalExtensionState.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) {
val supertypeMode = if (argsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(argsIncludingOuterClasses)
extractorWithCSource.extractClassSupertypes(c, classLabel, supertypeMode, true)
extractorWithCSource.extractNonPrivateMemberPrototypes(c, argsIncludingOuterClasses, classLabel)
if (inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) {
val supertypeMode = if (replacedArgsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(replacedArgsIncludingOuterClasses)
extractorWithCSource.extractClassSupertypes(replacedClass, classLabel, supertypeMode, true)
extractorWithCSource.extractNonPrivateMemberPrototypes(replacedClass, replacedArgsIncludingOuterClasses, classLabel)
}
}
return TypeResult(
classLabel,
c.fqNameWhenAvailable?.asString(),
replacedClass.fqNameWhenAvailable?.asString(),
classLabelResult.shortName)
}
private fun tryReplaceParcelizeRawType(c: IrClass): Pair<IrClass, List<IrTypeArgument>?>? {
if (c.superTypes.isNotEmpty() ||
c.origin != IrDeclarationOrigin.DEFINED ||
c.hasEqualFqName(FqName("java.lang.Object"))) {
return null
}
fun tryGetPair(arity: Int): Pair<IrClass, List<IrTypeArgument>?>? {
val replaced = pluginContext.referenceClass(c.fqNameWhenAvailable!!)?.owner ?: return null
return Pair(replaced, List(arity) { makeTypeProjection(pluginContext.irBuiltIns.anyNType, Variance.INVARIANT) })
}
// The list of types handled here match https://github.com/JetBrains/kotlin/blob/d7c7d1efd2c0983c13b175e9e4b1cda979521159/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/AndroidSymbols.kt
// Specifically, types are added for generic types created in AndroidSymbols.kt.
// This replacement is from a raw type to its matching parameterized type with `Object` type arguments.
return when (c.fqNameWhenAvailable?.asString()) {
"java.util.ArrayList" -> tryGetPair(1)
"java.util.LinkedHashMap" -> tryGetPair(2)
"java.util.LinkedHashSet" -> tryGetPair(1)
"java.util.List" -> tryGetPair(1)
"java.util.TreeMap" -> tryGetPair(2)
"java.util.TreeSet" -> tryGetPair(1)
"java.lang.Class" -> tryGetPair(1)
else -> null
}
}
fun useAnonymousClass(c: IrClass) =
tw.lm.anonymousTypeMapping.getOrPut(c) {
TypeResults(
@@ -615,14 +637,31 @@ open class KotlinUsesExtractor(
)
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
var dimensions = 1
var isPrimitiveArray = s.isPrimitiveArray()
val componentType = s.getArrayElementType(pluginContext.irBuiltIns)
var elementType = componentType
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrSimpleType =
if (dimensions == 0)
pluginContext.irBuiltIns.anyType as IrSimpleType
else
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
.let { oldArg ->
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
}
}.buildSimpleType()
var componentType = s.getArrayElementType(pluginContext.irBuiltIns)
var isPrimitiveArray = false
var dimensions = 0
var elementType: IrType = s
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
dimensions++
if(elementType.isPrimitiveArray())
if (elementType.isPrimitiveArray())
isPrimitiveArray = true
if (((elementType as IrSimpleType).arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
elementType = pluginContext.irBuiltIns.anyType as IrSimpleType
break
}
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
}
@@ -688,7 +727,17 @@ open class KotlinUsesExtractor(
} else {
extractFileClass(dp)
}
is IrClass -> if (classTypeArguments != null && !dp.isAnonymousObject) useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id else useClassSource(dp)
is IrClass ->
if (classTypeArguments != null && !dp.isAnonymousObject) {
useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id
} else {
val replacedType = tryReplaceParcelizeRawType(dp)
if (replacedType == null) {
useClassSource(dp)
} else {
useClassInstance(replacedType.first, replacedType.second, inReceiverContext).typeResult.id
}
}
is IrFunction -> useFunction(dp)
is IrExternalPackageFragment -> {
// TODO
@@ -775,6 +824,130 @@ open class KotlinUsesExtractor(
else -> null
}
val javaUtilCollection by lazy {
val result = pluginContext.referenceClass(FqName("java.util.Collection"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
val wildcardCollectionType by lazy {
javaUtilCollection?.let {
it.symbol.typeWithArguments(listOf(IrStarProjectionImpl))
}
}
private fun makeCovariant(t: IrTypeArgument) =
t.typeOrNull?.let { makeTypeProjection(it, Variance.OUT_VARIANCE) } ?: t
private fun makeArgumentsCovariant(t: IrType) = (t as? IrSimpleType)?.let {
t.toBuilder().also { b -> b.arguments = b.arguments.map(this::makeCovariant) }.buildSimpleType()
} ?: t
fun eraseCollectionsMethodParameterType(t: IrType, collectionsMethodName: String, paramIdx: Int) =
when(collectionsMethodName) {
"contains", "remove", "containsKey", "containsValue", "get", "indexOf", "lastIndexOf" -> javaLangObjectType
"getOrDefault" -> if (paramIdx == 0) javaLangObjectType else null
"containsAll", "removeAll", "retainAll" -> wildcardCollectionType
// Kotlin defines these like addAll(Collection<E>); Java uses addAll(Collection<? extends E>)
"putAll", "addAll" -> makeArgumentsCovariant(t)
else -> null
} ?: t
private fun overridesFunctionDefinedOn(f: IrFunction, packageName: String, className: String) =
(f as? IrSimpleFunction)?.let {
it.overriddenSymbols.any { overridden ->
overridden.owner.parentClassOrNull?.let { defnClass ->
defnClass.name.asString() == className &&
defnClass.packageFqName?.asString() == packageName
} ?: false
}
} ?: false
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun overridesCollectionsMethodWithAlteredParameterTypes(f: IrFunction) =
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(f.descriptor) != null ||
(f.name.asString() == "putAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableMap")) ||
(f.name.asString() == "addAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableCollection")) ||
(f.name.asString() == "addAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableList"))
private val jvmWildcardAnnotation = FqName("kotlin.jvm.JvmWildcard")
private val jvmWildcardSuppressionAnnotaton = FqName("kotlin.jvm.JvmSuppressWildcards")
private fun arrayExtendsAdditionAllowed(t: IrSimpleType): Boolean =
// Note the array special case includes Array<*>, which does permit adding `? extends ...` (making `? extends Object[]` in that case)
// Surprisingly Array<in X> does permit this as well, though the contravariant array lowers to Object[] so this ends up `? extends Object[]` as well.
t.arguments[0].let {
when (it) {
is IrTypeProjection -> when (it.variance) {
Variance.INVARIANT -> false
Variance.IN_VARIANCE -> !(it.type.isAny() || it.type.isNullableAny())
Variance.OUT_VARIANCE -> extendsAdditionAllowed(it.type)
}
else -> true
}
}
private fun extendsAdditionAllowed(t: IrType) =
if (t.isBoxedArray)
arrayExtendsAdditionAllowed(t as IrSimpleType)
else
((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean) =
when {
t.hasAnnotation(jvmWildcardAnnotation) -> true
!addByDefault -> false
t.hasAnnotation(jvmWildcardSuppressionAnnotaton) -> false
v == Variance.IN_VARIANCE -> !(t.isNullableAny() || t.isAny())
v == Variance.OUT_VARIANCE -> extendsAdditionAllowed(t)
else -> false
}
private fun addJavaLoweringArgumentWildcards(p: IrTypeParameter, t: IrTypeArgument, addByDefault: Boolean, javaType: JavaType?): IrTypeArgument =
(t as? IrTypeProjection)?.let {
val newBase = addJavaLoweringWildcards(it.type, addByDefault, javaType)
val newVariance =
if (it.variance == Variance.INVARIANT &&
p.variance != Variance.INVARIANT &&
// The next line forbids inferring a wildcard type when we have a corresponding Java type with conflicting variance.
// For example, Java might declare f(Comparable<CharSequence> cs), in which case we shouldn't add a `? super ...`
// wildcard. Note if javaType is unknown (e.g. this is a Kotlin source element), we assume wildcards should be added.
(javaType?.let { jt -> jt is JavaWildcardType && jt.isExtends == (p.variance == Variance.OUT_VARIANCE) } != false) &&
wildcardAdditionAllowed(p.variance, it.type, addByDefault))
p.variance
else
it.variance
if (newBase !== it.type || newVariance != it.variance)
makeTypeProjection(newBase, newVariance)
else
null
} ?: t
fun getJavaTypeArgument(jt: JavaType, idx: Int) =
when(jt) {
is JavaClassifierType -> jt.typeArguments.getOrNull(idx)
is JavaArrayType -> if (idx == 0) jt.componentType else null
else -> null
}
fun addJavaLoweringWildcards(t: IrType, addByDefault: Boolean, javaType: JavaType?): IrType =
(t as? IrSimpleType)?.let {
val typeParams = it.classOrNull?.owner?.typeParameters ?: return t
val newArgs = typeParams.zip(it.arguments).mapIndexed { idx, pair ->
addJavaLoweringArgumentWildcards(
pair.first,
pair.second,
addByDefault,
javaType?.let { jt -> getJavaTypeArgument(jt, idx) }
)
}
return if (newArgs.zip(it.arguments).all { pair -> pair.first === pair.second })
t
else
it.toBuilder().also { builder -> builder.arguments = newArgs }.buildSimpleType()
} ?: t
/*
* This is the normal getFunctionLabel function to use. If you want
* to refer to the function in its source class then
@@ -796,8 +969,21 @@ open class KotlinUsesExtractor(
* `java.lang.Throwable`, which isn't what we want. So we have to
* allow it to be passed in.
*/
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun getFunctionLabel(f: IrFunction, maybeParentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
getFunctionLabel(f.parent, maybeParentId, getFunctionShortName(f).nameInDB, f.valueParameters, f.returnType, f.extensionReceiverParameter, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses)
getFunctionLabel(
f.parent,
maybeParentId,
getFunctionShortName(f).nameInDB,
f.valueParameters,
getAdjustedReturnType(f),
f.extensionReceiverParameter,
getFunctionTypeParameters(f),
classTypeArgsIncludingOuterClasses,
overridesCollectionsMethodWithAlteredParameterTypes(f),
getJavaCallable(f),
!hasWildcardSuppressionAnnotation(f)
)
/*
* This function actually generates the label for a function.
@@ -823,6 +1009,14 @@ open class KotlinUsesExtractor(
functionTypeParameters: List<IrTypeParameter>,
// The type arguments of enclosing classes of the function.
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
// If true, this method implements a Java Collections interface (Collection, Map or List) and may need
// parameter erasure to match the way this class will appear to an external consumer of the .class file.
overridesCollectionsMethod: Boolean,
// The Java signature of this callable, if known.
javaSignature: JavaMember?,
// If true, Java wildcards implied by Kotlin type parameter variance should be added by default to this function's value parameters' types.
// (Return-type wildcard addition is always off by default)
addParameterWildcardsByDefault: Boolean,
// The prefix used in the label. "callable", unless a property label is created, then it's "property".
prefix: String = "callable"
): String {
@@ -841,19 +1035,28 @@ open class KotlinUsesExtractor(
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
}
}
val getIdForFunctionLabel = { it: IrValueParameter ->
// Mimic the Java extractor's behaviour: functions with type parameters are named for their erased types;
val getIdForFunctionLabel = { it: IndexedValue<IrValueParameter> ->
// Kotlin rewrites certain Java collections types adding additional generic constraints-- for example,
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
// If this has happened, erase the type again to get the correct Java signature.
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, addParameterWildcardsByDefault, javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) })
// Now substitute any class type parameters in:
val maybeSubbed = withAddedWildcards.substituteTypeAndArguments(substitutionMap, TypeContext.OTHER, pluginContext)
// Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
// those without type parameters are named for the generic type.
val maybeSubbed = it.type.substituteTypeAndArguments(substitutionMap, TypeContext.OTHER, pluginContext)
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
"{${useType(maybeErased).javaResult.id}}"
}
val paramTypeIds = allParams.joinToString(separator = ",", transform = getIdForFunctionLabel)
val paramTypeIds = allParams.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
val labelReturnType =
if (name == "<init>")
pluginContext.irBuiltIns.unitType
else
erase(returnType.substituteTypeAndArguments(substitutionMap, TypeContext.RETURN, pluginContext))
// Note that `addJavaLoweringWildcards` is not required here because the return type used to form the function
// label is always erased.
val returnTypeId = useType(labelReturnType, TypeContext.RETURN).javaResult.id
// This suffix is added to generic methods (and constructors) to match the Java extractor's behaviour.
// Comments in that extractor indicates it didn't want the label of the callable to clash with the raw
@@ -863,6 +1066,41 @@ open class KotlinUsesExtractor(
return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}${typeArgSuffix}\""
}
fun getAdjustedReturnType(f: IrFunction) : IrType {
// The return type of `java.util.concurrent.ConcurrentHashMap<K,V>.keySet/0` is defined as `Set<K>` in the stubs inside the Android SDK.
// This does not match the Java SDK return type: `ConcurrentHashMap.KeySetView<K,V>`, so it's adjusted here.
// This is a deliberate change in the Android SDK: https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-31/blob/2c56b25f619575bea12f9c5520ed2259620084ac/java/util/concurrent/ConcurrentHashMap.java#L1244-L1249
// The annotation on the source is not visible in the android.jar, so we can't make the change based on that.
// TODO: there are other instances of `dalvik.annotation.codegen.CovariantReturnType` in the Android SDK, we should handle those too if they cause DB inconsistencies
val parentClass = f.parentClassOrNull
if (parentClass == null ||
parentClass.fqNameWhenAvailable?.asString() != "java.util.concurrent.ConcurrentHashMap" ||
getFunctionShortName(f).nameInDB != "keySet" ||
f.valueParameters.isNotEmpty() ||
f.returnType.classFqName?.asString() != "kotlin.collections.MutableSet") {
return f.returnType
}
val otherKeySet = parentClass.declarations.filterIsInstance<IrFunction>().find { it.name.asString() == "keySet" && it.valueParameters.size == 1 }
?: return f.returnType
return otherKeySet.returnType.codeQlWithHasQuestionMark(false)
}
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun getJavaCallable(f: IrFunction) = (f.descriptor.source as? JavaSourceElement)?.javaElement as? JavaMember
fun getJavaValueParameterType(m: JavaMember, idx: Int) = when(m) {
is JavaMethod -> m.valueParameters[idx].type
is JavaConstructor -> m.valueParameters[idx].type
else -> null
}
fun hasWildcardSuppressionAnnotation(d: IrDeclaration) =
d.hasAnnotation(jvmWildcardSuppressionAnnotaton) ||
// Note not using `parentsWithSelf` as that only works if `d` is an IrDeclarationParent
d.parents.any { (it as? IrAnnotationContainer)?.hasAnnotation(jvmWildcardSuppressionAnnotaton) == true }
protected fun IrFunction.isLocalFunction(): Boolean {
return this.visibility == DescriptorVisibilities.LOCAL
}
@@ -947,7 +1185,19 @@ open class KotlinUsesExtractor(
decl.name == f.name &&
decl.valueParameters.size == f.valueParameters.size
} ?:
run {
// Or check property accessors:
if (f.isAccessor) {
val prop = javaClass.declarations.filterIsInstance<IrProperty>().find { decl ->
decl.name == (f.propertyIfAccessor as IrProperty).name
}
if (prop?.getter?.name == f.name)
prop.getter
else if (prop?.setter?.name == f.name)
prop.setter
else null
} else {
null
} ?: run {
val parentFqName = parentClass.fqNameWhenAvailable?.asString()
if (!expectedMissingEquivalents.contains(parentFqName)) {
logger.warn("Couldn't find a Java equivalent function to $parentFqName.${f.name} in ${javaClass.fqNameWhenAvailable}")
@@ -1083,8 +1333,21 @@ open class KotlinUsesExtractor(
return classTypeResult.id
}
fun getTypeParameterParentLabel(param: IrTypeParameter) =
param.parent.let {
when (it) {
is IrClass -> useClassSource(it)
is IrFunction -> useFunction(it, noReplace = true)
else -> { logger.error("Unexpected type parameter parent $it"); null }
}
}
fun getTypeParameterLabel(param: IrTypeParameter): String {
val parentLabel = useDeclarationParent(param.parent, false)
// Use this instead of `useDeclarationParent` so we can use useFunction with noReplace = true,
// ensuring that e.g. a method-scoped type variable declared on kotlin.String.transform <R> gets
// a different name to the corresponding java.lang.String.transform <R>, even though useFunction
// will usually replace references to one function with the other.
val parentLabel = getTypeParameterParentLabel(param)
return "@\"typevar;{$parentLabel};${param.name}\""
}
@@ -1188,7 +1451,7 @@ open class KotlinUsesExtractor(
if (t.isArray() || t.isNullableArray()) {
val elementType = t.getArrayElementType(pluginContext.irBuiltIns)
val erasedElementType = erase(elementType)
return withQuestionMark((classifier as IrClassSymbol).typeWith(erasedElementType), t.hasQuestionMark)
return (classifier as IrClassSymbol).typeWith(erasedElementType).codeQlWithHasQuestionMark(t.hasQuestionMark)
}
if (owner is IrClass) {
@@ -1230,9 +1493,34 @@ open class KotlinUsesExtractor(
fun useValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>?): Label<out DbParam> =
tw.getLabelFor(getValueParameterLabel(vp, parent))
fun isDirectlyExposedCompanionObjectField(f: IrField) =
f.hasAnnotation(FqName("kotlin.jvm.JvmField")) ||
f.correspondingPropertySymbol?.owner?.let {
it.isConst || it.isLateinit
} ?: false
fun getFieldParent(f: IrField) =
f.parentClassOrNull?.let {
if (it.isCompanion && isDirectlyExposedCompanionObjectField(f))
it.parent
else
null
} ?: f.parent
// Gets a field's corresponding property's extension receiver type, if any
fun getExtensionReceiverType(f: IrField) =
f.correspondingPropertySymbol?.owner?.let {
(it.getter ?: it.setter)?.extensionReceiverParameter?.type
}
fun getFieldLabel(f: IrField): String {
val parentId = useDeclarationParent(f.parent, false)
return "@\"field;{$parentId};${f.name.asString()}\""
val parentId = useDeclarationParent(getFieldParent(f), false)
// Distinguish backing fields of properties based on their extension receiver type;
// otherwise two extension properties declared in the same enclosing context will get
// clashing trap labels. These are always private, so we can just make up a label without
// worrying about their names as seen from Java.
val extensionPropertyDiscriminator = getExtensionReceiverType(f)?.let { "extension;${useType(it)}" } ?: ""
return "@\"field;{$parentId};${extensionPropertyDiscriminator}${f.name.asString()}\""
}
fun useField(f: IrField): Label<out DbField> =
@@ -1260,7 +1548,7 @@ open class KotlinUsesExtractor(
val returnType = getter?.returnType ?: setter?.valueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType
val typeParams = getFunctionTypeParameters(func)
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, "property")
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
}
}
@@ -1287,6 +1575,4 @@ open class KotlinUsesExtractor(
return tw.getVariableLabelFor<DbLocalvar>(v)
}
fun withQuestionMark(t: IrType, hasQuestionMark: Boolean) = if(hasQuestionMark) t.makeNullable() else t.makeNotNull()
}

View File

@@ -40,6 +40,15 @@ class TrapLabelManager {
val anonymousTypeMapping: MutableMap<IrClass, TypeResults> = mutableMapOf()
val locallyVisibleFunctionLabelMapping: MutableMap<IrFunction, LocallyVisibleFunctionLabels> = mutableMapOf()
/**
* The set of labels of generic specialisations that we have extracted
* in this TRAP file.
* We can't easily avoid duplication between TRAP files, as the labels
* contain references to other labels, so we just accept this
* duplication.
*/
val genericSpecialisationsExtracted = HashSet<String>()
}
/**
@@ -267,12 +276,6 @@ open class FileTrapWriter (
fun getLocation(e: IrElement): Label<DbLocation> {
return getLocation(e.startOffset, e.endOffset)
}
/**
* Gets a label for the location representing the whole of this file.
*/
fun getWholeFileLocation(): Label<DbLocation> {
return getWholeFileLocation(fileId)
}
/**
* Gets a label for the location corresponding to `startOffset` and
* `endOffset` within this file.
@@ -294,6 +297,12 @@ open class FileTrapWriter (
// to be 0.
return "file://$filePath"
}
/**
* Gets a label for the location representing the whole of this file.
*/
fun getWholeFileLocation(): Label<DbLocation> {
return getWholeFileLocation(fileId)
}
}
/**

View File

@@ -1,5 +1,6 @@
package com.github.codeql
import com.github.codeql.utils.getJvmName
import com.intellij.openapi.vfs.StandardFileSystems
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
@@ -18,17 +19,19 @@ import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
// and declarations within them into the parent class' JLS 13.1 name as
// specified above, followed by a `$` separator and then the short name
// for `that`.
private fun getName(d: IrDeclarationWithName) = (d as? IrAnnotationContainer)?.let { getJvmName(it) } ?: d.name.asString()
fun getIrDeclBinaryName(that: IrDeclaration): String {
val shortName = when(that) {
is IrDeclarationWithName -> that.name.asString()
is IrDeclarationWithName -> getName(that)
else -> "(unknown-name)"
}
val internalName = StringBuilder(shortName);
generateSequence(that.parent) { (it as? IrDeclaration)?.parent }
.forEach {
when (it) {
is IrClass -> internalName.insert(0, it.name.asString() + "$")
is IrPackageFragment -> it.fqName.asString().takeIf { it.isNotEmpty() }?.let { internalName.insert(0, "$it.") }
is IrClass -> internalName.insert(0, getName(it) + "$")
is IrPackageFragment -> it.fqName.asString().takeIf { fqName -> fqName.isNotEmpty() }?.let { fqName -> internalName.insert(0, "$fqName.") }
}
}
return internalName.toString()

View File

@@ -0,0 +1,90 @@
package com.github.codeql.utils
import org.jetbrains.kotlin.backend.common.ir.allOverridden
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.packageFqName
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
private data class MethodKey(val className: FqName, val functionName: Name)
private fun makeDescription(className: FqName, functionName: String) = MethodKey(className, Name.guessByFirstCharacter(functionName))
// This essentially mirrors SpecialBridgeMethods.kt, a backend pass which isn't easily available to our extractor.
private val specialFunctions = mapOf(
makeDescription(StandardNames.FqNames.collection, "<get-size>") to "size",
makeDescription(FqName("java.util.Collection"), "<get-size>") to "size",
makeDescription(StandardNames.FqNames.map, "<get-size>") to "size",
makeDescription(FqName("java.util.Map"), "<get-size>") to "size",
makeDescription(StandardNames.FqNames.charSequence.toSafe(), "<get-length>") to "length",
makeDescription(FqName("java.lang.CharSequence"), "<get-length>") to "length",
makeDescription(StandardNames.FqNames.map, "<get-keys>") to "keySet",
makeDescription(FqName("java.util.Map"), "<get-keys>") to "keySet",
makeDescription(StandardNames.FqNames.map, "<get-values>") to "values",
makeDescription(FqName("java.util.Map"), "<get-values>") to "values",
makeDescription(StandardNames.FqNames.map, "<get-entries>") to "entrySet",
makeDescription(FqName("java.util.Map"), "<get-entries>") to "entrySet",
makeDescription(StandardNames.FqNames.mutableList, "removeAt") to "remove",
makeDescription(FqName("java.util.List"), "removeAt") to "remove",
makeDescription(StandardNames.FqNames._enum.toSafe(), "<get-ordinal>") to "ordinal",
makeDescription(FqName("java.lang.Enum"), "<get-ordinal>") to "ordinal",
makeDescription(StandardNames.FqNames._enum.toSafe(), "<get-name>") to "name",
makeDescription(FqName("java.lang.Enum"), "<get-name>") to "name",
makeDescription(StandardNames.FqNames.number.toSafe(), "toByte") to "byteValue",
makeDescription(FqName("java.lang.Number"), "toByte") to "byteValue",
makeDescription(StandardNames.FqNames.number.toSafe(), "toShort") to "shortValue",
makeDescription(FqName("java.lang.Number"), "toShort") to "shortValue",
makeDescription(StandardNames.FqNames.number.toSafe(), "toInt") to "intValue",
makeDescription(FqName("java.lang.Number"), "toInt") to "intValue",
makeDescription(StandardNames.FqNames.number.toSafe(), "toLong") to "longValue",
makeDescription(FqName("java.lang.Number"), "toLong") to "longValue",
makeDescription(StandardNames.FqNames.number.toSafe(), "toFloat") to "floatValue",
makeDescription(FqName("java.lang.Number"), "toFloat") to "floatValue",
makeDescription(StandardNames.FqNames.number.toSafe(), "toDouble") to "doubleValue",
makeDescription(FqName("java.lang.Number"), "toDouble") to "doubleValue",
)
private val specialFunctionShortNames = specialFunctions.keys.map { it.functionName }.toSet()
fun getSpecialJvmName(f: IrFunction): String? {
if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) {
f.allOverridden(true).forEach { overriddenFunc ->
overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName ->
specialFunctions[MethodKey(parentFqName, f.name)]?.let {
return it
}
}
}
}
return null
}
fun getJvmName(container: IrAnnotationContainer): String? {
for(a: IrConstructorCall in container.annotations) {
val t = a.type
if (t is IrSimpleType && a.valueArgumentsCount == 1) {
val owner = t.classifier.owner
val v = a.getValueArgument(0)
if (owner is IrClass) {
val aPkg = owner.packageFqName?.asString()
val name = owner.name.asString()
if(aPkg == "kotlin.jvm" && name == "JvmName" && v is IrConst<*>) {
val value = v.value
if (value is String) {
return value
}
}
}
}
}
return (container as? IrFunction)?.let { getSpecialJvmName(container) }
}

View File

@@ -33,6 +33,36 @@ enum class Severity(val sev: Int) {
ErrorGlobal(8)
}
class LogMessage(private val kind: String, private val message: String) {
val timestamp: String
init {
timestamp = "${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}"
}
fun toText(): String {
return "[$timestamp K] [$kind] $message"
}
private fun escape(str: String): String {
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("/", "\\/")
.replace("\b", "\\b")
.replace("\u000C", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
}
fun toJsonLine(): String {
val kvs = listOf(Pair("origin", "CodeQL Kotlin extractor"),
Pair("timestamp", timestamp),
Pair("kind", kind),
Pair("message", message))
return "{ " + kvs.map { p -> "\"${p.first}\": \"${escape(p.second)}\""}.joinToString(", ") + " }\n"
}
}
data class ExtractorContext(val kind: String, val element: IrElement, val name: String, val loc: String)
open class LoggerBase(val logCounter: LogCounter) {
@@ -54,10 +84,6 @@ open class LoggerBase(val logCounter: LogCounter) {
}
}
private fun timestamp(): String {
return "[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} K]"
}
private fun getDiagnosticLocation(): String? {
val st = Exception().stackTrace
for(x in st) {
@@ -84,7 +110,6 @@ open class LoggerBase(val logCounter: LogCounter) {
fun diagnostic(tw: TrapWriter, severity: Severity, msg: String, extraInfo: String?, locationString: String? = null, mkLocationId: () -> Label<DbLocation> = { tw.unknownLocation }) {
val diagnosticLoc = getDiagnosticLocation()
val diagnosticLocStr = if(diagnosticLoc == null) "<unknown location>" else diagnosticLoc
val extraInfoStr = if (extraInfo == null) "" else (extraInfo + "\n")
val suffix =
if(diagnosticLoc == null) {
" Missing caller information.\n"
@@ -100,8 +125,10 @@ open class LoggerBase(val logCounter: LogCounter) {
}
val fullMsgBuilder = StringBuilder()
fullMsgBuilder.append(msg)
fullMsgBuilder.append('\n')
fullMsgBuilder.append(extraInfoStr)
if (extraInfo != null) {
fullMsgBuilder.append('\n')
fullMsgBuilder.append(extraInfo)
}
val iter = extractorContextStack.listIterator(extractorContextStack.size)
while (iter.hasPrevious()) {
@@ -111,38 +138,38 @@ open class LoggerBase(val logCounter: LogCounter) {
fullMsgBuilder.append(suffix)
val fullMsg = fullMsgBuilder.toString()
val ts = timestamp()
val locStr = if (locationString == null) "" else "At " + locationString + ": "
val kind = if (severity <= Severity.WarnHigh) "WARN" else "ERROR"
val logMessage = LogMessage(kind, "Diagnostic($diagnosticLocStr): $locStr$fullMsg")
// We don't actually make the location until after the `return` above
val locationId = mkLocationId()
val diagLabel = tw.getFreshIdLabel<DbDiagnostic>()
tw.writeDiagnostics(diagLabel, "CodeQL Kotlin extractor", severity.sev, "", msg, "$ts $fullMsg", locationId)
tw.writeDiagnostics(diagLabel, "CodeQL Kotlin extractor", severity.sev, "", msg, "${logMessage.timestamp} $fullMsg", locationId)
tw.writeDiagnostic_for(diagLabel, StringLabel("compilation"), file_number, file_number_diagnostic_number++)
val locStr = if (locationString == null) "" else "At " + locationString + ": "
val kind = if (severity <= Severity.WarnHigh) "WARN" else "ERROR"
logStream.write("$ts [$kind] Diagnostic($diagnosticLocStr): $locStr$fullMsg")
logStream.write(logMessage.toJsonLine())
}
fun trace(tw: TrapWriter, msg: String) {
if (verbosity >= 4) {
val fullMsg = "${timestamp()} [TRACE] $msg"
tw.writeComment(fullMsg)
logStream.write(fullMsg + "\n")
val logMessage = LogMessage("TRACE", msg)
tw.writeComment(logMessage.toText())
logStream.write(logMessage.toJsonLine())
}
}
fun debug(tw: TrapWriter, msg: String) {
if (verbosity >= 4) {
val fullMsg = "${timestamp()} [DEBUG] $msg"
tw.writeComment(fullMsg)
logStream.write(fullMsg + "\n")
val logMessage = LogMessage("DEBUG", msg)
tw.writeComment(logMessage.toText())
logStream.write(logMessage.toJsonLine())
}
}
fun info(tw: TrapWriter, msg: String) {
if (verbosity >= 3) {
val fullMsg = "${timestamp()} [INFO] $msg"
tw.writeComment(fullMsg)
logStream.write(fullMsg + "\n")
val logMessage = LogMessage("INFO", msg)
tw.writeComment(logMessage.toText())
logStream.write(logMessage.toJsonLine())
}
}
@@ -160,9 +187,12 @@ open class LoggerBase(val logCounter: LogCounter) {
fun printLimitedDiagnosticCounts(tw: TrapWriter) {
for((caller, count) in logCounter.diagnosticCounts) {
if(count >= logCounter.diagnosticLimit) {
val msg = "Total of $count diagnostics from $caller.\n"
tw.writeComment(msg)
logStream.write(msg)
// We don't know if this location relates to an error
// or a warning, so we just declare hitting the limit
// to be an error regardless.
val logMessage = LogMessage("ERROR", "Total of $count diagnostics from $caller.")
tw.writeComment(logMessage.toText())
logStream.write(logMessage.toJsonLine())
}
}
}

View File

@@ -2,8 +2,10 @@ package com.github.codeql.utils
import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.getJavaEquivalentClassId
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
@@ -27,6 +29,7 @@ import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
fun IrType.substituteTypeArguments(params: List<IrTypeParameter>, arguments: List<IrTypeArgument>) =
when(this) {
@@ -34,6 +37,30 @@ fun IrType.substituteTypeArguments(params: List<IrTypeParameter>, arguments: Lis
else -> this
}
fun IrSimpleType.substituteTypeArguments(substitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>): IrSimpleType {
if (substitutionMap.isEmpty()) return this
val newArguments = arguments.map {
if (it is IrTypeProjection) {
val itType = it.type
if (itType is IrSimpleType) {
subProjectedType(substitutionMap, itType, it.variance)
} else {
it
}
} else {
it
}
}
return IrSimpleTypeImpl(
classifier,
hasQuestionMark,
newArguments,
annotations
)
}
/**
* Returns true if substituting `innerVariance T` into the context `outerVariance []` discards all knowledge about
* what T could be.
@@ -64,7 +91,7 @@ private fun subProjectedType(substitutionMap: Map<IrTypeParameterSymbol, IrTypeA
if (conflictingVariance(outerVariance, substitutedTypeArg.variance))
IrStarProjectionImpl
else {
val newProjectedType = substitutedTypeArg.type.let { if (t.hasQuestionMark) it.withHasQuestionMark(true) else it }
val newProjectedType = substitutedTypeArg.type.let { if (t.hasQuestionMark) it.codeQlWithHasQuestionMark(true) else it }
val newVariance = combineVariance(outerVariance, substitutedTypeArg.variance)
makeTypeProjection(newProjectedType, newVariance)
}
@@ -73,30 +100,6 @@ private fun subProjectedType(substitutionMap: Map<IrTypeParameterSymbol, IrTypeA
}
} ?: makeTypeProjection(t.substituteTypeArguments(substitutionMap), outerVariance)
fun IrSimpleType.substituteTypeArguments(substitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>): IrSimpleType {
if (substitutionMap.isEmpty()) return this
val newArguments = arguments.map {
if (it is IrTypeProjection) {
val itType = it.type
if (itType is IrSimpleType) {
subProjectedType(substitutionMap, itType, it.variance)
} else {
it
}
} else {
it
}
}
return IrSimpleTypeImpl(
classifier,
hasQuestionMark,
newArguments,
annotations
)
}
fun IrTypeArgument.upperBound(context: IrPluginContext) =
when(this) {
is IrStarProjection -> context.irBuiltIns.anyNType
@@ -189,7 +192,7 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument =
is IrStarProjection -> this
is IrTypeProjection ->
this.type.let { when(it) {
is IrSimpleType -> if (it.hasQuestionMark == b) this else makeTypeProjection(it.withHasQuestionMark(b), this.variance)
is IrSimpleType -> if (it.hasQuestionMark == b) this else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance)
else -> this
}}
else -> this
@@ -219,12 +222,13 @@ fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List<IrTyp
} ?: false
}
val remainingArgs = args.drop(paramsContainer.typeParameters.size)
val parent = paramsContainer.parent as? IrTypeParametersContainer
val parentClass = paramsContainer.parents.firstIsInstanceOrNull<IrClass>()
val parentUnspecialised = when {
remainingArgs.isEmpty() -> true
parent == null -> false
parent !is IrClass -> false
else -> isUnspecialised(paramsContainer.parentAsClass, remainingArgs)
parentClass == null -> false
else -> isUnspecialised(parentClass, remainingArgs)
}
return unspecialisedHere && parentUnspecialised
}

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,17 @@
package com.github.codeql.utils.versions
import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.Severity
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun <TIrStub> KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? =
(pluginContext.symbolTable as? SymbolTable) ?.let {
val stubGenerator = DeclarationStubGenerator(pluginContext.moduleDescriptor, it, pluginContext.languageVersionSettings)
generateStub(stubGenerator)
} ?: run {
logger.error("Plugin context has no symbol table, couldn't get IR stub")
null
}

View File

@@ -0,0 +1,5 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.SourceManager
typealias FileEntry = SourceManager.FileEntry

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.declarations.IrClass
fun functionN(pluginContext: IrPluginContext): (Int) -> IrClass {
return { i -> pluginContext.irBuiltIns.functionFactory.functionN(i) }
}

View File

@@ -0,0 +1,21 @@
package com.github.codeql.utils.versions
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
class Psi2Ir : Psi2IrFacade {
companion object {
val psiManager = PsiSourceManager()
}
override fun getKtFile(irFile: IrFile): KtFile? {
return psiManager.getKtFile(irFile)
}
override fun findPsiElement(irElement: IrElement, irFile: IrFile): PsiElement? {
return psiManager.findPsiElement(irElement, irFile)
}
}

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.jvm.codegen.isRawType
import org.jetbrains.kotlin.ir.types.IrSimpleType
fun IrSimpleType.isRawType() = this.isRawType()

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,17 @@
package com.github.codeql.utils.versions
import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.Severity
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun <TIrStub> KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? =
(pluginContext.symbolTable as? SymbolTable) ?.let {
val stubGenerator = DeclarationStubGenerator(pluginContext.moduleDescriptor, it, pluginContext.languageVersionSettings)
generateStub(stubGenerator)
} ?: run {
logger.error("Plugin context has no symbol table, couldn't get IR stub")
null
}

View File

@@ -0,0 +1,5 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.SourceManager
typealias FileEntry = SourceManager.FileEntry

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.declarations.IrClass
fun functionN(pluginContext: IrPluginContext): (Int) -> IrClass {
return { i -> pluginContext.irBuiltIns.functionFactory.functionN(i) }
}

View File

@@ -0,0 +1,21 @@
package com.github.codeql.utils.versions
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
class Psi2Ir : Psi2IrFacade {
companion object {
val psiManager = PsiSourceManager()
}
override fun getKtFile(irFile: IrFile): KtFile? {
return psiManager.getKtFile(irFile)
}
override fun findPsiElement(irElement: IrElement, irFile: IrFile): PsiElement? {
return psiManager.findPsiElement(irElement, irFile)
}
}

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.jvm.codegen.isRawType
import org.jetbrains.kotlin.ir.types.IrSimpleType
fun IrSimpleType.isRawType() = this.isRawType()

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,18 @@
package com.github.codeql.utils.versions
import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.Severity
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun <TIrStub> KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? =
(pluginContext.symbolTable as? SymbolTable) ?.let {
val stubGenerator = DeclarationStubGeneratorImpl(pluginContext.moduleDescriptor, it, pluginContext.languageVersionSettings)
generateStub(stubGenerator)
} ?: run {
logger.error("Plugin context has no symbol table, couldn't get IR stub")
null
}

View File

@@ -0,0 +1,5 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.IrFileEntry
typealias FileEntry = IrFileEntry

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.declarations.IrClass
fun functionN(pluginContext: IrPluginContext): (Int) -> IrClass {
return { i -> pluginContext.irBuiltIns.functionFactory.functionN(i) }
}

View File

@@ -0,0 +1,18 @@
package com.github.codeql.utils.versions
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.psi.PsiSourceManager
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.psi.KtFile
class Psi2Ir: Psi2IrFacade {
override fun getKtFile(irFile: IrFile): KtFile? {
return irFile.getKtFile()
}
override fun findPsiElement(irElement: IrElement, irFile: IrFile): PsiElement? {
return PsiSourceManager.findPsiElement(irElement, irFile)
}
}

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.jvm.codegen.isRawType
import org.jetbrains.kotlin.ir.types.IrSimpleType
fun IrSimpleType.isRawType() = this.isRawType()

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
return this.withHasQuestionMark(b)
}

View File

@@ -0,0 +1,9 @@
package com.github.codeql.utils.versions
import com.github.codeql.KotlinUsesExtractor
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
fun <TIrStub> KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? {
logger.error("Descriptors not yet supported for Kotlin 1.7")
return null
}

View File

@@ -0,0 +1,5 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.IrFileEntry
typealias FileEntry = IrFileEntry

View File

@@ -0,0 +1,5 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
fun functionN(pluginContext: IrPluginContext) = pluginContext.irBuiltIns::functionN

View File

@@ -0,0 +1,18 @@
package com.github.codeql.utils.versions
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.psi.PsiSourceManager
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.psi.KtFile
class Psi2Ir: Psi2IrFacade {
override fun getKtFile(irFile: IrFile): KtFile? {
return irFile.getKtFile()
}
override fun findPsiElement(irElement: IrElement, irFile: IrFile): PsiElement? {
return PsiSourceManager.findPsiElement(irElement, irFile)
}
}

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.jvm.ir.isRawType
import org.jetbrains.kotlin.ir.types.IrSimpleType
fun IrSimpleType.isRawType() = this.isRawType()

View File

@@ -0,0 +1,13 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.makeNullable
fun IrType.codeQlWithHasQuestionMark(b : Boolean): IrType {
if (b) {
return this.makeNullable()
} else {
return this.makeNotNull()
}
}

View File

@@ -1,11 +1,15 @@
import java
class InstantiatedType extends ParameterizedType {
InstantiatedType() { typeArgs(_, _, this) }
}
Type getAMentionedType(RefType type) {
result = type
or
result = getAMentionedType(type).(Array).getElementType()
or
result = getAMentionedType(type).(ParameterizedType).getATypeArgument()
result = getAMentionedType(type).(InstantiatedType).getATypeArgument()
or
result = getAMentionedType(type).(NestedType).getEnclosingType()
}
@@ -24,17 +28,26 @@ Type getATypeUsedInClass(RefType type) {
result = getAMentionedType(getATypeUsedInClass(type))
}
Element getEnclosingElementStar(RefType e) {
result = e
or
result.contains(e)
}
TypeVariable getATypeVariableInScope(RefType type) {
result = type.getACallable().(GenericCallable).getATypeParameter()
or
result = type.(GenericType).getATypeParameter()
or
result = getAMentionedType(type.(ParameterizedType).getATypeArgument())
or
result = getATypeVariableInScope(type.getEnclosingType())
exists(Element e | e = getEnclosingElementStar(type) |
result = e.(RefType).getACallable().(GenericCallable).getATypeParameter()
or
result = e.(GenericType).getATypeParameter()
or
result = e.(GenericCallable).getATypeParameter()
or
result = getAMentionedType(e.(InstantiatedType).getATypeArgument())
)
}
from ClassOrInterface typeUser, TypeVariable outOfScope
where
outOfScope = getAMentionedType(typeUser) and not outOfScope = getATypeVariableInScope(typeUser)
select "Type " + typeUser + " uses out-of-scope type variable " + outOfScope
outOfScope = getATypeUsedInClass(typeUser) and not outOfScope = getATypeVariableInScope(typeUser)
select "Type " + typeUser + " uses out-of-scope type variable " + outOfScope +
". Note the Java extractor is known to sometimes do this; the Kotlin extractor should not."

View File

@@ -0,0 +1,22 @@
import java
string visibility(Method m) {
result = "public" and m.isPublic()
or
result = "protected" and m.isProtected()
or
result = "private" and m.isPrivate()
or
result = "internal" and m.isInternal()
}
// TODO: This ought to check more than just methods
from Method m
where
// TODO: This ought to work for everything, but for now we
// restrict to things in Kotlin source files
m.getFile().isKotlinSourceFile() and
// TODO: This ought to have visibility information
not m.getName() = "<clinit>" and
count(visibility(m)) != 1
select m, concat(visibility(m), ", ")

View File

@@ -1,3 +1,98 @@
## 0.2.3
## 0.2.2
### Deprecated APIs
* The QL class `FloatingPointLiteral` has been renamed to `FloatLiteral`.
### Minor Analysis Improvements
* Fixed a sanitizer of the query `java/android/intent-redirection`. Now, for an intent to be considered
safe against intent redirection, both its package name and class name must be checked.
## 0.2.1
### New Features
* A number of new classes and methods related to the upcoming Kotlin
support have been added. These are not yet stable, as Kotlin support
is still under development.
* `File::isSourceFile`
* `File::isJavaSourceFile`
* `File::isKotlinSourceFile`
* `Member::getKotlinType`
* `Element::isCompilerGenerated`
* `Expr::getKotlinType`
* `LambdaExpr::isKotlinFunctionN`
* `Callable::getReturnKotlinType`
* `Callable::getParameterKotlinType`
* `Method::isLocal`
* `Method::getKotlinName`
* `Field::getKotlinType`
* `Modifiable::isSealedKotlin`
* `Modifiable::isInternal`
* `Variable::getKotlinType`
* `LocalVariableDecl::getKotlinType`
* `Parameter::getKotlinType`
* `Parameter::isExtensionParameter`
* `Compilation` class
* `Diagnostic` class
* `KtInitializerAssignExpr` class
* `ValueEQExpr` class
* `ValueNEExpr` class
* `ValueOrReferenceEqualsExpr` class
* `ValueOrReferenceNotEqualsExpr` class
* `ReferenceEqualityTest` class
* `CastingExpr` class
* `SafeCastExpr` class
* `ImplicitCastExpr` class
* `ImplicitNotNullExpr` class
* `ImplicitCoercionToUnitExpr` class
* `UnsafeCoerceExpr` class
* `PropertyRefExpr` class
* `NotInstanceOfExpr` class
* `ExtensionReceiverAccess` class
* `WhenExpr` class
* `WhenBranch` class
* `ClassExpr` class
* `StmtExpr` class
* `StringTemplateExpr` class
* `NotNullExpr` class
* `TypeNullPointerException` class
* `KtComment` class
* `KtCommentSection` class
* `KotlinType` class
* `KotlinNullableType` class
* `KotlinNotnullType` class
* `KotlinTypeAlias` class
* `Property` class
* `DelegatedProperty` class
* `ExtensionMethod` class
* `KtInitializerNode` class
* `KtLoopStmt` class
* `KtBreakContinueStmt` class
* `KtBreakStmt` class
* `KtContinueStmt` class
* `ClassObject` class
* `CompanionObject` class
* `LiveLiteral` class
* `LiveLiteralMethod` class
* `CastConversionContext` renamed to `CastingConversionContext`
* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded.
### Minor Analysis Improvements
* Added models for the libraries OkHttp and Retrofit.
* Add taint models for the following `File` methods:
* `File::getAbsoluteFile`
* `File::getCanonicalFile`
* `File::getAbsolutePath`
* `File::getCanonicalPath`
* Added a flow step for `toString` calls on tainted `android.text.Editable` objects.
* Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`.
* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`.
## 0.2.0
### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`.

View File

@@ -1,8 +0,0 @@
---
category: minorAnalysis
---
* Add taint models for the following `File` methods:
* `File::getAbsoluteFile`
* `File::getCanonicalFile`
* `File::getAbsolutePath`
* `File::getCanonicalPath`

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
Added a flow step for `toString` calls on tainted `android.text.Editable` objects.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`.

View File

@@ -1,5 +0,0 @@
---
category: minorAnalysis
---
Fixed a sanitizer of the query `java/android/intent-redirection`. Now, for an intent to be considered
safe against intent redirection, both its package name and class name must be checked.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added models for the libraries OkHttp and Retrofit.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
Added a flow step for `String.valueOf` calls on tainted `android.text.Editable` objects.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -1,9 +1,10 @@
---
category: feature
---
* A number of new classes and methods related to the upcoming Kotlin
support have been added. These are not yet stable, as Kotlin support
is still under development.
## 0.2.1
### New Features
* A number of new classes and methods related to the upcoming Kotlin
support have been added. These are not yet stable, as Kotlin support
is still under development.
* `File::isSourceFile`
* `File::isJavaSourceFile`
* `File::isKotlinSourceFile`
@@ -65,3 +66,16 @@ category: feature
* `LiveLiteral` class
* `LiveLiteralMethod` class
* `CastConversionContext` renamed to `CastingConversionContext`
* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded.
### Minor Analysis Improvements
* Added models for the libraries OkHttp and Retrofit.
* Add taint models for the following `File` methods:
* `File::getAbsoluteFile`
* `File::getCanonicalFile`
* `File::getAbsolutePath`
* `File::getCanonicalPath`
* Added a flow step for `toString` calls on tainted `android.text.Editable` objects.
* Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`.
* Added modeling of MyBatis (`org.apache.ibatis`) Providers, resulting in additional sinks for the queries `java/ognl-injection`, `java/sql-injection`, `java/sql-injection-local` and `java/concatenated-sql-query`.

View File

@@ -0,0 +1,10 @@
## 0.2.2
### Deprecated APIs
* The QL class `FloatingPointLiteral` has been renamed to `FloatLiteral`.
### Minor Analysis Improvements
* Fixed a sanitizer of the query `java/android/intent-redirection`. Now, for an intent to be considered
safe against intent redirection, both its package name and class name must be checked.

View File

@@ -0,0 +1 @@
## 0.2.3

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.2.0
lastReleaseVersion: 0.2.3

View File

@@ -1,5 +1,5 @@
name: codeql/java-all
version: 0.2.1-dev
version: 0.3.0-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java

View File

@@ -92,7 +92,7 @@ class CollectionMutation extends MethodAccess {
/** A method that queries the contents of a collection without mutating it. */
class CollectionQueryMethod extends CollectionMethod {
CollectionQueryMethod() {
pragma[only_bind_into](this).getName().regexpMatch("contains|containsAll|get|size|peek")
pragma[only_bind_into](this).getName() = ["contains", "containsAll", "get", "size", "peek"]
}
}

View File

@@ -286,7 +286,7 @@ private module ControlFlowGraphImpl {
* That is, contexts where the control-flow edges depend on `value` given that `b` ends
* with a `booleanCompletion(value, _)`.
*/
private predicate inBooleanContext(Expr b) {
private predicate inBooleanContext(ControlFlowNode b) {
exists(LogicExpr logexpr |
logexpr.(BinaryExpr).getLeftOperand() = b
or
@@ -316,6 +316,10 @@ private module ControlFlowGraphImpl {
inBooleanContext(whenexpr) and
whenexpr.getBranch(_).getAResult() = b
)
or
inBooleanContext(b.(ExprStmt).getExpr())
or
inBooleanContext(b.(StmtExpr).getStmt())
}
/**
@@ -907,7 +911,8 @@ private module ControlFlowGraphImpl {
)
or
// the last node in an `ExprStmt` is the last node in the expression
last(n.(ExprStmt).getExpr(), last, completion) and completion = NormalCompletion()
last(n.(ExprStmt).getExpr(), last, completion) and
completion instanceof NormalOrBooleanCompletion
or
// the last node in a `StmtExpr` is the last node in the statement
last(n.(StmtExpr).getStmt(), last, completion)

View File

@@ -716,20 +716,23 @@ class LongLiteral extends Literal, @longliteral {
override string getAPrimaryQlClass() { result = "LongLiteral" }
}
/** DEPRECATED: Alias for FloatLiteral */
deprecated class FloatingPointLiteral = FloatLiteral;
/**
* A float literal. For example, `4.2f`.
*
* A float literal is never negative; a preceding minus, if any, will always
* be modeled as separate `MinusExpr`.
*/
class FloatingPointLiteral extends Literal, @floatingpointliteral {
class FloatLiteral extends Literal, @floatingpointliteral {
/**
* Gets the value of this literal as CodeQL 64-bit `float`. The value will
* be parsed as Java 32-bit `float` and then converted to a CodeQL `float`.
*/
float getFloatValue() { result = this.getValue().toFloat() }
override string getAPrimaryQlClass() { result = "FloatingPointLiteral" }
override string getAPrimaryQlClass() { result = "FloatLiteral" }
}
/**

View File

@@ -144,18 +144,6 @@ class NumberType extends RefType {
NumberType() { exists(TypeNumber number | hasDescendant(number, this)) }
}
/** A numeric type, including both primitive and boxed types. */
class NumericType extends Type {
NumericType() {
exists(string name |
name = this.(PrimitiveType).getName() or
name = this.(BoxedType).getPrimitiveType().getName()
|
name.regexpMatch("byte|short|int|long|double|float")
)
}
}
/** An immutable type. */
class ImmutableType extends Type {
ImmutableType() {

View File

@@ -153,6 +153,15 @@ class KtComment extends Top, @ktcomment {
/** Gets the full text of this comment. */
string getText() { ktComments(this, _, result) }
/** Holds if this comment is an EOL comment. */
predicate isEolComment() { ktComments(this, 1, _) }
/** Holds if this comment is a block comment. */
predicate isBlockComment() { ktComments(this, 2, _) }
/** Holds if this comment is a KDoc comment. */
predicate isDocComment() { ktComments(this, 3, _) }
/** Gets the sections of this comment. */
KtCommentSection getSections() { ktCommentSections(result, this, _) }

View File

@@ -59,9 +59,8 @@ class MapMutation extends MethodAccess {
/** A method that queries the contents of the map it belongs to without mutating it. */
class MapQueryMethod extends MapMethod {
MapQueryMethod() {
pragma[only_bind_into](this)
.getName()
.regexpMatch("get|containsKey|containsValue|entrySet|keySet|values|isEmpty|size")
pragma[only_bind_into](this).getName() =
["get", "containsKey", "containsValue", "entrySet", "keySet", "values", "isEmpty", "size"]
}
}

View File

@@ -29,7 +29,8 @@ class Stmt extends StmtParent, ExprParent, @stmt {
*/
Stmt getEnclosingStmt() {
result = this.getParent() or
result = this.getParent().(SwitchExpr).getEnclosingStmt()
result = this.getParent().(SwitchExpr).getEnclosingStmt() or
result = this.getParent().(WhenExpr).getEnclosingStmt()
}
/** Holds if this statement is the child of the specified parent at the specified (zero-based) position. */

View File

@@ -1002,7 +1002,9 @@ class FunctionalInterface extends Interface {
* and `double`.
*/
class PrimitiveType extends Type, @primitive {
PrimitiveType() { this.getName().regexpMatch("float|double|int|boolean|short|byte|char|long") }
PrimitiveType() {
this.getName() = ["float", "double", "int", "boolean", "short", "byte", "char", "long"]
}
/** Gets the boxed type corresponding to this primitive type. */
BoxedType getBoxedType() { result.getPrimitiveType() = this }
@@ -1217,9 +1219,9 @@ predicate erasedHaveIntersection(RefType t1, RefType t2) {
class IntegralType extends Type {
IntegralType() {
exists(string name |
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name.regexpMatch("byte|char|short|int|long")
name = ["byte", "char", "short", "int", "long"]
)
}
}
@@ -1228,7 +1230,7 @@ class IntegralType extends Type {
class BooleanType extends Type {
BooleanType() {
exists(string name |
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name = "boolean"
)
@@ -1239,20 +1241,31 @@ class BooleanType extends Type {
class CharacterType extends Type {
CharacterType() {
exists(string name |
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name = "char"
)
}
}
/** A numeric type, including both primitive and boxed types. */
class NumericType extends Type {
NumericType() {
exists(string name |
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name = ["byte", "short", "int", "long", "double", "float"]
)
}
}
/** A numeric or character type, which may be either a primitive or a boxed type. */
class NumericOrCharType extends Type {
NumericOrCharType() {
exists(string name |
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name.regexpMatch("byte|char|short|int|long|double|float")
name = ["byte", "char", "short", "int", "long", "double", "float"]
)
}
}
@@ -1261,9 +1274,9 @@ class NumericOrCharType extends Type {
class FloatingPointType extends Type {
FloatingPointType() {
exists(string name |
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
name = [this.(PrimitiveType).getName(), this.(BoxedType).getPrimitiveType().getName()]
|
name.regexpMatch("float|double")
name = ["float", "double"]
)
}
}

View File

@@ -62,6 +62,10 @@
* sources "remote" indicates a default remote flow source, and for summaries
* "taint" indicates a default additional taint step and "value" indicates a
* globally applicable value-preserving step.
* 9. The `provenance` column is a tag to indicate the origin of the summary.
* There are two supported values: "generated" and "manual". "generated" means that
* the model has been emitted by the model generator tool and "manual" means
* that the model has been written by hand.
*/
import java
@@ -92,6 +96,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.apache.IO
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.Flexjson
private import semmle.code.java.frameworks.generated
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
@@ -150,112 +155,112 @@ private predicate sourceModelCsv(string row) {
row =
[
// org.springframework.security.web.savedrequest.SavedRequest
"org.springframework.security.web.savedrequest;SavedRequest;true;getRedirectUrl;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getCookies;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderValues;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderNames;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterValues;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterMap;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getRedirectUrl;;;ReturnValue;remote;manual",
"org.springframework.security.web.savedrequest;SavedRequest;true;getCookies;;;ReturnValue;remote;manual",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderValues;;;ReturnValue;remote;manual",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderNames;;;ReturnValue;remote;manual",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterValues;;;ReturnValue;remote;manual",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterMap;;;ReturnValue;remote;manual",
// ServletRequestGetParameterMethod
"javax.servlet;ServletRequest;false;getParameter;(String);;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getParameterValues;(String);;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getParameter;(String);;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getParameterValues;(String);;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getParameter;(String);;ReturnValue;remote;manual",
"javax.servlet;ServletRequest;false;getParameterValues;(String);;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getParameter;(String);;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getParameterValues;(String);;ReturnValue;remote;manual",
// ServletRequestGetParameterMapMethod
"javax.servlet;ServletRequest;false;getParameterMap;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getParameterMap;();;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getParameterMap;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getParameterMap;();;ReturnValue;remote;manual",
// ServletRequestGetParameterNamesMethod
"javax.servlet;ServletRequest;false;getParameterNames;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getParameterNames;();;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getParameterNames;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getParameterNames;();;ReturnValue;remote;manual",
// HttpServletRequestGetQueryStringMethod
"javax.servlet.http;HttpServletRequest;false;getQueryString;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getQueryString;();;ReturnValue;remote;manual",
//
// URLConnectionGetInputStreamMethod
"java.net;URLConnection;false;getInputStream;();;ReturnValue;remote",
"java.net;URLConnection;false;getInputStream;();;ReturnValue;remote;manual",
// SocketGetInputStreamMethod
"java.net;Socket;false;getInputStream;();;ReturnValue;remote",
"java.net;Socket;false;getInputStream;();;ReturnValue;remote;manual",
// BeanValidationSource
"javax.validation;ConstraintValidator;true;isValid;;;Parameter[0];remote",
"javax.validation;ConstraintValidator;true;isValid;;;Parameter[0];remote;manual",
// SpringMultipartRequestSource
"org.springframework.web.multipart;MultipartRequest;true;getFile;(String);;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getFileMap;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getFileNames;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getFiles;(String);;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getMultiFileMap;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getMultipartContentType;(String);;ReturnValue;remote",
"org.springframework.web.multipart;MultipartRequest;true;getFile;(String);;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartRequest;true;getFileMap;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartRequest;true;getFileNames;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartRequest;true;getFiles;(String);;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartRequest;true;getMultiFileMap;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartRequest;true;getMultipartContentType;(String);;ReturnValue;remote;manual",
// SpringMultipartFileSource
"org.springframework.web.multipart;MultipartFile;true;getBytes;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getContentType;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getInputStream;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getName;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getOriginalFilename;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getResource;();;ReturnValue;remote",
"org.springframework.web.multipart;MultipartFile;true;getBytes;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartFile;true;getContentType;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartFile;true;getInputStream;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartFile;true;getName;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartFile;true;getOriginalFilename;();;ReturnValue;remote;manual",
"org.springframework.web.multipart;MultipartFile;true;getResource;();;ReturnValue;remote;manual",
// HttpServletRequest.get*
"javax.servlet.http;HttpServletRequest;false;getHeader;(String);;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getHeaders;(String);;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getHeaderNames;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getPathInfo;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getRequestURI;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getRequestURL;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getRemoteUser;();;ReturnValue;remote",
"javax.servlet.http;HttpServletRequest;false;getHeader;(String);;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getHeaders;(String);;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getHeaderNames;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getPathInfo;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getRequestURI;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getRequestURL;();;ReturnValue;remote;manual",
"javax.servlet.http;HttpServletRequest;false;getRemoteUser;();;ReturnValue;remote;manual",
// SpringWebRequestGetMethod
"org.springframework.web.context.request;WebRequest;false;getDescription;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getHeader;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getHeaderNames;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getHeaderValues;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getParameter;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getParameterMap;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getParameterNames;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getParameterValues;;;ReturnValue;remote",
"org.springframework.web.context.request;WebRequest;false;getDescription;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getHeader;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getHeaderNames;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getHeaderValues;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getParameter;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getParameterMap;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getParameterNames;;;ReturnValue;remote;manual",
"org.springframework.web.context.request;WebRequest;false;getParameterValues;;;ReturnValue;remote;manual",
// TODO consider org.springframework.web.context.request.WebRequest.getRemoteUser
// ServletRequestGetBodyMethod
"javax.servlet;ServletRequest;false;getInputStream;();;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getReader;();;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getInputStream;();;ReturnValue;remote;manual",
"javax.servlet;ServletRequest;false;getReader;();;ReturnValue;remote;manual",
// CookieGet*
"javax.servlet.http;Cookie;false;getValue;();;ReturnValue;remote",
"javax.servlet.http;Cookie;false;getName;();;ReturnValue;remote",
"javax.servlet.http;Cookie;false;getComment;();;ReturnValue;remote",
"javax.servlet.http;Cookie;false;getValue;();;ReturnValue;remote;manual",
"javax.servlet.http;Cookie;false;getName;();;ReturnValue;remote;manual",
"javax.servlet.http;Cookie;false;getComment;();;ReturnValue;remote;manual",
// ApacheHttp*
"org.apache.http;HttpMessage;false;getParams;();;ReturnValue;remote",
"org.apache.http;HttpEntity;false;getContent;();;ReturnValue;remote",
"org.apache.http;HttpMessage;false;getParams;();;ReturnValue;remote;manual",
"org.apache.http;HttpEntity;false;getContent;();;ReturnValue;remote;manual",
// In the setting of Android we assume that XML has been transmitted over
// the network, so may be tainted.
// XmlPullGetMethod
"org.xmlpull.v1;XmlPullParser;false;getName;();;ReturnValue;remote",
"org.xmlpull.v1;XmlPullParser;false;getNamespace;();;ReturnValue;remote",
"org.xmlpull.v1;XmlPullParser;false;getText;();;ReturnValue;remote",
"org.xmlpull.v1;XmlPullParser;false;getName;();;ReturnValue;remote;manual",
"org.xmlpull.v1;XmlPullParser;false;getNamespace;();;ReturnValue;remote;manual",
"org.xmlpull.v1;XmlPullParser;false;getText;();;ReturnValue;remote;manual",
// XmlAttrSetGetMethod
"android.util;AttributeSet;false;getAttributeBooleanValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeCount;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeFloatValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeIntValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeListValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeName;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeNameResource;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeNamespace;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeResourceValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeUnsignedIntValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getClassAttribute;;;ReturnValue;remote",
"android.util;AttributeSet;false;getIdAttribute;;;ReturnValue;remote",
"android.util;AttributeSet;false;getIdAttributeResourceValue;;;ReturnValue;remote",
"android.util;AttributeSet;false;getPositionDescription;;;ReturnValue;remote",
"android.util;AttributeSet;false;getStyleAttribute;;;ReturnValue;remote",
"android.util;AttributeSet;false;getAttributeBooleanValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeCount;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeFloatValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeIntValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeListValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeName;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeNameResource;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeNamespace;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeResourceValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeUnsignedIntValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getAttributeValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getClassAttribute;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getIdAttribute;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getIdAttributeResourceValue;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getPositionDescription;;;ReturnValue;remote;manual",
"android.util;AttributeSet;false;getStyleAttribute;;;ReturnValue;remote;manual",
// The current URL in a browser may be untrusted or uncontrolled.
// WebViewGetUrlMethod
"android.webkit;WebView;false;getUrl;();;ReturnValue;remote",
"android.webkit;WebView;false;getOriginalUrl;();;ReturnValue;remote",
"android.webkit;WebView;false;getUrl;();;ReturnValue;remote;manual",
"android.webkit;WebView;false;getOriginalUrl;();;ReturnValue;remote;manual",
// SpringRestTemplateResponseEntityMethod
"org.springframework.web.client;RestTemplate;false;exchange;;;ReturnValue;remote",
"org.springframework.web.client;RestTemplate;false;getForEntity;;;ReturnValue;remote",
"org.springframework.web.client;RestTemplate;false;postForEntity;;;ReturnValue;remote",
"org.springframework.web.client;RestTemplate;false;exchange;;;ReturnValue;remote;manual",
"org.springframework.web.client;RestTemplate;false;getForEntity;;;ReturnValue;remote;manual",
"org.springframework.web.client;RestTemplate;false;postForEntity;;;ReturnValue;remote;manual",
// WebSocketMessageParameterSource
"java.net.http;WebSocket$Listener;true;onText;(WebSocket,CharSequence,boolean);;Parameter[1];remote",
"java.net.http;WebSocket$Listener;true;onText;(WebSocket,CharSequence,boolean);;Parameter[1];remote;manual",
// PlayRequestGetMethod
"play.mvc;Http$RequestHeader;false;queryString;;;ReturnValue;remote",
"play.mvc;Http$RequestHeader;false;getQueryString;;;ReturnValue;remote",
"play.mvc;Http$RequestHeader;false;header;;;ReturnValue;remote",
"play.mvc;Http$RequestHeader;false;getHeader;;;ReturnValue;remote"
"play.mvc;Http$RequestHeader;false;queryString;;;ReturnValue;remote;manual",
"play.mvc;Http$RequestHeader;false;getQueryString;;;ReturnValue;remote;manual",
"play.mvc;Http$RequestHeader;false;header;;;ReturnValue;remote;manual",
"play.mvc;Http$RequestHeader;false;getHeader;;;ReturnValue;remote;manual"
]
}
@@ -263,21 +268,21 @@ private predicate sinkModelCsv(string row) {
row =
[
// Open URL
"java.net;URL;false;openConnection;;;Argument[-1];open-url",
"java.net;URL;false;openStream;;;Argument[-1];open-url",
"java.net.http;HttpRequest;false;newBuilder;;;Argument[0];open-url",
"java.net.http;HttpRequest$Builder;false;uri;;;Argument[0];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(URL[]);;Argument[0];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(URL[],ClassLoader);;Argument[0];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(URL[],ClassLoader,URLStreamHandlerFactory);;Argument[0];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader);;Argument[1];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader,URLStreamHandlerFactory);;Argument[1];open-url",
"java.net;URLClassLoader;false;newInstance;;;Argument[0];open-url",
"java.net;URL;false;openConnection;;;Argument[-1];open-url;manual",
"java.net;URL;false;openStream;;;Argument[-1];open-url;manual",
"java.net.http;HttpRequest;false;newBuilder;;;Argument[0];open-url;manual",
"java.net.http;HttpRequest$Builder;false;uri;;;Argument[0];open-url;manual",
"java.net;URLClassLoader;false;URLClassLoader;(URL[]);;Argument[0];open-url;manual",
"java.net;URLClassLoader;false;URLClassLoader;(URL[],ClassLoader);;Argument[0];open-url;manual",
"java.net;URLClassLoader;false;URLClassLoader;(URL[],ClassLoader,URLStreamHandlerFactory);;Argument[0];open-url;manual",
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader);;Argument[1];open-url;manual",
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader,URLStreamHandlerFactory);;Argument[1];open-url;manual",
"java.net;URLClassLoader;false;newInstance;;;Argument[0];open-url;manual",
// Bean validation
"javax.validation;ConstraintValidatorContext;true;buildConstraintViolationWithTemplate;;;Argument[0];bean-validation",
"javax.validation;ConstraintValidatorContext;true;buildConstraintViolationWithTemplate;;;Argument[0];bean-validation;manual",
// Set hostname
"javax.net.ssl;HttpsURLConnection;true;setDefaultHostnameVerifier;;;Argument[0];set-hostname-verifier",
"javax.net.ssl;HttpsURLConnection;true;setHostnameVerifier;;;Argument[0];set-hostname-verifier"
"javax.net.ssl;HttpsURLConnection;true;setDefaultHostnameVerifier;;;Argument[0];set-hostname-verifier;manual",
"javax.net.ssl;HttpsURLConnection;true;setHostnameVerifier;;;Argument[0];set-hostname-verifier;manual"
]
}
@@ -285,87 +290,87 @@ private predicate summaryModelCsv(string row) {
row =
[
// qualifier to arg
"java.io;InputStream;true;read;(byte[]);;Argument[-1];Argument[0];taint",
"java.io;InputStream;true;read;(byte[],int,int);;Argument[-1];Argument[0];taint",
"java.io;InputStream;true;readNBytes;(byte[],int,int);;Argument[-1];Argument[0];taint",
"java.io;InputStream;true;transferTo;(OutputStream);;Argument[-1];Argument[0];taint",
"java.io;ByteArrayOutputStream;false;writeTo;;;Argument[-1];Argument[0];taint",
"java.io;Reader;true;read;;;Argument[-1];Argument[0];taint",
"java.io;InputStream;true;read;(byte[]);;Argument[-1];Argument[0];taint;manual",
"java.io;InputStream;true;read;(byte[],int,int);;Argument[-1];Argument[0];taint;manual",
"java.io;InputStream;true;readNBytes;(byte[],int,int);;Argument[-1];Argument[0];taint;manual",
"java.io;InputStream;true;transferTo;(OutputStream);;Argument[-1];Argument[0];taint;manual",
"java.io;ByteArrayOutputStream;false;writeTo;;;Argument[-1];Argument[0];taint;manual",
"java.io;Reader;true;read;;;Argument[-1];Argument[0];taint;manual",
// qualifier to return
"java.io;ByteArrayOutputStream;false;toByteArray;;;Argument[-1];ReturnValue;taint",
"java.io;ByteArrayOutputStream;false;toString;;;Argument[-1];ReturnValue;taint",
"java.io;InputStream;true;readAllBytes;;;Argument[-1];ReturnValue;taint",
"java.io;InputStream;true;readNBytes;(int);;Argument[-1];ReturnValue;taint",
"java.util;StringTokenizer;false;nextElement;();;Argument[-1];ReturnValue;taint",
"java.util;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
"javax.xml.transform.sax;SAXSource;false;getInputSource;;;Argument[-1];ReturnValue;taint",
"javax.xml.transform.stream;StreamSource;false;getInputStream;;;Argument[-1];ReturnValue;taint",
"java.nio;ByteBuffer;false;get;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toString;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toAsciiString;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;toURI;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;toPath;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;getAbsoluteFile;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;getCanonicalFile;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;getAbsolutePath;;;Argument[-1];ReturnValue;taint",
"java.io;File;true;getCanonicalPath;;;Argument[-1];ReturnValue;taint",
"java.nio;ByteBuffer;false;array;();;Argument[-1];ReturnValue;taint",
"java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint",
"java.io;BufferedReader;true;readLine;;;Argument[-1];ReturnValue;taint",
"java.io;Reader;true;read;();;Argument[-1];ReturnValue;taint",
"java.io;ByteArrayOutputStream;false;toByteArray;;;Argument[-1];ReturnValue;taint;manual",
"java.io;ByteArrayOutputStream;false;toString;;;Argument[-1];ReturnValue;taint;manual",
"java.io;InputStream;true;readAllBytes;;;Argument[-1];ReturnValue;taint;manual",
"java.io;InputStream;true;readNBytes;(int);;Argument[-1];ReturnValue;taint;manual",
"java.util;StringTokenizer;false;nextElement;();;Argument[-1];ReturnValue;taint;manual",
"java.util;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint;manual",
"javax.xml.transform.sax;SAXSource;false;getInputSource;;;Argument[-1];ReturnValue;taint;manual",
"javax.xml.transform.stream;StreamSource;false;getInputStream;;;Argument[-1];ReturnValue;taint;manual",
"java.nio;ByteBuffer;false;get;;;Argument[-1];ReturnValue;taint;manual",
"java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint;manual",
"java.net;URI;false;toString;;;Argument[-1];ReturnValue;taint;manual",
"java.net;URI;false;toAsciiString;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;toURI;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;toPath;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;getAbsoluteFile;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;getCanonicalFile;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;getAbsolutePath;;;Argument[-1];ReturnValue;taint;manual",
"java.io;File;true;getCanonicalPath;;;Argument[-1];ReturnValue;taint;manual",
"java.nio;ByteBuffer;false;array;();;Argument[-1];ReturnValue;taint;manual",
"java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint;manual",
"java.io;BufferedReader;true;readLine;;;Argument[-1];ReturnValue;taint;manual",
"java.io;Reader;true;read;();;Argument[-1];ReturnValue;taint;manual",
// arg to return
"java.nio;ByteBuffer;false;wrap;(byte[]);;Argument[0];ReturnValue;taint",
"java.util;Base64$Encoder;false;encode;(byte[]);;Argument[0];ReturnValue;taint",
"java.util;Base64$Encoder;false;encode;(ByteBuffer);;Argument[0];ReturnValue;taint",
"java.util;Base64$Encoder;false;encodeToString;(byte[]);;Argument[0];ReturnValue;taint",
"java.util;Base64$Encoder;false;wrap;(OutputStream);;Argument[0];ReturnValue;taint",
"java.util;Base64$Decoder;false;decode;(byte[]);;Argument[0];ReturnValue;taint",
"java.util;Base64$Decoder;false;decode;(ByteBuffer);;Argument[0];ReturnValue;taint",
"java.util;Base64$Decoder;false;decode;(String);;Argument[0];ReturnValue;taint",
"java.util;Base64$Decoder;false;wrap;(InputStream);;Argument[0];ReturnValue;taint",
"cn.hutool.core.codec;Base64;true;decode;;;Argument[0];ReturnValue;taint",
"org.apache.shiro.codec;Base64;false;decode;(String);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;Encoder;true;encode;(Object);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;Decoder;true;decode;(Object);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;BinaryEncoder;true;encode;(byte[]);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;BinaryDecoder;true;decode;(byte[]);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;StringEncoder;true;encode;(String);;Argument[0];ReturnValue;taint",
"org.apache.commons.codec;StringDecoder;true;decode;(String);;Argument[0];ReturnValue;taint",
"java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint",
"java.net;URI;false;create;;;Argument[0];ReturnValue;taint",
"javax.xml.transform.sax;SAXSource;false;sourceToInputSource;;;Argument[0];ReturnValue;taint",
"java.nio;ByteBuffer;false;wrap;(byte[]);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Encoder;false;encode;(byte[]);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Encoder;false;encode;(ByteBuffer);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Encoder;false;encodeToString;(byte[]);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Encoder;false;wrap;(OutputStream);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Decoder;false;decode;(byte[]);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Decoder;false;decode;(ByteBuffer);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Decoder;false;decode;(String);;Argument[0];ReturnValue;taint;manual",
"java.util;Base64$Decoder;false;wrap;(InputStream);;Argument[0];ReturnValue;taint;manual",
"cn.hutool.core.codec;Base64;true;decode;;;Argument[0];ReturnValue;taint;manual",
"org.apache.shiro.codec;Base64;false;decode;(String);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;Encoder;true;encode;(Object);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;Decoder;true;decode;(Object);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;BinaryEncoder;true;encode;(byte[]);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;BinaryDecoder;true;decode;(byte[]);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;StringEncoder;true;encode;(String);;Argument[0];ReturnValue;taint;manual",
"org.apache.commons.codec;StringDecoder;true;decode;(String);;Argument[0];ReturnValue;taint;manual",
"java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint;manual",
"java.net;URI;false;create;;;Argument[0];ReturnValue;taint;manual",
"javax.xml.transform.sax;SAXSource;false;sourceToInputSource;;;Argument[0];ReturnValue;taint;manual",
// arg to arg
"java.lang;System;false;arraycopy;;;Argument[0];Argument[2];taint",
"java.lang;System;false;arraycopy;;;Argument[0];Argument[2];taint;manual",
// constructor flow
"java.io;File;false;File;;;Argument[0];Argument[-1];taint",
"java.io;File;false;File;;;Argument[1];Argument[-1];taint",
"java.net;URI;false;URI;(String);;Argument[0];Argument[-1];taint",
"java.net;URL;false;URL;(String);;Argument[0];Argument[-1];taint",
"javax.xml.transform.stream;StreamSource;false;StreamSource;;;Argument[0];Argument[-1];taint",
"javax.xml.transform.sax;SAXSource;false;SAXSource;(InputSource);;Argument[0];Argument[-1];taint",
"javax.xml.transform.sax;SAXSource;false;SAXSource;(XMLReader,InputSource);;Argument[1];Argument[-1];taint",
"org.xml.sax;InputSource;false;InputSource;;;Argument[0];Argument[-1];taint",
"javax.servlet.http;Cookie;false;Cookie;;;Argument[0];Argument[-1];taint",
"javax.servlet.http;Cookie;false;Cookie;;;Argument[1];Argument[-1];taint",
"java.util.zip;ZipInputStream;false;ZipInputStream;;;Argument[0];Argument[-1];taint",
"java.util.zip;GZIPInputStream;false;GZIPInputStream;;;Argument[0];Argument[-1];taint",
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",
"java.io;ObjectInputStream;false;ObjectInputStream;;;Argument[0];Argument[-1];taint",
"java.io;StringReader;false;StringReader;;;Argument[0];Argument[-1];taint",
"java.io;CharArrayReader;false;CharArrayReader;;;Argument[0];Argument[-1];taint",
"java.io;BufferedReader;false;BufferedReader;;;Argument[0];Argument[-1];taint",
"java.io;InputStreamReader;false;InputStreamReader;;;Argument[0];Argument[-1];taint",
"java.io;OutputStream;true;write;(byte[]);;Argument[0];Argument[-1];taint",
"java.io;OutputStream;true;write;(byte[],int,int);;Argument[0];Argument[-1];taint",
"java.io;OutputStream;true;write;(int);;Argument[0];Argument[-1];taint",
"java.io;FilterOutputStream;true;FilterOutputStream;(OutputStream);;Argument[0];Argument[-1];taint"
"java.io;File;false;File;;;Argument[0];Argument[-1];taint;manual",
"java.io;File;false;File;;;Argument[1];Argument[-1];taint;manual",
"java.net;URI;false;URI;(String);;Argument[0];Argument[-1];taint;manual",
"java.net;URL;false;URL;(String);;Argument[0];Argument[-1];taint;manual",
"javax.xml.transform.stream;StreamSource;false;StreamSource;;;Argument[0];Argument[-1];taint;manual",
"javax.xml.transform.sax;SAXSource;false;SAXSource;(InputSource);;Argument[0];Argument[-1];taint;manual",
"javax.xml.transform.sax;SAXSource;false;SAXSource;(XMLReader,InputSource);;Argument[1];Argument[-1];taint;manual",
"org.xml.sax;InputSource;false;InputSource;;;Argument[0];Argument[-1];taint;manual",
"javax.servlet.http;Cookie;false;Cookie;;;Argument[0];Argument[-1];taint;manual",
"javax.servlet.http;Cookie;false;Cookie;;;Argument[1];Argument[-1];taint;manual",
"java.util.zip;ZipInputStream;false;ZipInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.util.zip;GZIPInputStream;false;GZIPInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint;manual",
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint;manual",
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint;manual",
"com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint;manual",
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.io;ObjectInputStream;false;ObjectInputStream;;;Argument[0];Argument[-1];taint;manual",
"java.io;StringReader;false;StringReader;;;Argument[0];Argument[-1];taint;manual",
"java.io;CharArrayReader;false;CharArrayReader;;;Argument[0];Argument[-1];taint;manual",
"java.io;BufferedReader;false;BufferedReader;;;Argument[0];Argument[-1];taint;manual",
"java.io;InputStreamReader;false;InputStreamReader;;;Argument[0];Argument[-1];taint;manual",
"java.io;OutputStream;true;write;(byte[]);;Argument[0];Argument[-1];taint;manual",
"java.io;OutputStream;true;write;(byte[],int,int);;Argument[0];Argument[-1];taint;manual",
"java.io;OutputStream;true;write;(int);;Argument[0];Argument[-1];taint;manual",
"java.io;FilterOutputStream;true;FilterOutputStream;(OutputStream);;Argument[0];Argument[-1];taint;manual"
]
}
@@ -414,17 +419,10 @@ private predicate summaryModel(string row) {
any(SummaryModelCsv s).row(row)
}
bindingset[input]
private predicate getKind(string input, string kind, boolean generated) {
input.splitAt(":", 0) = "generated" and kind = input.splitAt(":", 1) and generated = true
or
not input.matches("%:%") and kind = input and generated = false
}
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, boolean generated
string output, string kind, string provenance
) {
exists(string row |
sourceModel(row) and
@@ -436,14 +434,15 @@ predicate sourceModel(
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = output and
exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
row.splitAt(";", 7) = kind and
row.splitAt(";", 8) = provenance
)
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, boolean generated
string input, string kind, string provenance
) {
exists(string row |
sinkModel(row) and
@@ -455,22 +454,23 @@ predicate sinkModel(
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
row.splitAt(";", 7) = kind and
row.splitAt(";", 8) = provenance
)
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, boolean generated
string input, string output, string kind, string provenance
) {
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated, _)
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
}
/** Holds if a summary model `row` exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, boolean generated, string row
string input, string output, string kind, string provenance, string row
) {
summaryModel(row) and
row.splitAt(";", 0) = namespace and
@@ -482,7 +482,8 @@ predicate summaryModel(
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = output and
exists(string k | row.splitAt(";", 8) = k and getKind(k, kind, generated))
row.splitAt(";", 8) = kind and
row.splitAt(";", 9) = provenance
}
private predicate relevantPackage(string package) {
@@ -516,25 +517,25 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
part = "source" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string output, boolean generated |
string ext, string output, string provenance |
canonicalPkgLink(package, subpkg) and
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, generated)
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance)
)
or
part = "sink" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, boolean generated |
string ext, string input, string provenance |
canonicalPkgLink(package, subpkg) and
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, generated)
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance)
)
or
part = "summary" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, string output, boolean generated |
string ext, string input, string output, string provenance |
canonicalPkgLink(package, subpkg) and
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, generated)
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance)
)
)
}
@@ -543,12 +544,16 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
module CsvValidation {
/** Holds if some row in a CSV-based flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
exists(string pred, string namespace, string type, string name, string signature, string ext |
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
exists(
string pred, string namespace, string type, string name, string signature, string ext,
string provenance
|
sourceModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "source"
or
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
sinkModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
pred = "summary"
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
@@ -564,6 +569,9 @@ module CsvValidation {
or
not ext.regexpMatch("|Annotated") and
msg = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
or
not provenance = ["manual", "generated"] and
msg = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
)
or
exists(string pred, string input, string part |
@@ -595,18 +603,18 @@ module CsvValidation {
)
or
exists(string pred, string row, int expect |
sourceModel(row) and expect = 8 and pred = "source"
sourceModel(row) and expect = 9 and pred = "source"
or
sinkModel(row) and expect = 8 and pred = "sink"
sinkModel(row) and expect = 9 and pred = "sink"
or
summaryModel(row) and expect = 9 and pred = "summary"
summaryModel(row) and expect = 10 and pred = "summary"
|
exists(int cols |
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
cols != expect and
msg =
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
"."
" in " + row + "."
)
or
exists(string b |
@@ -616,12 +624,32 @@ module CsvValidation {
)
)
or
exists(string row, string k, string kind | summaryModel(row) |
k = row.splitAt(";", 8) and
getKind(k, kind, _) and
exists(string row, string kind | summaryModel(row) |
kind = row.splitAt(";", 8) and
not kind = ["taint", "value"] and
msg = "Invalid kind \"" + kind + "\" in summary model."
)
or
exists(string row, string kind | sinkModel(row) |
kind = row.splitAt(";", 7) and
not kind =
[
"open-url", "jndi-injection", "ldap", "sql", "jdbc-url", "logging", "mvel", "xpath",
"groovy", "xss", "ognl-injection", "intent-start", "pending-intent-sent",
"url-open-stream", "url-redirect", "create-file", "write-file", "set-hostname-verifier",
"header-splitting", "information-leak", "xslt", "jexl", "bean-validation"
] and
not kind.matches("regex-use%") and
not kind.matches("qltest%") and
msg = "Invalid kind \"" + kind + "\" in sink model."
)
or
exists(string row, string kind | sourceModel(row) |
kind = row.splitAt(";", 7) and
not kind = ["remote", "contentprovider", "android-widget"] and
not kind.matches("qltest%") and
msg = "Invalid kind \"" + kind + "\" in source model."
)
}
}

View File

@@ -1,5 +1,5 @@
/**
* Provides classes and predicates for definining flow summaries.
* Provides classes and predicates for defining flow summaries.
*/
import java

View File

@@ -242,8 +242,9 @@ Guard nullGuard(SsaVariable v, boolean branch, boolean isnull) {
}
/**
* A return statement that on a return value of `retval` allows the conclusion that the
* parameter `p` either is null or non-null as specified by `isnull`.
* A return statement in a non-overridable method that on a return value of
* `retval` allows the conclusion that the parameter `p` either is null or
* non-null as specified by `isnull`.
*/
private predicate validReturnInCustomNullGuard(
ReturnStmt ret, Parameter p, boolean retval, boolean isnull
@@ -251,7 +252,10 @@ private predicate validReturnInCustomNullGuard(
exists(Method m |
ret.getEnclosingCallable() = m and
p.getCallable() = m and
m.getReturnType().(PrimitiveType).hasName("boolean")
m.getReturnType().(PrimitiveType).hasName("boolean") and
not p.isVarargs() and
p.getType() instanceof RefType and
not m.isOverridable()
) and
exists(SsaImplicitInit ssa | ssa.isParameterDefinition(p) |
nullGuardedReturn(ret, ssa, isnull) and
@@ -267,6 +271,11 @@ private predicate nullGuardedReturn(ReturnStmt ret, SsaImplicitInit ssa, boolean
)
}
pragma[nomagic]
private Method returnStmtGetEnclosingCallable(ReturnStmt ret) {
ret.getEnclosingCallable() = result
}
/**
* Gets a non-overridable method with a boolean return value that performs a null-check
* on the `index`th parameter. A return value equal to `retval` allows us to conclude
@@ -274,14 +283,10 @@ private predicate nullGuardedReturn(ReturnStmt ret, SsaImplicitInit ssa, boolean
*/
private Method customNullGuard(int index, boolean retval, boolean isnull) {
exists(Parameter p |
result.getReturnType().(PrimitiveType).hasName("boolean") and
not result.isOverridable() and
p.getCallable() = result and
not p.isVarargs() and
p.getType() instanceof RefType and
p.getPosition() = index and
forex(ReturnStmt ret |
ret.getEnclosingCallable() = result and
returnStmtGetEnclosingCallable(ret) = result and
exists(Expr res | res = ret.getResult() |
not res.(BooleanLiteral).getBooleanValue() = retval.booleanNot()
)

View File

@@ -337,15 +337,15 @@ private predicate safeCast(Type fromtyp, Type totyp) {
exists(PrimitiveType pfrom, PrimitiveType pto | pfrom = fromtyp and pto = totyp |
pfrom = pto
or
pfrom.hasName("char") and pto.getName().regexpMatch("int|long|float|double")
pfrom.hasName("char") and pto.hasName(["int", "long", "float", "double"])
or
pfrom.hasName("byte") and pto.getName().regexpMatch("short|int|long|float|double")
pfrom.hasName("byte") and pto.hasName(["short", "int", "long", "float", "double"])
or
pfrom.hasName("short") and pto.getName().regexpMatch("int|long|float|double")
pfrom.hasName("short") and pto.hasName(["int", "long", "float", "double"])
or
pfrom.hasName("int") and pto.getName().regexpMatch("long|float|double")
pfrom.hasName("int") and pto.hasName(["long", "float", "double"])
or
pfrom.hasName("long") and pto.getName().regexpMatch("float|double")
pfrom.hasName("long") and pto.hasName(["float", "double"])
or
pfrom.hasName("float") and pto.hasName("double")
or

View File

@@ -95,324 +95,324 @@ private class ContainerFlowSummaries extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"java.lang;Object;true;clone;;;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.lang;Object;true;clone;;;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.lang;Object;true;clone;;;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Map$Entry;true;getKey;;;Argument[-1].MapKey;ReturnValue;value",
"java.util;Map$Entry;true;getValue;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map$Entry;true;setValue;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map$Entry;true;setValue;;;Argument[0];Argument[-1].MapValue;value",
"java.lang;Iterable;true;iterator;();;Argument[-1].Element;ReturnValue.Element;value",
"java.lang;Iterable;true;spliterator;();;Argument[-1].Element;ReturnValue.Element;value",
"java.lang;Iterable;true;forEach;(Consumer);;Argument[-1].Element;Argument[0].Parameter[0];value",
"java.util;Iterator;true;next;;;Argument[-1].Element;ReturnValue;value",
"java.util;Iterator;true;forEachRemaining;(Consumer);;Argument[-1].Element;Argument[0].Parameter[0];value",
"java.util;ListIterator;true;previous;;;Argument[-1].Element;ReturnValue;value",
"java.util;ListIterator;true;add;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;ListIterator;true;set;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Enumeration;true;asIterator;;;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Enumeration;true;nextElement;;;Argument[-1].Element;ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;Argument[1].ReturnValue;ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;Argument[1].ReturnValue;Argument[-1].MapValue;value",
"java.util;Map;true;entrySet;;;Argument[-1].MapValue;ReturnValue.Element.MapValue;value",
"java.util;Map;true;entrySet;;;Argument[-1].MapKey;ReturnValue.Element.MapKey;value",
"java.util;Map;true;get;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;getOrDefault;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;getOrDefault;;;Argument[1];ReturnValue;value",
"java.util;Map;true;put;(Object,Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;put;(Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;Map;true;put;(Object,Object);;Argument[1];Argument[-1].MapValue;value",
"java.util;Map;true;putIfAbsent;;;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;putIfAbsent;;;Argument[0];Argument[-1].MapKey;value",
"java.util;Map;true;putIfAbsent;;;Argument[1];Argument[-1].MapValue;value",
"java.util;Map;true;remove;(Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;replace;(Object,Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;Map;true;replace;(Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;Map;true;replace;(Object,Object);;Argument[1];Argument[-1].MapValue;value",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[2];Argument[-1].MapValue;value",
"java.util;Map;true;keySet;();;Argument[-1].MapKey;ReturnValue.Element;value",
"java.util;Map;true;values;();;Argument[-1].MapValue;ReturnValue.Element;value",
"java.util;Map;true;merge;(Object,Object,BiFunction);;Argument[1];Argument[-1].MapValue;value",
"java.util;Map;true;putAll;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;Map;true;putAll;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;Map;true;forEach;(BiConsumer);;Argument[-1].MapKey;Argument[0].Parameter[0];value",
"java.util;Map;true;forEach;(BiConsumer);;Argument[-1].MapValue;Argument[0].Parameter[1];value",
"java.util;Collection;true;parallelStream;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Collection;true;stream;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Collection;true;toArray;;;Argument[-1].Element;ReturnValue.ArrayElement;value",
"java.util;Collection;true;toArray;;;Argument[-1].Element;Argument[0].ArrayElement;value",
"java.util;Collection;true;add;;;Argument[0];Argument[-1].Element;value",
"java.util;Collection;true;addAll;;;Argument[0].Element;Argument[-1].Element;value",
"java.util;List;true;get;(int);;Argument[-1].Element;ReturnValue;value",
"java.util;List;true;listIterator;;;Argument[-1].Element;ReturnValue.Element;value",
"java.util;List;true;remove;(int);;Argument[-1].Element;ReturnValue;value",
"java.util;List;true;set;(int,Object);;Argument[-1].Element;ReturnValue;value",
"java.util;List;true;set;(int,Object);;Argument[1];Argument[-1].Element;value",
"java.util;List;true;subList;;;Argument[-1].Element;ReturnValue.Element;value",
"java.util;List;true;add;(int,Object);;Argument[1];Argument[-1].Element;value",
"java.util;List;true;addAll;(int,Collection);;Argument[1].Element;Argument[-1].Element;value",
"java.util;Vector;true;elementAt;(int);;Argument[-1].Element;ReturnValue;value",
"java.util;Vector;true;elements;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Vector;true;firstElement;();;Argument[-1].Element;ReturnValue;value",
"java.util;Vector;true;lastElement;();;Argument[-1].Element;ReturnValue;value",
"java.util;Vector;true;addElement;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Vector;true;insertElementAt;(Object,int);;Argument[0];Argument[-1].Element;value",
"java.util;Vector;true;setElementAt;(Object,int);;Argument[0];Argument[-1].Element;value",
"java.util;Vector;true;copyInto;(Object[]);;Argument[-1].Element;Argument[0].ArrayElement;value",
"java.util;Stack;true;peek;();;Argument[-1].Element;ReturnValue;value",
"java.util;Stack;true;pop;();;Argument[-1].Element;ReturnValue;value",
"java.util;Stack;true;push;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Queue;true;element;();;Argument[-1].Element;ReturnValue;value",
"java.util;Queue;true;peek;();;Argument[-1].Element;ReturnValue;value",
"java.util;Queue;true;poll;();;Argument[-1].Element;ReturnValue;value",
"java.util;Queue;true;remove;();;Argument[-1].Element;ReturnValue;value",
"java.util;Queue;true;offer;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Deque;true;descendingIterator;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Deque;true;getFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;getLast;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;peekFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;peekLast;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;pollFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;pollLast;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;pop;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;removeFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;removeLast;();;Argument[-1].Element;ReturnValue;value",
"java.util;Deque;true;push;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Deque;true;offerLast;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Deque;true;offerFirst;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Deque;true;addLast;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;Deque;true;addFirst;(Object);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingDeque;true;pollFirst;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;pollLast;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;takeFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;takeLast;();;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;poll;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;take;();;Argument[-1].Element;ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;offer;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingQueue;true;put;(Object);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingDeque;true;offerLast;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingDeque;true;offerFirst;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingDeque;true;putLast;(Object);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingDeque;true;putFirst;(Object);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection,int);;Argument[-1].Element;Argument[0].Element;value",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection);;Argument[-1].Element;Argument[0].Element;value",
"java.util.concurrent;ConcurrentHashMap;true;elements;();;Argument[-1].MapValue;ReturnValue.Element;value",
"java.util;Dictionary;true;elements;();;Argument[-1].MapValue;ReturnValue.Element;value",
"java.util;Dictionary;true;get;(Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;Dictionary;true;keys;();;Argument[-1].MapKey;ReturnValue.Element;value",
"java.util;Dictionary;true;put;(Object,Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;Dictionary;true;put;(Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;Dictionary;true;put;(Object,Object);;Argument[1];Argument[-1].MapValue;value",
"java.util;Dictionary;true;remove;(Object);;Argument[-1].MapValue;ReturnValue;value",
"java.util;NavigableMap;true;ceilingEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;ceilingEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;descendingMap;();;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;descendingMap;();;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;firstEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;firstEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;floorEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;floorEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;headMap;(Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;headMap;(Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;higherEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;higherEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;lastEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;lastEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;lowerEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;lowerEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;pollFirstEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;pollFirstEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;pollLastEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;pollLastEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;NavigableSet;true;ceiling;(Object);;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;descendingIterator;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;NavigableSet;true;descendingSet;();;Argument[-1].Element;ReturnValue.Element;value",
"java.util;NavigableSet;true;floor;(Object);;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;headSet;(Object,boolean);;Argument[-1].Element;ReturnValue.Element;value",
"java.util;NavigableSet;true;higher;(Object);;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;lower;(Object);;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;pollFirst;();;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;pollLast;();;Argument[-1].Element;ReturnValue;value",
"java.util;NavigableSet;true;subSet;(Object,boolean,Object,boolean);;Argument[-1].Element;ReturnValue.Element;value",
"java.util;NavigableSet;true;tailSet;(Object,boolean);;Argument[-1].Element;ReturnValue.Element;value",
"java.util;Scanner;true;next;(Pattern);;Argument[-1];ReturnValue;taint",
"java.util;Scanner;true;next;(String);;Argument[-1];ReturnValue;taint",
"java.util;SortedMap;true;headMap;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;SortedMap;true;headMap;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;SortedMap;true;subMap;(Object,Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;SortedMap;true;subMap;(Object,Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;SortedMap;true;tailMap;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value",
"java.util;SortedMap;true;tailMap;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value",
"java.util;SortedSet;true;first;();;Argument[-1].Element;ReturnValue;value",
"java.util;SortedSet;true;headSet;(Object);;Argument[-1].Element;ReturnValue.Element;value",
"java.util;SortedSet;true;last;();;Argument[-1].Element;ReturnValue;value",
"java.util;SortedSet;true;subSet;(Object,Object);;Argument[-1].Element;ReturnValue.Element;value",
"java.util;SortedSet;true;tailSet;(Object);;Argument[-1].Element;ReturnValue.Element;value",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;TransferQueue;true;transfer;(Object);;Argument[0];Argument[-1].Element;value",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object);;Argument[0];Argument[-1].Element;value",
"java.util;List;false;copyOf;(Collection);;Argument[0].Element;ReturnValue.Element;value",
"java.util;List;false;of;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value",
"java.util;List;false;of;(Object);;Argument[0];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object);;Argument[0..1];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object);;Argument[0..2];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object);;Argument[0..3];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];ReturnValue.Element;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];ReturnValue.Element;value",
"java.util;Map;false;copyOf;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Map;false;copyOf;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Map;false;entry;(Object,Object);;Argument[0];ReturnValue.MapKey;value",
"java.util;Map;false;entry;(Object,Object);;Argument[1];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[0];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[1];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[2];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[3];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[4];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[5];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[6];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[7];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[8];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[9];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[10];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[11];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[12];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[13];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[14];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[15];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[16];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[17];ReturnValue.MapValue;value",
"java.util;Map;false;of;;;Argument[18];ReturnValue.MapKey;value",
"java.util;Map;false;of;;;Argument[19];ReturnValue.MapValue;value",
"java.util;Map;false;ofEntries;;;Argument[0].ArrayElement.MapKey;ReturnValue.MapKey;value",
"java.util;Map;false;ofEntries;;;Argument[0].ArrayElement.MapValue;ReturnValue.MapValue;value",
"java.util;Set;false;copyOf;(Collection);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Set;false;of;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value",
"java.util;Set;false;of;(Object);;Argument[0];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object);;Argument[0..1];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object);;Argument[0..2];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object);;Argument[0..3];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];ReturnValue.Element;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];ReturnValue.Element;value",
"java.util;Arrays;false;stream;;;Argument[0].ArrayElement;ReturnValue.Element;value",
"java.util;Arrays;false;spliterator;;;Argument[0].ArrayElement;ReturnValue.Element;value",
"java.util;Arrays;false;copyOfRange;;;Argument[0].ArrayElement;ReturnValue.ArrayElement;value",
"java.util;Arrays;false;copyOf;;;Argument[0].ArrayElement;ReturnValue.ArrayElement;value",
"java.util;Collections;false;list;(Enumeration);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;enumeration;(Collection);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;nCopies;(int,Object);;Argument[1];ReturnValue.Element;value",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[0];ReturnValue.MapKey;value",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[1];ReturnValue.MapValue;value",
"java.util;Collections;false;singletonList;(Object);;Argument[0];ReturnValue.Element;value",
"java.util;Collections;false;singleton;(Object);;Argument[0];ReturnValue.Element;value",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;checkedList;(List,Class);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;checkedNavigableSet;(NavigableSet,Class);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;checkedSortedSet;(SortedSet,Class);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;checkedSet;(Set,Class);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;checkedCollection;(Collection,Class);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;synchronizedMap;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;synchronizedMap;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;synchronizedList;(List);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;synchronizedNavigableSet;(NavigableSet);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;synchronizedSortedSet;(SortedSet);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;synchronizedSet;(Set);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;synchronizedCollection;(Collection);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;unmodifiableMap;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value",
"java.util;Collections;false;unmodifiableMap;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value",
"java.util;Collections;false;unmodifiableList;(List);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;unmodifiableNavigableSet;(NavigableSet);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;unmodifiableSortedSet;(SortedSet);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;unmodifiableSet;(Set);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;unmodifiableCollection;(Collection);;Argument[0].Element;ReturnValue.Element;value",
"java.util;Collections;false;max;;;Argument[0].Element;ReturnValue;value",
"java.util;Collections;false;min;;;Argument[0].Element;ReturnValue;value",
"java.util;Arrays;false;fill;(Object[],int,int,Object);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(Object[],Object);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(float[],int,int,float);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(float[],float);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(double[],int,int,double);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(double[],double);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(boolean[],int,int,boolean);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(boolean[],boolean);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(byte[],int,int,byte);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(byte[],byte);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(char[],int,int,char);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(char[],char);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(short[],int,int,short);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(short[],short);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(int[],int,int,int);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(int[],int);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(long[],int,int,long);;Argument[3];Argument[0].ArrayElement;value",
"java.util;Arrays;false;fill;(long[],long);;Argument[1];Argument[0].ArrayElement;value",
"java.util;Collections;false;replaceAll;(List,Object,Object);;Argument[2];Argument[0].Element;value",
"java.util;Collections;false;copy;(List,List);;Argument[1].Element;Argument[0].Element;value",
"java.util;Collections;false;fill;(List,Object);;Argument[1];Argument[0].Element;value",
"java.util;Arrays;false;asList;;;Argument[0].ArrayElement;ReturnValue.Element;value",
"java.util;Collections;false;addAll;(Collection,Object[]);;Argument[1].ArrayElement;Argument[0].Element;value",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Object,Object);;Argument[1];Argument[-1].MapValue;value",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Entry);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Entry);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Object,Object);;Argument[0];Argument[-1].MapKey;value",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Object,Object);;Argument[1];Argument[-1].MapValue;value",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Entry);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Entry);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;ArrayDeque;false;ArrayDeque;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;ArrayList;false;ArrayList;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;EnumMap;false;EnumMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;EnumMap;false;EnumMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;EnumMap;false;EnumMap;(EnumMap);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;EnumMap;false;EnumMap;(EnumMap);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;HashMap;false;HashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;HashMap;false;HashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;HashSet;false;HashSet;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;Hashtable;false;Hashtable;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;Hashtable;false;Hashtable;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;IdentityHashMap;false;IdentityHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;IdentityHashMap;false;IdentityHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;LinkedHashMap;false;LinkedHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;LinkedHashMap;false;LinkedHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;LinkedHashSet;false;LinkedHashSet;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;LinkedList;false;LinkedList;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;PriorityQueue;false;PriorityQueue;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;PriorityQueue;false;PriorityQueue;(PriorityQueue);;Argument[0].Element;Argument[-1].Element;value",
"java.util;PriorityQueue;false;PriorityQueue;(SortedSet);;Argument[0].Element;Argument[-1].Element;value",
"java.util;TreeMap;false;TreeMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;TreeMap;false;TreeMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;TreeMap;false;TreeMap;(SortedMap);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;TreeMap;false;TreeMap;(SortedMap);;Argument[0].MapValue;Argument[-1].MapValue;value",
"java.util;TreeSet;false;TreeSet;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;TreeSet;false;TreeSet;(SortedSet);;Argument[0].Element;Argument[-1].Element;value",
"java.util;Vector;false;Vector;(Collection);;Argument[0].Element;Argument[-1].Element;value",
"java.util;WeakHashMap;false;WeakHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value",
"java.util;WeakHashMap;false;WeakHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value"
"java.lang;Object;true;clone;;;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.lang;Object;true;clone;;;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.lang;Object;true;clone;;;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Map$Entry;true;getKey;;;Argument[-1].MapKey;ReturnValue;value;manual",
"java.util;Map$Entry;true;getValue;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map$Entry;true;setValue;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map$Entry;true;setValue;;;Argument[0];Argument[-1].MapValue;value;manual",
"java.lang;Iterable;true;iterator;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.lang;Iterable;true;spliterator;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.lang;Iterable;true;forEach;(Consumer);;Argument[-1].Element;Argument[0].Parameter[0];value;manual",
"java.util;Iterator;true;next;;;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Iterator;true;forEachRemaining;(Consumer);;Argument[-1].Element;Argument[0].Parameter[0];value;manual",
"java.util;ListIterator;true;previous;;;Argument[-1].Element;ReturnValue;value;manual",
"java.util;ListIterator;true;add;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;ListIterator;true;set;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Enumeration;true;asIterator;;;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Enumeration;true;nextElement;;;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Map;true;computeIfAbsent;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;computeIfAbsent;;;Argument[1].ReturnValue;ReturnValue;value;manual",
"java.util;Map;true;computeIfAbsent;;;Argument[1].ReturnValue;Argument[-1].MapValue;value;manual",
"java.util;Map;true;entrySet;;;Argument[-1].MapValue;ReturnValue.Element.MapValue;value;manual",
"java.util;Map;true;entrySet;;;Argument[-1].MapKey;ReturnValue.Element.MapKey;value;manual",
"java.util;Map;true;get;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;getOrDefault;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;getOrDefault;;;Argument[1];ReturnValue;value;manual",
"java.util;Map;true;put;(Object,Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;put;(Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;Map;true;put;(Object,Object);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;Map;true;putIfAbsent;;;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;putIfAbsent;;;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;Map;true;putIfAbsent;;;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;Map;true;remove;(Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;replace;(Object,Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Map;true;replace;(Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;Map;true;replace;(Object,Object);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[2];Argument[-1].MapValue;value;manual",
"java.util;Map;true;keySet;();;Argument[-1].MapKey;ReturnValue.Element;value;manual",
"java.util;Map;true;values;();;Argument[-1].MapValue;ReturnValue.Element;value;manual",
"java.util;Map;true;merge;(Object,Object,BiFunction);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;Map;true;putAll;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;Map;true;putAll;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;Map;true;forEach;(BiConsumer);;Argument[-1].MapKey;Argument[0].Parameter[0];value;manual",
"java.util;Map;true;forEach;(BiConsumer);;Argument[-1].MapValue;Argument[0].Parameter[1];value;manual",
"java.util;Collection;true;parallelStream;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Collection;true;stream;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Collection;true;toArray;;;Argument[-1].Element;ReturnValue.ArrayElement;value;manual",
"java.util;Collection;true;toArray;;;Argument[-1].Element;Argument[0].ArrayElement;value;manual",
"java.util;Collection;true;add;;;Argument[0];Argument[-1].Element;value;manual",
"java.util;Collection;true;addAll;;;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;List;true;get;(int);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;List;true;listIterator;;;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;List;true;remove;(int);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;List;true;set;(int,Object);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;List;true;set;(int,Object);;Argument[1];Argument[-1].Element;value;manual",
"java.util;List;true;subList;;;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;List;true;add;(int,Object);;Argument[1];Argument[-1].Element;value;manual",
"java.util;List;true;addAll;(int,Collection);;Argument[1].Element;Argument[-1].Element;value;manual",
"java.util;Vector;true;elementAt;(int);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Vector;true;elements;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Vector;true;firstElement;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Vector;true;lastElement;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Vector;true;addElement;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Vector;true;insertElementAt;(Object,int);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Vector;true;setElementAt;(Object,int);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Vector;true;copyInto;(Object[]);;Argument[-1].Element;Argument[0].ArrayElement;value;manual",
"java.util;Stack;true;peek;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Stack;true;pop;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Stack;true;push;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Queue;true;element;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Queue;true;peek;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Queue;true;poll;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Queue;true;remove;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Queue;true;offer;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Deque;true;descendingIterator;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Deque;true;getFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;getLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;peekFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;peekLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;pollFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;pollLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;pop;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;removeFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;removeLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;Deque;true;push;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Deque;true;offerLast;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Deque;true;offerFirst;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Deque;true;addLast;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;Deque;true;addFirst;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingDeque;true;pollFirst;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingDeque;true;pollLast;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingDeque;true;takeFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingDeque;true;takeLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingQueue;true;poll;(long,TimeUnit);;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingQueue;true;take;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util.concurrent;BlockingQueue;true;offer;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingQueue;true;put;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingDeque;true;offerLast;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingDeque;true;offerFirst;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingDeque;true;putLast;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingDeque;true;putFirst;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection,int);;Argument[-1].Element;Argument[0].Element;value;manual",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection);;Argument[-1].Element;Argument[0].Element;value;manual",
"java.util.concurrent;ConcurrentHashMap;true;elements;();;Argument[-1].MapValue;ReturnValue.Element;value;manual",
"java.util;Dictionary;true;elements;();;Argument[-1].MapValue;ReturnValue.Element;value;manual",
"java.util;Dictionary;true;get;(Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Dictionary;true;keys;();;Argument[-1].MapKey;ReturnValue.Element;value;manual",
"java.util;Dictionary;true;put;(Object,Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;Dictionary;true;put;(Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;Dictionary;true;put;(Object,Object);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;Dictionary;true;remove;(Object);;Argument[-1].MapValue;ReturnValue;value;manual",
"java.util;NavigableMap;true;ceilingEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;ceilingEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;descendingMap;();;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;descendingMap;();;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;firstEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;firstEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;floorEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;floorEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;headMap;(Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;headMap;(Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;higherEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;higherEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;lastEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;lastEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;lowerEntry;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;lowerEntry;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;pollFirstEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;pollFirstEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;pollLastEntry;();;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;pollLastEntry;();;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;NavigableSet;true;ceiling;(Object);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;descendingIterator;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;NavigableSet;true;descendingSet;();;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;NavigableSet;true;floor;(Object);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;headSet;(Object,boolean);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;NavigableSet;true;higher;(Object);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;lower;(Object);;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;pollFirst;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;pollLast;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;NavigableSet;true;subSet;(Object,boolean,Object,boolean);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;NavigableSet;true;tailSet;(Object,boolean);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;Scanner;true;next;(Pattern);;Argument[-1];ReturnValue;taint;manual",
"java.util;Scanner;true;next;(String);;Argument[-1];ReturnValue;taint;manual",
"java.util;SortedMap;true;headMap;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;SortedMap;true;headMap;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;SortedMap;true;subMap;(Object,Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;SortedMap;true;subMap;(Object,Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;SortedMap;true;tailMap;(Object);;Argument[-1].MapKey;ReturnValue.MapKey;value;manual",
"java.util;SortedMap;true;tailMap;(Object);;Argument[-1].MapValue;ReturnValue.MapValue;value;manual",
"java.util;SortedSet;true;first;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;SortedSet;true;headSet;(Object);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;SortedSet;true;last;();;Argument[-1].Element;ReturnValue;value;manual",
"java.util;SortedSet;true;subSet;(Object,Object);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util;SortedSet;true;tailSet;(Object);;Argument[-1].Element;ReturnValue.Element;value;manual",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object,long,TimeUnit);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;TransferQueue;true;transfer;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object);;Argument[0];Argument[-1].Element;value;manual",
"java.util;List;false;copyOf;(Collection);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object);;Argument[0];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object);;Argument[0..1];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object);;Argument[0..2];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object);;Argument[0..3];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];ReturnValue.Element;value;manual",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];ReturnValue.Element;value;manual",
"java.util;Map;false;copyOf;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Map;false;copyOf;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Map;false;entry;(Object,Object);;Argument[0];ReturnValue.MapKey;value;manual",
"java.util;Map;false;entry;(Object,Object);;Argument[1];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[0];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[1];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[2];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[3];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[4];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[5];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[6];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[7];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[8];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[9];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[10];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[11];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[12];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[13];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[14];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[15];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[16];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[17];ReturnValue.MapValue;value;manual",
"java.util;Map;false;of;;;Argument[18];ReturnValue.MapKey;value;manual",
"java.util;Map;false;of;;;Argument[19];ReturnValue.MapValue;value;manual",
"java.util;Map;false;ofEntries;;;Argument[0].ArrayElement.MapKey;ReturnValue.MapKey;value;manual",
"java.util;Map;false;ofEntries;;;Argument[0].ArrayElement.MapValue;ReturnValue.MapValue;value;manual",
"java.util;Set;false;copyOf;(Collection);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object);;Argument[0];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object);;Argument[0..1];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object);;Argument[0..2];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object);;Argument[0..3];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];ReturnValue.Element;value;manual",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];ReturnValue.Element;value;manual",
"java.util;Arrays;false;stream;;;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"java.util;Arrays;false;spliterator;;;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"java.util;Arrays;false;copyOfRange;;;Argument[0].ArrayElement;ReturnValue.ArrayElement;value;manual",
"java.util;Arrays;false;copyOf;;;Argument[0].ArrayElement;ReturnValue.ArrayElement;value;manual",
"java.util;Collections;false;list;(Enumeration);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;enumeration;(Collection);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;nCopies;(int,Object);;Argument[1];ReturnValue.Element;value;manual",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[0];ReturnValue.MapKey;value;manual",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[1];ReturnValue.MapValue;value;manual",
"java.util;Collections;false;singletonList;(Object);;Argument[0];ReturnValue.Element;value;manual",
"java.util;Collections;false;singleton;(Object);;Argument[0];ReturnValue.Element;value;manual",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;checkedList;(List,Class);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;checkedNavigableSet;(NavigableSet,Class);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;checkedSortedSet;(SortedSet,Class);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;checkedSet;(Set,Class);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;checkedCollection;(Collection,Class);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;synchronizedMap;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;synchronizedMap;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;synchronizedList;(List);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;synchronizedNavigableSet;(NavigableSet);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;synchronizedSortedSet;(SortedSet);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;synchronizedSet;(Set);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;synchronizedCollection;(Collection);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;unmodifiableMap;(Map);;Argument[0].MapKey;ReturnValue.MapKey;value;manual",
"java.util;Collections;false;unmodifiableMap;(Map);;Argument[0].MapValue;ReturnValue.MapValue;value;manual",
"java.util;Collections;false;unmodifiableList;(List);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;unmodifiableNavigableSet;(NavigableSet);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;unmodifiableSortedSet;(SortedSet);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;unmodifiableSet;(Set);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;unmodifiableCollection;(Collection);;Argument[0].Element;ReturnValue.Element;value;manual",
"java.util;Collections;false;max;;;Argument[0].Element;ReturnValue;value;manual",
"java.util;Collections;false;min;;;Argument[0].Element;ReturnValue;value;manual",
"java.util;Arrays;false;fill;(Object[],int,int,Object);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(Object[],Object);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(float[],int,int,float);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(float[],float);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(double[],int,int,double);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(double[],double);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(boolean[],int,int,boolean);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(boolean[],boolean);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(byte[],int,int,byte);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(byte[],byte);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(char[],int,int,char);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(char[],char);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(short[],int,int,short);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(short[],short);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(int[],int,int,int);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(int[],int);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(long[],int,int,long);;Argument[3];Argument[0].ArrayElement;value;manual",
"java.util;Arrays;false;fill;(long[],long);;Argument[1];Argument[0].ArrayElement;value;manual",
"java.util;Collections;false;replaceAll;(List,Object,Object);;Argument[2];Argument[0].Element;value;manual",
"java.util;Collections;false;copy;(List,List);;Argument[1].Element;Argument[0].Element;value;manual",
"java.util;Collections;false;fill;(List,Object);;Argument[1];Argument[0].Element;value;manual",
"java.util;Arrays;false;asList;;;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"java.util;Collections;false;addAll;(Collection,Object[]);;Argument[1].ArrayElement;Argument[0].Element;value;manual",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Object,Object);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Entry);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;AbstractMap$SimpleEntry;false;SimpleEntry;(Entry);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Object,Object);;Argument[0];Argument[-1].MapKey;value;manual",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Object,Object);;Argument[1];Argument[-1].MapValue;value;manual",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Entry);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;AbstractMap$SimpleImmutableEntry;false;SimpleImmutableEntry;(Entry);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;ArrayDeque;false;ArrayDeque;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;ArrayList;false;ArrayList;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;EnumMap;false;EnumMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;EnumMap;false;EnumMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;EnumMap;false;EnumMap;(EnumMap);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;EnumMap;false;EnumMap;(EnumMap);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;HashMap;false;HashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;HashMap;false;HashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;HashSet;false;HashSet;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;Hashtable;false;Hashtable;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;Hashtable;false;Hashtable;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;IdentityHashMap;false;IdentityHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;IdentityHashMap;false;IdentityHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;LinkedHashMap;false;LinkedHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;LinkedHashMap;false;LinkedHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;LinkedHashSet;false;LinkedHashSet;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;LinkedList;false;LinkedList;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;PriorityQueue;false;PriorityQueue;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;PriorityQueue;false;PriorityQueue;(PriorityQueue);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;PriorityQueue;false;PriorityQueue;(SortedSet);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;TreeMap;false;TreeMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;TreeMap;false;TreeMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;TreeMap;false;TreeMap;(SortedMap);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;TreeMap;false;TreeMap;(SortedMap);;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"java.util;TreeSet;false;TreeSet;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;TreeSet;false;TreeSet;(SortedSet);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;Vector;false;Vector;(Collection);;Argument[0].Element;Argument[-1].Element;value;manual",
"java.util;WeakHashMap;false;WeakHashMap;(Map);;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"java.util;WeakHashMap;false;WeakHashMap;(Map);;Argument[0].MapValue;Argument[-1].MapValue;value;manual"
]
}
}

View File

@@ -10,7 +10,7 @@ private module DispatchImpl {
DataFlowCallable viableCallable(DataFlowCall c) {
result.asCallable() = VirtualDispatch::viableCallable(c.asCall())
or
result.(SummarizedCallable).asCallable() = c.asCall().getCallee().getSourceDeclaration()
result.asCallable().(SummarizedCallable) = c.asCall().getCallee().getSourceDeclaration()
}
/**
@@ -118,7 +118,7 @@ private module DispatchImpl {
not failsUnification(t, t2)
)
or
result.asCallable() = def and result instanceof SummarizedCallable
result.asCallable() = def and def instanceof SummarizedCallable
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -216,10 +216,9 @@ private module LambdaFlow {
or
// jump step
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
toReturn = false and
toJump = true and
lastCall = TDataFlowCallNone()
toJump = true
|
jumpStepCached(node, mid) and
t = t0
@@ -305,7 +304,7 @@ cached
private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
* collapsing the two stages.
*/
cached
@@ -789,24 +788,31 @@ private module Cached {
cached
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
cached
predicate storeSet(
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readSet(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
exists(ContentSet cs | c = cs.getAStoreContent() |
storeStep(node1, cs, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
or
readSet(n2, cs, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
exists(ContentSet cs |
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -14,14 +14,14 @@ newtype TNode =
not e.getParent*() instanceof Annotation
} or
TExplicitParameterNode(Parameter p) {
exists(p.getCallable().getBody()) or p.getCallable() = any(SummarizedCallable sc).asCallable()
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
} or
TImplicitVarargsArray(Call c) {
c.getCallee().isVarargs() and
not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
} or
TInstanceParameterNode(Callable c) {
(exists(c.getBody()) or c = any(SummarizedCallable sc).asCallable()) and
(exists(c.getBody()) or c instanceof SummarizedCallable) and
not c.isStatic()
} or
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
@@ -336,7 +336,7 @@ module Private {
result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or
n = TSummaryInternalNode(result, _) or
n = TSummaryInternalNode(result.asCallable(), _) or
result.asFieldScope() = n.(FieldValueNode).getField()
}

View File

@@ -317,7 +317,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
/** Gets the data flow node that this call targets. */
Node getReceiver() { result = receiver }
override DataFlowCallable getEnclosingCallable() { result = c }
override DataFlowCallable getEnclosingCallable() { result.asCallable() = c }
override string toString() { result = "[summary] call to " + receiver + " in " + c }
@@ -378,7 +378,7 @@ predicate forceHighPrecision(Content c) {
predicate nodeIsHidden(Node n) {
n instanceof SummaryNode
or
n.(ParameterNode).isParameterOf(any(SummarizedCallable c).asCallable(), _)
n.(ParameterNode).isParameterOf(any(SummarizedCallable c), _)
}
class LambdaCallKind = Method; // the "apply" method in the functional interface

View File

@@ -75,7 +75,9 @@ private module ThisFlow {
* local (intra-procedural) steps.
*/
pragma[inline]
predicate localFlow(Node node1, Node node2) { localFlowStep*(node1, node2) }
predicate localFlow(Node node1, Node node2) { node1 = node2 or localFlowStepPlus(node1, node2) }
private predicate localFlowStepPlus(Node node1, Node node2) = fastTC(localFlowStep/2)(node1, node2)
/**
* Holds if data can flow from `e1` to `e2` in zero or more
@@ -97,27 +99,43 @@ predicate hasNonlocalValue(FieldRead fr) {
)
}
/**
* Holds if data can flow from `node1` to `node2` in one local step.
*/
predicate localFlowStep(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2)
or
adjacentUseUse(node1.asExpr(), node2.asExpr())
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, true)
cached
private module Cached {
/**
* Holds if data can flow from `node1` to `node2` in one local step.
*/
cached
predicate localFlowStep(Node node1, Node node2) {
simpleLocalFlowStep0(node1, node2)
or
adjacentUseUse(node1.asExpr(), node2.asExpr())
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(node1, node2, _)
}
/**
* INTERNAL: do not use.
*
* This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate.
*/
cached
predicate simpleLocalFlowStep(Node node1, Node node2) {
simpleLocalFlowStep0(node1, node2)
or
any(AdditionalValueStep a).step(node1, node2) and
pragma[only_bind_out](node1.getEnclosingCallable()) =
pragma[only_bind_out](node2.getEnclosingCallable()) and
// prevent recursive call
(any(AdditionalValueStep a).step(_, _) implies any())
}
}
/**
* INTERNAL: do not use.
*
* This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate.
*/
cached
predicate simpleLocalFlowStep(Node node1, Node node2) {
import Cached
private predicate simpleLocalFlowStep0(Node node1, Node node2) {
TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd |
@@ -136,7 +154,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
not exists(FieldRead fr |
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1)
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _)
or
ThisFlow::adjacentThisRefs(node1, node2)
or
@@ -166,10 +184,6 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2, true)
or
any(AdditionalValueStep a).step(node1, node2) and
pragma[only_bind_out](node1.getEnclosingCallable()) =
pragma[only_bind_out](node2.getEnclosingCallable())
}
private newtype TContent =
@@ -291,6 +305,35 @@ class ContentSet instanceof Content {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
exists(Guard g, SsaVariable v, boolean branch, RValue use |
guardChecks(g, v.getAUse(), branch) and
use = v.getAUse() and
g.controls(use.getBasicBlock(), branch) and
result.asExpr() = use
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
@@ -299,7 +342,7 @@ class ContentSet instanceof Content {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends Guard {
deprecated class BarrierGuard extends Guard {
/** Holds if this guard validates `e` upon evaluating to `branch`. */
abstract predicate checks(Expr e, boolean branch);

View File

@@ -195,7 +195,10 @@ module Public {
}
/** A callable with a flow summary. */
abstract class SummarizedCallable extends DataFlowCallable {
abstract class SummarizedCallable extends SummarizedCallableBase {
bindingset[this]
SummarizedCallable() { any() }
/**
* Holds if data may flow from `input` to `output` through this callable.
*
@@ -493,7 +496,7 @@ module Private {
or
exists(ParameterPosition pos |
parameterReadState(c, state, pos) and
result.(ParamNode).isParameterOf(c, pos)
result.(ParamNode).isParameterOf(inject(c), pos)
)
)
}
@@ -621,7 +624,7 @@ module Private {
predicate summaryPostUpdateNode(Node post, Node pre) {
exists(SummarizedCallable c, ParameterPosition pos |
isParameterPostUpdate(post, c, pos) and
pre.(ParamNode).isParameterOf(c, pos)
pre.(ParamNode).isParameterOf(inject(c), pos)
)
or
exists(SummarizedCallable callable, SummaryComponentStack s |
@@ -644,7 +647,7 @@ module Private {
* node, and back out to `p`.
*/
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(c, ppos) |
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(inject(c), ppos) |
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
summary(c, inputContents, outputContents, _) and
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
@@ -748,13 +751,16 @@ module Private {
private predicate viableParam(
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p
) {
p.isParameterOf(sc, ppos) and
sc = viableCallable(call)
exists(DataFlowCallable c |
c = inject(sc) and
p.isParameterOf(c, ppos) and
c = viableCallable(call)
)
}
pragma[nomagic]
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
exists(ParameterPosition ppos, SummarizedCallable sc |
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg, SummarizedCallable sc) {
exists(ParameterPosition ppos |
argumentPositionMatch(call, arg, ppos) and
viableParam(call, sc, ppos, result)
)
@@ -768,41 +774,56 @@ module Private {
* or expects contents.
*/
pragma[nomagic]
predicate prohibitsUseUseFlow(ArgNode arg) {
predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) {
exists(ParamNode p, Node mid, ParameterPosition ppos, Node ret |
p = summaryArgParam0(_, arg) and
p.isParameterOf(_, ppos) and
p = summaryArgParam0(_, arg, sc) and
p.isParameterOf(_, pragma[only_bind_into](ppos)) and
summaryLocalStep(p, mid, true) and
summaryLocalStep(mid, ret, true) and
isParameterPostUpdate(ret, _, ppos)
isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos))
|
summaryClearsContent(mid, _) or
summaryExpectsContent(mid, _)
)
}
pragma[nomagic]
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
exists(DataFlowCall call |
result = summaryArgParam0(call, arg) and
out = rk.getAnOutNode(call)
bindingset[ret]
private ParamNode summaryArgParam(
ArgNode arg, ReturnNodeExt ret, OutNodeExt out, SummarizedCallable sc
) {
exists(DataFlowCall call, ReturnKindExt rk |
result = summaryArgParam0(call, arg, sc) and
ret.getKind() = pragma[only_bind_into](rk) and
out = pragma[only_bind_into](rk).getAnOutNode(call)
)
}
/**
* Holds if `arg` flows to `out` using a simple flow summary, that is, a flow
* summary without reads and stores.
* Holds if `arg` flows to `out` using a simple value-preserving flow
* summary, that is, a flow summary without reads and stores.
*
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryThroughStep(ArgNode arg, Node out, boolean preservesValue) {
exists(ReturnKindExt rk, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, rk, out), ret, preservesValue) and
ret.getKind() = rk
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
exists(ReturnKind rk, ReturnNode ret, DataFlowCall call |
summaryLocalStep(summaryArgParam0(call, arg, sc), ret, true) and
ret.getKind() = pragma[only_bind_into](rk) and
out = getAnOutNode(call, pragma[only_bind_into](rk))
)
}
/**
* Holds if `arg` flows to `out` using a simple flow summary involving taint
* step, that is, a flow summary without reads and stores.
*
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
exists(ReturnNodeExt ret | summaryLocalStep(summaryArgParam(arg, ret, out, sc), ret, false))
}
/**
* Holds if there is a read(+taint) of `c` from `arg` to `out` using a
* flow summary.
@@ -810,11 +831,10 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out) {
exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and
summaryLocalStep(mid, ret, _) and
ret.getKind() = rk
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(Node mid, ReturnNodeExt ret |
summaryReadStep(summaryArgParam(arg, ret, out, sc), c, mid) and
summaryLocalStep(mid, ret, _)
)
}
@@ -825,11 +845,10 @@ module Private {
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out) {
exists(ReturnKindExt rk, Node mid, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and
summaryStoreStep(mid, c, ret) and
ret.getKind() = rk
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(Node mid, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, ret, out, sc), mid, _) and
summaryStoreStep(mid, c, ret)
)
}
}
@@ -912,11 +931,18 @@ module Private {
private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { summaryElement(this, _, _, _, _) }
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
summaryElement(this, inSpec, outSpec, kind, true) and
not summaryElement(this, _, _, _, false) and
not this.clearsContent(_, _)
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
summaryElement(this, inSpec, outSpec, kind, false)
or
summaryElement(this, inSpec, outSpec, kind, true) and
not summaryElement(this, _, _, _, false)
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
override predicate propagatesFlow(
@@ -933,7 +959,7 @@ module Private {
)
}
override predicate isAutoGenerated() { summaryElement(this, _, _, _, true) }
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
}
/** Holds if component `c` of specification `spec` cannot be parsed. */
@@ -1069,7 +1095,7 @@ module Private {
/** Provides a query predicate for outputting a set of relevant flow summaries. */
module TestOutput {
/** A flow summary to include in the `summary/3` query predicate. */
abstract class RelevantSummarizedCallable extends SummarizedCallable {
abstract class RelevantSummarizedCallable instanceof SummarizedCallable {
/** Gets the string representation of this callable used by `summary/1`. */
abstract string getCallableCsv();
@@ -1077,8 +1103,10 @@ module Private {
predicate relevantSummary(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
this.propagatesFlow(input, output, preservesValue)
super.propagatesFlow(input, output, preservesValue)
}
string toString() { result = super.toString() }
}
/** Render the kind in the format used in flow summaries. */
@@ -1088,13 +1116,13 @@ module Private {
preservesValue = false and result = "taint"
}
private string renderGenerated(RelevantSummarizedCallable c) {
if c.isAutoGenerated() then result = "generated:" else result = ""
private string renderProvenance(RelevantSummarizedCallable c) {
if c.(SummarizedCallable).isAutoGenerated() then result = "generated" else result = "manual"
}
/**
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;(generated:)?kind",
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
* ext is hardcoded to empty.
*/
query predicate summary(string csv) {
@@ -1105,7 +1133,7 @@ module Private {
c.relevantSummary(input, output, preservesValue) and
csv =
c.getCallableCsv() + getComponentStackCsv(input) + ";" + getComponentStackCsv(output) +
";" + renderGenerated(c) + renderKind(preservesValue)
";" + renderKind(preservesValue) + ";" + renderProvenance(c)
)
}
}
@@ -1119,19 +1147,21 @@ module Private {
*/
module RenderSummarizedCallable {
/** A summarized callable to include in the graph. */
abstract class RelevantSummarizedCallable extends SummarizedCallable { }
abstract class RelevantSummarizedCallable instanceof SummarizedCallable {
string toString() { result = super.toString() }
}
private newtype TNodeOrCall =
MkNode(Node n) {
exists(RelevantSummarizedCallable c |
n = summaryNode(c, _)
or
n.(ParamNode).isParameterOf(c, _)
n.(ParamNode).isParameterOf(inject(c), _)
)
} or
MkCall(DataFlowCall call) {
call = summaryDataFlowCall(_) and
call.getEnclosingCallable() instanceof RelevantSummarizedCallable
call.getEnclosingCallable() = inject(any(RelevantSummarizedCallable c))
}
private class NodeOrCall extends TNodeOrCall {

View File

@@ -1,5 +1,5 @@
/**
* Provides Java specific classes and predicates for definining flow summaries.
* Provides Java specific classes and predicates for defining flow summaries.
*/
private import java
@@ -14,6 +14,10 @@ private module FlowSummaries {
private import semmle.code.java.dataflow.FlowSummary as F
}
class SummarizedCallableBase = Callable;
DataFlowCallable inject(SummarizedCallable c) { result.asCallable() = c }
/** Gets the parameter position of the instance parameter. */
int instanceParameterPosition() { result = -1 }
@@ -28,7 +32,7 @@ DataFlowType getContentType(Content c) { result = c.getType() }
/** Gets the return type of kind `rk` for callable `c`. */
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
result = getErasedRepr(c.asCallable().getReturnType()) and
result = getErasedRepr(c.getReturnType()) and
exists(rk)
}
@@ -51,19 +55,26 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
exists(rk)
}
bindingset[provenance]
private boolean isGenerated(string provenance) {
provenance = "generated" and result = true
or
provenance != "generated" and result = false
}
/**
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, kind `kind`, and a flag `generated`
* stating whether the summary is autogenerated.
*/
predicate summaryElement(
DataFlowCallable c, string input, string output, string kind, boolean generated
) {
predicate summaryElement(Callable c, string input, string output, string kind, boolean generated) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string provenance
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
c.asCallable() = interpretElement(namespace, type, subtypes, name, signature, ext)
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
generated = isGenerated(provenance) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
@@ -120,9 +131,11 @@ class SourceOrSinkElement = Top;
*/
predicate sourceElement(SourceOrSinkElement e, string output, string kind, boolean generated) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string provenance
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, generated) and
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
generated = isGenerated(provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
@@ -134,9 +147,11 @@ predicate sourceElement(SourceOrSinkElement e, string output, string kind, boole
*/
predicate sinkElement(SourceOrSinkElement e, string input, string kind, boolean generated) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string provenance
|
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, generated) and
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
generated = isGenerated(provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}

View File

@@ -51,14 +51,14 @@ private module Cached {
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(src, sink, _)
or
// Treat container flow as taint for the local taint flow relation
exists(DataFlow::Content c | containerContent(c) |
readStep(src, c, sink) or
storeStep(src, c, sink) or
FlowSummaryImpl::Private::Steps::summaryGetterStep(src, c, sink) or
FlowSummaryImpl::Private::Steps::summarySetterStep(src, c, sink)
FlowSummaryImpl::Private::Steps::summaryGetterStep(src, c, sink, _) or
FlowSummaryImpl::Private::Steps::summarySetterStep(src, c, sink, _)
)
}
@@ -112,12 +112,6 @@ private module Cached {
}
}
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
import Cached
private RefType getElementType(RefType container) {
@@ -190,7 +184,7 @@ private predicate localAdditionalTaintUpdateStep(Expr src, Expr sink) {
private class BulkData extends RefType {
BulkData() {
this.(Array).getElementType().(PrimitiveType).getName().regexpMatch("byte|char")
this.(Array).getElementType().(PrimitiveType).hasName(["byte", "char"])
or
exists(RefType t | this.getASourceSupertype*() = t |
t.hasQualifiedName("java.io", "InputStream") or
@@ -321,7 +315,7 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
exists(Method springResponseEntityOfOk |
sink.getMethod() = springResponseEntityOfOk and
springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and
springResponseEntityOfOk.getName().regexpMatch("ok|of") and
springResponseEntityOfOk.hasName(["ok", "of"]) and
tracked = sink.getArgument(0) and
tracked.getType() instanceof TypeString
)
@@ -329,7 +323,7 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
exists(Method springResponseEntityBody |
sink.getMethod() = springResponseEntityBody and
springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and
springResponseEntityBody.getName().regexpMatch("body") and
springResponseEntityBody.hasName("body") and
tracked = sink.getArgument(0) and
tracked.getType() instanceof TypeString
)

View File

@@ -49,7 +49,7 @@ module Private {
/** Class to represent float and double literals. */
class RealLiteral extends J::Literal {
RealLiteral() {
this instanceof J::FloatingPointLiteral or
this instanceof J::FloatLiteral or
this instanceof J::DoubleLiteral
}
}
@@ -191,7 +191,7 @@ private module Impl {
/** Gets the constant `float` value of non-`ConstantIntegerExpr` expressions. */
float getNonIntegerValue(Expr e) {
result = e.(LongLiteral).getValue().toFloat() or
result = e.(FloatingPointLiteral).getValue().toFloat() or
result = e.(FloatLiteral).getValue().toFloat() or
result = e.(DoubleLiteral).getValue().toFloat()
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -302,6 +302,8 @@ class RootdefCallable extends Callable {
exists(MemberRefExpr mre | mre.getReferencedCallable() = this)
or
this.getAnAnnotation() instanceof OverrideAnnotation
or
this.hasModifier("override")
}
}

View File

@@ -13,7 +13,7 @@ class FitFixtureEntryPoint extends CallableEntryPoint {
* FitNesse entry points externally defined.
*/
class FitNesseSlimEntryPointData extends ExternalData {
FitNesseSlimEntryPointData() { getDataPath().matches("fitnesse.csv") }
FitNesseSlimEntryPointData() { getDataPath() = "fitnesse.csv" }
/**
* Gets the class name.

View File

@@ -46,9 +46,9 @@ private class ApacheHttpSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
"org.apache.http.protocol;HttpRequestHandler;true;handle;(HttpRequest,HttpResponse,HttpContext);;Parameter[0];remote",
"org.apache.hc.core5.http.io;HttpRequestHandler;true;handle;(ClassicHttpRequest,ClassicHttpResponse,HttpContext);;Parameter[0];remote",
"org.apache.hc.core5.http.io;HttpServerRequestHandler;true;handle;(ClassicHttpRequest,ResponseTrigger,HttpContext);;Parameter[0];remote"
"org.apache.http.protocol;HttpRequestHandler;true;handle;(HttpRequest,HttpResponse,HttpContext);;Parameter[0];remote;manual",
"org.apache.hc.core5.http.io;HttpRequestHandler;true;handle;(ClassicHttpRequest,ClassicHttpResponse,HttpContext);;Parameter[0];remote;manual",
"org.apache.hc.core5.http.io;HttpServerRequestHandler;true;handle;(ClassicHttpRequest,ResponseTrigger,HttpContext);;Parameter[0];remote;manual"
]
}
}
@@ -85,9 +85,9 @@ private class ApacheHttpXssSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"org.apache.http;HttpResponse;true;setEntity;(HttpEntity);;Argument[0];xss",
"org.apache.http.util;EntityUtils;true;updateEntity;(HttpResponse,HttpEntity);;Argument[1];xss",
"org.apache.hc.core5.http;HttpEntityContainer;true;setEntity;(HttpEntity);;Argument[0];xss"
"org.apache.http;HttpResponse;true;setEntity;(HttpEntity);;Argument[0];xss;manual",
"org.apache.http.util;EntityUtils;true;updateEntity;(HttpResponse,HttpEntity);;Argument[1];xss;manual",
"org.apache.hc.core5.http;HttpEntityContainer;true;setEntity;(HttpEntity);;Argument[0];xss;manual"
]
}
}
@@ -96,31 +96,31 @@ private class ApacheHttpOpenUrlSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"org.apache.http;HttpRequest;true;setURI;;;Argument[0];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(RequestLine);;Argument[0];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String);;Argument[1];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(RequestLine);;Argument[0];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String);;Argument[1];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
"org.apache.http.client.methods;HttpGet;false;HttpGet;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpHead;false;HttpHead;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPut;false;HttpPut;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPost;false;HttpPost;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpDelete;false;HttpDelete;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpOptions;false;HttpOptions;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpTrace;false;HttpTrace;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPatch;false;HttpPatch;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpRequestBase;true;setURI;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;setUri;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;get;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;post;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;put;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;options;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;head;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;delete;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;trace;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;patch;;;Argument[0];open-url"
"org.apache.http;HttpRequest;true;setURI;;;Argument[0];open-url;manual",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(RequestLine);;Argument[0];open-url;manual",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String);;Argument[1];open-url;manual",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String,ProtocolVersion);;Argument[1];open-url;manual",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(RequestLine);;Argument[0];open-url;manual",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String);;Argument[1];open-url;manual",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String,ProtocolVersion);;Argument[1];open-url;manual",
"org.apache.http.client.methods;HttpGet;false;HttpGet;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpHead;false;HttpHead;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpPut;false;HttpPut;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpPost;false;HttpPost;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpDelete;false;HttpDelete;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpOptions;false;HttpOptions;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpTrace;false;HttpTrace;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpPatch;false;HttpPatch;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;HttpRequestBase;true;setURI;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;setUri;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;get;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;post;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;put;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;options;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;head;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;delete;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;trace;;;Argument[0];open-url;manual",
"org.apache.http.client.methods;RequestBuilder;false;patch;;;Argument[0];open-url;manual"
]
}
}
@@ -129,142 +129,142 @@ private class ApacheHttpFlowStep extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"org.apache.http;HttpMessage;true;getAllHeaders;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;getHeaders;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;getParams;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;headerIterator;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpMessage;true;headerIterator;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpRequest;true;getRequestLine;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpEntityEnclosingRequest;true;getEntity;();;Argument[-1];ReturnValue;taint",
"org.apache.http;Header;true;getElements;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderElement;true;getName;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderElement;true;getValue;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderElement;true;getParameter;(int);;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderElement;true;getParameterByName;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderElement;true;getParameters;();;Argument[-1];ReturnValue;taint",
"org.apache.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint",
"org.apache.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HeaderIterator;true;nextHeader;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpEntity;true;getContentEncoding;();;Argument[-1];ReturnValue;taint",
"org.apache.http;HttpEntity;true;getContentType;();;Argument[-1];ReturnValue;taint",
"org.apache.http;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint",
"org.apache.http;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint",
"org.apache.http.params;HttpParams;true;getParameter;(String);;Argument[-1];ReturnValue;taint",
"org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[-1];ReturnValue;taint",
"org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[-1];ReturnValue;taint",
"org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[-1];ReturnValue;taint",
"org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[1];ReturnValue;value",
"org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[1];ReturnValue;value",
"org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[1];ReturnValue;value",
"org.apache.hc.core5.http;MessageHeaders;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;getHeader;(String);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;getHeaders;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;getHeaders;(String);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;headerIterator;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;MessageHeaders;true;headerIterator;(String);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpRequest;true;getAuthority;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpRequest;true;getMethod;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpRequest;true;getPath;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpRequest;true;getUri;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpRequest;true;getRequestUri;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpEntityContainer;true;getEntity;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;HttpEntity;true;getTrailers;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;EntityDetails;true;getContentType;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;EntityDetails;true;getContentEncoding;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http;EntityDetails;true;getTrailerNames;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(HttpRequest);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];Argument[-1];taint",
"org.apache.hc.core5.function;Supplier;true;get;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.net;URIAuthority;true;getHostName;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.net;URIAuthority;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint",
"org.apache.http.util;EntityUtils;true;toByteArray;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.util;EntityUtils;true;getContentCharSet;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.util;EntityUtils;true;getContentMimeType;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;toByteArray;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;parse;;;Argument[0];ReturnValue;taint",
"org.apache.http.util;EncodingUtils;true;getAsciiBytes;(String);;Argument[0];ReturnValue;taint",
"org.apache.http.util;EncodingUtils;true;getAsciiString;;;Argument[0];ReturnValue;taint",
"org.apache.http.util;EncodingUtils;true;getBytes;(String,String);;Argument[0];ReturnValue;taint",
"org.apache.http.util;EncodingUtils;true;getString;;;Argument[0];ReturnValue;taint",
"org.apache.http.util;Args;true;containsNoBlanks;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.http.util;Args;true;notNull;(Object,String);;Argument[0];ReturnValue;value",
"org.apache.http.util;Args;true;notEmpty;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.http.util;Args;true;notEmpty;(Collection,String);;Argument[0];ReturnValue;value",
"org.apache.http.util;Args;true;notBlank;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;containsNoBlanks;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;notNull;(Object,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;notEmpty;(Collection,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;notEmpty;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;notEmpty;(Object,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.util;Args;true;notBlank;(CharSequence,String);;Argument[0];ReturnValue;value",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;create;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;createGzipped;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;createUrlEncoded;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;gzip;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;withTrailers;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;BasicHttpEntity;true;setContent;(InputStream);;Argument[0];Argument[-1];taint",
"org.apache.http.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint",
"org.apache.http.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.io.entity;BasicHttpEntity;true;BasicHttpEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.io.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint",
"org.apache.http.util;CharArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.http.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;ByteArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.http.message;BasicRequestLine;false;BasicRequestLine;;;Argument[1];Argument[-1];taint",
"org.apache.http;RequestLine;true;getUri;;;Argument[-1];ReturnValue;taint",
"org.apache.http;RequestLine;true;toString;;;Argument[-1];ReturnValue;taint"
"org.apache.http;HttpMessage;true;getAllHeaders;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;getHeaders;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;getParams;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;headerIterator;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpMessage;true;headerIterator;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpRequest;true;getRequestLine;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpEntityEnclosingRequest;true;getEntity;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;Header;true;getElements;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderElement;true;getName;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderElement;true;getValue;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderElement;true;getParameter;(int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderElement;true;getParameterByName;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderElement;true;getParameters;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HeaderIterator;true;nextHeader;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpEntity;true;getContentEncoding;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;HttpEntity;true;getContentType;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.params;HttpParams;true;getParameter;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[1];ReturnValue;value;manual",
"org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[1];ReturnValue;value;manual",
"org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[1];ReturnValue;value;manual",
"org.apache.hc.core5.http;MessageHeaders;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;getHeader;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;getHeaders;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;getHeaders;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;headerIterator;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;MessageHeaders;true;headerIterator;(String);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpRequest;true;getAuthority;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpRequest;true;getMethod;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpRequest;true;getPath;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpRequest;true;getUri;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpRequest;true;getRequestUri;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpEntityContainer;true;getEntity;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;HttpEntity;true;getTrailers;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;EntityDetails;true;getContentType;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;EntityDetails;true;getContentEncoding;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http;EntityDetails;true;getTrailerNames;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http.message;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http.message;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http.message;RequestLine;true;toString;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(HttpRequest);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];Argument[-1];taint;manual",
"org.apache.hc.core5.function;Supplier;true;get;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.net;URIAuthority;true;getHostName;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.net;URIAuthority;true;toString;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EntityUtils;true;toByteArray;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EntityUtils;true;getContentCharSet;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EntityUtils;true;getContentMimeType;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;toByteArray;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;EntityUtils;true;parse;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EncodingUtils;true;getAsciiBytes;(String);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EncodingUtils;true;getAsciiString;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EncodingUtils;true;getBytes;(String,String);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;EncodingUtils;true;getString;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.util;Args;true;containsNoBlanks;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.http.util;Args;true;notNull;(Object,String);;Argument[0];ReturnValue;value;manual",
"org.apache.http.util;Args;true;notEmpty;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.http.util;Args;true;notEmpty;(Collection,String);;Argument[0];ReturnValue;value;manual",
"org.apache.http.util;Args;true;notBlank;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;containsNoBlanks;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;notNull;(Object,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;notEmpty;(Collection,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;notEmpty;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;notEmpty;(Object,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.util;Args;true;notBlank;(CharSequence,String);;Argument[0];ReturnValue;value;manual",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;create;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;createGzipped;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;createUrlEncoded;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;gzip;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;HttpEntities;true;withTrailers;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.entity;BasicHttpEntity;true;setContent;(InputStream);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint;manual",
"org.apache.http.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.http.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint;manual",
"org.apache.http.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.http.io.entity;BasicHttpEntity;true;BasicHttpEntity;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.http.io.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint;manual",
"org.apache.hc.core5.http.io.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;ByteArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint;manual",
"org.apache.http.util;CharArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;ByteArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint;manual",
"org.apache.http.message;BasicRequestLine;false;BasicRequestLine;;;Argument[1];Argument[-1];taint;manual",
"org.apache.http;RequestLine;true;getUri;;;Argument[-1];ReturnValue;taint;manual",
"org.apache.http;RequestLine;true;toString;;;Argument[-1];ReturnValue;taint;manual"
]
}
}

View File

@@ -36,6 +36,6 @@ class FlexjsonDeserializerUseMethod extends Method {
private class FluentUseMethodModel extends SummaryModelCsv {
override predicate row(string r) {
r = "flexjson;JSONDeserializer;true;use;;;Argument[-1];ReturnValue;value"
r = "flexjson;JSONDeserializer;true;use;;;Argument[-1];ReturnValue;value;manual"
}
}

View File

@@ -27,13 +27,13 @@ private class SqlSinkCsv extends SinkModelCsv {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"org.hibernate;QueryProducer;true;createQuery;;;Argument[0];sql",
"org.hibernate;QueryProducer;true;createNativeQuery;;;Argument[0];sql",
"org.hibernate;QueryProducer;true;createSQLQuery;;;Argument[0];sql",
"org.hibernate;SharedSessionContract;true;createQuery;;;Argument[0];sql",
"org.hibernate;SharedSessionContract;true;createSQLQuery;;;Argument[0];sql",
"org.hibernate;Session;true;createQuery;;;Argument[0];sql",
"org.hibernate;Session;true;createSQLQuery;;;Argument[0];sql"
"org.hibernate;QueryProducer;true;createQuery;;;Argument[0];sql;manual",
"org.hibernate;QueryProducer;true;createNativeQuery;;;Argument[0];sql;manual",
"org.hibernate;QueryProducer;true;createSQLQuery;;;Argument[0];sql;manual",
"org.hibernate;SharedSessionContract;true;createQuery;;;Argument[0];sql;manual",
"org.hibernate;SharedSessionContract;true;createSQLQuery;;;Argument[0];sql;manual",
"org.hibernate;Session;true;createQuery;;;Argument[0];sql;manual",
"org.hibernate;Session;true;createSQLQuery;;;Argument[0];sql;manual"
]
}
}

View File

@@ -10,8 +10,8 @@ private class SsrfSinkCsv extends SinkModelCsv {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"com.zaxxer.hikari;HikariConfig;false;HikariConfig;(Properties);;Argument[0];jdbc-url",
"com.zaxxer.hikari;HikariConfig;false;setJdbcUrl;(String);;Argument[0];jdbc-url"
"com.zaxxer.hikari;HikariConfig;false;HikariConfig;(Properties);;Argument[0];jdbc-url;manual",
"com.zaxxer.hikari;HikariConfig;false;setJdbcUrl;(String);;Argument[0];jdbc-url;manual"
]
}
}

View File

@@ -14,11 +14,11 @@ private class Jms1Source extends SourceModelCsv {
row =
[
// incoming messages are considered tainted
"javax.jms;MessageListener;true;onMessage;(Message);;Parameter[0];remote",
"javax.jms;MessageConsumer;true;receive;;;ReturnValue;remote",
"javax.jms;MessageConsumer;true;receiveNoWait;();;ReturnValue;remote",
"javax.jms;QueueRequestor;true;request;(Message);;ReturnValue;remote",
"javax.jms;TopicRequestor;true;request;(Message);;ReturnValue;remote",
"javax.jms;MessageListener;true;onMessage;(Message);;Parameter[0];remote;manual",
"javax.jms;MessageConsumer;true;receive;;;ReturnValue;remote;manual",
"javax.jms;MessageConsumer;true;receiveNoWait;();;ReturnValue;remote;manual",
"javax.jms;QueueRequestor;true;request;(Message);;ReturnValue;remote;manual",
"javax.jms;TopicRequestor;true;request;(Message);;ReturnValue;remote;manual",
]
}
}
@@ -29,64 +29,64 @@ private class Jms1FlowStep extends SummaryModelCsv {
row =
[
// if a message is tainted, then it returns tainted data
"javax.jms;Message;true;getBody;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getJMSCorrelationIDAsBytes;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getJMSCorrelationID;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getJMSReplyTo;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getJMSDestination;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getJMSType;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getBooleanProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getByteProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getShortProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getIntProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getLongProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getFloatProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getDoubleProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getStringProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getObjectProperty;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getPropertyNames;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readBoolean;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readByte;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readUnsignedByte;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readShort;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readUnsignedShort;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readChar;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readInt;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readLong;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readFloat;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readDouble;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readUTF;();;Argument[-1];ReturnValue;taint",
"javax.jms;BytesMessage;true;readBytes;;;Argument[-1];Argument[0];taint",
"javax.jms;MapMessage;true;getBoolean;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getByte;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getShort;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getChar;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getInt;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getLong;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getFloat;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getDouble;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getString;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getBytes;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getObject;(String);;Argument[-1];ReturnValue;taint",
"javax.jms;MapMessage;true;getMapNames;();;Argument[-1];ReturnValue;taint",
"javax.jms;ObjectMessage;true;getObject;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readBoolean;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readByte;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readShort;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readChar;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readInt;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readLong;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readFloat;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readDouble;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readString;();;Argument[-1];ReturnValue;taint",
"javax.jms;StreamMessage;true;readBytes;(byte[]);;Argument[-1];Argument[0];taint",
"javax.jms;StreamMessage;true;readObject;();;Argument[-1];ReturnValue;taint",
"javax.jms;TextMessage;true;getText;();;Argument[-1];ReturnValue;taint",
"javax.jms;Message;true;getBody;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getJMSCorrelationIDAsBytes;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getJMSCorrelationID;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getJMSReplyTo;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getJMSDestination;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getJMSType;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getBooleanProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getByteProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getShortProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getIntProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getLongProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getFloatProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getDoubleProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getStringProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getObjectProperty;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Message;true;getPropertyNames;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readBoolean;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readByte;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readUnsignedByte;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readShort;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readUnsignedShort;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readChar;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readInt;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readLong;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readFloat;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readDouble;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readUTF;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;BytesMessage;true;readBytes;;;Argument[-1];Argument[0];taint;manual",
"javax.jms;MapMessage;true;getBoolean;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getByte;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getShort;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getChar;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getInt;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getLong;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getFloat;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getDouble;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getString;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getBytes;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getObject;(String);;Argument[-1];ReturnValue;taint;manual",
"javax.jms;MapMessage;true;getMapNames;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;ObjectMessage;true;getObject;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readBoolean;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readByte;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readShort;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readChar;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readInt;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readLong;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readFloat;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readDouble;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readString;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;StreamMessage;true;readBytes;(byte[]);;Argument[-1];Argument[0];taint;manual",
"javax.jms;StreamMessage;true;readObject;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;TextMessage;true;getText;();;Argument[-1];ReturnValue;taint;manual",
// if a destination is tainted, then it returns tainted data
"javax.jms;Queue;true;getQueueName;();;Argument[-1];ReturnValue;taint",
"javax.jms;Queue;true;toString;();;Argument[-1];ReturnValue;taint",
"javax.jms;Topic;true;getTopicName;();;Argument[-1];ReturnValue;taint",
"javax.jms;Topic;true;toString;();;Argument[-1];ReturnValue;taint",
"javax.jms;Queue;true;getQueueName;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Queue;true;toString;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Topic;true;getTopicName;();;Argument[-1];ReturnValue;taint;manual",
"javax.jms;Topic;true;toString;();;Argument[-1];ReturnValue;taint;manual",
]
}
}
@@ -96,10 +96,10 @@ private class Jms2Source extends SourceModelCsv {
override predicate row(string row) {
row =
[
"javax.jms;JMSConsumer;true;receive;;;ReturnValue;remote",
"javax.jms;JMSConsumer;true;receiveBody;;;ReturnValue;remote",
"javax.jms;JMSConsumer;true;receiveNoWait;();;ReturnValue;remote",
"javax.jms;JMSConsumer;true;receiveBodyNoWait;();;ReturnValue;remote",
"javax.jms;JMSConsumer;true;receive;;;ReturnValue;remote;manual",
"javax.jms;JMSConsumer;true;receiveBody;;;ReturnValue;remote;manual",
"javax.jms;JMSConsumer;true;receiveNoWait;();;ReturnValue;remote;manual",
"javax.jms;JMSConsumer;true;receiveBodyNoWait;();;ReturnValue;remote;manual",
]
}
}
@@ -107,6 +107,6 @@ private class Jms2Source extends SourceModelCsv {
/** Defines additional taint propagation steps in JMS 2. */
private class Jms2FlowStep extends SummaryModelCsv {
override predicate row(string row) {
row = "javax.jms;Message;true;getBody;();;Argument[-1];ReturnValue;taint"
row = "javax.jms;Message;true;getBody;();;Argument[-1];ReturnValue;taint;manual"
}
}

Some files were not shown because too many files have changed in this diff Show More