mirror of
https://github.com/github/codeql.git
synced 2026-01-24 20:02:58 +01:00
merge in main
This commit is contained in:
@@ -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
|
||||
|
||||
|
@@ -9,7 +9,7 @@ Java framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑036` :sub:`Path traversal`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑319` :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
|
||||
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) + ')')
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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?>()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
|
||||
90
java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt
Normal file
90
java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt
Normal 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) }
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
|
||||
typealias FileEntry = SourceManager.FileEntry
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
|
||||
typealias FileEntry = SourceManager.FileEntry
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrFileEntry
|
||||
|
||||
typealias FileEntry = IrFileEntry
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrFileEntry
|
||||
|
||||
typealias FileEntry = IrFileEntry
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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."
|
||||
|
||||
22
java/ql/consistency-queries/visibility.ql
Normal file
22
java/ql/consistency-queries/visibility.ql
Normal 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), ", ")
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Add taint models for the following `File` methods:
|
||||
* `File::getAbsoluteFile`
|
||||
* `File::getCanonicalFile`
|
||||
* `File::getAbsolutePath`
|
||||
* `File::getCanonicalPath`
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
Added a flow step for `toString` calls on tainted `android.text.Editable` objects.
|
||||
@@ -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()`.
|
||||
@@ -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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added models for the libraries OkHttp and Retrofit.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
Added a flow step for `String.valueOf` calls on tainted `android.text.Editable` objects.
|
||||
@@ -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.
|
||||
@@ -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`.
|
||||
10
java/ql/lib/change-notes/released/0.2.2.md
Normal file
10
java/ql/lib/change-notes/released/0.2.2.md
Normal 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.
|
||||
1
java/ql/lib/change-notes/released/0.2.3.md
Normal file
1
java/ql/lib/change-notes/released/0.2.3.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.2.3
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.2.0
|
||||
lastReleaseVersion: 0.2.3
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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, _) }
|
||||
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Provides classes and predicates for definining flow summaries.
|
||||
* Provides classes and predicates for defining flow summaries.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -302,6 +302,8 @@ class RootdefCallable extends Callable {
|
||||
exists(MemberRefExpr mre | mre.getReferencedCallable() = this)
|
||||
or
|
||||
this.getAnAnnotation() instanceof OverrideAnnotation
|
||||
or
|
||||
this.hasModifier("override")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user