mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge branch 'main' into atorralba/android_slice_models
This commit is contained in:
2
java/change-notes/2021-05-11-ratpack-support.md
Normal file
2
java/change-notes/2021-05-11-ratpack-support.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Add support for [Ratpack](https://ratpack.io/) HTTP framework.
|
||||
@@ -0,0 +1,5 @@
|
||||
lgtm,codescanning
|
||||
* A new query "Android Intent redirection" (`java/android/intent-redirection`) has been added.
|
||||
This query finds exported Android components using received Intents to start other components,
|
||||
which can provide access to internal components of the application or cause other unintended
|
||||
effects.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The query "Leaking sensitive information through an implicit Intent" (`java/android/sensitive-communication`) has been promoted from experimental to the main query pack. Its results will now appear by default. The query was originally [submitted as an experimental query by @luchua-bc.](https://github.com/github/codeql/pull/4512)
|
||||
2
java/change-notes/2021-10-20-more-specific-types.md
Normal file
2
java/change-notes/2021-10-20-more-specific-types.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Some uses of `RefType` in the support for 'generics' and 'imports' now use the more specific `ClassOrInterface` instead
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The predicate `StringLiteral.getRepresentedString()` has been deprecated for removal in a future version because it is just an alias for `getValue()`. That predicate should be used instead.
|
||||
2
java/change-notes/2021-10-29-optional-lambda-flow.md
Normal file
2
java/change-notes/2021-10-29-optional-lambda-flow.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added data flow models for lambda methods on `java.util.Optional`.
|
||||
2
java/change-notes/2021-11-15-overrides.md
Normal file
2
java/change-notes/2021-11-15-overrides.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The predicate `Method.overrides(Method)` was accidentally transitive. This has been fixed. This fix also affects `Method.overridesOrInstantiates(Method)` and `Method.getASourceOverriddenMethod()`.
|
||||
3
java/change-notes/2021-11-25-surrogate-char-literals.md
Normal file
3
java/change-notes/2021-11-25-surrogate-char-literals.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* `CharacterLiteral`'s `getCodePointValue` predicate now returns the correct value for UTF-16 surrogates.
|
||||
* The `RangeAnalysis` module and the `java/constant-comparison` queries no longer raise false alerts regarding comparisons with Unicode surrogate character literals.
|
||||
2
java/change-notes/2021-19-29-improved-ratpack-support.md
Normal file
2
java/change-notes/2021-19-29-improved-ratpack-support.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Improved support for the [Ratpack](https://ratpack.io/) HTTP framework: added data-flow models of `ratpack.func.Pair` and `ratpack.exec.Result`, and improved models of `ratpack.exec.Promise`.
|
||||
@@ -1,92 +1,102 @@
|
||||
package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:jexl,sink:jndi-injection,sink:ldap,sink:mvel,sink:ognl-injection,sink:open-url,sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:xpath,sink:xslt,sink:xss,source:contentprovider,source:remote,summary:taint,summary:value
|
||||
android.content,8,27,73,,,,,,,,,,,,,8,,,,,,27,,8,65
|
||||
android.database,59,,30,,,,,,,,,,,,,59,,,,,,,,30,
|
||||
android.net,,,60,,,,,,,,,,,,,,,,,,,,,45,15
|
||||
android.os,,,122,,,,,,,,,,,,,,,,,,,,,41,81
|
||||
android.util,,16,,,,,,,,,,,,,,,,,,,,,16,,
|
||||
android.webkit,3,2,,,,,,,,,,,,,,,,,,,3,,2,,
|
||||
cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.fasterxml.jackson.databind,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
com.google.common.base,,,85,,,,,,,,,,,,,,,,,,,,,62,23
|
||||
com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,17
|
||||
com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,2,551
|
||||
com.google.common.io,6,,73,,,,,,,,,,,,,,6,,,,,,,72,1
|
||||
com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,3,,,,,,,,,,,,
|
||||
com.unboundid.ldap.sdk,17,,,,,,,,,,17,,,,,,,,,,,,,,
|
||||
flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,1
|
||||
groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,
|
||||
groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,
|
||||
jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,2,,7,,
|
||||
jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,100,23
|
||||
jakarta.ws.rs.client,1,,,,,,,,,,,,,1,,,,,,,,,,,
|
||||
jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,9,,
|
||||
jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,2,,,,,,94,55
|
||||
java.beans,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
java.io,3,,27,,3,,,,,,,,,,,,,,,,,,,26,1
|
||||
java.lang,,,50,,,,,,,,,,,,,,,,,,,,,41,9
|
||||
java.net,10,3,7,,,,,,,,,,,10,,,,,,,,,3,7,
|
||||
java.nio,10,,4,,10,,,,,,,,,,,,,,,,,,,4,
|
||||
java.sql,7,,,,,,,,,,,,,,,7,,,,,,,,,
|
||||
java.util,,,417,,,,,,,,,,,,,,,,,,,,,15,402
|
||||
javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,2,,7,,
|
||||
javax.json,,,123,,,,,,,,,,,,,,,,,,,,,100,23
|
||||
javax.management.remote,2,,,,,,,,,2,,,,,,,,,,,,,,,
|
||||
javax.naming,7,,,,,,,,,6,1,,,,,,,,,,,,,,
|
||||
javax.net.ssl,2,,,,,,,,,,,,,,2,,,,,,,,,,
|
||||
javax.script,1,,,,,,,,,,,1,,,,,,,,,,,,,
|
||||
javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,21,2,
|
||||
javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,1,,
|
||||
javax.ws.rs.client,1,,,,,,,,,,,,,1,,,,,,,,,,,
|
||||
javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,9,,
|
||||
javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,2,,,,,,94,55
|
||||
javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,1,,,,6,
|
||||
javax.xml.xpath,3,,,,,,,,,,,,,,,,,,3,,,,,,
|
||||
jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,10
|
||||
net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,5,,,,,
|
||||
ognl,6,,,,,,,,,,,,6,,,,,,,,,,,,
|
||||
org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,6,
|
||||
org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,17,783
|
||||
org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,17,783
|
||||
org.apache.commons.io,,,22,,,,,,,,,,,,,,,,,,,,,22,
|
||||
org.apache.commons.jexl2,15,,,,,,,,15,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.jexl3,15,,,,,,,,15,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.lang3,,,423,,,,,,,,,,,,,,,,,,,,,292,131
|
||||
org.apache.commons.ognl,6,,,,,,,,,,,,6,,,,,,,,,,,,
|
||||
org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,220,52
|
||||
org.apache.directory.ldap.client.api,1,,,,,,,,,,1,,,,,,,,,,,,,,
|
||||
org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,1,,2,39,
|
||||
org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,2,
|
||||
org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,18,6
|
||||
org.apache.http,27,3,70,,,,,,,,,,,25,,,,,,,2,,3,62,8
|
||||
org.apache.ibatis.jdbc,6,,,,,,,,,,,,,,,6,,,,,,,,,
|
||||
org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.apache.shiro.jndi,1,,,,,,,,,1,,,,,,,,,,,,,,,
|
||||
org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,
|
||||
org.dom4j,20,,,,,,,,,,,,,,,,,,20,,,,,,
|
||||
org.hibernate,7,,,,,,,,,,,,,,,7,,,,,,,,,
|
||||
org.jooq,1,,,,,,,,,,,,,,,1,,,,,,,,,
|
||||
org.json,,,236,,,,,,,,,,,,,,,,,,,,,198,38
|
||||
org.mvel2,16,,,,,,,,,,,16,,,,,,,,,,,,,
|
||||
org.springframework.beans,,,26,,,,,,,,,,,,,,,,,,,,,,26
|
||||
org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,13
|
||||
org.springframework.http,14,,70,,,,,,,,,,,14,,,,,,,,,,60,10
|
||||
org.springframework.jdbc.core,10,,,,,,,,,,,,,,,10,,,,,,,,,
|
||||
org.springframework.jdbc.object,9,,,,,,,,,,,,,,,9,,,,,,,,,
|
||||
org.springframework.jndi,1,,,,,,,,,1,,,,,,,,,,,,,,,
|
||||
org.springframework.ldap,42,,,,,,,,,28,14,,,,,,,,,,,,,,
|
||||
org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,6,,
|
||||
org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,32
|
||||
org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,87,52
|
||||
org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,13,
|
||||
org.springframework.web.client,13,3,,,,,,,,,,,,13,,,,,,,,,3,,
|
||||
org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,8,,
|
||||
org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,12,13,
|
||||
org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,2,,,,,,,,,,,
|
||||
org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,138,25
|
||||
org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,3,,
|
||||
play.mvc,,4,,,,,,,,,,,,,,,,,,,,,4,,
|
||||
package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jexl,sink:jndi-injection,sink:ldap,sink:mvel,sink:ognl-injection,sink:open-url,sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:xpath,sink:xslt,sink:xss,source:contentprovider,source:remote,summary:taint,summary:value
|
||||
android.app,7,,,,,,,,7,,,,,,,,,,,,,,,,,
|
||||
android.content,24,27,96,,,,,,16,,,,,,,,8,,,,,,27,,31,65
|
||||
android.database,59,,30,,,,,,,,,,,,,,59,,,,,,,,30,
|
||||
android.net,,,60,,,,,,,,,,,,,,,,,,,,,,45,15
|
||||
android.os,,,122,,,,,,,,,,,,,,,,,,,,,,41,81
|
||||
android.util,,16,,,,,,,,,,,,,,,,,,,,,,16,,
|
||||
android.webkit,3,2,,,,,,,,,,,,,,,,,,,,3,,2,,
|
||||
cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,6,
|
||||
com.google.common.base,,,85,,,,,,,,,,,,,,,,,,,,,,62,23
|
||||
com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,17
|
||||
com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,2,551
|
||||
com.google.common.io,6,,73,,,,,,,,,,,,,,,6,,,,,,,72,1
|
||||
com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,3,,,,,,,,,,,,
|
||||
com.unboundid.ldap.sdk,17,,,,,,,,,,,17,,,,,,,,,,,,,,
|
||||
flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,1
|
||||
groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,,
|
||||
groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,,
|
||||
jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,2,,7,,
|
||||
jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,100,23
|
||||
jakarta.ws.rs.client,1,,,,,,,,,,,,,,1,,,,,,,,,,,
|
||||
jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,9,,
|
||||
jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,2,,,,,,94,55
|
||||
java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
java.io,3,,31,,3,,,,,,,,,,,,,,,,,,,,30,1
|
||||
java.lang,,,52,,,,,,,,,,,,,,,,,,,,,,42,10
|
||||
java.net,10,3,7,,,,,,,,,,,,10,,,,,,,,,3,7,
|
||||
java.nio,10,,4,,10,,,,,,,,,,,,,,,,,,,,4,
|
||||
java.sql,7,,,,,,,,,,,,,,,,7,,,,,,,,,
|
||||
java.util,,,429,,,,,,,,,,,,,,,,,,,,,,15,414
|
||||
javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,2,,7,,
|
||||
javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,100,23
|
||||
javax.management.remote,2,,,,,,,,,,2,,,,,,,,,,,,,,,
|
||||
javax.naming,7,,,,,,,,,,6,1,,,,,,,,,,,,,,
|
||||
javax.net.ssl,2,,,,,,,,,,,,,,,2,,,,,,,,,,
|
||||
javax.script,1,,,,,,,,,,,,1,,,,,,,,,,,,,
|
||||
javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,,21,2,
|
||||
javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,1,,
|
||||
javax.ws.rs.client,1,,,,,,,,,,,,,,1,,,,,,,,,,,
|
||||
javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,9,,
|
||||
javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,,2,,,,,,94,55
|
||||
javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,1,,,,6,
|
||||
javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,3,,,,,,
|
||||
jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,10
|
||||
net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,5,,,,,
|
||||
ognl,6,,,,,,,,,,,,,6,,,,,,,,,,,,
|
||||
org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,6,
|
||||
org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,17,783
|
||||
org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,17,783
|
||||
org.apache.commons.io,,,22,,,,,,,,,,,,,,,,,,,,,,22,
|
||||
org.apache.commons.jexl2,15,,,,,,,,,15,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.jexl3,15,,,,,,,,,15,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.lang3,,,423,,,,,,,,,,,,,,,,,,,,,,292,131
|
||||
org.apache.commons.ognl,6,,,,,,,,,,,,,6,,,,,,,,,,,,
|
||||
org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,220,52
|
||||
org.apache.directory.ldap.client.api,1,,,,,,,,,,,1,,,,,,,,,,,,,,
|
||||
org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,1,,2,39,
|
||||
org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,2,
|
||||
org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,18,6
|
||||
org.apache.http,27,3,70,,,,,,,,,,,,25,,,,,,,2,,3,62,8
|
||||
org.apache.ibatis.jdbc,6,,,,,,,,,,,,,,,,6,,,,,,,,,
|
||||
org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.apache.shiro.jndi,1,,,,,,,,,,1,,,,,,,,,,,,,,,
|
||||
org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
org.dom4j,20,,,,,,,,,,,,,,,,,,,20,,,,,,
|
||||
org.hibernate,7,,,,,,,,,,,,,,,,7,,,,,,,,,
|
||||
org.jooq,1,,,,,,,,,,,,,,,,1,,,,,,,,,
|
||||
org.json,,,236,,,,,,,,,,,,,,,,,,,,,,198,38
|
||||
org.mvel2,16,,,,,,,,,,,,16,,,,,,,,,,,,,
|
||||
org.springframework.beans,,,26,,,,,,,,,,,,,,,,,,,,,,,26
|
||||
org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,13
|
||||
org.springframework.http,14,,70,,,,,,,,,,,,14,,,,,,,,,,60,10
|
||||
org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,10,,,,,,,,,
|
||||
org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,9,,,,,,,,,
|
||||
org.springframework.jndi,1,,,,,,,,,,1,,,,,,,,,,,,,,,
|
||||
org.springframework.ldap,42,,,,,,,,,,28,14,,,,,,,,,,,,,,
|
||||
org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,6,,
|
||||
org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,32
|
||||
org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,87,52
|
||||
org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,13,
|
||||
org.springframework.web.client,13,3,,,,,,,,,,,,,13,,,,,,,,,3,,
|
||||
org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,8,,
|
||||
org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,12,13,
|
||||
org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,2,,,,,,,,,,,
|
||||
org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,138,25
|
||||
org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,3,,
|
||||
play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,4,,
|
||||
ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,3,
|
||||
ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,6,4,
|
||||
ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,10,10,
|
||||
ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,48
|
||||
ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,3,
|
||||
ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,35
|
||||
ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,6,4,
|
||||
ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,10,10,
|
||||
ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,35
|
||||
|
||||
|
@@ -7,7 +7,7 @@ Java framework & library support
|
||||
:widths: auto
|
||||
|
||||
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.*``,45,285,70,,,3,67,,,
|
||||
Android,``android.*``,45,308,93,,,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``,,22,,,,,,,,
|
||||
`Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,423,,,,,,,,
|
||||
@@ -15,9 +15,9 @@ Java framework & library support
|
||||
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25
|
||||
`Google Guava <https://guava.dev/>`_,``com.google.common.*``,,728,6,,6,,,,,
|
||||
`JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,,
|
||||
Java Standard Library,``java.*``,3,506,30,13,,,7,,,10
|
||||
Java Standard Library,``java.*``,3,524,30,13,,,7,,,10
|
||||
Java extensions,"``javax.*``, ``jakarta.*``",54,552,32,,,4,,1,1,2
|
||||
`Spring <https://spring.io/>`_,``org.springframework.*``,29,469,91,,,,19,14,,29
|
||||
Others,"``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.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,28,151,,,,14,18,,
|
||||
Totals,,143,5257,408,13,6,10,107,33,1,66
|
||||
Others,"``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.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``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``",39,181,151,,,,14,18,,
|
||||
Totals,,175,5451,431,13,6,10,107,33,1,66
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ typeVars(
|
||||
string nodeName: string ref,
|
||||
int pos: int ref,
|
||||
int kind: int ref, // deprecated
|
||||
int parentid: @typeorcallable ref
|
||||
int parentid: @classorinterfaceorcallable ref
|
||||
);
|
||||
|
||||
wildcards(
|
||||
@@ -414,7 +414,7 @@ typeBounds(
|
||||
typeArgs(
|
||||
int argumentid: @reftype ref,
|
||||
int pos: int ref,
|
||||
int parentid: @typeorcallable ref
|
||||
int parentid: @classorinterfaceorcallable ref
|
||||
);
|
||||
|
||||
isParameterized(
|
||||
@@ -487,7 +487,7 @@ hasModifier(
|
||||
|
||||
imports(
|
||||
unique int id: @import,
|
||||
int holder: @typeorpackage ref,
|
||||
int holder: @classorinterfaceorpackage ref,
|
||||
string name: string ref,
|
||||
int kind: int ref
|
||||
);
|
||||
@@ -857,10 +857,9 @@ javadocText(
|
||||
@javadocParent = @javadoc | @javadocTag;
|
||||
@javadocElement = @javadocTag | @javadocText;
|
||||
|
||||
@typeorpackage = @type | @package;
|
||||
|
||||
@typeorcallable = @type | @callable;
|
||||
@classorinterface = @interface | @class;
|
||||
@classorinterfaceorpackage = @classorinterface | @package;
|
||||
@classorinterfaceorcallable = @classorinterface | @callable;
|
||||
@boundedtype = @typevariable | @wildcard;
|
||||
@reftype = @classorinterface | @array | @boundedtype;
|
||||
@classorarray = @class | @array;
|
||||
|
||||
19
java/ql/lib/external/ExternalArtifact.qll
vendored
19
java/ql/lib/external/ExternalArtifact.qll
vendored
@@ -3,24 +3,25 @@ import java
|
||||
class ExternalData extends @externalDataElement {
|
||||
string getDataPath() { externalData(this, result, _, _) }
|
||||
|
||||
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
|
||||
string getQueryPath() { result = this.getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
|
||||
|
||||
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
|
||||
|
||||
string getField(int index) { externalData(this, _, index, result) }
|
||||
|
||||
int getFieldAsInt(int index) { result = getField(index).toInt() }
|
||||
int getFieldAsInt(int index) { result = this.getField(index).toInt() }
|
||||
|
||||
float getFieldAsFloat(int index) { result = getField(index).toFloat() }
|
||||
float getFieldAsFloat(int index) { result = this.getField(index).toFloat() }
|
||||
|
||||
date getFieldAsDate(int index) { result = getField(index).toDate() }
|
||||
date getFieldAsDate(int index) { result = this.getField(index).toDate() }
|
||||
|
||||
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
|
||||
string toString() { result = this.getQueryPath() + ": " + this.buildTupleString(0) }
|
||||
|
||||
private string buildTupleString(int start) {
|
||||
start = getNumFields() - 1 and result = getField(start)
|
||||
start = this.getNumFields() - 1 and result = this.getField(start)
|
||||
or
|
||||
start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1)
|
||||
start < this.getNumFields() - 1 and
|
||||
result = this.getField(start) + "," + this.buildTupleString(start + 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ class DefectExternalData extends ExternalData {
|
||||
this.getNumFields() = 2
|
||||
}
|
||||
|
||||
string getURL() { result = getField(0) }
|
||||
string getURL() { result = this.getField(0) }
|
||||
|
||||
string getMessage() { result = getField(1) }
|
||||
string getMessage() { result = this.getField(1) }
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class Container extends @container, Top {
|
||||
*/
|
||||
string getRelativePath() {
|
||||
exists(string absPath, string pref |
|
||||
absPath = getAbsolutePath() and sourceLocationPrefix(pref)
|
||||
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
||||
|
|
||||
absPath = pref and result = ""
|
||||
or
|
||||
@@ -74,7 +74,7 @@ class Container extends @container, Top {
|
||||
* </table>
|
||||
*/
|
||||
string getBaseName() {
|
||||
result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +100,9 @@ class Container extends @container, Top {
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) }
|
||||
string getExtension() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stem of this container, that is, the prefix of its base name up to
|
||||
@@ -119,7 +121,9 @@ class Container extends @container, Top {
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) }
|
||||
string getStem() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
|
||||
}
|
||||
|
||||
/** Gets the parent container of this file or folder, if any. */
|
||||
Container getParentContainer() { containerparent(result, this) }
|
||||
@@ -128,20 +132,20 @@ class Container extends @container, Top {
|
||||
Container getAChildContainer() { this = result.getParentContainer() }
|
||||
|
||||
/** Gets a file in this container. */
|
||||
File getAFile() { result = getAChildContainer() }
|
||||
File getAFile() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the file in this container that has the given `baseName`, if any. */
|
||||
File getFile(string baseName) {
|
||||
result = getAFile() and
|
||||
result = this.getAFile() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets a sub-folder in this container. */
|
||||
Folder getAFolder() { result = getAChildContainer() }
|
||||
Folder getAFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
|
||||
Folder getFolder(string baseName) {
|
||||
result = getAFolder() and
|
||||
result = this.getAFolder() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
@@ -152,7 +156,7 @@ class Container extends @container, Top {
|
||||
* to provide a different result. To get the absolute path of any `Container`, call
|
||||
* `Container.getAbsolutePath()` directly.
|
||||
*/
|
||||
override string toString() { result = getAbsolutePath() }
|
||||
override string toString() { result = this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
/** A folder. */
|
||||
@@ -160,7 +164,7 @@ class Folder extends Container, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
|
||||
/** Gets the URL of this folder. */
|
||||
override string getURL() { result = "folder://" + getAbsolutePath() }
|
||||
override string getURL() { result = "folder://" + this.getAbsolutePath() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Folder" }
|
||||
}
|
||||
@@ -183,7 +187,7 @@ class File extends Container, @file {
|
||||
* A Java archive file with a ".jar" extension.
|
||||
*/
|
||||
class JarFile extends File {
|
||||
JarFile() { getExtension() = "jar" }
|
||||
JarFile() { this.getExtension() = "jar" }
|
||||
|
||||
/**
|
||||
* Gets the main attribute with the specified `key`
|
||||
@@ -195,13 +199,17 @@ class JarFile extends File {
|
||||
* Gets the "Specification-Version" main attribute
|
||||
* from this JAR file's manifest.
|
||||
*/
|
||||
string getSpecificationVersion() { result = getManifestMainAttribute("Specification-Version") }
|
||||
string getSpecificationVersion() {
|
||||
result = this.getManifestMainAttribute("Specification-Version")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "Implementation-Version" main attribute
|
||||
* from this JAR file's manifest.
|
||||
*/
|
||||
string getImplementationVersion() { result = getManifestMainAttribute("Implementation-Version") }
|
||||
string getImplementationVersion() {
|
||||
result = this.getManifestMainAttribute("Implementation-Version")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the per-entry attribute for the specified `entry` and `key`
|
||||
|
||||
@@ -63,10 +63,10 @@ class Top extends @top {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn)
|
||||
this.hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn)
|
||||
or
|
||||
exists(string outFilepath, int outStartline, int outEndline |
|
||||
hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and
|
||||
this.hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and
|
||||
hasSmapLocationInfo(filepath, startline, startcolumn, endline, endcolumn, outFilepath,
|
||||
outStartline, outEndline)
|
||||
)
|
||||
@@ -103,7 +103,7 @@ class Top extends @top {
|
||||
/**
|
||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||
*/
|
||||
final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
|
||||
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
|
||||
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this element belongs.
|
||||
|
||||
@@ -51,7 +51,7 @@ class Annotation extends @annotation, Expr {
|
||||
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
|
||||
|
||||
/** Gets the element being annotated. */
|
||||
Element getTarget() { result = getAnnotatedElement() }
|
||||
Element getTarget() { result = this.getAnnotatedElement() }
|
||||
|
||||
override string toString() { result = this.getType().getName() }
|
||||
|
||||
@@ -67,8 +67,8 @@ class Annotation extends @annotation, Expr {
|
||||
* expression defined for the value.
|
||||
*/
|
||||
Expr getAValue(string name) {
|
||||
getType().getAnnotationElement(name).getType() instanceof Array and
|
||||
exists(Expr value | value = getValue(name) |
|
||||
this.getType().getAnnotationElement(name).getType() instanceof Array and
|
||||
exists(Expr value | value = this.getValue(name) |
|
||||
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
|
||||
)
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class Annotatable extends Element {
|
||||
|
||||
/** Holds if this element has the specified annotation. */
|
||||
predicate hasAnnotation(string package, string name) {
|
||||
exists(AnnotationType at | at = getAnAnnotation().getType() |
|
||||
exists(AnnotationType at | at = this.getAnAnnotation().getType() |
|
||||
at.nestedName() = name and at.getPackage().getName() = package
|
||||
)
|
||||
}
|
||||
@@ -118,7 +118,7 @@ class Annotatable extends Element {
|
||||
* annotation attached to it for the specified `category`.
|
||||
*/
|
||||
predicate suppressesWarningsAbout(string category) {
|
||||
category = getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning()
|
||||
category = this.getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning()
|
||||
or
|
||||
this.(Member).getDeclaringType().suppressesWarningsAbout(category)
|
||||
or
|
||||
|
||||
@@ -150,7 +150,7 @@ private module ControlFlowGraphImpl {
|
||||
* `TypeThrowable` which results in both `TypeError` and `TypeRuntimeException`.
|
||||
*/
|
||||
UncheckedThrowableType getAnUncheckedSubtype() {
|
||||
result = this.(UncheckedThrowableType)
|
||||
result = this
|
||||
or
|
||||
result instanceof TypeError and this instanceof TypeThrowable
|
||||
or
|
||||
@@ -528,13 +528,13 @@ private module ControlFlowGraphImpl {
|
||||
|
||||
/** Gets the first child node, if any. */
|
||||
ControlFlowNode firstChild() {
|
||||
result = getChildNode(-1)
|
||||
result = this.getChildNode(-1)
|
||||
or
|
||||
result = getChildNode(0) and not exists(getChildNode(-1))
|
||||
result = this.getChildNode(0) and not exists(this.getChildNode(-1))
|
||||
}
|
||||
|
||||
/** Holds if this CFG node has any child nodes. */
|
||||
predicate isLeafNode() { not exists(getChildNode(_)) }
|
||||
predicate isLeafNode() { not exists(this.getChildNode(_)) }
|
||||
|
||||
/** Holds if this node can finish with a `normalCompletion`. */
|
||||
predicate mayCompleteNormally() {
|
||||
@@ -1222,10 +1222,10 @@ class ConditionNode extends ControlFlowNode {
|
||||
ControlFlowNode getABranchSuccessor(boolean branch) { result = branchSuccessor(this, branch) }
|
||||
|
||||
/** Gets a true-successor of the `ConditionNode`. */
|
||||
ControlFlowNode getATrueSuccessor() { result = getABranchSuccessor(true) }
|
||||
ControlFlowNode getATrueSuccessor() { result = this.getABranchSuccessor(true) }
|
||||
|
||||
/** Gets a false-successor of the `ConditionNode`. */
|
||||
ControlFlowNode getAFalseSuccessor() { result = getABranchSuccessor(false) }
|
||||
ControlFlowNode getAFalseSuccessor() { result = this.getABranchSuccessor(false) }
|
||||
|
||||
/** Gets the condition of this `ConditionNode`. This is equal to the node itself. */
|
||||
Expr getCondition() { result = this }
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class ConversionSite extends Expr {
|
||||
/**
|
||||
* Whether this conversion site actually induces a conversion.
|
||||
*/
|
||||
predicate isTrivial() { getConversionTarget() = getConversionSource() }
|
||||
predicate isTrivial() { this.getConversionTarget() = this.getConversionSource() }
|
||||
|
||||
/**
|
||||
* Whether this conversion is implicit.
|
||||
|
||||
@@ -34,10 +34,10 @@ class Element extends @element, Top {
|
||||
* Elements pertaining to source files may include generated elements
|
||||
* not visible in source code, such as implicit default constructors.
|
||||
*/
|
||||
predicate fromSource() { getCompilationUnit().getExtension() = "java" }
|
||||
predicate fromSource() { this.getCompilationUnit().getExtension() = "java" }
|
||||
|
||||
/** Gets the compilation unit that this element belongs to. */
|
||||
CompilationUnit getCompilationUnit() { result = getFile() }
|
||||
CompilationUnit getCompilationUnit() { result = this.getFile() }
|
||||
|
||||
/** Cast this element to a `Documentable`. */
|
||||
Documentable getDoc() { result = this }
|
||||
|
||||
@@ -86,13 +86,15 @@ class Expr extends ExprParent, @expr {
|
||||
* explicit constructor invocation statement.
|
||||
*/
|
||||
|
||||
getEnclosingCallable().isStatic()
|
||||
this.getEnclosingCallable().isStatic()
|
||||
or
|
||||
getParent+() instanceof ThisConstructorInvocationStmt
|
||||
this.getParent+() instanceof ThisConstructorInvocationStmt
|
||||
or
|
||||
getParent+() instanceof SuperConstructorInvocationStmt
|
||||
this.getParent+() instanceof SuperConstructorInvocationStmt
|
||||
or
|
||||
exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() and lam.isInStaticContext())
|
||||
exists(LambdaExpr lam |
|
||||
lam.asMethod() = this.getEnclosingCallable() and lam.isInStaticContext()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this expression is parenthesized. */
|
||||
@@ -116,7 +118,7 @@ private predicate primitiveOrString(Type t) {
|
||||
*/
|
||||
class CompileTimeConstantExpr extends Expr {
|
||||
CompileTimeConstantExpr() {
|
||||
primitiveOrString(getType()) and
|
||||
primitiveOrString(this.getType()) and
|
||||
(
|
||||
// Literals of primitive type and literals of type `String`.
|
||||
this instanceof Literal
|
||||
@@ -164,7 +166,7 @@ class CompileTimeConstantExpr extends Expr {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
string getStringValue() {
|
||||
result = this.(StringLiteral).getRepresentedString()
|
||||
result = this.(StringLiteral).getValue()
|
||||
or
|
||||
result =
|
||||
this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() +
|
||||
@@ -296,18 +298,15 @@ class CompileTimeConstantExpr extends Expr {
|
||||
*
|
||||
* Note that this does not handle the following cases:
|
||||
*
|
||||
* - values of type `long`,
|
||||
* - `char` literals.
|
||||
* - values of type `long`.
|
||||
*/
|
||||
cached
|
||||
int getIntValue() {
|
||||
exists(IntegralType t | this.getType() = t | t.getName().toLowerCase() != "long") and
|
||||
(
|
||||
exists(string lit | lit = this.(Literal).getValue() |
|
||||
// `char` literals may get parsed incorrectly, so disallow.
|
||||
not this instanceof CharacterLiteral and
|
||||
result = lit.toInt()
|
||||
)
|
||||
result = this.(IntegerLiteral).getIntValue()
|
||||
or
|
||||
result = this.(CharacterLiteral).getCodePointValue()
|
||||
or
|
||||
exists(CastExpr cast, int val |
|
||||
cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue()
|
||||
@@ -425,9 +424,9 @@ class ArrayCreationExpr extends Expr, @arraycreationexpr {
|
||||
* Gets the size of the first dimension, if it can be statically determined.
|
||||
*/
|
||||
int getFirstDimensionSize() {
|
||||
if exists(getInit())
|
||||
then result = getInit().getSize()
|
||||
else result = getDimension(0).(CompileTimeConstantExpr).getIntValue()
|
||||
if exists(this.getInit())
|
||||
then result = this.getInit().getSize()
|
||||
else result = this.getDimension(0).(CompileTimeConstantExpr).getIntValue()
|
||||
}
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
@@ -463,7 +462,7 @@ class ArrayInit extends Expr, @arrayinit {
|
||||
* Gets the number of expressions in this initializer, that is, the size the
|
||||
* created array will have.
|
||||
*/
|
||||
int getSize() { result = count(getAnInit()) }
|
||||
int getSize() { result = count(this.getAnInit()) }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "{...}" }
|
||||
@@ -632,9 +631,9 @@ class Literal extends Expr, @literal {
|
||||
class BooleanLiteral extends Literal, @booleanliteral {
|
||||
/** Gets the boolean representation of this literal. */
|
||||
boolean getBooleanValue() {
|
||||
result = true and getValue() = "true"
|
||||
result = true and this.getValue() = "true"
|
||||
or
|
||||
result = false and getValue() = "false"
|
||||
result = false and this.getValue() = "false"
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BooleanLiteral" }
|
||||
@@ -657,7 +656,7 @@ class BooleanLiteral extends Literal, @booleanliteral {
|
||||
*/
|
||||
class IntegerLiteral extends Literal, @integerliteral {
|
||||
/** Gets the int representation of this literal. */
|
||||
int getIntValue() { result = getValue().toInt() }
|
||||
int getIntValue() { result = this.getValue().toInt() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IntegerLiteral" }
|
||||
}
|
||||
@@ -693,7 +692,7 @@ class FloatingPointLiteral 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 = getValue().toFloat() }
|
||||
float getFloatValue() { result = this.getValue().toFloat() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FloatingPointLiteral" }
|
||||
}
|
||||
@@ -709,14 +708,45 @@ class DoubleLiteral extends Literal, @doubleliteral {
|
||||
* Gets the value of this literal as CodeQL 64-bit `float`. The result will
|
||||
* have the same effective value as the Java `double` literal.
|
||||
*/
|
||||
float getDoubleValue() { result = getValue().toFloat() }
|
||||
float getDoubleValue() { result = this.getValue().toFloat() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DoubleLiteral" }
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
private int fromHex(string s) {
|
||||
exists(string digits | s.toUpperCase() = digits |
|
||||
result =
|
||||
sum(int i |
|
||||
|
|
||||
"0123456789ABCDEF".indexOf(digits.charAt(i)).bitShiftLeft((digits.length() - i - 1) * 4)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** A character literal. For example, `'\n'`. */
|
||||
class CharacterLiteral extends Literal, @characterliteral {
|
||||
override string getAPrimaryQlClass() { result = "CharacterLiteral" }
|
||||
|
||||
/**
|
||||
* Gets a string which consists of the single character represented by
|
||||
* this literal.
|
||||
*
|
||||
* Unicode surrogate characters (U+D800 to U+DFFF) have the replacement character
|
||||
* U+FFFD as result instead.
|
||||
*/
|
||||
override string getValue() { result = super.getValue() }
|
||||
|
||||
/**
|
||||
* Gets the Unicode code point value of the character represented by
|
||||
* this literal. The result is the same as if the Java code had cast
|
||||
* the character to an `int`.
|
||||
*/
|
||||
int getCodePointValue() {
|
||||
if this.getLiteral().matches("'\\u____'")
|
||||
then result = fromHex(this.getLiteral().substring(3, 7))
|
||||
else result.toUnicode() = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -730,12 +760,24 @@ class CharacterLiteral extends Literal, @characterliteral {
|
||||
*/
|
||||
class StringLiteral extends Literal, @stringliteral {
|
||||
/**
|
||||
* Gets the string represented by this string literal, that is, the content
|
||||
* of the literal without enclosing quotes and with escape sequences translated.
|
||||
*
|
||||
* Unpaired Unicode surrogate characters (U+D800 to U+DFFF) are replaced with the
|
||||
* replacement character U+FFFD.
|
||||
*/
|
||||
override string getValue() { result = super.getValue() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: This predicate will be removed in a future version because
|
||||
* it is just an alias for `getValue()`; that predicate should be used instead.
|
||||
*
|
||||
* Gets the literal string without the quotes.
|
||||
*/
|
||||
string getRepresentedString() { result = getValue() }
|
||||
deprecated string getRepresentedString() { result = this.getValue() }
|
||||
|
||||
/** Holds if this string literal is a text block (`""" ... """`). */
|
||||
predicate isTextBlock() { getLiteral().matches("\"\"\"%") }
|
||||
predicate isTextBlock() { this.getLiteral().matches("\"\"\"%") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StringLiteral" }
|
||||
}
|
||||
@@ -1184,7 +1226,7 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr {
|
||||
* Gets the implicit method corresponding to this lambda expression.
|
||||
* The parameters of the lambda expression are the parameters of this method.
|
||||
*/
|
||||
override Method asMethod() { result = getAnonymousClass().getAMethod() }
|
||||
override Method asMethod() { result = this.getAnonymousClass().getAMethod() }
|
||||
|
||||
/** Holds if the body of this lambda is an expression. */
|
||||
predicate hasExprBody() { lambdaKind(this, 0) }
|
||||
@@ -1194,11 +1236,11 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr {
|
||||
|
||||
/** Gets the body of this lambda expression, if it is an expression. */
|
||||
Expr getExprBody() {
|
||||
hasExprBody() and result = asMethod().getBody().getAChild().(ReturnStmt).getResult()
|
||||
this.hasExprBody() and result = this.asMethod().getBody().getAChild().(ReturnStmt).getResult()
|
||||
}
|
||||
|
||||
/** Gets the body of this lambda expression, if it is a statement. */
|
||||
BlockStmt getStmtBody() { hasStmtBody() and result = asMethod().getBody() }
|
||||
BlockStmt getStmtBody() { this.hasStmtBody() and result = this.asMethod().getBody() }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "...->..." }
|
||||
@@ -1223,7 +1265,29 @@ class MemberRefExpr extends FunctionalExpr, @memberref {
|
||||
* (if the reference is to a constructor) or an array creation expression (if the reference
|
||||
* is to an array constructor).
|
||||
*/
|
||||
override Method asMethod() { result = getAnonymousClass().getAMethod() }
|
||||
override Method asMethod() { result = this.getAnonymousClass().getAMethod() }
|
||||
|
||||
/**
|
||||
* Gets the receiver type whose member this expression refers to. The result might not be
|
||||
* the type which actually declares the member. For example, for the member reference `ArrayList::toString`,
|
||||
* this predicate has the result `java.util.ArrayList`, the type explicitly referred to, while
|
||||
* `getReferencedCallable` will have `java.util.AbstractCollection.toString` as result, which `ArrayList` inherits.
|
||||
*/
|
||||
RefType getReceiverType() {
|
||||
exists(Stmt stmt, Expr resultExpr |
|
||||
stmt = asMethod().getBody().(SingletonBlock).getStmt() and
|
||||
(
|
||||
resultExpr = stmt.(ReturnStmt).getResult()
|
||||
or
|
||||
// Note: Currently never an ExprStmt, but might change once https://github.com/github/codeql/issues/3605 is fixed
|
||||
resultExpr = stmt.(ExprStmt).getExpr()
|
||||
)
|
||||
|
|
||||
result = resultExpr.(MethodAccess).getReceiverType() or
|
||||
result = resultExpr.(ClassInstanceExpr).getConstructedType() or
|
||||
result = resultExpr.(ArrayCreationExpr).getType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method or constructor referenced by this member reference expression.
|
||||
@@ -1274,16 +1338,16 @@ class ConditionalExpr extends Expr, @conditionalexpr {
|
||||
* it is `getFalseExpr()`.
|
||||
*/
|
||||
Expr getBranchExpr(boolean branch) {
|
||||
branch = true and result = getTrueExpr()
|
||||
branch = true and result = this.getTrueExpr()
|
||||
or
|
||||
branch = false and result = getFalseExpr()
|
||||
branch = false and result = this.getFalseExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expressions that is evaluated by one of the branches (`true`
|
||||
* or `false` branch) of this conditional expression.
|
||||
*/
|
||||
Expr getABranchExpr() { result = getBranchExpr(_) }
|
||||
Expr getABranchExpr() { result = this.getBranchExpr(_) }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "...?...:..." }
|
||||
@@ -1308,7 +1372,7 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
* Gets a case of this `switch` expression,
|
||||
* which may be either a normal `case` or a `default`.
|
||||
*/
|
||||
SwitchCase getACase() { result = getAConstCase() or result = getDefaultCase() }
|
||||
SwitchCase getACase() { result = this.getAConstCase() or result = this.getDefaultCase() }
|
||||
|
||||
/** Gets a (non-default) `case` of this `switch` expression. */
|
||||
ConstCase getAConstCase() { result.getParent() = this }
|
||||
@@ -1321,7 +1385,7 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
|
||||
/** Gets a result expression of this `switch` expression. */
|
||||
Expr getAResult() {
|
||||
result = getACase().getRuleExpression()
|
||||
result = this.getACase().getRuleExpression()
|
||||
or
|
||||
exists(YieldStmt yield | yield.(JumpStmt).getTarget() = this and result = yield.getValue())
|
||||
}
|
||||
@@ -1336,21 +1400,17 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr {
|
||||
class InstanceOfExpr extends Expr, @instanceofexpr {
|
||||
/** Gets the expression on the left-hand side of the `instanceof` operator. */
|
||||
Expr getExpr() {
|
||||
if isPattern()
|
||||
then result = getLocalVariableDeclExpr().getInit()
|
||||
if this.isPattern()
|
||||
then result = this.getLocalVariableDeclExpr().getInit()
|
||||
else result.isNthChildOf(this, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* PREVIEW FEATURE in Java 14. Subject to removal in a future release.
|
||||
*
|
||||
* Holds if this `instanceof` expression uses pattern matching.
|
||||
*/
|
||||
predicate isPattern() { exists(getLocalVariableDeclExpr()) }
|
||||
predicate isPattern() { exists(this.getLocalVariableDeclExpr()) }
|
||||
|
||||
/**
|
||||
* PREVIEW FEATURE in Java 14. Subject to removal in a future release.
|
||||
*
|
||||
* Gets the local variable declaration of this `instanceof` expression if pattern matching is used.
|
||||
*/
|
||||
LocalVariableDeclExpr getLocalVariableDeclExpr() { result.isNthChildOf(this, 0) }
|
||||
@@ -1359,7 +1419,7 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
|
||||
Expr getTypeName() { result.isNthChildOf(this, 1) }
|
||||
|
||||
/** Gets the type this `instanceof` expression checks for. */
|
||||
RefType getCheckedType() { result = getTypeName().getType() }
|
||||
RefType getCheckedType() { result = this.getTypeName().getType() }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "...instanceof..." }
|
||||
@@ -1457,7 +1517,7 @@ class TypeLiteral extends Expr, @typeliteral {
|
||||
* Gets the type this type literal refers to. For example for `String.class` the
|
||||
* result is the type representing `String`.
|
||||
*/
|
||||
Type getReferencedType() { result = getTypeName().getType() }
|
||||
Type getReferencedType() { result = this.getTypeName().getType() }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = this.getTypeName().toString() + ".class" }
|
||||
@@ -1482,15 +1542,15 @@ abstract class InstanceAccess extends Expr {
|
||||
* This never holds for accesses in lambda expressions as they cannot access
|
||||
* their own instance directly.
|
||||
*/
|
||||
predicate isOwnInstanceAccess() { not isEnclosingInstanceAccess(_) }
|
||||
predicate isOwnInstanceAccess() { not this.isEnclosingInstanceAccess(_) }
|
||||
|
||||
/** Holds if this instance access is to an enclosing instance of type `t`. */
|
||||
predicate isEnclosingInstanceAccess(RefType t) {
|
||||
t = getQualifier().getType().(RefType).getSourceDeclaration() and
|
||||
t != getEnclosingCallable().getDeclaringType()
|
||||
t = this.getQualifier().getType().(RefType).getSourceDeclaration() and
|
||||
t != this.getEnclosingCallable().getDeclaringType()
|
||||
or
|
||||
not exists(getQualifier()) and
|
||||
exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() |
|
||||
not exists(this.getQualifier()) and
|
||||
exists(LambdaExpr lam | lam.asMethod() = this.getEnclosingCallable() |
|
||||
t = lam.getAnonymousClass().getEnclosingType()
|
||||
)
|
||||
}
|
||||
@@ -1538,7 +1598,7 @@ class VarAccess extends Expr, @varaccess {
|
||||
Expr getQualifier() { result.getParent() = this }
|
||||
|
||||
/** Holds if this variable access has a qualifier. */
|
||||
predicate hasQualifier() { exists(getQualifier()) }
|
||||
predicate hasQualifier() { exists(this.getQualifier()) }
|
||||
|
||||
/** Gets the variable accessed by this variable access. */
|
||||
Variable getVariable() { variableBinding(this, result) }
|
||||
@@ -1580,11 +1640,11 @@ class VarAccess extends Expr, @varaccess {
|
||||
*/
|
||||
predicate isLocal() {
|
||||
// The access has no qualifier, or...
|
||||
not hasQualifier()
|
||||
not this.hasQualifier()
|
||||
or
|
||||
// the qualifier is either `this` or `A.this`, where `A` is the enclosing type, or
|
||||
// the qualifier is either `super` or `A.super`, where `A` is the enclosing type.
|
||||
getQualifier().(InstanceAccess).isOwnInstanceAccess()
|
||||
this.getQualifier().(InstanceAccess).isOwnInstanceAccess()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VarAccess" }
|
||||
@@ -1626,7 +1686,7 @@ class MethodAccess extends Expr, Call, @methodaccess {
|
||||
override Expr getQualifier() { result.isNthChildOf(this, -1) }
|
||||
|
||||
/** Holds if this method access has a qualifier. */
|
||||
predicate hasQualifier() { exists(getQualifier()) }
|
||||
predicate hasQualifier() { exists(this.getQualifier()) }
|
||||
|
||||
/** Gets an argument supplied to the method that is invoked using this method access. */
|
||||
override Expr getAnArgument() { result.getIndex() >= 0 and result.getParent() = this }
|
||||
@@ -1663,9 +1723,9 @@ class MethodAccess extends Expr, Call, @methodaccess {
|
||||
* the enclosing type if there is no qualifier.
|
||||
*/
|
||||
RefType getReceiverType() {
|
||||
result = getQualifier().getType()
|
||||
result = this.getQualifier().getType()
|
||||
or
|
||||
not hasQualifier() and result = getEnclosingCallable().getDeclaringType()
|
||||
not this.hasQualifier() and result = this.getEnclosingCallable().getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1841,7 +1901,7 @@ class Call extends ExprParent, @caller {
|
||||
Callable getCallee() { callableBinding(this, result) }
|
||||
|
||||
/** Gets the callable invoking this call. */
|
||||
Callable getCaller() { result = getEnclosingCallable() }
|
||||
Callable getCaller() { result = this.getEnclosingCallable() }
|
||||
}
|
||||
|
||||
/** A polymorphic call to an instance method. */
|
||||
@@ -2042,14 +2102,14 @@ class Argument extends Expr {
|
||||
}
|
||||
|
||||
/** Holds if this argument is part of an implicit varargs array. */
|
||||
predicate isVararg() { isNthVararg(_) }
|
||||
predicate isVararg() { this.isNthVararg(_) }
|
||||
|
||||
/**
|
||||
* Holds if this argument is part of an implicit varargs array at the
|
||||
* given array index.
|
||||
*/
|
||||
predicate isNthVararg(int arrayindex) {
|
||||
not isExplicitVarargsArray() and
|
||||
not this.isExplicitVarargsArray() and
|
||||
exists(Callable tgt |
|
||||
call.getCallee() = tgt and
|
||||
tgt.isVarargs() and
|
||||
|
||||
@@ -38,7 +38,7 @@ import Type
|
||||
*
|
||||
* For example, `X` in `class X<T> { }`.
|
||||
*/
|
||||
class GenericType extends RefType {
|
||||
class GenericType extends ClassOrInterface {
|
||||
GenericType() { typeVars(_, _, _, _, this) }
|
||||
|
||||
/**
|
||||
@@ -69,12 +69,12 @@ class GenericType extends RefType {
|
||||
/**
|
||||
* Gets a type parameter of this generic type.
|
||||
*/
|
||||
TypeVariable getATypeParameter() { result = getTypeParameter(_) }
|
||||
TypeVariable getATypeParameter() { result = this.getTypeParameter(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of type parameters of this generic type.
|
||||
*/
|
||||
int getNumberOfTypeParameters() { result = strictcount(getATypeParameter()) }
|
||||
int getNumberOfTypeParameters() { result = strictcount(this.getATypeParameter()) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GenericType" }
|
||||
}
|
||||
@@ -107,7 +107,7 @@ abstract class BoundedType extends RefType, @boundedtype {
|
||||
TypeBound getATypeBound() { result.getBoundedType() = this }
|
||||
|
||||
/** Gets the first type bound for this type, if any. */
|
||||
TypeBound getFirstTypeBound() { result = getATypeBound() and result.getPosition() = 0 }
|
||||
TypeBound getFirstTypeBound() { result = this.getATypeBound() and result.getPosition() = 0 }
|
||||
|
||||
/**
|
||||
* Gets an upper type bound of this type, or `Object`
|
||||
@@ -123,9 +123,9 @@ abstract class BoundedType extends RefType, @boundedtype {
|
||||
|
||||
/** Gets a transitive upper bound for this type that is not itself a bounded type. */
|
||||
RefType getAnUltimateUpperBoundType() {
|
||||
result = getUpperBoundType() and not result instanceof BoundedType
|
||||
result = this.getUpperBoundType() and not result instanceof BoundedType
|
||||
or
|
||||
result = getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType()
|
||||
result = this.getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BoundedType" }
|
||||
@@ -139,7 +139,7 @@ abstract class BoundedType extends RefType, @boundedtype {
|
||||
*/
|
||||
class TypeVariable extends BoundedType, @typevariable {
|
||||
/** Gets the generic type that is parameterized by this type parameter, if any. */
|
||||
RefType getGenericType() { typeVars(this, _, _, _, result) }
|
||||
GenericType getGenericType() { typeVars(this, _, _, _, result) }
|
||||
|
||||
/** Gets the generic callable that is parameterized by this type parameter, if any. */
|
||||
GenericCallable getGenericCallable() { typeVars(this, _, _, _, result) }
|
||||
@@ -168,8 +168,8 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
|
||||
/** Gets the lexically enclosing package of this type parameter, if any. */
|
||||
override Package getPackage() {
|
||||
result = getGenericType().getPackage() or
|
||||
result = getGenericCallable().getDeclaringType().getPackage()
|
||||
result = this.getGenericType().getPackage() or
|
||||
result = this.getGenericCallable().getDeclaringType().getPackage()
|
||||
}
|
||||
|
||||
/** Finds a type that was supplied for this parameter. */
|
||||
@@ -190,9 +190,9 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
|
||||
/** Finds a non-typevariable type that was transitively supplied for this parameter. */
|
||||
RefType getAnUltimatelySuppliedType() {
|
||||
result = getASuppliedType() and not result instanceof TypeVariable
|
||||
result = this.getASuppliedType() and not result instanceof TypeVariable
|
||||
or
|
||||
result = getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType()
|
||||
result = this.getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeVariable" }
|
||||
@@ -261,7 +261,7 @@ class Wildcard extends BoundedType, @wildcard {
|
||||
* Holds if this is the unconstrained wildcard `?`.
|
||||
*/
|
||||
predicate isUnconstrained() {
|
||||
not hasLowerBound() and
|
||||
not this.hasLowerBound() and
|
||||
wildcards(this, "?", _)
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ class TypeBound extends @typebound {
|
||||
* For example, `List<Number>` is a parameterization of
|
||||
* the generic type `List<E>`, where `E` is a type parameter.
|
||||
*/
|
||||
class ParameterizedType extends RefType {
|
||||
class ParameterizedType extends ClassOrInterface {
|
||||
ParameterizedType() {
|
||||
typeArgs(_, _, this) or
|
||||
typeVars(_, _, _, _, this)
|
||||
@@ -367,7 +367,9 @@ class ParameterizedType extends RefType {
|
||||
}
|
||||
|
||||
/** Holds if this type originates from source code. */
|
||||
override predicate fromSource() { typeVars(_, _, _, _, this) and RefType.super.fromSource() }
|
||||
override predicate fromSource() {
|
||||
typeVars(_, _, _, _, this) and ClassOrInterface.super.fromSource()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ParameterizedType" }
|
||||
}
|
||||
@@ -451,12 +453,12 @@ class GenericCallable extends Callable {
|
||||
/**
|
||||
* Gets a type parameter of this generic callable.
|
||||
*/
|
||||
TypeVariable getATypeParameter() { result = getTypeParameter(_) }
|
||||
TypeVariable getATypeParameter() { result = this.getTypeParameter(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of type parameters of this generic callable.
|
||||
*/
|
||||
int getNumberOfTypeParameters() { result = strictcount(getATypeParameter()) }
|
||||
int getNumberOfTypeParameters() { result = strictcount(this.getATypeParameter()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -484,10 +486,10 @@ class GenericCall extends Call {
|
||||
|
||||
/** Gets a type argument of the call for the given `TypeVariable`. */
|
||||
RefType getATypeArgument(TypeVariable v) {
|
||||
result = getAnExplicitTypeArgument(v)
|
||||
result = this.getAnExplicitTypeArgument(v)
|
||||
or
|
||||
not exists(getAnExplicitTypeArgument(v)) and
|
||||
result = getAnInferredTypeArgument(v)
|
||||
not exists(this.getAnExplicitTypeArgument(v)) and
|
||||
result = this.getAnInferredTypeArgument(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class ImportType extends Import {
|
||||
ImportType() { imports(this, _, _, 1) }
|
||||
|
||||
/** Gets the imported type. */
|
||||
RefType getImportedType() { imports(this, result, _, _) }
|
||||
ClassOrInterface getImportedType() { imports(this, result, _, _) }
|
||||
|
||||
override string toString() { result = "import " + this.getImportedType().toString() }
|
||||
|
||||
@@ -44,7 +44,7 @@ class ImportOnDemandFromType extends Import {
|
||||
ImportOnDemandFromType() { imports(this, _, _, 2) }
|
||||
|
||||
/** Gets the type from which accessible nested types are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets an imported type. */
|
||||
NestedType getAnImport() { result.getEnclosingType() = this.getTypeHoldingImport() }
|
||||
@@ -87,7 +87,7 @@ class ImportStaticOnDemand extends Import {
|
||||
ImportStaticOnDemand() { imports(this, _, _, 4) }
|
||||
|
||||
/** Gets the type from which accessible static members are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets an imported type. */
|
||||
NestedType getATypeImport() { result.getEnclosingType() = this.getTypeHoldingImport() }
|
||||
@@ -118,7 +118,7 @@ class ImportStaticTypeMember extends Import {
|
||||
ImportStaticTypeMember() { imports(this, _, _, 5) }
|
||||
|
||||
/** Gets the type from which static members with a given name are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets the name of the imported member(s). */
|
||||
override string getName() { imports(this, _, result, _) }
|
||||
|
||||
@@ -19,12 +19,12 @@ class TypeCloneable extends Interface {
|
||||
|
||||
/** The class `java.lang.ProcessBuilder`. */
|
||||
class TypeProcessBuilder extends Class {
|
||||
TypeProcessBuilder() { hasQualifiedName("java.lang", "ProcessBuilder") }
|
||||
TypeProcessBuilder() { this.hasQualifiedName("java.lang", "ProcessBuilder") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.Runtime`. */
|
||||
class TypeRuntime extends Class {
|
||||
TypeRuntime() { hasQualifiedName("java.lang", "Runtime") }
|
||||
TypeRuntime() { this.hasQualifiedName("java.lang", "Runtime") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.String`. */
|
||||
@@ -143,22 +143,22 @@ class ImmutableType extends Type {
|
||||
// --- Java IO ---
|
||||
/** The interface `java.io.Serializable`. */
|
||||
class TypeSerializable extends Interface {
|
||||
TypeSerializable() { hasQualifiedName("java.io", "Serializable") }
|
||||
TypeSerializable() { this.hasQualifiedName("java.io", "Serializable") }
|
||||
}
|
||||
|
||||
/** The interface `java.io.ObjectOutput`. */
|
||||
class TypeObjectOutput extends Interface {
|
||||
TypeObjectOutput() { hasQualifiedName("java.io", "ObjectOutput") }
|
||||
TypeObjectOutput() { this.hasQualifiedName("java.io", "ObjectOutput") }
|
||||
}
|
||||
|
||||
/** The type `java.io.ObjectOutputStream`. */
|
||||
class TypeObjectOutputStream extends RefType {
|
||||
TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") }
|
||||
TypeObjectOutputStream() { this.hasQualifiedName("java.io", "ObjectOutputStream") }
|
||||
}
|
||||
|
||||
/** The type `java.io.ObjectInputStream`. */
|
||||
class TypeObjectInputStream extends RefType {
|
||||
TypeObjectInputStream() { hasQualifiedName("java.io", "ObjectInputStream") }
|
||||
TypeObjectInputStream() { this.hasQualifiedName("java.io", "ObjectInputStream") }
|
||||
}
|
||||
|
||||
/** The class `java.nio.file.Paths`. */
|
||||
@@ -196,8 +196,8 @@ class ProcessBuilderConstructor extends Constructor, ExecCallable {
|
||||
*/
|
||||
class MethodProcessBuilderCommand extends Method, ExecCallable {
|
||||
MethodProcessBuilderCommand() {
|
||||
hasName("command") and
|
||||
getDeclaringType() instanceof TypeProcessBuilder
|
||||
this.hasName("command") and
|
||||
this.getDeclaringType() instanceof TypeProcessBuilder
|
||||
}
|
||||
|
||||
override int getAnExecutedArgument() { result = 0 }
|
||||
@@ -208,8 +208,8 @@ class MethodProcessBuilderCommand extends Method, ExecCallable {
|
||||
*/
|
||||
class MethodRuntimeExec extends Method, ExecCallable {
|
||||
MethodRuntimeExec() {
|
||||
hasName("exec") and
|
||||
getDeclaringType() instanceof TypeRuntime
|
||||
this.hasName("exec") and
|
||||
this.getDeclaringType() instanceof TypeRuntime
|
||||
}
|
||||
|
||||
override int getAnExecutedArgument() { result = 0 }
|
||||
@@ -220,8 +220,8 @@ class MethodRuntimeExec extends Method, ExecCallable {
|
||||
*/
|
||||
class MethodSystemGetenv extends Method {
|
||||
MethodSystemGetenv() {
|
||||
hasName("getenv") and
|
||||
getDeclaringType() instanceof TypeSystem
|
||||
this.hasName("getenv") and
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,8 +230,8 @@ class MethodSystemGetenv extends Method {
|
||||
*/
|
||||
class MethodSystemGetProperty extends Method {
|
||||
MethodSystemGetProperty() {
|
||||
hasName("getProperty") and
|
||||
getDeclaringType() instanceof TypeSystem
|
||||
this.hasName("getProperty") and
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ class MethodSystemGetProperty extends Method {
|
||||
* An access to a method named `getProperty` on class `java.lang.System`.
|
||||
*/
|
||||
class MethodAccessSystemGetProperty extends MethodAccess {
|
||||
MethodAccessSystemGetProperty() { getMethod() instanceof MethodSystemGetProperty }
|
||||
MethodAccessSystemGetProperty() { this.getMethod() instanceof MethodSystemGetProperty }
|
||||
|
||||
/**
|
||||
* Holds if this call has a compile-time constant first argument with the value `propertyName`.
|
||||
@@ -255,8 +255,11 @@ class MethodAccessSystemGetProperty extends MethodAccess {
|
||||
*/
|
||||
class MethodExit extends Method {
|
||||
MethodExit() {
|
||||
hasName("exit") and
|
||||
(getDeclaringType() instanceof TypeRuntime or getDeclaringType() instanceof TypeSystem)
|
||||
this.hasName("exit") and
|
||||
(
|
||||
this.getDeclaringType() instanceof TypeRuntime or
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +269,10 @@ class MethodExit extends Method {
|
||||
*/
|
||||
class WriteObjectMethod extends Method {
|
||||
WriteObjectMethod() {
|
||||
hasName("writeObject") and
|
||||
this.hasName("writeObject") and
|
||||
(
|
||||
getDeclaringType() instanceof TypeObjectOutputStream or
|
||||
getDeclaringType() instanceof TypeObjectOutput
|
||||
this.getDeclaringType() instanceof TypeObjectOutputStream or
|
||||
this.getDeclaringType() instanceof TypeObjectOutput
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -293,16 +296,16 @@ class ReadObjectMethod extends Method {
|
||||
/** The method `Class.getName()`. */
|
||||
class ClassNameMethod extends Method {
|
||||
ClassNameMethod() {
|
||||
hasName("getName") and
|
||||
getDeclaringType() instanceof TypeClass
|
||||
this.hasName("getName") and
|
||||
this.getDeclaringType() instanceof TypeClass
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `Class.getSimpleName()`. */
|
||||
class ClassSimpleNameMethod extends Method {
|
||||
ClassSimpleNameMethod() {
|
||||
hasName("getSimpleName") and
|
||||
getDeclaringType() instanceof TypeClass
|
||||
this.hasName("getSimpleName") and
|
||||
this.getDeclaringType() instanceof TypeClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,24 +337,24 @@ class MethodMathMax extends Method {
|
||||
/** The field `System.in`. */
|
||||
class SystemIn extends Field {
|
||||
SystemIn() {
|
||||
hasName("in") and
|
||||
getDeclaringType() instanceof TypeSystem
|
||||
this.hasName("in") and
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
}
|
||||
}
|
||||
|
||||
/** The field `System.out`. */
|
||||
class SystemOut extends Field {
|
||||
SystemOut() {
|
||||
hasName("out") and
|
||||
getDeclaringType() instanceof TypeSystem
|
||||
this.hasName("out") and
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
}
|
||||
}
|
||||
|
||||
/** The field `System.err`. */
|
||||
class SystemErr extends Field {
|
||||
SystemErr() {
|
||||
hasName("err") and
|
||||
getDeclaringType() instanceof TypeSystem
|
||||
this.hasName("err") and
|
||||
this.getDeclaringType() instanceof TypeSystem
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class SuppressWarningsAnnotation extends Annotation {
|
||||
}
|
||||
|
||||
/** Gets the name of a warning suppressed by this annotation. */
|
||||
string getASuppressedWarning() { result = getASuppressedWarningLiteral().getRepresentedString() }
|
||||
string getASuppressedWarning() { result = this.getASuppressedWarningLiteral().getValue() }
|
||||
}
|
||||
|
||||
/** A `@Target` annotation. */
|
||||
|
||||
@@ -26,27 +26,27 @@ class MXBean extends ManagedBean {
|
||||
*/
|
||||
class RegisteredManagedBeanImpl extends Class {
|
||||
RegisteredManagedBeanImpl() {
|
||||
getAnAncestor() instanceof ManagedBean and
|
||||
this.getAnAncestor() instanceof ManagedBean and
|
||||
exists(JMXRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a managed bean that this registered bean class implements.
|
||||
*/
|
||||
ManagedBean getAnImplementedManagedBean() { result = getAnAncestor() }
|
||||
ManagedBean getAnImplementedManagedBean() { result = this.getAnAncestor() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that registers an object with the `MBeanServer`, directly or indirectly.
|
||||
*/
|
||||
class JMXRegistrationCall extends MethodAccess {
|
||||
JMXRegistrationCall() { getCallee() instanceof JMXRegistrationMethod }
|
||||
JMXRegistrationCall() { this.getCallee() instanceof JMXRegistrationMethod }
|
||||
|
||||
/**
|
||||
* Gets the argument that represents the object in the registration call.
|
||||
*/
|
||||
Expr getObjectArgument() {
|
||||
result = getArgument(getCallee().(JMXRegistrationMethod).getObjectPosition())
|
||||
result = this.getArgument(this.getCallee().(JMXRegistrationMethod).getObjectPosition())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,15 +59,15 @@ class JMXRegistrationCall extends MethodAccess {
|
||||
class JMXRegistrationMethod extends Method {
|
||||
JMXRegistrationMethod() {
|
||||
// A direct registration with the `MBeanServer`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean"
|
||||
this.getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
this.getName() = "registerMBean"
|
||||
or
|
||||
// The `MBeanServer` is often wrapped by an application specific management class, so identify
|
||||
// methods that wrap a call to another `JMXRegistrationMethod`.
|
||||
exists(JMXRegistrationCall c |
|
||||
// This must be a call to another JMX registration method, where the object argument is an access
|
||||
// of one of the parameters of this method.
|
||||
c.getObjectArgument().(VarAccess).getVariable() = getAParameter()
|
||||
c.getObjectArgument().(VarAccess).getVariable() = this.getAParameter()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -76,13 +76,13 @@ class JMXRegistrationMethod extends Method {
|
||||
*/
|
||||
int getObjectPosition() {
|
||||
// Passed as the first argument to `registerMBean`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean" and
|
||||
this.getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
this.getName() = "registerMBean" and
|
||||
result = 0
|
||||
or
|
||||
// Identify the position in this method where the object parameter should be passed.
|
||||
exists(JMXRegistrationCall c |
|
||||
c.getObjectArgument().(VarAccess).getVariable() = getParameter(result)
|
||||
c.getObjectArgument().(VarAccess).getVariable() = this.getParameter(result)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class JavadocParent extends @javadocParent, Top {
|
||||
JavadocElement getChild(int index) { result = this.getAChild() and result.getIndex() = index }
|
||||
|
||||
/** Gets the number of documentation elements attached to this parent. */
|
||||
int getNumChild() { result = count(getAChild()) }
|
||||
int getNumChild() { result = count(this.getAChild()) }
|
||||
|
||||
/** Gets a documentation element with the specified Javadoc tag name. */
|
||||
JavadocTag getATag(string name) { result = this.getAChild() and result.getTagName() = name }
|
||||
@@ -33,7 +33,9 @@ class Javadoc extends JavadocParent, @javadoc {
|
||||
/** Gets the value of the `@author` tag, if any. */
|
||||
string getAuthor() { result = this.getATag("@author").getChild(0).toString() }
|
||||
|
||||
override string toString() { result = toStringPrefix() + getChild(0) + toStringPostfix() }
|
||||
override string toString() {
|
||||
result = this.toStringPrefix() + this.getChild(0) + this.toStringPostfix()
|
||||
}
|
||||
|
||||
private string toStringPrefix() {
|
||||
if isEolComment(this)
|
||||
@@ -47,7 +49,7 @@ class Javadoc extends JavadocParent, @javadoc {
|
||||
if isEolComment(this)
|
||||
then result = ""
|
||||
else (
|
||||
if strictcount(getAChild()) = 1 then result = " */" else result = " ... */"
|
||||
if strictcount(this.getAChild()) = 1 then result = " */" else result = " ... */"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -119,10 +121,10 @@ class ThrowsTag extends JavadocTag {
|
||||
|
||||
/** A Javadoc `@see` tag. */
|
||||
class SeeTag extends JavadocTag {
|
||||
SeeTag() { getTagName() = "@see" }
|
||||
SeeTag() { this.getTagName() = "@see" }
|
||||
|
||||
/** Gets the name of the entity referred to. */
|
||||
string getReference() { result = getChild(0).toString() }
|
||||
string getReference() { result = this.getChild(0).toString() }
|
||||
}
|
||||
|
||||
/** A Javadoc `@author` tag. */
|
||||
|
||||
@@ -76,11 +76,11 @@ class FreshMap extends ClassInstanceExpr {
|
||||
* A call to `Map.put(key, value)`.
|
||||
*/
|
||||
class MapPutCall extends MethodAccess {
|
||||
MapPutCall() { getCallee().(MapMethod).hasName("put") }
|
||||
MapPutCall() { this.getCallee().(MapMethod).hasName("put") }
|
||||
|
||||
/** Gets the key argument of this call. */
|
||||
Expr getKey() { result = getArgument(0) }
|
||||
Expr getKey() { result = this.getArgument(0) }
|
||||
|
||||
/** Gets the value argument of this call. */
|
||||
Expr getValue() { result = getArgument(1) }
|
||||
Expr getValue() { result = this.getArgument(1) }
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class Member extends Element, Annotatable, Modifiable, @member {
|
||||
RefType getDeclaringType() { declaresMember(result, this) }
|
||||
|
||||
/** Gets the qualified name of this member. */
|
||||
string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() }
|
||||
string getQualifiedName() { result = this.getDeclaringType().getName() + "." + this.getName() }
|
||||
|
||||
/**
|
||||
* Holds if this member has the specified name and is declared in the
|
||||
@@ -33,9 +33,9 @@ class Member extends Element, Annotatable, Modifiable, @member {
|
||||
|
||||
/** Holds if this member is package protected, that is, neither public nor private nor protected. */
|
||||
predicate isPackageProtected() {
|
||||
not isPrivate() and
|
||||
not isProtected() and
|
||||
not isPublic()
|
||||
not this.isPrivate() and
|
||||
not this.isProtected() and
|
||||
not this.isPublic()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +78,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
*/
|
||||
string getMethodDescriptor() {
|
||||
exists(string return | return = this.getReturnType().getTypeDescriptor() |
|
||||
result = "(" + descriptorUpTo(this.getNumberOfParameters()) + ")" + return
|
||||
result = "(" + this.descriptorUpTo(this.getNumberOfParameters()) + ")" + return
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,19 +86,19 @@ class Callable extends StmtParent, Member, @callable {
|
||||
n = 0 and result = ""
|
||||
or
|
||||
exists(Parameter p | p = this.getParameter(n - 1) |
|
||||
result = descriptorUpTo(n - 1) + p.getType().getTypeDescriptor()
|
||||
result = this.descriptorUpTo(n - 1) + p.getType().getTypeDescriptor()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this callable calls `target`. */
|
||||
predicate calls(Callable target) { exists(getACallSite(target)) }
|
||||
predicate calls(Callable target) { exists(this.getACallSite(target)) }
|
||||
|
||||
/**
|
||||
* Holds if this callable calls `target`
|
||||
* using a `super(...)` constructor call.
|
||||
*/
|
||||
predicate callsSuperConstructor(Constructor target) {
|
||||
getACallSite(target) instanceof SuperConstructorInvocationStmt
|
||||
this.getACallSite(target) instanceof SuperConstructorInvocationStmt
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,14 +106,14 @@ class Callable extends StmtParent, Member, @callable {
|
||||
* using a `this(...)` constructor call.
|
||||
*/
|
||||
predicate callsThis(Constructor target) {
|
||||
getACallSite(target) instanceof ThisConstructorInvocationStmt
|
||||
this.getACallSite(target) instanceof ThisConstructorInvocationStmt
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this callable calls `target`
|
||||
* using a `super` method call.
|
||||
*/
|
||||
predicate callsSuper(Method target) { getACallSite(target) instanceof SuperMethodAccess }
|
||||
predicate callsSuper(Method target) { this.getACallSite(target) instanceof SuperMethodAccess }
|
||||
|
||||
/**
|
||||
* Holds if this callable calls `c` using
|
||||
@@ -165,13 +165,13 @@ class Callable extends StmtParent, Member, @callable {
|
||||
Field getAnAccessedField() { this.accesses(result) }
|
||||
|
||||
/** Gets the type of a formal parameter of this callable. */
|
||||
Type getAParamType() { result = getParameterType(_) }
|
||||
Type getAParamType() { result = this.getParameterType(_) }
|
||||
|
||||
/** Holds if this callable does not have any formal parameters. */
|
||||
predicate hasNoParameters() { not exists(getAParameter()) }
|
||||
predicate hasNoParameters() { not exists(this.getAParameter()) }
|
||||
|
||||
/** Gets the number of formal parameters of this callable. */
|
||||
int getNumberOfParameters() { result = count(getAParameter()) }
|
||||
int getNumberOfParameters() { result = count(this.getAParameter()) }
|
||||
|
||||
/** Gets a formal parameter of this callable. */
|
||||
Parameter getAParameter() { result.getCallable() = this }
|
||||
@@ -205,7 +205,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
string paramsString() {
|
||||
exists(int n | n = getNumberOfParameters() |
|
||||
exists(int n | n = this.getNumberOfParameters() |
|
||||
n = 0 and result = "()"
|
||||
or
|
||||
n > 0 and result = "(" + this.paramUpTo(n - 1) + ")"
|
||||
@@ -217,9 +217,9 @@ class Callable extends StmtParent, Member, @callable {
|
||||
* from left to right, up to (and including) the `n`-th parameter.
|
||||
*/
|
||||
private string paramUpTo(int n) {
|
||||
n = 0 and result = getParameterType(0).toString()
|
||||
n = 0 and result = this.getParameterType(0).toString()
|
||||
or
|
||||
n > 0 and result = paramUpTo(n - 1) + ", " + getParameterType(n)
|
||||
n > 0 and result = this.paramUpTo(n - 1) + ", " + this.getParameterType(n)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,7 +234,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
Exception getAnException() { exceptions(result, _, this) }
|
||||
|
||||
/** Gets an exception type that occurs in the `throws` clause of this callable. */
|
||||
RefType getAThrownExceptionType() { result = getAnException().getType() }
|
||||
RefType getAThrownExceptionType() { result = this.getAnException().getType() }
|
||||
|
||||
/** Gets a call site that references this callable. */
|
||||
Call getAReference() { result.getCallee() = this }
|
||||
@@ -285,7 +285,20 @@ private predicate overrides(Method m1, Method m2) {
|
||||
or
|
||||
m2.isProtected()
|
||||
or
|
||||
m2.isPackageProtected() and t1.getPackage() = t2.getPackage()
|
||||
m2.isPackageProtected() and
|
||||
pragma[only_bind_out](t1.getPackage()) = pragma[only_bind_out](t2.getPackage())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate overridesCandidateType(RefType tsup, string sig, RefType t, Method m) {
|
||||
virtualMethodWithSignature(sig, t, m) and
|
||||
t.extendsOrImplements(tsup)
|
||||
or
|
||||
exists(RefType mid |
|
||||
overridesCandidateType(mid, sig, t, m) and
|
||||
mid.extendsOrImplements(tsup) and
|
||||
not virtualMethodWithSignature(sig, mid, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -294,11 +307,10 @@ private predicate overrides(Method m1, Method m2) {
|
||||
* ignoring any access modifiers. Additionally, this predicate binds
|
||||
* `t1` to the type declaring `m1` and `t2` to the type declaring `m2`.
|
||||
*/
|
||||
pragma[noopt]
|
||||
cached
|
||||
predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) {
|
||||
exists(string sig |
|
||||
virtualMethodWithSignature(sig, t1, m1) and
|
||||
t1.extendsOrImplements+(t2) and
|
||||
overridesCandidateType(t2, sig, t1, m1) and
|
||||
virtualMethodWithSignature(sig, t2, m2)
|
||||
)
|
||||
}
|
||||
@@ -392,7 +404,7 @@ class Method extends Callable, @method {
|
||||
or
|
||||
// JLS 9.4: Every method declaration in the body of an interface without an
|
||||
// access modifier is implicitly public.
|
||||
getDeclaringType() instanceof Interface and
|
||||
this.getDeclaringType() instanceof Interface and
|
||||
not this.isPrivate()
|
||||
or
|
||||
exists(FunctionalExpr func | func.asMethod() = this)
|
||||
@@ -413,7 +425,7 @@ class Method extends Callable, @method {
|
||||
Callable.super.isStrictfp()
|
||||
or
|
||||
// JLS 8.1.1.3, JLS 9.1.1.2
|
||||
getDeclaringType().isStrictfp()
|
||||
this.getDeclaringType().isStrictfp()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -421,8 +433,8 @@ class Method extends Callable, @method {
|
||||
* nor an initializer method, and hence could be inherited.
|
||||
*/
|
||||
predicate isInheritable() {
|
||||
not isPrivate() and
|
||||
not (isStatic() and getDeclaringType() instanceof Interface) and
|
||||
not this.isPrivate() and
|
||||
not (this.isStatic() and this.getDeclaringType() instanceof Interface) and
|
||||
not this instanceof InitializerMethod
|
||||
}
|
||||
|
||||
@@ -430,13 +442,13 @@ class Method extends Callable, @method {
|
||||
* Holds if this method is neither private nor static, and hence
|
||||
* uses dynamic dispatch.
|
||||
*/
|
||||
predicate isVirtual() { not isPrivate() and not isStatic() }
|
||||
predicate isVirtual() { not this.isPrivate() and not this.isStatic() }
|
||||
|
||||
/** Holds if this method can be overridden. */
|
||||
predicate isOverridable() {
|
||||
isVirtual() and
|
||||
not isFinal() and
|
||||
not getDeclaringType().isFinal()
|
||||
this.isVirtual() and
|
||||
not this.isFinal() and
|
||||
not this.getDeclaringType().isFinal()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Method" }
|
||||
@@ -549,7 +561,7 @@ abstract class InitializerMethod extends Method { }
|
||||
* field initializations and static initializer blocks.
|
||||
*/
|
||||
class StaticInitializer extends InitializerMethod {
|
||||
StaticInitializer() { hasName("<clinit>") }
|
||||
StaticInitializer() { this.hasName("<clinit>") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,7 +641,7 @@ class Field extends Member, ExprParent, @field, Variable {
|
||||
or
|
||||
// JLS 9.3: Every field declaration in the body of an interface is
|
||||
// implicitly public, static, and final
|
||||
getDeclaringType() instanceof Interface
|
||||
this.getDeclaringType() instanceof Interface
|
||||
}
|
||||
|
||||
override predicate isStatic() {
|
||||
|
||||
@@ -25,7 +25,7 @@ abstract class Modifiable extends Element {
|
||||
* abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")`
|
||||
* does not.
|
||||
*/
|
||||
predicate hasModifier(string m) { modifiers(getAModifier(), m) }
|
||||
predicate hasModifier(string m) { modifiers(this.getAModifier(), m) }
|
||||
|
||||
/** Holds if this element has no modifier. */
|
||||
predicate hasNoModifier() { not hasModifier(this, _) }
|
||||
@@ -34,31 +34,31 @@ abstract class Modifiable extends Element {
|
||||
Modifier getAModifier() { this = result.getElement() }
|
||||
|
||||
/** Holds if this element has an `abstract` modifier or is implicitly abstract. */
|
||||
predicate isAbstract() { hasModifier("abstract") }
|
||||
predicate isAbstract() { this.hasModifier("abstract") }
|
||||
|
||||
/** Holds if this element has a `static` modifier or is implicitly static. */
|
||||
predicate isStatic() { hasModifier("static") }
|
||||
predicate isStatic() { this.hasModifier("static") }
|
||||
|
||||
/** Holds if this element has a `final` modifier or is implicitly final. */
|
||||
predicate isFinal() { hasModifier("final") }
|
||||
predicate isFinal() { this.hasModifier("final") }
|
||||
|
||||
/** Holds if this element has a `public` modifier or is implicitly public. */
|
||||
predicate isPublic() { hasModifier("public") }
|
||||
predicate isPublic() { this.hasModifier("public") }
|
||||
|
||||
/** Holds if this element has a `protected` modifier. */
|
||||
predicate isProtected() { hasModifier("protected") }
|
||||
predicate isProtected() { this.hasModifier("protected") }
|
||||
|
||||
/** Holds if this element has a `private` modifier or is implicitly private. */
|
||||
predicate isPrivate() { hasModifier("private") }
|
||||
predicate isPrivate() { this.hasModifier("private") }
|
||||
|
||||
/** Holds if this element has a `volatile` modifier. */
|
||||
predicate isVolatile() { hasModifier("volatile") }
|
||||
predicate isVolatile() { this.hasModifier("volatile") }
|
||||
|
||||
/** Holds if this element has a `synchronized` modifier. */
|
||||
predicate isSynchronized() { hasModifier("synchronized") }
|
||||
predicate isSynchronized() { this.hasModifier("synchronized") }
|
||||
|
||||
/** Holds if this element has a `native` modifier. */
|
||||
predicate isNative() { hasModifier("native") }
|
||||
predicate isNative() { this.hasModifier("native") }
|
||||
|
||||
/** Holds if this element has a `default` modifier. */
|
||||
predicate isDefault() { this.hasModifier("default") }
|
||||
|
||||
@@ -169,27 +169,27 @@ private class PpArrayCreationExpr extends PpAst, ArrayCreationExpr {
|
||||
override string getPart(int i) {
|
||||
i = 0 and result = "new "
|
||||
or
|
||||
i = 1 and result = baseType()
|
||||
i = 1 and result = this.baseType()
|
||||
or
|
||||
i = 2 + 3 * dimensionIndex() and result = "["
|
||||
i = 2 + 3 * this.dimensionIndex() and result = "["
|
||||
or
|
||||
i = 4 + 3 * dimensionIndex() and result = "]"
|
||||
i = 4 + 3 * this.dimensionIndex() and result = "]"
|
||||
or
|
||||
i = 4 + 3 * exprDims() + [1 .. nonExprDims()] and result = "[]"
|
||||
i = 4 + 3 * this.exprDims() + [1 .. this.nonExprDims()] and result = "[]"
|
||||
}
|
||||
|
||||
private string baseType() { result = this.getType().(Array).getElementType().toString() }
|
||||
|
||||
private int dimensionIndex() { exists(this.getDimension(result)) }
|
||||
|
||||
private int exprDims() { result = max(int j | j = 0 or j = 1 + dimensionIndex()) }
|
||||
private int exprDims() { result = max(int j | j = 0 or j = 1 + this.dimensionIndex()) }
|
||||
|
||||
private int nonExprDims() { result = this.getType().(Array).getDimension() - exprDims() }
|
||||
private int nonExprDims() { result = this.getType().(Array).getDimension() - this.exprDims() }
|
||||
|
||||
override PpAst getChild(int i) {
|
||||
exists(int j | result = this.getDimension(j) and i = 3 + 3 * j)
|
||||
or
|
||||
i = 5 + 3 * exprDims() + nonExprDims() and result = this.getInit()
|
||||
i = 5 + 3 * this.exprDims() + this.nonExprDims() and result = this.getInit()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,27 +539,27 @@ private class PpForStmt extends PpAst, ForStmt {
|
||||
or
|
||||
exists(int j | j > 0 and exists(this.getInit(j)) and i = 2 + 2 * j and result = ", ")
|
||||
or
|
||||
i = 1 + lastInitIndex() and result = "; "
|
||||
i = 1 + this.lastInitIndex() and result = "; "
|
||||
or
|
||||
i = 3 + lastInitIndex() and result = "; "
|
||||
i = 3 + this.lastInitIndex() and result = "; "
|
||||
or
|
||||
exists(int j |
|
||||
j > 0 and exists(this.getUpdate(j)) and i = 3 + lastInitIndex() + 2 * j and result = ", "
|
||||
j > 0 and exists(this.getUpdate(j)) and i = 3 + this.lastInitIndex() + 2 * j and result = ", "
|
||||
)
|
||||
or
|
||||
i = 1 + lastUpdateIndex() and result = ")"
|
||||
i = 1 + this.lastUpdateIndex() and result = ")"
|
||||
or
|
||||
i = 2 + lastUpdateIndex() and result = " " and this.getStmt() instanceof BlockStmt
|
||||
i = 2 + this.lastUpdateIndex() and result = " " and this.getStmt() instanceof BlockStmt
|
||||
}
|
||||
|
||||
private int lastInitIndex() { result = 3 + 2 * max(int j | exists(this.getInit(j))) }
|
||||
|
||||
private int lastUpdateIndex() {
|
||||
result = 4 + lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j)))
|
||||
result = 4 + this.lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j)))
|
||||
}
|
||||
|
||||
override predicate newline(int i) {
|
||||
i = 2 + lastUpdateIndex() and not this.getStmt() instanceof BlockStmt
|
||||
i = 2 + this.lastUpdateIndex() and not this.getStmt() instanceof BlockStmt
|
||||
}
|
||||
|
||||
override PpAst getChild(int i) {
|
||||
@@ -567,15 +567,15 @@ private class PpForStmt extends PpAst, ForStmt {
|
||||
or
|
||||
exists(int j | result = this.getInit(j) and i = 3 + 2 * j)
|
||||
or
|
||||
i = 2 + lastInitIndex() and result = this.getCondition()
|
||||
i = 2 + this.lastInitIndex() and result = this.getCondition()
|
||||
or
|
||||
exists(int j | result = this.getUpdate(j) and i = 4 + lastInitIndex() + 2 * j)
|
||||
exists(int j | result = this.getUpdate(j) and i = 4 + this.lastInitIndex() + 2 * j)
|
||||
or
|
||||
i = 3 + lastUpdateIndex() and result = this.getStmt()
|
||||
i = 3 + this.lastUpdateIndex() and result = this.getStmt()
|
||||
}
|
||||
|
||||
override predicate indents(int i) {
|
||||
i = 3 + lastUpdateIndex() and not this.getStmt() instanceof BlockStmt
|
||||
i = 3 + this.lastUpdateIndex() and not this.getStmt() instanceof BlockStmt
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,9 +654,9 @@ private class PpTryStmt extends PpAst, TryStmt {
|
||||
or
|
||||
exists(int j | exists(this.getResourceExpr(j)) and i = 3 + 2 * j and result = ";")
|
||||
or
|
||||
i = 2 + lastResourceIndex() and result = ") " and exists(this.getAResource())
|
||||
i = 2 + this.lastResourceIndex() and result = ") " and exists(this.getAResource())
|
||||
or
|
||||
i = 1 + lastCatchIndex() and result = " finally " and exists(this.getFinally())
|
||||
i = 1 + this.lastCatchIndex() and result = " finally " and exists(this.getFinally())
|
||||
}
|
||||
|
||||
private int lastResourceIndex() {
|
||||
@@ -664,17 +664,17 @@ private class PpTryStmt extends PpAst, TryStmt {
|
||||
}
|
||||
|
||||
private int lastCatchIndex() {
|
||||
result = 4 + lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0)
|
||||
result = 4 + this.lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0)
|
||||
}
|
||||
|
||||
override PpAst getChild(int i) {
|
||||
exists(int j | i = 2 + 2 * j and result = this.getResource(j))
|
||||
or
|
||||
i = 3 + lastResourceIndex() and result = this.getBlock()
|
||||
i = 3 + this.lastResourceIndex() and result = this.getBlock()
|
||||
or
|
||||
exists(int j | i = 4 + lastResourceIndex() + j and result = this.getCatchClause(j))
|
||||
exists(int j | i = 4 + this.lastResourceIndex() + j and result = this.getCatchClause(j))
|
||||
or
|
||||
i = 2 + lastCatchIndex() and result = this.getFinally()
|
||||
i = 2 + this.lastCatchIndex() and result = this.getFinally()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,11 +728,11 @@ private class PpSwitchCase extends PpAst, SwitchCase {
|
||||
or
|
||||
exists(int j | i = 2 * j and j != 0 and result = ", " and exists(this.(ConstCase).getValue(j)))
|
||||
or
|
||||
i = 1 + lastConstCaseValueIndex() and result = ":" and not this.isRule()
|
||||
i = 1 + this.lastConstCaseValueIndex() and result = ":" and not this.isRule()
|
||||
or
|
||||
i = 1 + lastConstCaseValueIndex() and result = " -> " and this.isRule()
|
||||
i = 1 + this.lastConstCaseValueIndex() and result = " -> " and this.isRule()
|
||||
or
|
||||
i = 3 + lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression())
|
||||
i = 3 + this.lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression())
|
||||
}
|
||||
|
||||
private int lastConstCaseValueIndex() {
|
||||
@@ -742,9 +742,9 @@ private class PpSwitchCase extends PpAst, SwitchCase {
|
||||
override PpAst getChild(int i) {
|
||||
exists(int j | i = 1 + 2 * j and result = this.(ConstCase).getValue(j))
|
||||
or
|
||||
i = 2 + lastConstCaseValueIndex() and result = this.getRuleExpression()
|
||||
i = 2 + this.lastConstCaseValueIndex() and result = this.getRuleExpression()
|
||||
or
|
||||
i = 2 + lastConstCaseValueIndex() and result = this.getRuleStatement()
|
||||
i = 2 + this.lastConstCaseValueIndex() and result = this.getRuleStatement()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
/**
|
||||
* Gets a child of this node.
|
||||
*/
|
||||
final PrintAstNode getAChild() { result = getChild(_) }
|
||||
final PrintAstNode getAChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the parent of this node, if any.
|
||||
@@ -169,7 +169,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and
|
||||
result = toString()
|
||||
result = this.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +178,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* this.
|
||||
*/
|
||||
string getChildEdgeLabel(int childIndex) {
|
||||
exists(getChild(childIndex)) and
|
||||
exists(this.getChild(childIndex)) and
|
||||
result = childIndex.toString()
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ final class AnnotationPartNode extends ExprStmtNode {
|
||||
override ElementNode getChild(int childIndex) {
|
||||
result.getElement() =
|
||||
rank[childIndex](Element ch, string file, int line, int column |
|
||||
ch = getAnAnnotationChild() and locationSortKeys(ch, file, line, column)
|
||||
ch = this.getAnAnnotationChild() and locationSortKeys(ch, file, line, column)
|
||||
|
|
||||
ch order by file, line, column
|
||||
)
|
||||
@@ -352,7 +352,7 @@ private class SingleLocalVarDeclParent extends ExprOrStmt {
|
||||
LocalVariableDeclExpr getVariable() { result.getParent() = this }
|
||||
|
||||
/** Gets the type access of the variable */
|
||||
Expr getTypeAccess() { result = getVariable().getTypeAccess() }
|
||||
Expr getTypeAccess() { result = this.getVariable().getTypeAccess() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,7 +460,7 @@ final class ClassInterfaceNode extends ElementNode {
|
||||
childIndex >= 0 and
|
||||
result.(ElementNode).getElement() =
|
||||
rank[childIndex](Element e, string file, int line, int column |
|
||||
e = getADeclaration() and locationSortKeys(e, file, line, column)
|
||||
e = this.getADeclaration() and locationSortKeys(e, file, line, column)
|
||||
|
|
||||
e order by file, line, column
|
||||
)
|
||||
@@ -507,7 +507,7 @@ final class CompilationUnitNode extends ElementNode {
|
||||
childIndex >= 0 and
|
||||
result.(ElementNode).getElement() =
|
||||
rank[childIndex](Element e, string file, int line, int column |
|
||||
e = getADeclaration() and locationSortKeys(e, file, line, column)
|
||||
e = this.getADeclaration() and locationSortKeys(e, file, line, column)
|
||||
|
|
||||
e order by file, line, column
|
||||
)
|
||||
@@ -665,7 +665,7 @@ final class GenericTypeNode extends PrintAstNode, TGenericTypeNode {
|
||||
override Location getLocation() { none() }
|
||||
|
||||
override ElementNode getChild(int childIndex) {
|
||||
result.getElement().(TypeVariable) = ty.getTypeParameter(childIndex)
|
||||
result.getElement() = ty.getTypeParameter(childIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -686,7 +686,7 @@ final class GenericCallableNode extends PrintAstNode, TGenericCallableNode {
|
||||
override string toString() { result = "(Generic Parameters)" }
|
||||
|
||||
override ElementNode getChild(int childIndex) {
|
||||
result.getElement().(TypeVariable) = c.getTypeParameter(childIndex)
|
||||
result.getElement() = c.getTypeParameter(childIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,7 +55,7 @@ abstract private class ReflectiveClassIdentifier extends Expr {
|
||||
|
||||
private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier, TypeLiteral {
|
||||
override RefType getReflectivelyIdentifiedClass() {
|
||||
result = getReferencedType().(RefType).getSourceDeclaration()
|
||||
result = this.getReferencedType().(RefType).getSourceDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,21 +65,21 @@ private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier
|
||||
class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdentifier, MethodAccess {
|
||||
ReflectiveClassIdentifierMethodAccess() {
|
||||
// A call to `Class.forName(...)`, from which we can infer `T` in the returned type `Class<T>`.
|
||||
getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName")
|
||||
this.getCallee().getDeclaringType() instanceof TypeClass and this.getCallee().hasName("forName")
|
||||
or
|
||||
// A call to `ClassLoader.loadClass(...)`, from which we can infer `T` in the returned type `Class<T>`.
|
||||
getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and
|
||||
getCallee().hasName("loadClass")
|
||||
this.getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and
|
||||
this.getCallee().hasName("loadClass")
|
||||
}
|
||||
|
||||
/**
|
||||
* If the argument to this call is a `StringLiteral`, then return that string.
|
||||
*/
|
||||
string getTypeName() { result = getArgument(0).(StringLiteral).getRepresentedString() }
|
||||
string getTypeName() { result = this.getArgument(0).(StringLiteral).getValue() }
|
||||
|
||||
override RefType getReflectivelyIdentifiedClass() {
|
||||
// We only handle cases where the class is specified as a string literal to this call.
|
||||
result.getQualifiedName() = getTypeName()
|
||||
result.getQualifiedName() = this.getTypeName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ private Type parameterForSubTypes(ParameterizedType type) {
|
||||
lowerBound = arg.(Wildcard).getLowerBoundType()
|
||||
|
|
||||
// `T super Foo` implies that `Foo`, or any super-type of `Foo`, may be represented.
|
||||
lowerBound.(RefType).getAnAncestor() = result
|
||||
lowerBound.getAnAncestor() = result
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -214,10 +214,10 @@ private predicate expectsEnclosingInstance(RefType r) {
|
||||
class NewInstance extends MethodAccess {
|
||||
NewInstance() {
|
||||
(
|
||||
getCallee().getDeclaringType() instanceof TypeClass or
|
||||
getCallee().getDeclaringType() instanceof TypeConstructor
|
||||
this.getCallee().getDeclaringType() instanceof TypeClass or
|
||||
this.getCallee().getDeclaringType() instanceof TypeConstructor
|
||||
) and
|
||||
getCallee().hasName("newInstance")
|
||||
this.getCallee().hasName("newInstance")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,26 +225,26 @@ class NewInstance extends MethodAccess {
|
||||
* called.
|
||||
*/
|
||||
Constructor getInferredConstructor() {
|
||||
result = getInferredConstructedType().getAConstructor() and
|
||||
if getCallee().getDeclaringType() instanceof TypeClass
|
||||
result = this.getInferredConstructedType().getAConstructor() and
|
||||
if this.getCallee().getDeclaringType() instanceof TypeClass
|
||||
then result.getNumberOfParameters() = 0
|
||||
else
|
||||
if getNumArgument() = 1 and getArgument(0).getType() instanceof Array
|
||||
if this.getNumArgument() = 1 and this.getArgument(0).getType() instanceof Array
|
||||
then
|
||||
// This is a var-args array argument. If array argument is initialized inline, then identify
|
||||
// the number of arguments specified in the array.
|
||||
if exists(getArgument(0).(ArrayCreationExpr).getInit())
|
||||
if exists(this.getArgument(0).(ArrayCreationExpr).getInit())
|
||||
then
|
||||
// Count the number of elements in the initializer, and find the matching constructors.
|
||||
matchConstructorArguments(result,
|
||||
count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit()))
|
||||
this.matchConstructorArguments(result,
|
||||
count(this.getArgument(0).(ArrayCreationExpr).getInit().getAnInit()))
|
||||
else
|
||||
// Could be any of the constructors on this class.
|
||||
any()
|
||||
else
|
||||
// No var-args in play, just use the number of arguments to the `newInstance(..)` to determine
|
||||
// which constructors may be called.
|
||||
matchConstructorArguments(result, getNumArgument())
|
||||
this.matchConstructorArguments(result, this.getNumArgument())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,13 +273,13 @@ class NewInstance extends MethodAccess {
|
||||
not result instanceof TypeVariable and
|
||||
(
|
||||
// If this is called on a `Class<T>` instance, return the inferred type `T`.
|
||||
result = inferClassParameterType(getQualifier())
|
||||
result = inferClassParameterType(this.getQualifier())
|
||||
or
|
||||
// If this is called on a `Constructor<T>` instance, return the inferred type `T`.
|
||||
result = inferConstructorParameterType(getQualifier())
|
||||
result = inferConstructorParameterType(this.getQualifier())
|
||||
or
|
||||
// If the result of this is cast to a particular type, then use that type.
|
||||
result = getCastInferredConstructedTypes()
|
||||
result = this.getCastInferredConstructedTypes()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ class ClassMethodAccess extends MethodAccess {
|
||||
// `TypeVariable`s do not have methods themselves.
|
||||
not result instanceof TypeVariable and
|
||||
// If this is called on a `Class<T>` instance, return the inferred type `T`.
|
||||
result = inferClassParameterType(getQualifier())
|
||||
result = inferClassParameterType(this.getQualifier())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,13 +354,13 @@ class ReflectiveMethodAccess extends ClassMethodAccess {
|
||||
if this.getCallee().hasName("getDeclaredMethod")
|
||||
then
|
||||
// The method must be declared on the type itself.
|
||||
result.getDeclaringType() = getInferredClassType()
|
||||
result.getDeclaringType() = this.getInferredClassType()
|
||||
else
|
||||
// The method may be declared on an inferred type or a super-type.
|
||||
getInferredClassType().inherits(result)
|
||||
this.getInferredClassType().inherits(result)
|
||||
) and
|
||||
// Only consider instances where the method name is provided as a `StringLiteral`.
|
||||
result.hasName(getArgument(0).(StringLiteral).getRepresentedString())
|
||||
result.hasName(this.getArgument(0).(StringLiteral).getValue())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +373,9 @@ class ReflectiveAnnotationAccess extends ClassMethodAccess {
|
||||
/**
|
||||
* Gets a possible annotation type for this reflective annotation access.
|
||||
*/
|
||||
AnnotationType getAPossibleAnnotationType() { result = inferClassParameterType(getArgument(0)) }
|
||||
AnnotationType getAPossibleAnnotationType() {
|
||||
result = inferClassParameterType(this.getArgument(0))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,13 +393,13 @@ class ReflectiveFieldAccess extends ClassMethodAccess {
|
||||
if this.getCallee().hasName("getDeclaredField")
|
||||
then
|
||||
// Declared fields must be on the type itself.
|
||||
result.getDeclaringType() = getInferredClassType()
|
||||
result.getDeclaringType() = this.getInferredClassType()
|
||||
else (
|
||||
// This field must be public, and be inherited by one of the inferred class types.
|
||||
result.isPublic() and
|
||||
getInferredClassType().inherits(result)
|
||||
this.getInferredClassType().inherits(result)
|
||||
)
|
||||
) and
|
||||
result.hasName(getArgument(0).(StringLiteral).getRepresentedString())
|
||||
result.hasName(this.getArgument(0).(StringLiteral).getValue())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class BlockStmt extends Stmt, @block {
|
||||
int getNumStmt() { result = count(this.getAStmt()) }
|
||||
|
||||
/** Gets the last statement in this block. */
|
||||
Stmt getLastStmt() { result = getStmt(getNumStmt() - 1) }
|
||||
Stmt getLastStmt() { result = this.getStmt(this.getNumStmt() - 1) }
|
||||
|
||||
override string pp() { result = "{ ... }" }
|
||||
|
||||
@@ -93,7 +93,7 @@ class SingletonBlock extends BlockStmt {
|
||||
SingletonBlock() { this.getNumStmt() = 1 }
|
||||
|
||||
/** Gets the single statement in this block. */
|
||||
Stmt getStmt() { result = getStmt(0) }
|
||||
Stmt getStmt() { result = this.getStmt(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +125,7 @@ class IfStmt extends ConditionalStmt, @ifstmt {
|
||||
* Gets the statement that is executed whenever the condition
|
||||
* of this branch statement evaluates to `true`.
|
||||
*/
|
||||
deprecated override Stmt getTrueSuccessor() { result = getThen() }
|
||||
deprecated override Stmt getTrueSuccessor() { result = this.getThen() }
|
||||
|
||||
/** Gets the `else` branch of this `if` statement. */
|
||||
Stmt getElse() { result.isNthChildOf(this, 2) }
|
||||
@@ -155,7 +155,7 @@ class ForStmt extends ConditionalStmt, @forstmt {
|
||||
|
||||
/** Gets the initializer expression of the loop at the specified (zero-based) position. */
|
||||
Expr getInit(int index) {
|
||||
result = getAnInit() and
|
||||
result = this.getAnInit() and
|
||||
index = -1 - result.getIndex()
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ class ForStmt extends ConditionalStmt, @forstmt {
|
||||
|
||||
/** Gets the update expression of this loop at the specified (zero-based) position. */
|
||||
Expr getUpdate(int index) {
|
||||
result = getAnUpdate() and
|
||||
result = this.getAnUpdate() and
|
||||
index = result.getIndex() - 3
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ class ForStmt extends ConditionalStmt, @forstmt {
|
||||
* Gets the statement that is executed whenever the condition
|
||||
* of this branch statement evaluates to true.
|
||||
*/
|
||||
deprecated override Stmt getTrueSuccessor() { result = getStmt() }
|
||||
deprecated override Stmt getTrueSuccessor() { result = this.getStmt() }
|
||||
|
||||
/**
|
||||
* Gets a variable that is used as an iteration variable: it is defined,
|
||||
@@ -193,12 +193,12 @@ class ForStmt extends ConditionalStmt, @forstmt {
|
||||
*/
|
||||
Variable getAnIterationVariable() {
|
||||
// Check that the variable is assigned to, incremented or decremented in the update expression, and...
|
||||
exists(Expr update | update = getAnUpdate().getAChildExpr*() |
|
||||
exists(Expr update | update = this.getAnUpdate().getAChildExpr*() |
|
||||
update.(UnaryAssignExpr).getExpr() = result.getAnAccess() or
|
||||
update = result.getAnAssignedValue()
|
||||
) and
|
||||
// ...that it is checked or used in the condition.
|
||||
getCondition().getAChildExpr*() = result.getAnAccess()
|
||||
this.getCondition().getAChildExpr*() = result.getAnAccess()
|
||||
}
|
||||
|
||||
override string pp() { result = "for (...;...;...) " + this.getStmt().pp() }
|
||||
@@ -242,7 +242,7 @@ class WhileStmt extends ConditionalStmt, @whilestmt {
|
||||
* Gets the statement that is executed whenever the condition
|
||||
* of this branch statement evaluates to true.
|
||||
*/
|
||||
deprecated override Stmt getTrueSuccessor() { result = getStmt() }
|
||||
deprecated override Stmt getTrueSuccessor() { result = this.getStmt() }
|
||||
|
||||
override string pp() { result = "while (...) " + this.getStmt().pp() }
|
||||
|
||||
@@ -265,7 +265,7 @@ class DoStmt extends ConditionalStmt, @dostmt {
|
||||
* Gets the statement that is executed whenever the condition
|
||||
* of this branch statement evaluates to `true`.
|
||||
*/
|
||||
deprecated override Stmt getTrueSuccessor() { result = getStmt() }
|
||||
deprecated override Stmt getTrueSuccessor() { result = this.getStmt() }
|
||||
|
||||
override string pp() { result = "do " + this.getStmt().pp() + " while (...)" }
|
||||
|
||||
@@ -343,17 +343,17 @@ class TryStmt extends Stmt, @trystmt {
|
||||
}
|
||||
|
||||
/** Gets a resource in this `try` statement, if any. */
|
||||
ExprParent getAResource() { result = getAResourceDecl() or result = getAResourceExpr() }
|
||||
ExprParent getAResource() { result = this.getAResourceDecl() or result = this.getAResourceExpr() }
|
||||
|
||||
/** Gets the resource at the specified position in this `try` statement. */
|
||||
ExprParent getResource(int index) {
|
||||
result = getResourceDecl(index) or result = getResourceExpr(index)
|
||||
result = this.getResourceDecl(index) or result = this.getResourceExpr(index)
|
||||
}
|
||||
|
||||
/** Gets a resource variable, if any, either from a resource variable declaration or resource expression. */
|
||||
Variable getAResourceVariable() {
|
||||
result = getAResourceDecl().getAVariable().getVariable() or
|
||||
result = getAResourceExpr().getVariable()
|
||||
result = this.getAResourceDecl().getAVariable().getVariable() or
|
||||
result = this.getAResourceExpr().getVariable()
|
||||
}
|
||||
|
||||
override string pp() { result = "try " + this.getBlock().pp() + " catch (...)" }
|
||||
@@ -381,7 +381,7 @@ class CatchClause extends Stmt, @catchclause {
|
||||
|
||||
/** Gets a type caught by this `catch` clause. */
|
||||
RefType getACaughtType() {
|
||||
exists(Expr ta | ta = getVariable().getTypeAccess() |
|
||||
exists(Expr ta | ta = this.getVariable().getTypeAccess() |
|
||||
result = ta.(TypeAccess).getType() or
|
||||
result = ta.(UnionTypeAccess).getAnAlternative().getType()
|
||||
)
|
||||
@@ -411,7 +411,7 @@ class SwitchStmt extends Stmt, @switchstmt {
|
||||
* Gets a case of this `switch` statement,
|
||||
* which may be either a normal `case` or a `default`.
|
||||
*/
|
||||
SwitchCase getACase() { result = getAConstCase() or result = getDefaultCase() }
|
||||
SwitchCase getACase() { result = this.getAConstCase() or result = this.getDefaultCase() }
|
||||
|
||||
/** Gets a (non-default) `case` of this `switch` statement. */
|
||||
ConstCase getAConstCase() { result.getParent() = this }
|
||||
@@ -550,7 +550,7 @@ class ThrowStmt extends Stmt, @throwstmt {
|
||||
override string getHalsteadID() { result = "ThrowStmt" }
|
||||
|
||||
/** Gets the type of the expression thrown by this `throw` statement. */
|
||||
RefType getThrownExceptionType() { result = getExpr().getType() }
|
||||
RefType getThrownExceptionType() { result = this.getExpr().getType() }
|
||||
|
||||
/**
|
||||
* Gets the `catch` clause that catches the exception
|
||||
@@ -559,15 +559,15 @@ class ThrowStmt extends Stmt, @throwstmt {
|
||||
* provided such a `catch` exists.
|
||||
*/
|
||||
CatchClause getLexicalCatchIfAny() {
|
||||
exists(TryStmt try | try = findEnclosing() and result = catchClauseForThis(try))
|
||||
exists(TryStmt try | try = this.findEnclosing() and result = this.catchClauseForThis(try))
|
||||
}
|
||||
|
||||
private Stmt findEnclosing() {
|
||||
result = getEnclosingStmt()
|
||||
result = this.getEnclosingStmt()
|
||||
or
|
||||
exists(Stmt mid |
|
||||
mid = findEnclosing() and
|
||||
not exists(this.catchClauseForThis(mid.(TryStmt))) and
|
||||
mid = this.findEnclosing() and
|
||||
not exists(this.catchClauseForThis(mid)) and
|
||||
result = mid.getEnclosingStmt()
|
||||
)
|
||||
}
|
||||
@@ -575,7 +575,7 @@ class ThrowStmt extends Stmt, @throwstmt {
|
||||
private CatchClause catchClauseForThis(TryStmt try) {
|
||||
result = try.getACatchClause() and
|
||||
result.getEnclosingCallable() = this.getEnclosingCallable() and
|
||||
getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType().(RefType)) and
|
||||
this.getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType()) and
|
||||
not this.getEnclosingStmt+() = result
|
||||
}
|
||||
|
||||
@@ -599,7 +599,7 @@ class JumpStmt extends Stmt {
|
||||
namestrings(result.getLabel(), _, this)
|
||||
}
|
||||
|
||||
private Stmt getLabelTarget() { result = getTargetLabel().getStmt() }
|
||||
private Stmt getLabelTarget() { result = this.getTargetLabel().getStmt() }
|
||||
|
||||
private Stmt getAPotentialTarget() {
|
||||
this.getEnclosingStmt+() = result and
|
||||
@@ -613,20 +613,20 @@ class JumpStmt extends Stmt {
|
||||
private SwitchExpr getSwitchExprTarget() { result = this.(YieldStmt).getParent+() }
|
||||
|
||||
private StmtParent getEnclosingTarget() {
|
||||
result = getSwitchExprTarget()
|
||||
result = this.getSwitchExprTarget()
|
||||
or
|
||||
not exists(getSwitchExprTarget()) and
|
||||
result = getAPotentialTarget() and
|
||||
not exists(Stmt other | other = getAPotentialTarget() | other.getEnclosingStmt+() = result)
|
||||
not exists(this.getSwitchExprTarget()) and
|
||||
result = this.getAPotentialTarget() and
|
||||
not exists(Stmt other | other = this.getAPotentialTarget() | other.getEnclosingStmt+() = result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the statement or `switch` expression that this `break`, `yield` or `continue` jumps to.
|
||||
*/
|
||||
StmtParent getTarget() {
|
||||
result = getLabelTarget()
|
||||
result = this.getLabelTarget()
|
||||
or
|
||||
not exists(getLabelTarget()) and result = getEnclosingTarget()
|
||||
not exists(this.getLabelTarget()) and result = this.getEnclosingTarget()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,9 +714,9 @@ class ExprStmt extends Stmt, @exprstmt {
|
||||
|
||||
/** Holds if this statement represents a field declaration with an initializer. */
|
||||
predicate isFieldDecl() {
|
||||
getEnclosingCallable() instanceof InitializerMethod and
|
||||
this.getEnclosingCallable() instanceof InitializerMethod and
|
||||
exists(FieldDeclaration fd, Location fdl, Location sl |
|
||||
fdl = fd.getLocation() and sl = getLocation()
|
||||
fdl = fd.getLocation() and sl = this.getLocation()
|
||||
|
|
||||
fdl.getFile() = sl.getFile() and
|
||||
fdl.getStartLine() = sl.getStartLine() and
|
||||
@@ -775,7 +775,7 @@ class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt {
|
||||
}
|
||||
|
||||
/** Gets an index of a variable declared in this local variable declaration statement. */
|
||||
int getAVariableIndex() { exists(getVariable(result)) }
|
||||
int getAVariableIndex() { exists(this.getVariable(result)) }
|
||||
|
||||
override string pp() { result = "var ...;" }
|
||||
|
||||
|
||||
@@ -152,15 +152,15 @@ class FormattingCall extends Call {
|
||||
private Expr getLastArg() {
|
||||
exists(Expr last | last = this.getArgument(this.getNumArgument() - 1) |
|
||||
if this.hasExplicitVarargsArray()
|
||||
then result = last.(ArrayCreationExpr).getInit().getInit(getVarargsCount() - 1)
|
||||
then result = last.(ArrayCreationExpr).getInit().getInit(this.getVarargsCount() - 1)
|
||||
else result = last
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this uses the "logger ({})" format syntax and the last argument is a `Throwable`. */
|
||||
predicate hasTrailingThrowableArgument() {
|
||||
getSyntax() = TFmtLogger() and
|
||||
getLastArg().getType().(RefType).getASourceSupertype*() instanceof TypeThrowable
|
||||
this.getSyntax() = TFmtLogger() and
|
||||
this.getLastArg().getType().(RefType).getASourceSupertype*() instanceof TypeThrowable
|
||||
}
|
||||
|
||||
/** Gets the argument to this call in the position of the format string */
|
||||
@@ -171,7 +171,7 @@ class FormattingCall extends Call {
|
||||
exists(int i |
|
||||
result = this.getArgument(i) and
|
||||
i > this.getFormatStringIndex() and
|
||||
not hasExplicitVarargsArray()
|
||||
not this.hasExplicitVarargsArray()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ private predicate formatStringFragment(Expr fmt) {
|
||||
private predicate formatStringValue(Expr e, string fmtvalue) {
|
||||
formatStringFragment(e) and
|
||||
(
|
||||
e.(StringLiteral).getRepresentedString() = fmtvalue
|
||||
e.(StringLiteral).getValue() = fmtvalue
|
||||
or
|
||||
e.getType() instanceof IntegralType and fmtvalue = "1" // dummy value
|
||||
or
|
||||
@@ -318,7 +318,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) {
|
||||
getprop.hasName("getProperty") and
|
||||
getprop.getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
getprop.getNumberOfParameters() = 1 and
|
||||
ma.getAnArgument().(StringLiteral).getRepresentedString() = prop and
|
||||
ma.getAnArgument().(StringLiteral).getValue() = prop and
|
||||
(prop = "line.separator" or prop = "file.separator" or prop = "path.separator") and
|
||||
fmtvalue = "x" // dummy value
|
||||
)
|
||||
@@ -433,15 +433,15 @@ private class PrintfFormatString extends FormatString {
|
||||
override int getMaxFmtSpecIndex() {
|
||||
result =
|
||||
max(int ix |
|
||||
ix = fmtSpecRefersToSpecificIndex(_) or
|
||||
ix = count(int i | fmtSpecRefersToSequentialIndex(i))
|
||||
ix = this.fmtSpecRefersToSpecificIndex(_) or
|
||||
ix = count(int i | this.fmtSpecRefersToSequentialIndex(i))
|
||||
)
|
||||
}
|
||||
|
||||
override int getASkippedFmtSpecIndex() {
|
||||
result in [1 .. getMaxFmtSpecIndex()] and
|
||||
result > count(int i | fmtSpecRefersToSequentialIndex(i)) and
|
||||
not result = fmtSpecRefersToSpecificIndex(_)
|
||||
result in [1 .. this.getMaxFmtSpecIndex()] and
|
||||
result > count(int i | this.fmtSpecRefersToSequentialIndex(i)) and
|
||||
not result = this.fmtSpecRefersToSpecificIndex(_)
|
||||
}
|
||||
|
||||
private int getFmtSpecRank(int specOffset) {
|
||||
@@ -449,14 +449,14 @@ private class PrintfFormatString extends FormatString {
|
||||
}
|
||||
|
||||
override int getAnArgUsageOffset(int argNo) {
|
||||
argNo = fmtSpecRefersToSpecificIndex(result)
|
||||
argNo = this.fmtSpecRefersToSpecificIndex(result)
|
||||
or
|
||||
result = rank[argNo](int i | fmtSpecRefersToSequentialIndex(i))
|
||||
result = rank[argNo](int i | this.fmtSpecRefersToSequentialIndex(i))
|
||||
or
|
||||
fmtSpecRefersToPrevious(result) and
|
||||
this.fmtSpecRefersToPrevious(result) and
|
||||
exists(int previousOffset |
|
||||
getFmtSpecRank(previousOffset) = getFmtSpecRank(result) - 1 and
|
||||
previousOffset = getAnArgUsageOffset(argNo)
|
||||
this.getFmtSpecRank(previousOffset) = this.getFmtSpecRank(result) - 1 and
|
||||
previousOffset = this.getAnArgUsageOffset(argNo)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -479,10 +479,12 @@ private class LoggerFormatString extends FormatString {
|
||||
private predicate fmtPlaceholder(int i) {
|
||||
this.charAt(i) = "{" and
|
||||
this.charAt(i + 1) = "}" and
|
||||
not true = isUnescapedBackslash(i - 1)
|
||||
not true = this.isUnescapedBackslash(i - 1)
|
||||
}
|
||||
|
||||
override int getMaxFmtSpecIndex() { result = count(int i | fmtPlaceholder(i)) }
|
||||
override int getMaxFmtSpecIndex() { result = count(int i | this.fmtPlaceholder(i)) }
|
||||
|
||||
override int getAnArgUsageOffset(int argNo) { result = rank[argNo](int i | fmtPlaceholder(i)) }
|
||||
override int getAnArgUsageOffset(int argNo) {
|
||||
result = rank[argNo](int i | this.fmtPlaceholder(i))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ predicate hasSubtype(RefType t, Type sub) {
|
||||
arraySubtype(t, sub) and t != sub
|
||||
or
|
||||
// Type parameter containment for parameterized types.
|
||||
parContainmentSubtype(t, sub) and t != sub
|
||||
parContainmentSubtype(t, sub)
|
||||
or
|
||||
// Type variables are subtypes of their upper bounds.
|
||||
typeVarSubtypeBound(t, sub) and t != sub
|
||||
@@ -59,19 +59,23 @@ private predicate arraySubtype(Array sup, Array sub) {
|
||||
* )
|
||||
* ```
|
||||
* For performance several transformations are made. First, the `forex` is
|
||||
* written as a loop where `typeArgumentsContain(_, pt, psub, n)` encode that
|
||||
* the `forex` holds for `i in [0..n]`. Second, the relation is split into two
|
||||
* cases depending on whether `pt.getNumberOfTypeArguments()` is 1 or 2+, as
|
||||
* this allows us to unroll the loop and collapse the first two iterations. The
|
||||
* base case for `typeArgumentsContain` is therefore `n=1` and this allows an
|
||||
* improved join order implemented by `contains01`.
|
||||
* written as a loop where `typePrefixContains(ppt, ppsub)` encode that
|
||||
* `ppt` and `ppsub` are prefixes of `pt` and `ptsub` and that
|
||||
* the `forex` holds for `i in [0..n-1]` where `n` is the length of the prefixes.
|
||||
* Second, the recursive case that determines containment of length `n+1`
|
||||
* prefixes is split into three cases depending on whether there is
|
||||
* non-reflexive type parameter containment:
|
||||
* - only in the length `n` prefix,
|
||||
* - only in the `n`th position,
|
||||
* - both in the length `n` prefix and the `n`th position.
|
||||
*/
|
||||
|
||||
private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) {
|
||||
pt != psub and
|
||||
typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments() - 1)
|
||||
or
|
||||
typeArgumentsContain0(_, pt, psub)
|
||||
exists(ParameterizedPrefix ppt, ParameterizedPrefix ppsub |
|
||||
typePrefixContains(ppt, ppsub) and
|
||||
ppt.equals(pt) and
|
||||
ppsub.equals(psub)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,100 +98,116 @@ private RefType parameterisationTypeArgumentVarianceCand(
|
||||
varianceCandidate(t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if every type argument of `s` (up to `n` with `n >= 1`) contains the
|
||||
* corresponding type argument of `t`. Both `s` and `t` are constrained to
|
||||
* being parameterizations of `g`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate typeArgumentsContain(
|
||||
GenericType g, ParameterizedType s, ParameterizedType t, int n
|
||||
) {
|
||||
contains01(g, s, t) and n = 1
|
||||
private newtype TParameterizedPrefix =
|
||||
TGenericType(GenericType g) or
|
||||
TTypeParam(ParameterizedPrefix pp, RefType t) { prefixMatches(pp, t, _, _) }
|
||||
|
||||
/** Holds if `pp` is a length `n` prefix of `pt`. */
|
||||
private predicate prefixMatches(ParameterizedPrefix pp, ParameterizedType pt, int n) {
|
||||
pp = TGenericType(pt.getGenericType()) and n = 0
|
||||
or
|
||||
contains(g, s, t, n) and
|
||||
typeArgumentsContain(g, s, t, n - 1)
|
||||
}
|
||||
|
||||
private predicate typeArgumentsContain0(
|
||||
GenericType g, ParameterizedType sParm, ParameterizedType tParm
|
||||
) {
|
||||
exists(RefType s, RefType t |
|
||||
containsAux0(g, tParm, s, t) and
|
||||
s = parameterisationTypeArgument(g, sParm, 0) and
|
||||
s != t
|
||||
exists(ParameterizedPrefix pp0, RefType t |
|
||||
pp = TTypeParam(pp0, t) and prefixMatches(pp0, t, pt, n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `n`-th type argument of `sParm` contain the `n`-th type
|
||||
* argument of `tParm` for both `n = 0` and `n = 1`, where both `sParm` and
|
||||
* `tParm` are parameterizations of the same generic type `g`.
|
||||
*
|
||||
* This is equivalent to
|
||||
* ```
|
||||
* contains(g, sParm, tParm, 0) and
|
||||
* contains(g, sParm, tParm, 1)
|
||||
* ```
|
||||
* except `contains` is restricted to only include `n >= 2`.
|
||||
* Holds if `pp` is a length `n` prefix of `pt` and `t` is the `n`th type
|
||||
* argument of `pt`.
|
||||
*/
|
||||
private predicate contains01(GenericType g, ParameterizedType sParm, ParameterizedType tParm) {
|
||||
exists(RefType s0, RefType t0, RefType s1, RefType t1 |
|
||||
contains01Aux0(g, tParm, s0, t0, t1) and
|
||||
contains01Aux1(g, sParm, s0, s1, t1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contains01Aux0(
|
||||
GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1
|
||||
) {
|
||||
typeArgumentContains(g, s0, t0, 0) and
|
||||
t0 = parameterisationTypeArgument(g, tParm, 0) and
|
||||
t1 = parameterisationTypeArgument(g, tParm, 1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contains01Aux1(
|
||||
GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1
|
||||
) {
|
||||
typeArgumentContains(g, s1, t1, 1) and
|
||||
s0 = parameterisationTypeArgumentVarianceCand(g, sParm, 0) and
|
||||
s1 = parameterisationTypeArgumentVarianceCand(g, sParm, 1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate containsAux0(GenericType g, ParameterizedType tParm, RefType s, RefType t) {
|
||||
typeArgumentContains(g, s, t, 0) and
|
||||
t = parameterisationTypeArgument(g, tParm, 0) and
|
||||
g.getNumberOfTypeParameters() = 1
|
||||
private predicate prefixMatches(ParameterizedPrefix pp, RefType t, ParameterizedType pt, int n) {
|
||||
prefixMatches(pp, pt, n) and
|
||||
t = pt.getTypeArgument(n)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `n`-th type argument of `sParm` contain the `n`-th type
|
||||
* argument of `tParm`, where both `sParm` and `tParm` are parameterizations of
|
||||
* the same generic type `g`. The index `n` is restricted to `n >= 2`, the
|
||||
* cases `n < 2` are handled by `contains01`.
|
||||
*
|
||||
* See JLS 4.5.1, Type Arguments of Parameterized Types.
|
||||
* A prefix of a `ParameterizedType`. This encodes the corresponding
|
||||
* `GenericType` and the first `n` type arguments where `n` is the prefix
|
||||
* length.
|
||||
*/
|
||||
private predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) {
|
||||
exists(RefType s, RefType t |
|
||||
containsAux(g, tParm, n, s, t) and
|
||||
s = parameterisationTypeArgumentVarianceCand(g, sParm, n)
|
||||
private class ParameterizedPrefix extends TParameterizedPrefix {
|
||||
string toString() { result = "ParameterizedPrefix" }
|
||||
|
||||
predicate equals(ParameterizedType pt) { prefixMatches(this, pt, pt.getNumberOfTypeArguments()) }
|
||||
|
||||
/** Holds if this prefix has length `n`, applies to `g`, and equals `TTypeParam(pp, t)`. */
|
||||
predicate split(GenericType g, ParameterizedPrefix pp, RefType t, int n) {
|
||||
this = TTypeParam(pp, t) and
|
||||
(
|
||||
pp = TGenericType(g) and n = 0
|
||||
or
|
||||
pp.split(g, _, _, n - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if every type argument of `pps` contains the corresponding type
|
||||
* argument of `ppt`. Both `pps` and `ppt` are constrained to be equal-length
|
||||
* prefixes of parameterizations of the same `GenericType`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate typePrefixContains(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
|
||||
// Let `pps = TTypeParam(pps0, s)` and `ppt = TTypeParam(ppt0, t)`.
|
||||
// Case 1: pps0 = ppt0 and typeArgumentContains(_, s, t, _)
|
||||
typePrefixContains_base(pps, ppt)
|
||||
or
|
||||
// Case 2: typePrefixContains(pps0, ppt0) and s = t
|
||||
typePrefixContains_ext_eq(pps, ppt)
|
||||
or
|
||||
// Case 3: typePrefixContains(pps0, ppt0) and typeArgumentContains(_, s, t, _)
|
||||
typePrefixContains_ext_neq(pps, ppt)
|
||||
}
|
||||
|
||||
private predicate typePrefixContains_base(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
|
||||
exists(ParameterizedPrefix pp, RefType s |
|
||||
pps = TTypeParam(pp, s) and
|
||||
typePrefixContainsAux2(ppt, pp, s)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate typePrefixContains_ext_eq(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
|
||||
exists(ParameterizedPrefix pps0, ParameterizedPrefix ppt0, RefType t |
|
||||
typePrefixContains(pragma[only_bind_into](pps0), pragma[only_bind_into](ppt0)) and
|
||||
pps = TTypeParam(pragma[only_bind_into](pps0), t) and
|
||||
ppt = TTypeParam(ppt0, t)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate typePrefixContains_ext_neq(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
|
||||
exists(ParameterizedPrefix ppt0, RefType s |
|
||||
typePrefixContainsAux1(pps, ppt0, s) and
|
||||
typePrefixContainsAux2(ppt, ppt0, s)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate containsAux(GenericType g, ParameterizedType tParm, int n, RefType s, RefType t) {
|
||||
typeArgumentContains(g, s, t, n) and
|
||||
t = parameterisationTypeArgument(g, tParm, n) and
|
||||
n >= 2
|
||||
private predicate typePrefixContainsAux1(
|
||||
ParameterizedPrefix pps, ParameterizedPrefix ppt0, RefType s
|
||||
) {
|
||||
exists(ParameterizedPrefix pps0 |
|
||||
typePrefixContains(pps0, ppt0) and
|
||||
pps = TTypeParam(pps0, s) and
|
||||
s instanceof Wildcard // manual magic, implied by `typeArgumentContains(_, s, t, _)`
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typePrefixContainsAux2(
|
||||
ParameterizedPrefix ppt, ParameterizedPrefix ppt0, RefType s
|
||||
) {
|
||||
exists(GenericType g, int n, RefType t |
|
||||
// Implies `ppt = TTypeParam(ppt0, t)`
|
||||
ppt.split(g, ppt0, t, n) and
|
||||
typeArgumentContains(g, s, t, n)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type argument `s` contains the type argument `t`, where both
|
||||
* type arguments occur as index `n` in an instantiation of `g`.
|
||||
*
|
||||
* The case `s = t` is not included.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate typeArgumentContains(GenericType g, RefType s, RefType t, int n) {
|
||||
@@ -205,18 +225,18 @@ private predicate typeArgumentContainsAux2(GenericType g, RefType s, RefType t,
|
||||
* Holds if the type argument `s` contains the type argument `t`, where both
|
||||
* type arguments occur as index `n` in some parameterized types.
|
||||
*
|
||||
* The case `s = t` is not included.
|
||||
*
|
||||
* See JLS 4.5.1, Type Arguments of Parameterized Types.
|
||||
*/
|
||||
private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
exists(int i |
|
||||
s = parameterisationTypeArgumentVarianceCand(_, _, i) and
|
||||
t = parameterisationTypeArgument(_, _, n) and
|
||||
i <= n and
|
||||
n <= i
|
||||
|
|
||||
s = parameterisationTypeArgumentVarianceCand(_, _, pragma[only_bind_into](n)) and
|
||||
t = parameterisationTypeArgument(_, _, pragma[only_bind_into](n)) and
|
||||
s != t and
|
||||
(
|
||||
exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() |
|
||||
// ? extends T <= ? extends S if T <: S
|
||||
hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), tUpperBound)
|
||||
hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), tUpperBound)
|
||||
or
|
||||
// ? extends T <= ?
|
||||
s.(Wildcard).isUnconstrained()
|
||||
@@ -224,7 +244,7 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
or
|
||||
exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() |
|
||||
// ? super T <= ? super S if s <: T
|
||||
hasSubtypeStar(tLowerBound, s.(Wildcard).getLowerBound().getType())
|
||||
hasSubtypeStar2(tLowerBound, s.(Wildcard).getLowerBound().getType())
|
||||
or
|
||||
// ? super T <= ?
|
||||
s.(Wildcard).isUnconstrained()
|
||||
@@ -233,14 +253,14 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
wildcardExtendsObject(s)
|
||||
)
|
||||
or
|
||||
// T <= T
|
||||
s = t
|
||||
or
|
||||
// T <= ? extends T
|
||||
hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), t)
|
||||
hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), t)
|
||||
or
|
||||
// T <= ? super T
|
||||
hasSubtypeStar(t, s.(Wildcard).getLowerBound().getType())
|
||||
hasSubtypeStar2(t, s.(Wildcard).getLowerBound().getType())
|
||||
// or
|
||||
// T <= T
|
||||
// but this case is handled directly in `typePrefixContains`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -249,12 +269,38 @@ private predicate wildcardExtendsObject(Wildcard wc) {
|
||||
wc.getUpperBound().getType() instanceof TypeObject
|
||||
}
|
||||
|
||||
private predicate hasSubtypeStar(RefType t, RefType sub) {
|
||||
sub = t
|
||||
// manual magic for `hasSubtypeStar1`
|
||||
private predicate getAWildcardUpperBound(RefType t) {
|
||||
t = any(Wildcard w).getUpperBound().getType()
|
||||
}
|
||||
|
||||
// manual magic for `hasSubtypeStar2`
|
||||
private predicate getAWildcardLowerBound(RefType t) {
|
||||
t = any(Wildcard w).getLowerBound().getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardUpperBound(t)`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate hasSubtypeStar1(RefType t, RefType sub) {
|
||||
sub = t and getAWildcardUpperBound(t)
|
||||
or
|
||||
hasSubtype(t, sub)
|
||||
hasSubtype(t, sub) and getAWildcardUpperBound(t)
|
||||
or
|
||||
exists(RefType mid | hasSubtypeStar(t, mid) and hasSubtype(mid, sub))
|
||||
exists(RefType mid | hasSubtypeStar1(t, mid) and hasSubtype(mid, sub))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardLowerBound(sub)`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate hasSubtypeStar2(RefType t, RefType sub) {
|
||||
sub = t and getAWildcardLowerBound(sub)
|
||||
or
|
||||
hasSubtype(t, sub) and getAWildcardLowerBound(sub)
|
||||
or
|
||||
exists(RefType mid | hasSubtype(t, mid) and hasSubtypeStar2(mid, sub))
|
||||
}
|
||||
|
||||
/** Holds if type `t` declares member `m`. */
|
||||
@@ -379,7 +425,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
}
|
||||
|
||||
/** Holds if this type declares any members. */
|
||||
predicate hasMember() { exists(getAMember()) }
|
||||
predicate hasMember() { exists(this.getAMember()) }
|
||||
|
||||
/** Gets a member declared in this type. */
|
||||
Member getAMember() { this = result.getDeclaringType() }
|
||||
@@ -511,7 +557,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
this.getSourceDeclaration().inherits(f)
|
||||
)
|
||||
or
|
||||
this.hasMethod(m.(Method), _)
|
||||
this.hasMethod(m, _)
|
||||
}
|
||||
|
||||
/** Holds if this is a top-level type, which is not nested inside any other types. */
|
||||
@@ -545,8 +591,10 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
* `java.lang.Thread$State`.
|
||||
*/
|
||||
string getQualifiedName() {
|
||||
exists(string pkgName | pkgName = getPackage().getName() |
|
||||
if pkgName = "" then result = nestedName() else result = pkgName + "." + nestedName()
|
||||
exists(string pkgName | pkgName = this.getPackage().getName() |
|
||||
if pkgName = ""
|
||||
then result = this.nestedName()
|
||||
else result = pkgName + "." + this.nestedName()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -656,7 +704,7 @@ class IntersectionType extends RefType, @class {
|
||||
|
||||
/** Gets a textual representation of this type that includes all the intersected types. */
|
||||
string getLongName() {
|
||||
result = superType().toString() + concat(" & " + superInterface().toString())
|
||||
result = this.superType().toString() + concat(" & " + this.superInterface().toString())
|
||||
}
|
||||
|
||||
/** Gets the first bound of this intersection type. */
|
||||
@@ -690,7 +738,8 @@ class AnonymousClass extends NestedClass {
|
||||
override string getTypeDescriptor() {
|
||||
exists(RefType parent | parent = this.getEnclosingType() |
|
||||
exists(int num |
|
||||
num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent))
|
||||
num =
|
||||
1 + count(AnonymousClass other | other.rankInParent(parent) < this.rankInParent(parent))
|
||||
|
|
||||
exists(string parentWithSemi | parentWithSemi = parent.getTypeDescriptor() |
|
||||
result = parentWithSemi.prefix(parentWithSemi.length() - 1) + "$" + num + ";"
|
||||
@@ -760,8 +809,8 @@ class NestedType extends RefType {
|
||||
|
||||
/** Gets the nesting depth of this nested type. Top-level types have nesting depth 0. */
|
||||
int getNestingDepth() {
|
||||
if getEnclosingType() instanceof NestedType
|
||||
then result = getEnclosingType().(NestedType).getNestingDepth() + 1
|
||||
if this.getEnclosingType() instanceof NestedType
|
||||
then result = this.getEnclosingType().(NestedType).getNestingDepth() + 1
|
||||
else result = 1
|
||||
}
|
||||
|
||||
@@ -776,7 +825,7 @@ class NestedType extends RefType {
|
||||
super.isStrictfp()
|
||||
or
|
||||
// JLS 8.1.1.3, JLS 9.1.1.2
|
||||
getEnclosingType().isStrictfp()
|
||||
this.getEnclosingType().isStrictfp()
|
||||
}
|
||||
|
||||
override predicate isStatic() {
|
||||
@@ -860,9 +909,9 @@ class ClassOrInterface extends RefType, @classorinterface {
|
||||
|
||||
/** Holds if this class or interface is package protected, that is, neither public nor private nor protected. */
|
||||
predicate isPackageProtected() {
|
||||
not isPrivate() and
|
||||
not isProtected() and
|
||||
not isPublic()
|
||||
not this.isPrivate() and
|
||||
not this.isProtected() and
|
||||
not this.isPublic()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,12 +997,12 @@ class PrimitiveType extends Type, @primitive {
|
||||
* require an explicit cast.
|
||||
*/
|
||||
Literal getADefaultValue() {
|
||||
getName() = "boolean" and result.getLiteral() = "false"
|
||||
this.getName() = "boolean" and result.getLiteral() = "false"
|
||||
or
|
||||
getName() = "char" and
|
||||
this.getName() = "char" and
|
||||
(result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'")
|
||||
or
|
||||
getName().regexpMatch("(float|double|int|short|byte|long)") and
|
||||
this.getName().regexpMatch("(float|double|int|short|byte|long)") and
|
||||
result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+")
|
||||
}
|
||||
|
||||
@@ -1047,7 +1096,7 @@ class EnumType extends Class {
|
||||
override predicate isFinal() {
|
||||
// JLS 8.9: An enum declaration is implicitly `final` unless it contains
|
||||
// at least one enum constant that has a class body.
|
||||
not getAnEnumConstant().getAnAssignedValue().getType() instanceof AnonymousClass
|
||||
not this.getAnEnumConstant().getAnAssignedValue().getType() instanceof AnonymousClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1120,7 +1169,10 @@ predicate erasedHaveIntersection(RefType t1, RefType t2) {
|
||||
t2 = erase(_)
|
||||
}
|
||||
|
||||
/** An integral type, which may be either a primitive or a boxed type. */
|
||||
/**
|
||||
* An integral type, which may be either a primitive or a boxed type.
|
||||
* This includes the types `char` and `Character`.
|
||||
*/
|
||||
class IntegralType extends Type {
|
||||
IntegralType() {
|
||||
exists(string name |
|
||||
|
||||
@@ -38,11 +38,12 @@ class TearDownMethod extends Method {
|
||||
|
||||
private class TestRelatedAnnotation extends Annotation {
|
||||
TestRelatedAnnotation() {
|
||||
this.getType().getPackage().hasName("org.testng.annotations") or
|
||||
this.getType().getPackage().hasName("org.junit") or
|
||||
this.getType().getPackage().hasName("org.junit.runner") or
|
||||
this.getType().getPackage().hasName("org.junit.jupiter.api") or
|
||||
this.getType().getPackage().hasName("org.junit.jupiter.params")
|
||||
this.getType()
|
||||
.getPackage()
|
||||
.hasName([
|
||||
"org.testng.annotations", "org.junit", "org.junit.runner", "org.junit.jupiter.api",
|
||||
"org.junit.jupiter.params"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +116,7 @@ class JUnitJupiterTestMethod extends Method {
|
||||
* A JUnit `@Ignore` annotation.
|
||||
*/
|
||||
class JUnitIgnoreAnnotation extends Annotation {
|
||||
JUnitIgnoreAnnotation() { getType().hasQualifiedName("org.junit", "Ignore") }
|
||||
JUnitIgnoreAnnotation() { this.getType().hasQualifiedName("org.junit", "Ignore") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +125,7 @@ class JUnitIgnoreAnnotation extends Annotation {
|
||||
*/
|
||||
class JUnitIgnoredMethod extends Method {
|
||||
JUnitIgnoredMethod() {
|
||||
getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
||||
this.getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
||||
or
|
||||
exists(Class c | c = this.getDeclaringType() |
|
||||
c.getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
||||
@@ -136,14 +137,14 @@ class JUnitIgnoredMethod extends Method {
|
||||
* An annotation in TestNG.
|
||||
*/
|
||||
class TestNGAnnotation extends Annotation {
|
||||
TestNGAnnotation() { getType().getPackage().hasName("org.testng.annotations") }
|
||||
TestNGAnnotation() { this.getType().getPackage().hasName("org.testng.annotations") }
|
||||
}
|
||||
|
||||
/**
|
||||
* An annotation of type `org.test.ng.annotations.Test`.
|
||||
*/
|
||||
class TestNGTestAnnotation extends TestNGAnnotation {
|
||||
TestNGTestAnnotation() { getType().hasName("Test") }
|
||||
TestNGTestAnnotation() { this.getType().hasName("Test") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,13 +159,13 @@ class TestNGTestMethod extends Method {
|
||||
*/
|
||||
TestNGDataProviderMethod getADataProvider() {
|
||||
exists(TestNGTestAnnotation testAnnotation |
|
||||
testAnnotation = getAnAnnotation() and
|
||||
testAnnotation = this.getAnAnnotation() and
|
||||
// The data provider must have the same name as the referenced data provider
|
||||
result.getDataProviderName() =
|
||||
testAnnotation.getValue("dataProvider").(StringLiteral).getRepresentedString()
|
||||
testAnnotation.getValue("dataProvider").(StringLiteral).getValue()
|
||||
|
|
||||
// Either the data provider should be on the current class, or a supertype
|
||||
getDeclaringType().getAnAncestor() = result.getDeclaringType()
|
||||
this.getDeclaringType().getAnAncestor() = result.getDeclaringType()
|
||||
or
|
||||
// Or the data provider class should be declared
|
||||
result.getDeclaringType() =
|
||||
@@ -190,14 +191,14 @@ class TestMethod extends Method {
|
||||
* A TestNG annotation used to mark a method that runs "before".
|
||||
*/
|
||||
class TestNGBeforeAnnotation extends TestNGAnnotation {
|
||||
TestNGBeforeAnnotation() { getType().getName().matches("Before%") }
|
||||
TestNGBeforeAnnotation() { this.getType().getName().matches("Before%") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A TestNG annotation used to mark a method that runs "after".
|
||||
*/
|
||||
class TestNGAfterAnnotation extends TestNGAnnotation {
|
||||
TestNGAfterAnnotation() { getType().getName().matches("After%") }
|
||||
TestNGAfterAnnotation() { this.getType().getName().matches("After%") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +206,7 @@ class TestNGAfterAnnotation extends TestNGAnnotation {
|
||||
* them as data provider methods for TestNG.
|
||||
*/
|
||||
class TestNGDataProviderAnnotation extends TestNGAnnotation {
|
||||
TestNGDataProviderAnnotation() { getType().hasName("DataProvider") }
|
||||
TestNGDataProviderAnnotation() { this.getType().hasName("DataProvider") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +214,7 @@ class TestNGDataProviderAnnotation extends TestNGAnnotation {
|
||||
* them as factory methods for TestNG.
|
||||
*/
|
||||
class TestNGFactoryAnnotation extends TestNGAnnotation {
|
||||
TestNGFactoryAnnotation() { getType().hasName("Factory") }
|
||||
TestNGFactoryAnnotation() { this.getType().hasName("Factory") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,13 +222,13 @@ class TestNGFactoryAnnotation extends TestNGAnnotation {
|
||||
* which listeners apply to them.
|
||||
*/
|
||||
class TestNGListenersAnnotation extends TestNGAnnotation {
|
||||
TestNGListenersAnnotation() { getType().hasName("Listeners") }
|
||||
TestNGListenersAnnotation() { this.getType().hasName("Listeners") }
|
||||
|
||||
/**
|
||||
* Gets a listener defined in this annotation.
|
||||
*/
|
||||
TestNGListenerImpl getAListener() {
|
||||
result = getAValue("value").(TypeLiteral).getReferencedType()
|
||||
result = this.getAValue("value").(TypeLiteral).getReferencedType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +236,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation {
|
||||
* A concrete implementation class of one or more of the TestNG listener interfaces.
|
||||
*/
|
||||
class TestNGListenerImpl extends Class {
|
||||
TestNGListenerImpl() { getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") }
|
||||
TestNGListenerImpl() { this.getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,18 +247,18 @@ class TestNGListenerImpl extends Class {
|
||||
* an instance of a particular value when running a test method.
|
||||
*/
|
||||
class TestNGDataProviderMethod extends Method {
|
||||
TestNGDataProviderMethod() { getAnAnnotation() instanceof TestNGDataProviderAnnotation }
|
||||
TestNGDataProviderMethod() { this.getAnAnnotation() instanceof TestNGDataProviderAnnotation }
|
||||
|
||||
/**
|
||||
* Gets the name associated with this data provider.
|
||||
*/
|
||||
string getDataProviderName() {
|
||||
result =
|
||||
getAnAnnotation()
|
||||
this.getAnAnnotation()
|
||||
.(TestNGDataProviderAnnotation)
|
||||
.getValue("name")
|
||||
.(StringLiteral)
|
||||
.getRepresentedString()
|
||||
.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +269,7 @@ class TestNGDataProviderMethod extends Method {
|
||||
* This factory callable is used to generate instances of parameterized test classes.
|
||||
*/
|
||||
class TestNGFactoryCallable extends Callable {
|
||||
TestNGFactoryCallable() { getAnAnnotation() instanceof TestNGFactoryAnnotation }
|
||||
TestNGFactoryCallable() { this.getAnAnnotation() instanceof TestNGFactoryAnnotation }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +277,7 @@ class TestNGFactoryCallable extends Callable {
|
||||
*/
|
||||
class ParameterizedJUnitTest extends Class {
|
||||
ParameterizedJUnitTest() {
|
||||
getAnAnnotation()
|
||||
this.getAnAnnotation()
|
||||
.(RunWithAnnotation)
|
||||
.getRunner()
|
||||
.(Class)
|
||||
@@ -289,7 +290,7 @@ class ParameterizedJUnitTest extends Class {
|
||||
*/
|
||||
class JUnitCategoryAnnotation extends Annotation {
|
||||
JUnitCategoryAnnotation() {
|
||||
getType().hasQualifiedName("org.junit.experimental.categories", "Category")
|
||||
this.getType().hasQualifiedName("org.junit.experimental.categories", "Category")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +298,7 @@ class JUnitCategoryAnnotation extends Annotation {
|
||||
*/
|
||||
Type getACategory() {
|
||||
exists(TypeLiteral literal, Expr value |
|
||||
value = getValue("value") and
|
||||
value = this.getValue("value") and
|
||||
(
|
||||
literal = value or
|
||||
literal = value.(ArrayCreationExpr).getInit().getAnInit()
|
||||
@@ -313,7 +314,7 @@ class JUnitCategoryAnnotation extends Annotation {
|
||||
*/
|
||||
class JUnitTheoryTest extends Class {
|
||||
JUnitTheoryTest() {
|
||||
getAnAnnotation()
|
||||
this.getAnAnnotation()
|
||||
.(RunWithAnnotation)
|
||||
.getRunner()
|
||||
.(Class)
|
||||
|
||||
@@ -47,12 +47,12 @@ class LocalVariableDecl extends @localvar, LocalScopeVariable {
|
||||
override Callable getCallable() { result = this.getParent().getEnclosingCallable() }
|
||||
|
||||
/** Gets the callable in which this declaration occurs. */
|
||||
Callable getEnclosingCallable() { result = getCallable() }
|
||||
Callable getEnclosingCallable() { result = this.getCallable() }
|
||||
|
||||
override string toString() { result = this.getType().getName() + " " + this.getName() }
|
||||
|
||||
/** Gets the initializer expression of this local variable declaration. */
|
||||
override Expr getInitializer() { result = getDeclExpr().getInit() }
|
||||
override Expr getInitializer() { result = this.getDeclExpr().getInit() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LocalVariableDecl" }
|
||||
}
|
||||
@@ -63,7 +63,7 @@ class Parameter extends Element, @param, LocalScopeVariable {
|
||||
override Type getType() { params(this, result, _, _, _) }
|
||||
|
||||
/** Holds if the parameter is never assigned a value in the body of the callable. */
|
||||
predicate isEffectivelyFinal() { not exists(getAnAssignedValue()) }
|
||||
predicate isEffectivelyFinal() { not exists(this.getAnAssignedValue()) }
|
||||
|
||||
/** Gets the (zero-based) index of this formal parameter. */
|
||||
int getPosition() { params(this, _, result, _, _) }
|
||||
@@ -87,8 +87,8 @@ class Parameter extends Element, @param, LocalScopeVariable {
|
||||
* Varargs parameters will have no results for this method.
|
||||
*/
|
||||
Expr getAnArgument() {
|
||||
not isVarargs() and
|
||||
result = getACallArgument(getPosition())
|
||||
not this.isVarargs() and
|
||||
result = this.getACallArgument(this.getPosition())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -2,9 +2,9 @@ import java
|
||||
|
||||
/** A subclass of `PrimitiveType` with width-based ordering methods. */
|
||||
class OrdPrimitiveType extends PrimitiveType {
|
||||
predicate widerThan(OrdPrimitiveType that) { getWidthRank() > that.getWidthRank() }
|
||||
predicate widerThan(OrdPrimitiveType that) { this.getWidthRank() > that.getWidthRank() }
|
||||
|
||||
predicate widerThanOrEqualTo(OrdPrimitiveType that) { getWidthRank() >= that.getWidthRank() }
|
||||
predicate widerThanOrEqualTo(OrdPrimitiveType that) { this.getWidthRank() >= that.getWidthRank() }
|
||||
|
||||
OrdPrimitiveType maxType(OrdPrimitiveType that) {
|
||||
this.widerThan(that) and result = this
|
||||
|
||||
@@ -25,13 +25,13 @@ class BasicBlock extends ControlFlowNode {
|
||||
|
||||
/** Gets an immediate successor of this basic block. */
|
||||
cached
|
||||
BasicBlock getABBSuccessor() { result = getLastNode().getASuccessor() }
|
||||
BasicBlock getABBSuccessor() { result = this.getLastNode().getASuccessor() }
|
||||
|
||||
/** Gets an immediate predecessor of this basic block. */
|
||||
BasicBlock getABBPredecessor() { result.getABBSuccessor() = this }
|
||||
|
||||
/** Gets a control-flow node contained in this basic block. */
|
||||
ControlFlowNode getANode() { result = getNode(_) }
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
|
||||
/** Gets the control-flow node at a specific (zero-indexed) position in this basic block. */
|
||||
cached
|
||||
@@ -39,7 +39,7 @@ class BasicBlock extends ControlFlowNode {
|
||||
result = this and pos = 0
|
||||
or
|
||||
exists(ControlFlowNode mid, int mid_pos | pos = mid_pos + 1 |
|
||||
getNode(mid_pos) = mid and
|
||||
this.getNode(mid_pos) = mid and
|
||||
mid.getASuccessor() = result and
|
||||
not result instanceof BasicBlock
|
||||
)
|
||||
@@ -49,11 +49,11 @@ class BasicBlock extends ControlFlowNode {
|
||||
ControlFlowNode getFirstNode() { result = this }
|
||||
|
||||
/** Gets the last control-flow node in this basic block. */
|
||||
ControlFlowNode getLastNode() { result = getNode(length() - 1) }
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
/** Gets the number of control-flow nodes contained in this basic block. */
|
||||
cached
|
||||
int length() { result = strictcount(getANode()) }
|
||||
int length() { result = strictcount(this.getANode()) }
|
||||
|
||||
/** Holds if this basic block strictly dominates `node`. */
|
||||
predicate bbStrictlyDominates(BasicBlock node) { bbStrictlyDominates(this, node) }
|
||||
|
||||
@@ -12,13 +12,13 @@ import semmle.code.java.controlflow.Guards
|
||||
*/
|
||||
class ConstantField extends Field {
|
||||
ConstantField() {
|
||||
getType() instanceof ImmutableType and
|
||||
this.getType() instanceof ImmutableType and
|
||||
// Assigned once
|
||||
count(getAnAssignedValue()) = 1 and
|
||||
count(this.getAnAssignedValue()) = 1 and
|
||||
// And that assignment is either in the appropriate initializer, or, for instance fields on
|
||||
// classes with one constructor, in the constructor.
|
||||
forall(FieldWrite fa | fa = getAnAccess() |
|
||||
if isStatic()
|
||||
forall(FieldWrite fa | fa = this.getAnAccess() |
|
||||
if this.isStatic()
|
||||
then fa.getEnclosingCallable() instanceof StaticInitializer
|
||||
else (
|
||||
// Defined in the instance initializer.
|
||||
@@ -26,7 +26,7 @@ class ConstantField extends Field {
|
||||
or
|
||||
// It can be defined in the constructor if there is only one constructor.
|
||||
fa.getEnclosingCallable() instanceof Constructor and
|
||||
count(getDeclaringType().getAConstructor()) = 1
|
||||
count(this.getDeclaringType().getAConstructor()) = 1
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class ConstantField extends Field {
|
||||
*
|
||||
* Note: although this value is constant, we may not be able to statically determine the value.
|
||||
*/
|
||||
ConstantExpr getConstantValue() { result = getAnAssignedValue() }
|
||||
ConstantExpr getConstantValue() { result = this.getAnAssignedValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,18 +162,18 @@ class ConstSwitchStmt extends SwitchStmt {
|
||||
|
||||
/** Gets the `ConstCase` that matches, if any. */
|
||||
ConstCase getMatchingConstCase() {
|
||||
result = getAConstCase() and
|
||||
result = this.getAConstCase() and
|
||||
// Only handle the int case for now
|
||||
result.getValue().(ConstantExpr).getIntValue() = getExpr().(ConstantExpr).getIntValue()
|
||||
result.getValue().(ConstantExpr).getIntValue() = this.getExpr().(ConstantExpr).getIntValue()
|
||||
}
|
||||
|
||||
/** Gets the matching case, if it can be deduced. */
|
||||
SwitchCase getMatchingCase() {
|
||||
// Must be a value we can deduce
|
||||
exists(getExpr().(ConstantExpr).getIntValue()) and
|
||||
if exists(getMatchingConstCase())
|
||||
then result = getMatchingConstCase()
|
||||
else result = getDefaultCase()
|
||||
exists(this.getExpr().(ConstantExpr).getIntValue()) and
|
||||
if exists(this.getMatchingConstCase())
|
||||
then result = this.getMatchingConstCase()
|
||||
else result = this.getDefaultCase()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,8 +184,8 @@ class ConstSwitchStmt extends SwitchStmt {
|
||||
SwitchCase getAFailingCase() {
|
||||
exists(SwitchCase matchingCase |
|
||||
// We must have found the matching case, otherwise we can't deduce which cases are not matched
|
||||
matchingCase = getMatchingCase() and
|
||||
result = getACase() and
|
||||
matchingCase = this.getMatchingCase() and
|
||||
result = this.getACase() and
|
||||
result != matchingCase
|
||||
)
|
||||
}
|
||||
@@ -208,7 +208,7 @@ class UnreachableBasicBlock extends BasicBlock {
|
||||
or
|
||||
// This block is not reachable in the CFG, and is not a callable, a body of a callable, an
|
||||
// expression in an annotation, an expression in an assert statement, or a catch clause.
|
||||
forall(BasicBlock bb | bb = getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
forall(BasicBlock bb | bb = this.getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
not exists(Callable c | c.getBody() = this) and
|
||||
not this instanceof Callable and
|
||||
not exists(Annotation a | a.getAChildExpr*() = this) and
|
||||
@@ -231,12 +231,12 @@ class UnreachableBasicBlock extends BasicBlock {
|
||||
* An unreachable expression is an expression contained in an `UnreachableBasicBlock`.
|
||||
*/
|
||||
class UnreachableExpr extends Expr {
|
||||
UnreachableExpr() { getBasicBlock() instanceof UnreachableBasicBlock }
|
||||
UnreachableExpr() { this.getBasicBlock() instanceof UnreachableBasicBlock }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unreachable statement is a statement contained in an `UnreachableBasicBlock`.
|
||||
*/
|
||||
class UnreachableStmt extends Stmt {
|
||||
UnreachableStmt() { getBasicBlock() instanceof UnreachableBasicBlock }
|
||||
UnreachableStmt() { this.getBasicBlock() instanceof UnreachableBasicBlock }
|
||||
}
|
||||
|
||||
@@ -17,16 +17,11 @@ import semmle.code.java.controlflow.UnreachableBlocks
|
||||
class ExcludeDebuggingProfilingLogging extends ExcludedConstantField {
|
||||
ExcludeDebuggingProfilingLogging() {
|
||||
exists(string validFieldName |
|
||||
validFieldName = "debug" or
|
||||
validFieldName = "profiling" or
|
||||
validFieldName = "profile" or
|
||||
validFieldName = "time" or
|
||||
validFieldName = "verbose" or
|
||||
validFieldName = "report" or
|
||||
validFieldName = "dbg" or
|
||||
validFieldName = "timing" or
|
||||
validFieldName = "assert" or
|
||||
validFieldName = "log"
|
||||
validFieldName =
|
||||
[
|
||||
"debug", "profiling", "profile", "time", "verbose", "report", "dbg", "timing", "assert",
|
||||
"log"
|
||||
]
|
||||
|
|
||||
getName().regexpMatch(".*(?i)" + validFieldName + ".*")
|
||||
) and
|
||||
|
||||
@@ -79,9 +79,12 @@ private module Frameworks {
|
||||
private import internal.ContainerFlow
|
||||
private import semmle.code.java.frameworks.android.Android
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
private import semmle.code.java.frameworks.android.Slice
|
||||
private import semmle.code.java.frameworks.android.SQLite
|
||||
private import semmle.code.java.frameworks.android.XssSinks
|
||||
private import semmle.code.java.frameworks.ApacheHttp
|
||||
private import semmle.code.java.frameworks.apache.Collections
|
||||
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.guava.Guava
|
||||
@@ -95,6 +98,8 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.Optional
|
||||
private import semmle.code.java.frameworks.Stream
|
||||
private import semmle.code.java.frameworks.Strings
|
||||
private import semmle.code.java.frameworks.ratpack.Ratpack
|
||||
private import semmle.code.java.frameworks.ratpack.RatpackExec
|
||||
private import semmle.code.java.frameworks.spring.SpringCache
|
||||
private import semmle.code.java.frameworks.spring.SpringHttp
|
||||
private import semmle.code.java.frameworks.spring.SpringUtil
|
||||
@@ -104,6 +109,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.spring.SpringBeans
|
||||
private import semmle.code.java.frameworks.spring.SpringWebMultipart
|
||||
private import semmle.code.java.frameworks.spring.SpringWebUtil
|
||||
private import semmle.code.java.security.AndroidIntentRedirection
|
||||
private import semmle.code.java.security.ResponseSplitting
|
||||
private import semmle.code.java.security.InformationLeak
|
||||
private import semmle.code.java.security.GroovyInjection
|
||||
@@ -114,9 +120,6 @@ private module Frameworks {
|
||||
private import semmle.code.java.security.OgnlInjection
|
||||
private import semmle.code.java.security.XPath
|
||||
private import semmle.code.java.security.XsltInjection
|
||||
private import semmle.code.java.frameworks.android.Android
|
||||
private import semmle.code.java.frameworks.android.Slice
|
||||
private import semmle.code.java.frameworks.android.SQLite
|
||||
private import semmle.code.java.frameworks.Jdbc
|
||||
private import semmle.code.java.frameworks.SpringJdbc
|
||||
private import semmle.code.java.frameworks.MyBatis
|
||||
@@ -321,33 +324,11 @@ private predicate summaryModelCsv(string row) {
|
||||
"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",
|
||||
"org.apache.commons.io;IOUtils;false;buffer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;readLines;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedReader;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toByteArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toCharArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toString;;;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",
|
||||
// arg to arg
|
||||
"java.lang;System;false;arraycopy;;;Argument[0];Argument[2];taint",
|
||||
"org.apache.commons.io;IOUtils;false;copy;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;copyLarge;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;read;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(ReadableByteChannel,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;write;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeChunked;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[0];Argument[2];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[1];Argument[2];taint",
|
||||
// constructor flow
|
||||
"java.io;File;false;File;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;File;false;File;;;Argument[1];Argument[-1];taint",
|
||||
@@ -372,7 +353,11 @@ private predicate summaryModelCsv(string row) {
|
||||
"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;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"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ private class RmiMethodParameterSource extends RemoteFlowSource {
|
||||
exists(RemoteCallableMethod method |
|
||||
method.getAParameter() = this.asParameter() and
|
||||
(
|
||||
getType() instanceof PrimitiveType or
|
||||
getType() instanceof TypeString
|
||||
this.getType() instanceof PrimitiveType or
|
||||
this.getType() instanceof TypeString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ private import semmle.code.java.dataflow.DataFlow
|
||||
*/
|
||||
private module Frameworks {
|
||||
private import semmle.code.java.frameworks.jackson.JacksonSerializability
|
||||
private import semmle.code.java.frameworks.android.AsyncTask
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
private import semmle.code.java.frameworks.android.SQLite
|
||||
private import semmle.code.java.frameworks.Guice
|
||||
@@ -64,6 +65,20 @@ class AdditionalTaintStep extends Unit {
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional value steps.
|
||||
*
|
||||
* Extend this class to add additional value-preserving steps that should apply
|
||||
* to all data flow configurations.
|
||||
*/
|
||||
class AdditionalValueStep extends Unit {
|
||||
/**
|
||||
* Holds if the step from `node1` to `node2` is a value-preserving step and
|
||||
* should apply to all data flow configurations.
|
||||
*/
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A method or constructor that preserves taint.
|
||||
*
|
||||
|
||||
@@ -97,7 +97,7 @@ class SsaSourceVariable extends TSsaSourceVariable {
|
||||
else result = c.getName() + "(..)." + v.getName()
|
||||
)
|
||||
or
|
||||
result = this.(SsaSourceField).ppQualifier() + "." + getVariable().toString()
|
||||
result = this.(SsaSourceField).ppQualifier() + "." + this.getVariable().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +117,7 @@ class SsaSourceVariable extends TSsaSourceVariable {
|
||||
Location getLocation() {
|
||||
exists(LocalScopeVariable v | this = TLocalVar(_, v) and result = v.getLocation())
|
||||
or
|
||||
this instanceof SsaSourceField and result = getFirstAccess().getLocation()
|
||||
this instanceof SsaSourceField and result = this.getFirstAccess().getLocation()
|
||||
}
|
||||
|
||||
/** Gets the type of this variable. */
|
||||
@@ -140,7 +140,7 @@ class SsaSourceField extends SsaSourceVariable {
|
||||
}
|
||||
|
||||
/** Gets the field corresponding to this named field. */
|
||||
Field getField() { result = getVariable() }
|
||||
Field getField() { result = this.getVariable() }
|
||||
|
||||
/** Gets a string representation of the qualifier. */
|
||||
string ppQualifier() {
|
||||
@@ -155,8 +155,8 @@ class SsaSourceField extends SsaSourceVariable {
|
||||
|
||||
/** Holds if the field itself or any of the fields part of the qualifier are volatile. */
|
||||
predicate isVolatile() {
|
||||
getField().isVolatile() or
|
||||
getQualifier().(SsaSourceField).isVolatile()
|
||||
this.getField().isVolatile() or
|
||||
this.getQualifier().(SsaSourceField).isVolatile()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,10 +932,10 @@ class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { result = getCFGNode().getLocation() }
|
||||
Location getLocation() { result = this.getCFGNode().getLocation() }
|
||||
|
||||
/** Gets the `BasicBlock` in which this SSA variable is defined. */
|
||||
BasicBlock getBasicBlock() { result = getCFGNode().getBasicBlock() }
|
||||
BasicBlock getBasicBlock() { result = this.getCFGNode().getBasicBlock() }
|
||||
|
||||
/** Gets an access of this SSA variable. */
|
||||
RValue getAUse() {
|
||||
@@ -989,14 +989,16 @@ class SsaUpdate extends SsaVariable {
|
||||
/** An SSA variable that is defined by a `VariableUpdate`. */
|
||||
class SsaExplicitUpdate extends SsaUpdate, TSsaCertainUpdate {
|
||||
SsaExplicitUpdate() {
|
||||
exists(VariableUpdate upd | upd = this.getCFGNode() and getDestVar(upd) = getSourceVariable())
|
||||
exists(VariableUpdate upd |
|
||||
upd = this.getCFGNode() and getDestVar(upd) = this.getSourceVariable()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "SSA def(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Gets the `VariableUpdate` defining the SSA variable. */
|
||||
VariableUpdate getDefiningExpr() {
|
||||
result = this.getCFGNode() and getDestVar(result) = getSourceVariable()
|
||||
result = this.getCFGNode() and getDestVar(result) = this.getSourceVariable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,22 +1012,22 @@ class SsaImplicitUpdate extends SsaUpdate {
|
||||
SsaImplicitUpdate() { not this instanceof SsaExplicitUpdate }
|
||||
|
||||
override string toString() {
|
||||
result = "SSA impl upd[" + getKind() + "](" + getSourceVariable() + ")"
|
||||
result = "SSA impl upd[" + this.getKind() + "](" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
private string getKind() {
|
||||
this = TSsaUntracked(_, _) and result = "untracked"
|
||||
or
|
||||
certainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) and
|
||||
certainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) and
|
||||
result = "explicit qualifier"
|
||||
or
|
||||
if uncertainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _)
|
||||
if uncertainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _)
|
||||
then
|
||||
if exists(getANonLocalUpdate())
|
||||
if exists(this.getANonLocalUpdate())
|
||||
then result = "nonlocal + nonlocal qualifier"
|
||||
else result = "nonlocal qualifier"
|
||||
else (
|
||||
exists(getANonLocalUpdate()) and result = "nonlocal"
|
||||
exists(this.getANonLocalUpdate()) and result = "nonlocal"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1034,9 +1036,9 @@ class SsaImplicitUpdate extends SsaUpdate {
|
||||
*/
|
||||
FieldWrite getANonLocalUpdate() {
|
||||
exists(SsaSourceField f, Callable setter |
|
||||
f = getSourceVariable() and
|
||||
f = this.getSourceVariable() and
|
||||
relevantFieldUpdate(setter, f.getField(), result) and
|
||||
updatesNamedField(getCFGNode(), f, setter)
|
||||
updatesNamedField(this.getCFGNode(), f, setter)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1049,8 +1051,8 @@ class SsaImplicitUpdate extends SsaUpdate {
|
||||
*/
|
||||
predicate assignsUnknownValue() {
|
||||
this = TSsaUntracked(_, _) or
|
||||
certainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) or
|
||||
uncertainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _)
|
||||
certainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) or
|
||||
uncertainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1072,30 +1074,31 @@ class SsaUncertainImplicitUpdate extends SsaImplicitUpdate, TSsaUncertainUpdate
|
||||
* includes initial values of parameters, fields, and closure variables.
|
||||
*/
|
||||
class SsaImplicitInit extends SsaVariable, TSsaEntryDef {
|
||||
override string toString() { result = "SSA init(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA init(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Holds if this is a closure variable that captures the value of `capturedvar`. */
|
||||
predicate captures(SsaVariable capturedvar) {
|
||||
ssaDefReachesCapture(_, capturedvar, getSourceVariable())
|
||||
ssaDefReachesCapture(_, capturedvar, this.getSourceVariable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA variable is a parameter defined by its initial value in the callable.
|
||||
*/
|
||||
predicate isParameterDefinition(Parameter p) {
|
||||
getSourceVariable() = TLocalVar(p.getCallable(), p) and p.getCallable().getBody() = getCFGNode()
|
||||
this.getSourceVariable() = TLocalVar(p.getCallable(), p) and
|
||||
p.getCallable().getBody() = this.getCFGNode()
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA phi node. */
|
||||
class SsaPhiNode extends SsaVariable, TSsaPhiNode {
|
||||
override string toString() { result = "SSA phi(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Gets an input to the phi node defining the SSA variable. */
|
||||
SsaVariable getAPhiInput() {
|
||||
exists(BasicBlock phiPred, TrackedVar v |
|
||||
v = getSourceVariable() and
|
||||
getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and
|
||||
v = this.getSourceVariable() and
|
||||
this.getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and
|
||||
ssaDefReachesEndOfBlock(v, result, phiPred)
|
||||
)
|
||||
}
|
||||
|
||||
178
java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll
Normal file
178
java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying expressions that may be appended to an interesting prefix.
|
||||
*
|
||||
* To use this library, extend the abstract class `InterestingPrefix` to have the library identify expressions that
|
||||
* may be appended to it, then check `InterestingPrefix.getAnAppendedExpression(Expr)` to get your results.
|
||||
*
|
||||
* For example, to identify expressions that may follow "foo:" in some string, we could define:
|
||||
*
|
||||
* ```
|
||||
* private class FooPrefix extends InterestingPrefix {
|
||||
* int offset;
|
||||
* FooPrefix() { this.getStringValue().substring("foo:") = offset };
|
||||
* override int getOffset() { result = offset }
|
||||
* };
|
||||
*
|
||||
* predicate mayFollowFoo(Expr e) { e = any(FooPrefix fp).getAnAppendedExpression() }
|
||||
* ```
|
||||
*
|
||||
* This will identify all the `suffix` expressions in contexts such as:
|
||||
*
|
||||
* ```
|
||||
* "foo:" + suffix1
|
||||
* "barfoo:" + suffix2
|
||||
* stringBuilder.append("foo:").append(suffix3);
|
||||
* String.format("%sfoo:%s", notSuffix, suffix4);
|
||||
* ```
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.StringFormat
|
||||
|
||||
/**
|
||||
* A string constant that contains a prefix whose possibly-appended strings are
|
||||
* returned by `getAnAppendedExpression`.
|
||||
*
|
||||
* Extend this class to specify prefixes whose possibly-appended strings should be analysed.
|
||||
*/
|
||||
abstract class InterestingPrefix extends CompileTimeConstantExpr {
|
||||
/**
|
||||
* Gets the offset in this constant string where the interesting prefix begins.
|
||||
*/
|
||||
abstract int getOffset();
|
||||
|
||||
/**
|
||||
* Gets an expression that may follow this prefix in a derived string.
|
||||
*/
|
||||
Expr getAnAppendedExpression() { mayFollowInterestingPrefix(this, result) }
|
||||
}
|
||||
|
||||
private Expr getAnInterestingPrefix(InterestingPrefix root) {
|
||||
result = root
|
||||
or
|
||||
result.(AddExpr).getAnOperand() = getAnInterestingPrefix(root)
|
||||
}
|
||||
|
||||
private class StringBuilderAppend extends MethodAccess {
|
||||
StringBuilderAppend() {
|
||||
this.getMethod().getDeclaringType() instanceof StringBuildingType and
|
||||
this.getMethod().hasName("append")
|
||||
}
|
||||
}
|
||||
|
||||
private class StringBuilderConstructorOrAppend extends Call {
|
||||
StringBuilderConstructorOrAppend() {
|
||||
this instanceof StringBuilderAppend or
|
||||
this.(ClassInstanceExpr).getConstructedType() instanceof StringBuildingType
|
||||
}
|
||||
}
|
||||
|
||||
private Expr getQualifier(Expr e) { result = e.(MethodAccess).getQualifier() }
|
||||
|
||||
/**
|
||||
* An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor
|
||||
* and in `append` calls chained onto the constructor call.
|
||||
*
|
||||
* The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and
|
||||
* in taint rules terms these are not needed, as the connection between construction, appends and the
|
||||
* eventual `toString` is more obvious.
|
||||
*/
|
||||
private class StringBuilderVarExt extends StringBuilderVar {
|
||||
/**
|
||||
* Returns a first assignment after this StringBuilderVar is first assigned.
|
||||
*
|
||||
* For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");`
|
||||
* this returns the append of `"3"`.
|
||||
*/
|
||||
private StringBuilderAppend getAFirstAppendAfterAssignment() {
|
||||
result = this.getAnAppend() and not result = this.getNextAppend(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other
|
||||
* chained calls, assigned to this `StringBuilderVar`.
|
||||
*/
|
||||
private StringBuilderAppend getNextAssignmentChainedAppend(StringBuilderConstructorOrAppend prev) {
|
||||
getQualifier*(result) = this.getAnAssignedValue() and
|
||||
result.getQualifier() = prev
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a constructor call or `append` call that contributes a string to this string builder.
|
||||
*/
|
||||
StringBuilderConstructorOrAppend getAConstructorOrAppend() {
|
||||
exists(this.getNextAssignmentChainedAppend(result)) or
|
||||
result = this.getAnAssignedValue() or
|
||||
result = this.getAnAppend()
|
||||
}
|
||||
|
||||
/**
|
||||
* Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly
|
||||
* assigned to this `StringBuilderVar`.
|
||||
*/
|
||||
private StringBuilderAppend getNextAppendIncludingAssignmentChains(
|
||||
StringBuilderConstructorOrAppend prev
|
||||
) {
|
||||
result = this.getNextAssignmentChainedAppend(prev)
|
||||
or
|
||||
prev = this.getAnAssignedValue() and
|
||||
result = this.getAFirstAppendAfterAssignment()
|
||||
or
|
||||
result = this.getNextAppend(prev)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
StringBuilderAppend getSubsequentAppendIncludingAssignmentChains(
|
||||
StringBuilderConstructorOrAppend prev
|
||||
) {
|
||||
result = this.getNextAppendIncludingAssignmentChains(prev) or
|
||||
result =
|
||||
this.getSubsequentAppendIncludingAssignmentChains(this.getNextAppendIncludingAssignmentChains(prev))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `follows` may be concatenated after `prefix`.
|
||||
*/
|
||||
private predicate mayFollowInterestingPrefix(InterestingPrefix prefix, Expr follows) {
|
||||
// Expressions that come after an interesting prefix in a tree of string additions:
|
||||
follows =
|
||||
any(AddExpr add | add.getLeftOperand() = getAnInterestingPrefix(prefix)).getRightOperand()
|
||||
or
|
||||
// Sanitize expressions that come after an interesting prefix in a sequence of StringBuilder operations:
|
||||
exists(
|
||||
StringBuilderConstructorOrAppend appendSanitizingConstant, StringBuilderAppend subsequentAppend,
|
||||
StringBuilderVarExt v
|
||||
|
|
||||
appendSanitizingConstant = v.getAConstructorOrAppend() and
|
||||
appendSanitizingConstant.getArgument(0) = getAnInterestingPrefix(prefix) and
|
||||
v.getSubsequentAppendIncludingAssignmentChains(appendSanitizingConstant) = subsequentAppend and
|
||||
follows = subsequentAppend.getArgument(0)
|
||||
)
|
||||
or
|
||||
// Sanitize expressions that come after an interesting prefix in the args to a format call:
|
||||
exists(
|
||||
FormattingCall formatCall, FormatString formatString, int prefixOffset, int laterOffset,
|
||||
int sanitizedArg
|
||||
|
|
||||
formatString = unique(FormatString fs | fs = formatCall.getAFormatString()) and
|
||||
(
|
||||
// An interesting prefix argument comes before this:
|
||||
exists(int argIdx |
|
||||
formatCall.getArgumentToBeFormatted(argIdx) = prefix and
|
||||
prefixOffset = formatString.getAnArgUsageOffset(argIdx)
|
||||
)
|
||||
or
|
||||
// The format string itself contains an interesting prefix that precedes subsequent arguments:
|
||||
formatString = prefix.getStringValue() and
|
||||
prefixOffset = prefix.getOffset()
|
||||
) and
|
||||
laterOffset > prefixOffset and
|
||||
laterOffset = formatString.getAnArgUsageOffset(sanitizedArg) and
|
||||
follows = formatCall.getArgumentToBeFormatted(sanitizedArg)
|
||||
)
|
||||
}
|
||||
@@ -484,10 +484,10 @@ class BaseSsaVariable extends TBaseSsaVariable {
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
Location getLocation() { result = getCFGNode().getLocation() }
|
||||
Location getLocation() { result = this.getCFGNode().getLocation() }
|
||||
|
||||
/** Gets the `BasicBlock` in which this SSA variable is defined. */
|
||||
BasicBlock getBasicBlock() { result = getCFGNode().getBasicBlock() }
|
||||
BasicBlock getBasicBlock() { result = this.getCFGNode().getBasicBlock() }
|
||||
|
||||
/** Gets an access of this SSA variable. */
|
||||
RValue getAUse() { ssaDefReachesUse(_, this, result) }
|
||||
@@ -532,14 +532,16 @@ class BaseSsaVariable extends TBaseSsaVariable {
|
||||
/** An SSA variable that is defined by a `VariableUpdate`. */
|
||||
class BaseSsaUpdate extends BaseSsaVariable, TSsaUpdate {
|
||||
BaseSsaUpdate() {
|
||||
exists(VariableUpdate upd | upd = this.getCFGNode() and getDestVar(upd) = getSourceVariable())
|
||||
exists(VariableUpdate upd |
|
||||
upd = this.getCFGNode() and getDestVar(upd) = this.getSourceVariable()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "SSA def(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Gets the `VariableUpdate` defining the SSA variable. */
|
||||
VariableUpdate getDefiningExpr() {
|
||||
result = this.getCFGNode() and getDestVar(result) = getSourceVariable()
|
||||
result = this.getCFGNode() and getDestVar(result) = this.getSourceVariable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,30 +550,31 @@ class BaseSsaUpdate extends BaseSsaVariable, TSsaUpdate {
|
||||
* includes initial values of parameters, fields, and closure variables.
|
||||
*/
|
||||
class BaseSsaImplicitInit extends BaseSsaVariable, TSsaEntryDef {
|
||||
override string toString() { result = "SSA init(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA init(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Holds if this is a closure variable that captures the value of `capturedvar`. */
|
||||
predicate captures(BaseSsaVariable capturedvar) {
|
||||
ssaDefReachesCapture(_, capturedvar, getSourceVariable())
|
||||
ssaDefReachesCapture(_, capturedvar, this.getSourceVariable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA variable is a parameter defined by its initial value in the callable.
|
||||
*/
|
||||
predicate isParameterDefinition(Parameter p) {
|
||||
getSourceVariable() = TLocalVar(p.getCallable(), p) and p.getCallable().getBody() = getCFGNode()
|
||||
this.getSourceVariable() = TLocalVar(p.getCallable(), p) and
|
||||
p.getCallable().getBody() = this.getCFGNode()
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA phi node. */
|
||||
class BaseSsaPhiNode extends BaseSsaVariable, TSsaPhiNode {
|
||||
override string toString() { result = "SSA phi(" + getSourceVariable() + ")" }
|
||||
override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" }
|
||||
|
||||
/** Gets an input to the phi node defining the SSA variable. */
|
||||
BaseSsaVariable getAPhiInput() {
|
||||
exists(BasicBlock phiPred, BaseSsaSourceVariable v |
|
||||
v = getSourceVariable() and
|
||||
getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and
|
||||
v = this.getSourceVariable() and
|
||||
this.getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and
|
||||
ssaDefReachesEndOfBlock(v, result, phiPred)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,7 +104,9 @@ private class ContainerFlowSummaries extends SummaryModelCsv {
|
||||
"java.util;Map$Entry;true;setValue;;;Argument[0];MapValue of Argument[-1];value",
|
||||
"java.lang;Iterable;true;iterator;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.lang;Iterable;true;spliterator;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.lang;Iterable;true;forEach;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Iterator;true;next;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;Iterator;true;forEachRemaining;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;ListIterator;true;previous;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;ListIterator;true;add;(Object);;Argument[0];Element of Argument[-1];value",
|
||||
"java.util;ListIterator;true;set;(Object);;Argument[0];Element of Argument[-1];value",
|
||||
@@ -135,6 +137,8 @@ private class ContainerFlowSummaries extends SummaryModelCsv {
|
||||
"java.util;Map;true;merge;(Object,Object,BiFunction);;Argument[1];MapValue of Argument[-1];value",
|
||||
"java.util;Map;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
|
||||
"java.util;Map;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value",
|
||||
"java.util;Map;true;forEach;(BiConsumer);;MapKey of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Map;true;forEach;(BiConsumer);;MapValue of Argument[-1];Parameter[1] of Argument[0];value",
|
||||
"java.util;Collection;true;parallelStream;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util;Collection;true;stream;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util;Collection;true;toArray;;;Element of Argument[-1];ArrayElement of ReturnValue;value",
|
||||
|
||||
@@ -8,9 +8,9 @@ private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
|
||||
private module DispatchImpl {
|
||||
/** Gets a viable implementation of the target of the given `Call`. */
|
||||
DataFlowCallable viableCallable(DataFlowCall c) {
|
||||
result = VirtualDispatch::viableCallable(c.asCall())
|
||||
result.asCallable() = VirtualDispatch::viableCallable(c.asCall())
|
||||
or
|
||||
result.(SummarizedCallable) = c.asCall().getCallee().getSourceDeclaration()
|
||||
result.(SummarizedCallable).asCallable() = c.asCall().getCallee().getSourceDeclaration()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,31 +93,32 @@ private module DispatchImpl {
|
||||
* qualifier is a parameter of the enclosing callable `c`.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
|
||||
mayBenefitFromCallContext(call.asCall(), c, _)
|
||||
mayBenefitFromCallContext(call.asCall(), c.asCallable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
Method viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableCallable(call) and
|
||||
exists(int i, Callable c, Method def, RefType t, boolean exact, MethodAccess ma |
|
||||
ma = call.asCall() and
|
||||
mayBenefitFromCallContext(ma, c, i) and
|
||||
c = viableCallable(ctx) and
|
||||
c = viableCallable(ctx).asCallable() and
|
||||
contextArgHasType(ctx.asCall(), i, t, exact) and
|
||||
ma.getMethod().getSourceDeclaration() = def
|
||||
|
|
||||
exact = true and result = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration())
|
||||
exact = true and
|
||||
result.asCallable() = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration())
|
||||
or
|
||||
exact = false and
|
||||
exists(RefType t2 |
|
||||
result = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
|
||||
result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
|
||||
not failsUnification(t, t2)
|
||||
)
|
||||
or
|
||||
result = def and def instanceof SummarizedCallable
|
||||
result.asCallable() = def and result instanceof SummarizedCallable
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
private newtype TFlowFeature =
|
||||
TFeatureHasSourceCallContext() or
|
||||
TFeatureHasSinkCallContext() or
|
||||
TFeatureEqualSourceSinkCallContext()
|
||||
|
||||
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
|
||||
class FlowFeature extends TFlowFeature {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration feature that implies that sources have some existing
|
||||
* call context.
|
||||
*/
|
||||
class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext {
|
||||
override string toString() { result = "FeatureHasSourceCallContext" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration feature that implies that sinks have some existing
|
||||
* call context.
|
||||
*/
|
||||
class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext {
|
||||
override string toString() { result = "FeatureHasSinkCallContext" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration feature that implies that source-sink pairs have some
|
||||
* shared existing call context.
|
||||
*/
|
||||
class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext {
|
||||
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion.
|
||||
*
|
||||
@@ -251,7 +287,7 @@ private module Cached {
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) }
|
||||
|
||||
cached
|
||||
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
|
||||
@@ -316,9 +352,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node n, DataFlowCallable c, int i) {
|
||||
n.(ParameterNode).isParameterOf(c, i)
|
||||
}
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
@@ -801,6 +835,9 @@ private module Cached {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) }
|
||||
|
||||
cached
|
||||
newtype TCallContext =
|
||||
TAnyCallContext() or
|
||||
|
||||
@@ -9,6 +9,19 @@ private import tainttracking1.TaintTrackingParameter::Private
|
||||
private import tainttracking1.TaintTrackingParameter::Public
|
||||
|
||||
module Consistency {
|
||||
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
|
||||
|
||||
/** A class for configuring the consistency queries. */
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
RelevantNode() {
|
||||
this instanceof ArgumentNode or
|
||||
@@ -31,7 +44,7 @@ module Consistency {
|
||||
query predicate uniqueEnclosingCallable(Node n, string msg) {
|
||||
exists(int c |
|
||||
n instanceof RelevantNode and
|
||||
c = count(n.getEnclosingCallable()) and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
@@ -85,13 +98,13 @@ module Consistency {
|
||||
}
|
||||
|
||||
query predicate parameterCallable(ParameterNode p, string msg) {
|
||||
exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and
|
||||
exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and
|
||||
msg = "Callable mismatch for parameter."
|
||||
}
|
||||
|
||||
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
|
||||
simpleLocalFlowStep(n1, n2) and
|
||||
n1.getEnclosingCallable() != n2.getEnclosingCallable() and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
@@ -106,7 +119,7 @@ module Consistency {
|
||||
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
|
||||
isUnreachableInCall(n, call) and
|
||||
exists(DataFlowCallable c |
|
||||
c = n.getEnclosingCallable() and
|
||||
c = nodeGetEnclosingCallable(n) and
|
||||
not viableCallable(call) = c
|
||||
) and
|
||||
msg = "Call context for isUnreachableInCall is inconsistent with call graph."
|
||||
@@ -120,7 +133,7 @@ module Consistency {
|
||||
n.(ArgumentNode).argumentOf(call, _) and
|
||||
msg = "ArgumentNode and call does not share enclosing callable."
|
||||
) and
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
nodeGetEnclosingCallable(n) != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
@@ -151,7 +164,7 @@ module Consistency {
|
||||
}
|
||||
|
||||
query predicate postIsInSameCallable(PostUpdateNode n, string msg) {
|
||||
n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and
|
||||
nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and
|
||||
msg = "PostUpdateNode does not share callable with its pre-update node."
|
||||
}
|
||||
|
||||
@@ -164,7 +177,7 @@ module Consistency {
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
|
||||
msg = "ArgumentNode is missing PostUpdateNode."
|
||||
}
|
||||
|
||||
@@ -175,7 +188,9 @@ module Consistency {
|
||||
|
||||
query predicate postWithInFlow(Node n, string msg) {
|
||||
isPostUpdateNode(n) and
|
||||
not clearsContent(n, _) and
|
||||
simpleLocalFlowStep(_, n) and
|
||||
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
|
||||
msg = "PostUpdateNode should not be the target of local flow."
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,14 +14,14 @@ newtype TNode =
|
||||
not e.getParent*() instanceof Annotation
|
||||
} or
|
||||
TExplicitParameterNode(Parameter p) {
|
||||
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
|
||||
exists(p.getCallable().getBody()) or p.getCallable() = any(SummarizedCallable sc).asCallable()
|
||||
} 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 instanceof SummarizedCallable) and
|
||||
(exists(c.getBody()) or c = any(SummarizedCallable sc).asCallable()) and
|
||||
not c.isStatic()
|
||||
} or
|
||||
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
|
||||
@@ -44,7 +44,8 @@ newtype TNode =
|
||||
} or
|
||||
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
}
|
||||
} or
|
||||
TFieldValueNode(Field f)
|
||||
|
||||
private predicate explicitInstanceArgument(Call call, Expr instarg) {
|
||||
call instanceof MethodAccess and
|
||||
@@ -94,19 +95,12 @@ module Public {
|
||||
result = this.(MallocNode).getClassInstanceExpr().getType()
|
||||
or
|
||||
result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getType()
|
||||
or
|
||||
result = this.(FieldValueNode).getField().getType()
|
||||
}
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
Callable getEnclosingCallable() {
|
||||
result = this.asExpr().getEnclosingCallable() or
|
||||
result = this.asParameter().getCallable() or
|
||||
result = this.(ImplicitVarargsArray).getCall().getEnclosingCallable() or
|
||||
result = this.(InstanceParameterNode).getCallable() or
|
||||
result = this.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
|
||||
result = this.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
|
||||
result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getEnclosingCallable() or
|
||||
this = TSummaryInternalNode(result, _)
|
||||
}
|
||||
Callable getEnclosingCallable() { result = nodeGetEnclosingCallable(this).asCallable() }
|
||||
|
||||
private Type getImprovedTypeBound() {
|
||||
exprTypeFlow(this.asExpr(), result, _) or
|
||||
@@ -117,9 +111,9 @@ module Public {
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
Type getTypeBound() {
|
||||
result = getImprovedTypeBound()
|
||||
result = this.getImprovedTypeBound()
|
||||
or
|
||||
result = getType() and not exists(getImprovedTypeBound())
|
||||
result = this.getType() and not exists(this.getImprovedTypeBound())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +126,7 @@ module Public {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +251,18 @@ module Public {
|
||||
abstract Node getPreUpdateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the value of a field.
|
||||
*/
|
||||
class FieldValueNode extends Node, TFieldValueNode {
|
||||
/** Gets the field corresponding to this node. */
|
||||
Field getField() { this = TFieldValueNode(result) }
|
||||
|
||||
override string toString() { result = getField().toString() }
|
||||
|
||||
override Location getLocation() { result = getField().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node that occurs as the qualifier of `fa`.
|
||||
*/
|
||||
@@ -288,9 +294,9 @@ private class NewExpr extends PostUpdateNode, TExprNode {
|
||||
* A `PostUpdateNode` that is not a `ClassInstanceExpr`.
|
||||
*/
|
||||
abstract private class ImplicitPostUpdateNode extends PostUpdateNode {
|
||||
override Location getLocation() { result = getPreUpdateNode().getLocation() }
|
||||
override Location getLocation() { result = this.getPreUpdateNode().getLocation() }
|
||||
|
||||
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
|
||||
override string toString() { result = this.getPreUpdateNode().toString() + " [post update]" }
|
||||
}
|
||||
|
||||
private class ExplicitExprPostUpdate extends ImplicitPostUpdateNode, TExplicitExprPostUpdate {
|
||||
@@ -304,6 +310,24 @@ private class ImplicitExprPostUpdate extends ImplicitPostUpdateNode, TImplicitEx
|
||||
}
|
||||
|
||||
module Private {
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) {
|
||||
result.asCallable() = n.asExpr().getEnclosingCallable() or
|
||||
result.asCallable() = n.asParameter().getCallable() or
|
||||
result.asCallable() = n.(ImplicitVarargsArray).getCall().getEnclosingCallable() or
|
||||
result.asCallable() = n.(InstanceParameterNode).getCallable() or
|
||||
result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
|
||||
result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
|
||||
result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or
|
||||
n = TSummaryInternalNode(result, _) or
|
||||
result.asFieldScope() = n.(FieldValueNode).getField()
|
||||
}
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) {
|
||||
p.isParameterOf(c.asCallable(), pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that occurs as the argument of a call and is passed as-is
|
||||
* to the callable. Arguments that are wrapped in an implicit varargs array
|
||||
|
||||
@@ -5,8 +5,10 @@ private import DataFlowDispatch
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
private import ContainerFlow
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.dataflow.FlowSummary
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import DataFlowImplConsistency
|
||||
import DataFlowNodes::Private
|
||||
|
||||
private newtype TReturnKind = TNormalReturnKind()
|
||||
@@ -32,12 +34,18 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` through a static field.
|
||||
*/
|
||||
private predicate staticFieldStep(ExprNode node1, ExprNode node2) {
|
||||
private predicate staticFieldStep(Node node1, Node node2) {
|
||||
exists(Field f |
|
||||
f.isStatic() and
|
||||
f.getAnAssignedValue() = node1.asExpr() and
|
||||
node2.(FieldValueNode).getField() = f
|
||||
)
|
||||
or
|
||||
exists(Field f, FieldRead fr |
|
||||
f.isStatic() and
|
||||
f.getAnAssignedValue() = node1.getExpr() and
|
||||
node1.(FieldValueNode).getField() = f and
|
||||
fr.getField() = f and
|
||||
fr = node2.getExpr() and
|
||||
fr = node2.asExpr() and
|
||||
hasNonlocalValue(fr)
|
||||
)
|
||||
}
|
||||
@@ -67,9 +75,14 @@ private predicate variableCaptureStep(Node node1, ExprNode node2) {
|
||||
* variable capture.
|
||||
*/
|
||||
predicate jumpStep(Node node1, Node node2) {
|
||||
staticFieldStep(node1, node2) or
|
||||
variableCaptureStep(node1, node2) or
|
||||
staticFieldStep(node1, node2)
|
||||
or
|
||||
variableCaptureStep(node1, node2)
|
||||
or
|
||||
variableCaptureStep(node1.(PostUpdateNode).getPreUpdateNode(), node2)
|
||||
or
|
||||
any(AdditionalValueStep a).step(node1, node2) and
|
||||
node1.getEnclosingCallable() != node2.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,11 +151,10 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
* in `x.f = newValue`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
c instanceof FieldContent and
|
||||
(
|
||||
n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n)
|
||||
exists(FieldAccess fa |
|
||||
instanceFieldAssign(_, fa) and
|
||||
n = getFieldQualifier(fa) and
|
||||
c.(FieldContent).getField() = fa.getField()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
|
||||
@@ -209,7 +221,30 @@ class CastNode extends ExprNode {
|
||||
CastNode() { this.getExpr() instanceof CastExpr }
|
||||
}
|
||||
|
||||
class DataFlowCallable = Callable;
|
||||
private newtype TDataFlowCallable =
|
||||
TCallable(Callable c) or
|
||||
TFieldScope(Field f)
|
||||
|
||||
class DataFlowCallable extends TDataFlowCallable {
|
||||
Callable asCallable() { this = TCallable(result) }
|
||||
|
||||
Field asFieldScope() { this = TFieldScope(result) }
|
||||
|
||||
RefType getDeclaringType() {
|
||||
result = asCallable().getDeclaringType() or
|
||||
result = asFieldScope().getDeclaringType()
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = asCallable().toString() or
|
||||
result = "Field scope: " + asFieldScope().toString()
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
result = asCallable().getLocation() or
|
||||
result = asFieldScope().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
@@ -255,7 +290,9 @@ class SrcCall extends DataFlowCall, TCall {
|
||||
|
||||
SrcCall() { this = TCall(call) }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingCallable() }
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asCallable() = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
@@ -329,19 +366,12 @@ predicate forceHighPrecision(Content c) {
|
||||
c instanceof ArrayContent or c instanceof CollectionContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
|
||||
* modified or its modification cannot be observed, for example if it is a
|
||||
* freshly created object that is not saved in a variable.
|
||||
*
|
||||
* This predicate is only used for consistency checks.
|
||||
*/
|
||||
predicate isImmutableOrUnobservable(Node n) {
|
||||
n.getType() instanceof ImmutableType or n instanceof ImplicitVarargsArray
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { n instanceof SummaryNode }
|
||||
predicate nodeIsHidden(Node n) {
|
||||
n instanceof SummaryNode
|
||||
or
|
||||
n.(ParameterNode).isParameterOf(any(SummarizedCallable c).asCallable(), _)
|
||||
}
|
||||
|
||||
class LambdaCallKind = Method; // the "apply" method in the functional interface
|
||||
|
||||
@@ -349,10 +379,10 @@ class LambdaCallKind = Method; // the "apply" method in the functional interface
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(ClassInstanceExpr func, Interface t, FunctionalInterface interface |
|
||||
creation.asExpr() = func and
|
||||
func.getAnonymousClass().getAMethod() = c and
|
||||
func.getAnonymousClass().getAMethod() = c.asCallable() and
|
||||
func.getConstructedType().extendsOrImplements+(t) and
|
||||
t.getSourceDeclaration() = interface and
|
||||
c.(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and
|
||||
c.asCallable().(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and
|
||||
pragma[only_bind_into](kind) = interface.getRunMethod().getSourceDeclaration()
|
||||
)
|
||||
}
|
||||
@@ -369,3 +399,20 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
|
||||
* side-effect, resulting in a summary from `p` to itself.
|
||||
*
|
||||
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
|
||||
* by default as a heuristic.
|
||||
*/
|
||||
predicate allowParameterReturnInSelf(ParameterNode p) {
|
||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
|
||||
}
|
||||
|
||||
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
||||
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||
n.getType() instanceof ImmutableType or n instanceof ImplicitVarargsArray
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ predicate hasNonlocalValue(FieldRead fr) {
|
||||
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)
|
||||
@@ -131,7 +133,8 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
|
||||
not exists(FieldRead fr |
|
||||
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
|
||||
)
|
||||
) and
|
||||
not FlowSummaryImpl::Private::Steps::summaryClearsContentArg(node1, _)
|
||||
or
|
||||
ThisFlow::adjacentThisRefs(node1, node2)
|
||||
or
|
||||
@@ -155,6 +158,10 @@ 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 =
|
||||
|
||||
@@ -85,6 +85,9 @@ module Public {
|
||||
/** Holds if this stack contains summary component `c`. */
|
||||
predicate contains(SummaryComponent c) { c = this.drop(_).head() }
|
||||
|
||||
/** Gets the bottom element of this stack. */
|
||||
SummaryComponent bottom() { result = this.drop(this.length() - 1).head() }
|
||||
|
||||
/** Gets a textual representation of this stack. */
|
||||
string toString() {
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
@@ -124,6 +127,38 @@ module Public {
|
||||
SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) }
|
||||
}
|
||||
|
||||
private predicate noComponentSpecificCsv(SummaryComponent sc) {
|
||||
not exists(getComponentSpecificCsv(sc))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this component used for flow summaries. */
|
||||
private string getComponentCsv(SummaryComponent sc) {
|
||||
result = getComponentSpecificCsv(sc)
|
||||
or
|
||||
noComponentSpecificCsv(sc) and
|
||||
(
|
||||
exists(int i | sc = TParameterSummaryComponent(i) and result = "Parameter[" + i + "]")
|
||||
or
|
||||
exists(int i | sc = TArgumentSummaryComponent(i) and result = "Argument[" + i + "]")
|
||||
or
|
||||
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this stack used for flow summaries. */
|
||||
string getComponentStackCsv(SummaryComponentStack stack) {
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
head = stack.head() and
|
||||
tail = stack.tail() and
|
||||
result = getComponentCsv(head) + " of " + getComponentStackCsv(tail)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponent c |
|
||||
stack = TSingletonSummaryComponentStack(c) and
|
||||
result = getComponentCsv(c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that exists for QL technical reasons only (the IPA type used
|
||||
* to represent component stacks needs to be bounded).
|
||||
@@ -197,6 +232,8 @@ module Private {
|
||||
or
|
||||
tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and
|
||||
head = thisParam()
|
||||
or
|
||||
derivedFluentFlowPush(_, _, _, head, tail, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -210,7 +247,7 @@ module Private {
|
||||
c.propagatesFlow(output, input, preservesValue) and
|
||||
preservesValue = true and
|
||||
isCallbackParameter(input) and
|
||||
isContentOfArgument(output)
|
||||
isContentOfArgument(output, _)
|
||||
or
|
||||
// flow from the receiver of a callback into the instance-parameter
|
||||
exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
|
||||
@@ -222,16 +259,81 @@ module Private {
|
||||
output = TConsSummaryComponentStack(thisParam(), input) and
|
||||
preservesValue = true
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack arg, SummaryComponentStack return |
|
||||
derivedFluentFlow(c, input, arg, return, preservesValue)
|
||||
|
|
||||
arg.length() = 1 and
|
||||
output = return
|
||||
or
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
derivedFluentFlowPush(c, input, arg, head, tail, 0) and
|
||||
output = SummaryComponentStack::push(head, tail)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Chain together summaries where values get passed into callbacks along the way
|
||||
exists(SummaryComponentStack mid, boolean preservesValue1, boolean preservesValue2 |
|
||||
c.propagatesFlow(input, mid, preservesValue1) and
|
||||
c.propagatesFlow(mid, output, preservesValue2) and
|
||||
mid.drop(mid.length() - 2) =
|
||||
SummaryComponentStack::push(TParameterSummaryComponent(_),
|
||||
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
|
||||
preservesValue = preservesValue1.booleanAnd(preservesValue2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c` has a flow summary from `input` to `arg`, where `arg`
|
||||
* writes to (contents of) the `i`th argument, and `c` has a
|
||||
* value-preserving flow summary from the `i`th argument to a return value
|
||||
* (`return`).
|
||||
*
|
||||
* In such a case, we derive flow from `input` to (contents of) the return
|
||||
* value.
|
||||
*
|
||||
* As an example, this simplifies modeling of fluent methods:
|
||||
* for `StringBuilder.append(x)` with a specified value flow from qualifier to
|
||||
* return value and taint flow from argument 0 to the qualifier, then this
|
||||
* allows us to infer taint flow from argument 0 to the return value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate derivedFluentFlow(
|
||||
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
|
||||
SummaryComponentStack return, boolean preservesValue
|
||||
) {
|
||||
exists(int i |
|
||||
summary(c, input, arg, preservesValue) and
|
||||
isContentOfArgument(arg, i) and
|
||||
summary(c, SummaryComponentStack::singleton(TArgumentSummaryComponent(i)), return, true) and
|
||||
return.bottom() = TReturnSummaryComponent(_)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate derivedFluentFlowPush(
|
||||
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
|
||||
SummaryComponent head, SummaryComponentStack tail, int i
|
||||
) {
|
||||
derivedFluentFlow(c, input, arg, tail, _) and
|
||||
head = arg.drop(i).head() and
|
||||
i = arg.length() - 2
|
||||
or
|
||||
exists(SummaryComponent head0, SummaryComponentStack tail0 |
|
||||
derivedFluentFlowPush(c, input, arg, head0, tail0, i + 1) and
|
||||
head = arg.drop(i).head() and
|
||||
tail = SummaryComponentStack::push(head0, tail0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isCallbackParameter(SummaryComponentStack s) {
|
||||
s.head() = TParameterSummaryComponent(_) and exists(s.tail())
|
||||
}
|
||||
|
||||
private predicate isContentOfArgument(SummaryComponentStack s) {
|
||||
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail())
|
||||
private predicate isContentOfArgument(SummaryComponentStack s, int i) {
|
||||
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail(), i)
|
||||
or
|
||||
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(_))
|
||||
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(i))
|
||||
}
|
||||
|
||||
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
@@ -261,7 +363,10 @@ module Private {
|
||||
|
||||
private newtype TSummaryNodeState =
|
||||
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) }
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or
|
||||
TSummaryNodeClearsContentState(int i, boolean post) {
|
||||
any(SummarizedCallable sc).clearsContent(i, _) and post in [false, true]
|
||||
}
|
||||
|
||||
/**
|
||||
* A state used to break up (complex) flow summaries into atomic flow steps.
|
||||
@@ -308,6 +413,12 @@ module Private {
|
||||
this = TSummaryNodeOutputState(s) and
|
||||
result = "to write: " + s
|
||||
)
|
||||
or
|
||||
exists(int i, boolean post, string postStr |
|
||||
this = TSummaryNodeClearsContentState(i, post) and
|
||||
(if post = true then postStr = " (post)" else postStr = "") and
|
||||
result = "clear: " + i + postStr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,6 +440,11 @@ module Private {
|
||||
not parameterReadState(c, state, _)
|
||||
or
|
||||
state.isOutputState(c, _)
|
||||
or
|
||||
exists(int i |
|
||||
c.clearsContent(i, _) and
|
||||
state = TSummaryNodeClearsContentState(i, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -364,6 +480,8 @@ module Private {
|
||||
parameterReadState(c, _, i)
|
||||
or
|
||||
isParameterPostUpdate(_, c, i)
|
||||
or
|
||||
c.clearsContent(i, _)
|
||||
}
|
||||
|
||||
private predicate callbackOutput(
|
||||
@@ -436,6 +554,12 @@ module Private {
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable c, int i, ParamNode p |
|
||||
n = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and
|
||||
p.isParameterOf(c, i) and
|
||||
result = getNodeType(p)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
|
||||
@@ -461,6 +585,9 @@ module Private {
|
||||
exists(SummarizedCallable c, int i |
|
||||
isParameterPostUpdate(post, c, i) and
|
||||
pre.(ParamNode).isParameterOf(c, i)
|
||||
or
|
||||
pre = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and
|
||||
post = summaryNode(c, TSummaryNodeClearsContentState(i, true))
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||
@@ -478,6 +605,22 @@ module Private {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow is allowed to pass from parameter `p`, to a return
|
||||
* node, and back out to `p`.
|
||||
*/
|
||||
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
||||
exists(SummarizedCallable c, int i | p.isParameterOf(c, i) |
|
||||
c.clearsContent(i, _)
|
||||
or
|
||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||
summary(c, inputContents, outputContents, _) and
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i)) and
|
||||
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a compilation of flow summaries to atomic data-flow steps. */
|
||||
module Steps {
|
||||
/**
|
||||
@@ -498,17 +641,11 @@ module Private {
|
||||
preservesValue = false and not summary(c, inputContents, outputContents, true)
|
||||
)
|
||||
or
|
||||
// If flow through a method updates a parameter from some input A, and that
|
||||
// parameter also is returned through B, then we'd like a combined flow from A
|
||||
// to B as well. As an example, this simplifies modeling of fluent methods:
|
||||
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
|
||||
// return value and taint flow from argument 0 to the qualifier, then this
|
||||
// allows us to infer taint flow from argument 0 to the return value.
|
||||
succ instanceof ParamNode and summaryPostUpdateNode(pred, succ) and preservesValue = true
|
||||
or
|
||||
// Similarly we would like to chain together summaries where values get passed
|
||||
// into callbacks along the way.
|
||||
pred instanceof ArgNode and summaryPostUpdateNode(succ, pred) and preservesValue = true
|
||||
exists(SummarizedCallable c, int i |
|
||||
pred.(ParamNode).isParameterOf(c, i) and
|
||||
succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -536,10 +673,39 @@ module Private {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared when passed as
|
||||
* input of type `input` in `call`.
|
||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||
* synthesized summary node, so in order for values to be cleared at calls
|
||||
* to the relevant method, it is important that flow does not pass over
|
||||
* the argument, either via use-use flow or def-use flow.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* a.b = taint;
|
||||
* a.clearB(); // assume we have a flow summary for `clearB` that clears `b` on the qualifier
|
||||
* sink(a.b);
|
||||
* ```
|
||||
*
|
||||
* In the above, flow should not pass from `a` on the first line (or the second
|
||||
* line) to `a` on the third line. Instead, there will be synthesized flow from
|
||||
* `a` on line 2 to the post-update node for `a` on that line (via an intermediate
|
||||
* node where field `b` is cleared).
|
||||
*/
|
||||
predicate summaryClearsContent(ArgNode arg, Content c) {
|
||||
predicate summaryClearsContent(Node n, Content c) {
|
||||
exists(SummarizedCallable sc, int i |
|
||||
n = summaryNode(sc, TSummaryNodeClearsContentState(i, true)) and
|
||||
sc.clearsContent(i, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared inside a
|
||||
* callable to which `arg` is an argument.
|
||||
*
|
||||
* In such cases, it is important to prevent use-use flow out of
|
||||
* `arg` (see comment for `summaryClearsContent`).
|
||||
*/
|
||||
predicate summaryClearsContentArg(ArgNode arg, Content c) {
|
||||
exists(DataFlowCall call, int i |
|
||||
viableCallable(call).(SummarizedCallable).clearsContent(i, c) and
|
||||
arg.argumentOf(call, i)
|
||||
@@ -599,25 +765,6 @@ module Private {
|
||||
ret.getKind() = rk
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data is written into content `c` of argument `arg` using a flow summary.
|
||||
*
|
||||
* Depending on the type of `c`, this predicate may be relevant to include in the
|
||||
* definition of `clearsContent()`.
|
||||
*/
|
||||
predicate summaryStoresIntoArg(Content c, Node arg) {
|
||||
exists(ParamUpdateReturnKind rk, ReturnNodeExt ret, PostUpdateNode out |
|
||||
exists(DataFlowCall call, SummarizedCallable callable |
|
||||
getNodeEnclosingCallable(ret) = callable and
|
||||
viableCallable(call) = callable and
|
||||
summaryStoreStep(_, c, ret) and
|
||||
ret.getKind() = pragma[only_bind_into](rk) and
|
||||
out = rk.getAnOutNode(call) and
|
||||
arg = out.getPreUpdateNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,18 +1002,38 @@ module Private {
|
||||
module TestOutput {
|
||||
/** A flow summary to include in the `summary/3` query predicate. */
|
||||
abstract class RelevantSummarizedCallable extends SummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/3`. */
|
||||
string getFullString() { result = this.toString() }
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
/** Holds if flow is propagated between `input` and `output`. */
|
||||
predicate relevantSummary(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
this.propagatesFlow(input, output, preservesValue)
|
||||
}
|
||||
}
|
||||
|
||||
/** A query predicate for outputting flow summaries in QL tests. */
|
||||
query predicate summary(string callable, string flow, boolean preservesValue) {
|
||||
/** Render the kind in the format used in flow summaries. */
|
||||
private string renderKind(boolean preservesValue) {
|
||||
preservesValue = true and result = "value"
|
||||
or
|
||||
preservesValue = false and result = "taint"
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;kind",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
exists(
|
||||
RelevantSummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output
|
||||
RelevantSummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output,
|
||||
boolean preservesValue
|
||||
|
|
||||
callable = c.getFullString() and
|
||||
c.propagatesFlow(input, output, preservesValue) and
|
||||
flow = input + " -> " + output
|
||||
c.relevantSummary(input, output, preservesValue) and
|
||||
csv =
|
||||
c.getCallableCsv() + ";;" + getComponentStackCsv(input) + ";" +
|
||||
getComponentStackCsv(output) + ";" + renderKind(preservesValue)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,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.getReturnType()) and
|
||||
result = getErasedRepr(c.asCallable().getReturnType()) and
|
||||
exists(rk)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
|
||||
c = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
c.asCallable() = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,32 @@ SummaryComponent interpretComponentSpecific(string c) {
|
||||
exists(Content content | parseContent(c, content) and result = SummaryComponent::content(content))
|
||||
}
|
||||
|
||||
/** Gets the summary component for specification component `c`, if any. */
|
||||
private string getContentSpecificCsv(Content c) {
|
||||
exists(Field f, string package, string className, string fieldName |
|
||||
f = c.(FieldContent).getField() and
|
||||
f.hasQualifiedName(package, className, fieldName) and
|
||||
result = "Field[" + package + "." + className + "." + fieldName + "]"
|
||||
)
|
||||
or
|
||||
exists(SyntheticField f |
|
||||
f = c.(SyntheticFieldContent).getField() and result = "SyntheticField[" + f + "]"
|
||||
)
|
||||
or
|
||||
c instanceof ArrayContent and result = "ArrayElement"
|
||||
or
|
||||
c instanceof CollectionContent and result = "Element"
|
||||
or
|
||||
c instanceof MapKeyContent and result = "MapKey"
|
||||
or
|
||||
c instanceof MapValueContent and result = "MapValue"
|
||||
}
|
||||
|
||||
/** Gets the textual representation of the content in the format used for flow summaries. */
|
||||
string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecificCsv(c))
|
||||
}
|
||||
|
||||
class SourceOrSinkElement = Top;
|
||||
|
||||
/**
|
||||
@@ -119,7 +145,7 @@ class InterpretNode extends TInterpretNode {
|
||||
DataFlowCall asCall() { result.asCall() = this.asElement() }
|
||||
|
||||
/** Gets the callable that this node corresponds to, if any. */
|
||||
DataFlowCallable asCallable() { result = this.asElement() }
|
||||
DataFlowCallable asCallable() { result.asCallable() = this.asElement() }
|
||||
|
||||
/** Gets the target of this call, if any. */
|
||||
Callable getCallTarget() { result = this.asCall().asCall().getCallee().getSourceDeclaration() }
|
||||
|
||||
@@ -285,11 +285,11 @@ private predicate taintPreservingQualifierToMethod(Method m) {
|
||||
|
||||
private class StringReplaceMethod extends TaintPreservingCallable {
|
||||
StringReplaceMethod() {
|
||||
getDeclaringType() instanceof TypeString and
|
||||
this.getDeclaringType() instanceof TypeString and
|
||||
(
|
||||
hasName("replace") or
|
||||
hasName("replaceAll") or
|
||||
hasName("replaceFirst")
|
||||
this.hasName("replace") or
|
||||
this.hasName("replaceAll") or
|
||||
this.hasName("replaceFirst")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -300,8 +300,8 @@ private predicate unsafeEscape(MethodAccess ma) {
|
||||
// Removing `<script>` tags using a string-replace method is
|
||||
// unsafe if such a tag is embedded inside another one (e.g. `<scr<script>ipt>`).
|
||||
exists(StringReplaceMethod m | ma.getMethod() = m |
|
||||
ma.getArgument(0).(StringLiteral).getRepresentedString() = "(<script>)" and
|
||||
ma.getArgument(1).(StringLiteral).getRepresentedString() = ""
|
||||
ma.getArgument(0).(StringLiteral).getValue() = "(<script>)" and
|
||||
ma.getArgument(1).(StringLiteral).getValue() = ""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -376,13 +376,6 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
|
||||
* `arg` is the index of the argument.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
|
||||
exists(Method write |
|
||||
method.overrides*(write) and
|
||||
write.hasName("write") and
|
||||
arg = 0 and
|
||||
write.getDeclaringType().hasQualifiedName("java.io", "OutputStream")
|
||||
)
|
||||
or
|
||||
method.(TaintPreservingCallable).transfersTaint(arg, -1)
|
||||
}
|
||||
|
||||
@@ -443,7 +436,7 @@ class ObjectOutputStreamVar extends LocalVariableDecl {
|
||||
}
|
||||
|
||||
MethodAccess getAWriteObjectMethodAccess() {
|
||||
result.getQualifier() = getAnAccess() and
|
||||
result.getQualifier() = this.getAnAccess() and
|
||||
result.getMethod().hasName("writeObject")
|
||||
}
|
||||
}
|
||||
@@ -488,7 +481,7 @@ private class FormatterVar extends LocalVariableDecl {
|
||||
}
|
||||
|
||||
MethodAccess getAFormatMethodAccess() {
|
||||
result.getQualifier() = getAnAccess() and
|
||||
result.getQualifier() = this.getAnAccess() and
|
||||
result.getMethod().hasName("format")
|
||||
}
|
||||
}
|
||||
@@ -513,13 +506,13 @@ private class FormatterCallable extends TaintPreservingCallable {
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) {
|
||||
if this instanceof Constructor then arg = 0 else arg = [-1 .. getNumberOfParameters()]
|
||||
if this instanceof Constructor then arg = 0 else arg = [-1 .. this.getNumberOfParameters()]
|
||||
}
|
||||
|
||||
override predicate transfersTaint(int src, int sink) {
|
||||
this.hasName("format") and
|
||||
sink = -1 and
|
||||
src = [0 .. getNumberOfParameters()]
|
||||
src = [0 .. this.getNumberOfParameters()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,13 +525,13 @@ module StringBuilderVarModule {
|
||||
* build up a query using string concatenation.
|
||||
*/
|
||||
class StringBuilderVar extends LocalVariableDecl {
|
||||
StringBuilderVar() { getType() instanceof StringBuildingType }
|
||||
StringBuilderVar() { this.getType() instanceof StringBuildingType }
|
||||
|
||||
/**
|
||||
* Gets a call that adds something to this string builder, from the argument at the given index.
|
||||
*/
|
||||
MethodAccess getAnInput(int arg) {
|
||||
result.getQualifier() = getAChainedReference() and
|
||||
result.getQualifier() = this.getAChainedReference() and
|
||||
(
|
||||
result.getMethod().getName() = "append" and arg = 0
|
||||
or
|
||||
@@ -552,20 +545,20 @@ module StringBuilderVarModule {
|
||||
* Gets a call that appends something to this string builder.
|
||||
*/
|
||||
MethodAccess getAnAppend() {
|
||||
result.getQualifier() = getAChainedReference() and
|
||||
result.getQualifier() = this.getAChainedReference() and
|
||||
result.getMethod().getName() = "append"
|
||||
}
|
||||
|
||||
MethodAccess getNextAppend(MethodAccess append) {
|
||||
result = getAnAppend() and
|
||||
append = getAnAppend() and
|
||||
result = this.getAnAppend() and
|
||||
append = this.getAnAppend() and
|
||||
(
|
||||
result.getQualifier() = append
|
||||
or
|
||||
not exists(MethodAccess chainAccess | chainAccess.getQualifier() = append) and
|
||||
exists(RValue sbva1, RValue sbva2 |
|
||||
adjacentUseUse(sbva1, sbva2) and
|
||||
append.getQualifier() = getAChainedReference(sbva1) and
|
||||
append.getQualifier() = this.getAChainedReference(sbva1) and
|
||||
result.getQualifier() = sbva2
|
||||
)
|
||||
)
|
||||
@@ -575,7 +568,7 @@ module StringBuilderVarModule {
|
||||
* Gets a call that converts this string builder to a string.
|
||||
*/
|
||||
MethodAccess getToStringCall() {
|
||||
result.getQualifier() = getAChainedReference() and
|
||||
result.getQualifier() = this.getAChainedReference() and
|
||||
result.getMethod().getName() = "toString"
|
||||
}
|
||||
|
||||
@@ -590,7 +583,7 @@ module StringBuilderVarModule {
|
||||
/**
|
||||
* Gets an expression that refers to this `StringBuilder`, possibly after some chained calls.
|
||||
*/
|
||||
Expr getAChainedReference() { result = getAChainedReference(_) }
|
||||
Expr getAChainedReference() { result = this.getAChainedReference(_) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ predicate isLive(Callable c) {
|
||||
* would imply the liveness of `c`.
|
||||
*/
|
||||
Callable possibleLivenessCause(Callable c, string reason) {
|
||||
c.(Method).overridesOrInstantiates(result.(Method)) and
|
||||
c.(Method).overridesOrInstantiates(result) and
|
||||
reason = "is overridden or instantiated by"
|
||||
or
|
||||
result.calls(c) and reason = "calls"
|
||||
or
|
||||
result.callsConstructor(c.(Constructor)) and reason = "calls constructor"
|
||||
result.callsConstructor(c) and reason = "calls constructor"
|
||||
or
|
||||
exists(ClassInstanceExpr e | e.getEnclosingCallable() = result |
|
||||
e.getConstructor() = c and reason = "constructs"
|
||||
@@ -82,19 +82,19 @@ class SuppressedConstructor extends Constructor {
|
||||
SuppressedConstructor() {
|
||||
// Must be private or protected to suppress it.
|
||||
(
|
||||
isPrivate()
|
||||
this.isPrivate()
|
||||
or
|
||||
// A protected, suppressed constructor only makes sense in a non-abstract class.
|
||||
isProtected() and not getDeclaringType().isAbstract()
|
||||
this.isProtected() and not this.getDeclaringType().isAbstract()
|
||||
) and
|
||||
// Must be no-arg in order to replace the compiler generated default constructor.
|
||||
getNumberOfParameters() = 0 and
|
||||
this.getNumberOfParameters() = 0 and
|
||||
// Not the compiler-generated constructor itself.
|
||||
not isDefaultConstructor() and
|
||||
not this.isDefaultConstructor() and
|
||||
// Verify that there is only one statement, which is the `super()` call. This exists
|
||||
// even for empty constructors.
|
||||
getBody().(BlockStmt).getNumStmt() = 1 and
|
||||
getBody().(BlockStmt).getAStmt().(SuperConstructorInvocationStmt).getNumArgument() = 0 and
|
||||
this.getBody().getNumStmt() = 1 and
|
||||
this.getBody().getAStmt().(SuperConstructorInvocationStmt).getNumArgument() = 0 and
|
||||
// A constructor that is called is not acting to suppress the default constructor. We permit
|
||||
// calls from suppressed and default constructors - in both cases, they can only come from
|
||||
// sub-class constructors.
|
||||
@@ -105,7 +105,9 @@ class SuppressedConstructor extends Constructor {
|
||||
) and
|
||||
// If other constructors are declared, then no compiler-generated constructor is added, so
|
||||
// this constructor is not acting to suppress the default compiler-generated constructor.
|
||||
not exists(Constructor other | other = getDeclaringType().getAConstructor() and other != this)
|
||||
not exists(Constructor other |
|
||||
other = this.getDeclaringType().getAConstructor() and other != this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +116,7 @@ class SuppressedConstructor extends Constructor {
|
||||
*/
|
||||
class NamespaceClass extends RefType {
|
||||
NamespaceClass() {
|
||||
fromSource() and
|
||||
this.fromSource() and
|
||||
// All members, apart from the default constructor and, if present, a "suppressed" constructor
|
||||
// must be static. There must be at least one member apart from the permitted constructors.
|
||||
forex(Member m |
|
||||
@@ -125,7 +127,9 @@ class NamespaceClass extends RefType {
|
||||
m.isStatic()
|
||||
) and
|
||||
// Must only extend other namespace classes, or `Object`.
|
||||
forall(RefType r | r = getASupertype() | r instanceof TypeObject or r instanceof NamespaceClass)
|
||||
forall(RefType r | r = this.getASupertype() |
|
||||
r instanceof TypeObject or r instanceof NamespaceClass
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +201,7 @@ class DeadClass extends SourceClassOrInterface {
|
||||
/**
|
||||
* Identify all the "dead" roots of this dead class.
|
||||
*/
|
||||
DeadRoot getADeadRoot() { result = getADeadRoot(getACallable()) }
|
||||
DeadRoot getADeadRoot() { result = getADeadRoot(this.getACallable()) }
|
||||
|
||||
/**
|
||||
* Holds if this dead class is only used within the class itself.
|
||||
@@ -206,8 +210,8 @@ class DeadClass extends SourceClassOrInterface {
|
||||
// Accessed externally if any callable in the class has a possible liveness cause outside the
|
||||
// class. Only one step is required.
|
||||
not exists(Callable c |
|
||||
c = possibleLivenessCause(getACallable()) and
|
||||
not c = getACallable()
|
||||
c = possibleLivenessCause(this.getACallable()) and
|
||||
not c = this.getACallable()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -229,7 +233,7 @@ abstract class WhitelistedLiveClass extends RefType { }
|
||||
*/
|
||||
class DeadMethod extends Callable {
|
||||
DeadMethod() {
|
||||
fromSource() and
|
||||
this.fromSource() and
|
||||
not isLive(this) and
|
||||
not this.(Constructor).isDefaultConstructor() and
|
||||
// Ignore `SuppressedConstructor`s in `NamespaceClass`es. There is no reason to use a suppressed
|
||||
@@ -239,7 +243,7 @@ class DeadMethod extends Callable {
|
||||
) and
|
||||
not (
|
||||
this.(Method).isAbstract() and
|
||||
exists(Method m | m.overridesOrInstantiates+(this.(Method)) | isLive(m))
|
||||
exists(Method m | m.overridesOrInstantiates+(this) | isLive(m))
|
||||
) and
|
||||
// A getter or setter associated with a live JPA field.
|
||||
//
|
||||
|
||||
@@ -10,7 +10,7 @@ import semmle.code.java.frameworks.jackson.JacksonSerializability
|
||||
* This defines the set of fields for which we will determine liveness.
|
||||
*/
|
||||
library class SourceField extends Field {
|
||||
SourceField() { fromSource() }
|
||||
SourceField() { this.fromSource() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class DeadField extends SourceField {
|
||||
*/
|
||||
predicate isInDeadScope() {
|
||||
// `EnumConstant`s, and fields in dead classes, are reported in other queries.
|
||||
getDeclaringType() instanceof DeadClass or
|
||||
this.getDeclaringType() instanceof DeadClass or
|
||||
this instanceof EnumConstant
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class DeadField extends SourceField {
|
||||
*/
|
||||
class LiveField extends SourceField {
|
||||
LiveField() {
|
||||
exists(FieldRead access | access = getAnAccess() |
|
||||
exists(FieldRead access | access = this.getAnAccess() |
|
||||
isLive(access.getEnclosingCallable())
|
||||
or
|
||||
exists(Annotation a |
|
||||
@@ -89,11 +89,11 @@ abstract class WhitelistedLiveField extends Field { }
|
||||
*/
|
||||
class SerialVersionUIDField extends ReflectivelyReadField {
|
||||
SerialVersionUIDField() {
|
||||
hasName("serialVersionUID") and
|
||||
isStatic() and
|
||||
isFinal() and
|
||||
getType().hasName("long") and
|
||||
getDeclaringType().getASupertype*() instanceof TypeSerializable
|
||||
this.hasName("serialVersionUID") and
|
||||
this.isStatic() and
|
||||
this.isFinal() and
|
||||
this.getType().hasName("long") and
|
||||
this.getDeclaringType().getASupertype*() instanceof TypeSerializable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class SerialVersionUIDField extends ReflectivelyReadField {
|
||||
class LiveJaxbBoundField extends ReflectivelyReadField, JaxbBoundField {
|
||||
LiveJaxbBoundField() {
|
||||
// If the class is considered live, it must have at least one live constructor.
|
||||
exists(Constructor c | c = getDeclaringType().getAConstructor() | isLive(c))
|
||||
exists(Constructor c | c = this.getDeclaringType().getAConstructor() | isLive(c))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,11 +114,11 @@ class LiveJaxbBoundField extends ReflectivelyReadField, JaxbBoundField {
|
||||
*/
|
||||
class JUnitAnnotatedField extends ReflectivelyReadField {
|
||||
JUnitAnnotatedField() {
|
||||
hasAnnotation("org.junit.experimental.theories", "DataPoint") or
|
||||
hasAnnotation("org.junit.experimental.theories", "DataPoints") or
|
||||
hasAnnotation("org.junit.runners", "Parameterized$Parameter") or
|
||||
hasAnnotation("org.junit", "Rule") or
|
||||
hasAnnotation("org.junit", "ClassRule")
|
||||
this.hasAnnotation("org.junit.experimental.theories", "DataPoint") or
|
||||
this.hasAnnotation("org.junit.experimental.theories", "DataPoints") or
|
||||
this.hasAnnotation("org.junit.runners", "Parameterized$Parameter") or
|
||||
this.hasAnnotation("org.junit", "Rule") or
|
||||
this.hasAnnotation("org.junit", "ClassRule")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ class JPAReadField extends ReflectivelyReadField {
|
||||
)
|
||||
|
|
||||
not this.hasAnnotation("javax.persistence", "Transient") and
|
||||
not isStatic() and
|
||||
not isFinal()
|
||||
not this.isStatic() and
|
||||
not this.isFinal()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructe
|
||||
override Callable getALiveCallable() {
|
||||
// Constructors may be called by Jackson, if they are a no-arg, they have a suitable annotation,
|
||||
// or inherit a suitable annotation through a mixin.
|
||||
result = getAConstructor() and
|
||||
result = this.getAConstructor() and
|
||||
(
|
||||
result.getNumberOfParameters() = 0 or
|
||||
result.getAnAnnotation() instanceof JacksonAnnotation or
|
||||
@@ -153,7 +153,7 @@ class DeserializedClass extends ReflectivelyConstructedClass {
|
||||
*/
|
||||
class NewInstanceCall extends EntryPoint, NewInstance {
|
||||
override Constructor getALiveCallable() {
|
||||
result = getInferredConstructor() and
|
||||
result = this.getInferredConstructor() and
|
||||
// The `newInstance(...)` call must be used in a live context.
|
||||
isLive(this.getEnclosingCallable())
|
||||
}
|
||||
@@ -164,7 +164,7 @@ class NewInstanceCall extends EntryPoint, NewInstance {
|
||||
*/
|
||||
class ReflectiveMethodAccessEntryPoint extends EntryPoint, ReflectiveMethodAccess {
|
||||
override Method getALiveCallable() {
|
||||
result = inferAccessedMethod() and
|
||||
result = this.inferAccessedMethod() and
|
||||
// The `getMethod(...)` call must be used in a live context.
|
||||
isLive(this.getEnclosingCallable())
|
||||
}
|
||||
@@ -210,8 +210,8 @@ class JaxbXmlEnum extends AnnotationEntryPoint {
|
||||
class JaxbXmlType extends AnnotationEntryPoint, JaxbType {
|
||||
override Callable getALiveCallable() {
|
||||
// Must have a live no-arg constructor for JAXB to perform marshal/unmarshal.
|
||||
exists(Constructor c | c = getAConstructor() and c.getNumberOfParameters() = 0 | isLive(c)) and
|
||||
result = getACallable() and
|
||||
exists(Constructor c | c = this.getAConstructor() and c.getNumberOfParameters() = 0 | isLive(c)) and
|
||||
result = this.getACallable() and
|
||||
(
|
||||
// A bound getter or setter.
|
||||
result instanceof JaxbBoundGetterSetter
|
||||
@@ -262,7 +262,7 @@ class ManagedBeanImplEntryPoint extends EntryPoint, RegisteredManagedBeanImpl {
|
||||
// Find the method that will be called for each method on each managed bean that this class
|
||||
// implements.
|
||||
this.inherits(result) and
|
||||
result.(Method).overrides(getAnImplementedManagedBean().getAMethod())
|
||||
result.overrides+(this.getAnImplementedManagedBean().getAMethod())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ class JavaxResourceAnnotatedMethod extends CallableEntryPointOnConstructedClass
|
||||
*/
|
||||
class JavaxManagedBeanReflectivelyConstructed extends ReflectivelyConstructedClass {
|
||||
JavaxManagedBeanReflectivelyConstructed() {
|
||||
getAnAnnotation() instanceof JavaxManagedBeanAnnotation
|
||||
this.getAnAnnotation() instanceof JavaxManagedBeanAnnotation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,13 +413,13 @@ class PersistencePropertyMethod extends CallableEntryPoint {
|
||||
*/
|
||||
class PersistenceCallbackMethod extends CallableEntryPoint {
|
||||
PersistenceCallbackMethod() {
|
||||
getAnAnnotation() instanceof PrePersistAnnotation or
|
||||
getAnAnnotation() instanceof PreRemoveAnnotation or
|
||||
getAnAnnotation() instanceof PreUpdateAnnotation or
|
||||
getAnAnnotation() instanceof PostPersistAnnotation or
|
||||
getAnAnnotation() instanceof PostRemoveAnnotation or
|
||||
getAnAnnotation() instanceof PostUpdateAnnotation or
|
||||
getAnAnnotation() instanceof PostLoadAnnotation
|
||||
this.getAnAnnotation() instanceof PrePersistAnnotation or
|
||||
this.getAnAnnotation() instanceof PreRemoveAnnotation or
|
||||
this.getAnAnnotation() instanceof PreUpdateAnnotation or
|
||||
this.getAnAnnotation() instanceof PostPersistAnnotation or
|
||||
this.getAnAnnotation() instanceof PostRemoveAnnotation or
|
||||
this.getAnAnnotation() instanceof PostUpdateAnnotation or
|
||||
this.getAnAnnotation() instanceof PostLoadAnnotation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,20 +429,20 @@ class PersistenceCallbackMethod extends CallableEntryPoint {
|
||||
*/
|
||||
class ArbitraryXMLEntryPoint extends ReflectivelyConstructedClass {
|
||||
ArbitraryXMLEntryPoint() {
|
||||
fromSource() and
|
||||
this.fromSource() and
|
||||
exists(XMLAttribute attribute |
|
||||
attribute.getName() = "className" or
|
||||
attribute.getName().matches("%ClassName") or
|
||||
attribute.getName() = "class" or
|
||||
attribute.getName().matches("%Class")
|
||||
|
|
||||
attribute.getValue() = getQualifiedName()
|
||||
attribute.getValue() = this.getQualifiedName()
|
||||
)
|
||||
}
|
||||
|
||||
override Callable getALiveCallable() {
|
||||
// Any constructor on these classes, as we don't know which may be called.
|
||||
result = getAConstructor()
|
||||
result = this.getAConstructor()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class Struts1ActionEntryPoint extends EntryPoint, Class {
|
||||
exists(Method methodFromAction |
|
||||
methodFromAction.getDeclaringType().hasQualifiedName("org.apache.struts.action", "Action")
|
||||
|
|
||||
result.(Method).overrides(methodFromAction)
|
||||
result.(Method).overrides+(methodFromAction)
|
||||
)
|
||||
or
|
||||
this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and
|
||||
|
||||
@@ -18,7 +18,7 @@ class TestMethodEntry extends CallableEntryPoint {
|
||||
or
|
||||
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
|
||||
a.hasQualifiedName("org.junit.runners", "Parameterized$Parameters") and
|
||||
getDeclaringType() instanceof ParameterizedJUnitTest
|
||||
this.getDeclaringType() instanceof ParameterizedJUnitTest
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,12 @@ class TestMethodEntry extends CallableEntryPoint {
|
||||
*/
|
||||
class BeforeOrAfterEntry extends CallableEntryPoint {
|
||||
BeforeOrAfterEntry() {
|
||||
getAnAnnotation() instanceof TestNGBeforeAnnotation or
|
||||
getAnAnnotation() instanceof TestNGAfterAnnotation or
|
||||
getAnAnnotation() instanceof BeforeAnnotation or
|
||||
getAnAnnotation() instanceof BeforeClassAnnotation or
|
||||
getAnAnnotation() instanceof AfterAnnotation or
|
||||
getAnAnnotation() instanceof AfterClassAnnotation
|
||||
this.getAnAnnotation() instanceof TestNGBeforeAnnotation or
|
||||
this.getAnAnnotation() instanceof TestNGAfterAnnotation or
|
||||
this.getAnAnnotation() instanceof BeforeAnnotation or
|
||||
this.getAnAnnotation() instanceof BeforeClassAnnotation or
|
||||
this.getAnAnnotation() instanceof AfterAnnotation or
|
||||
this.getAnAnnotation() instanceof AfterClassAnnotation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class JUnitTheories extends CallableEntryPoint {
|
||||
JUnitTheories() {
|
||||
exists(AnnotationType a |
|
||||
a = this.getAnAnnotation().getType() and
|
||||
getDeclaringType() instanceof JUnitTheoryTest
|
||||
this.getDeclaringType() instanceof JUnitTheoryTest
|
||||
|
|
||||
a.hasQualifiedName("org.junit.experimental.theories", "Theory") or
|
||||
a.hasQualifiedName("org.junit.experimental.theories", "DataPoint") or
|
||||
@@ -63,7 +63,7 @@ class JUnitDataPointField extends ReflectivelyReadField {
|
||||
a.hasQualifiedName("org.junit.experimental.theories", "DataPoint") or
|
||||
a.hasQualifiedName("org.junit.experimental.theories", "DataPoints")
|
||||
) and
|
||||
getDeclaringType() instanceof JUnitTheoryTest
|
||||
this.getDeclaringType() instanceof JUnitTheoryTest
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ class CucumberConstructedClass extends ReflectivelyConstructedClass {
|
||||
// Consider any constructor to be live - Cucumber calls a runtime-specified dependency
|
||||
// injection framework (possibly an in-built one) to construct these instances, so any
|
||||
// constructor could be called.
|
||||
result = getAConstructor()
|
||||
result = this.getAConstructor()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class ServletConstructedClass extends ReflectivelyConstructedClass {
|
||||
*/
|
||||
class ServletListenerClass extends ReflectivelyConstructedClass {
|
||||
ServletListenerClass() {
|
||||
getAnAncestor() instanceof ServletWebXMLListenerType and
|
||||
this.getAnAncestor() instanceof ServletWebXMLListenerType and
|
||||
// If we have seen any `web.xml` files, this listener will be considered to be live only if it is
|
||||
// referred to as a listener-class in at least one. If no `web.xml` files are found, we assume
|
||||
// that XML extraction was not enabled, and therefore consider all listener classes as live.
|
||||
@@ -47,7 +47,7 @@ class ServletListenerClass extends ReflectivelyConstructedClass {
|
||||
*/
|
||||
class ServletFilterClass extends ReflectivelyConstructedClass {
|
||||
ServletFilterClass() {
|
||||
getASupertype*().hasQualifiedName("javax.servlet", "Filter") and
|
||||
this.getASupertype*().hasQualifiedName("javax.servlet", "Filter") and
|
||||
// If we have seen any `web.xml` files, this filter will be considered to be live only if it is
|
||||
// referred to as a filter-class in at least one. If no `web.xml` files are found, we assume
|
||||
// that XML extraction was not enabled, and therefore consider all filter classes as live.
|
||||
|
||||
@@ -189,10 +189,9 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) {
|
||||
n2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() = c
|
||||
)
|
||||
or
|
||||
exists(Field f |
|
||||
f.getAnAssignedValue() = n1.asExpr() and
|
||||
n2.asExpr().(FieldRead).getField() = f
|
||||
)
|
||||
n2.(FieldValueNode).getField().getAnAssignedValue() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(FieldRead).getField() = n1.(FieldValueNode).getField()
|
||||
or
|
||||
exists(EnumType enum, Method getValue |
|
||||
enum.getAnEnumConstant().getAnAssignedValue() = n1.asExpr() and
|
||||
|
||||
@@ -94,10 +94,9 @@ private predicate step(Node n1, Node n2) {
|
||||
n2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() = c
|
||||
)
|
||||
or
|
||||
exists(Field f |
|
||||
f.getAnAssignedValue() = n1.asExpr() and
|
||||
n2.asExpr().(FieldRead).getField() = f
|
||||
)
|
||||
n2.(FieldValueNode).getField().getAnAssignedValue() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(FieldRead).getField() = n1.(FieldValueNode).getField()
|
||||
or
|
||||
n2.asExpr().(CastExpr).getExpr() = n1.asExpr()
|
||||
or
|
||||
@@ -132,7 +131,7 @@ private predicate step(Node n1, Node n2) {
|
||||
or
|
||||
exists(Field v |
|
||||
containerStep(n1.asExpr(), v.getAnAccess()) and
|
||||
n2.asExpr() = v.getAnAccess()
|
||||
n2.(FieldValueNode).getField() = v
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,10 @@ private Expr getRunnerArgument(MethodAccess ma, Method runmethod) {
|
||||
or
|
||||
getRunnerArgument(ma, runmethod).(CastExpr).getExpr() = result
|
||||
or
|
||||
getRunnerArgument(ma, runmethod).(VarAccess).getVariable().getAnAssignedValue() = result
|
||||
pragma[only_bind_out](getRunnerArgument(ma, runmethod))
|
||||
.(VarAccess)
|
||||
.getVariable()
|
||||
.getAnAssignedValue() = result
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ class CamelToBeanURI extends CamelToURI {
|
||||
/**
|
||||
* Gets the bean referenced by this URI.
|
||||
*/
|
||||
SpringBean getRefBean() { result.getBeanIdentifier() = getBeanIdentifier() }
|
||||
SpringBean getRefBean() { result.getBeanIdentifier() = this.getBeanIdentifier() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ class GuiceProvider extends Interface {
|
||||
* A method that overrides the `get` method on the interface `com.google.inject.Provider`.
|
||||
*/
|
||||
Method getAnOverridingGetMethod() {
|
||||
exists(Method m | m.getSourceDeclaration() = getGetMethod() | result.overrides*(m))
|
||||
exists(Method m | m.getSourceDeclaration() = this.getGetMethod() | result.overrides*(m))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ library class JAXBMarshalMethod extends Method {
|
||||
}
|
||||
|
||||
class JaxbAnnotationType extends AnnotationType {
|
||||
JaxbAnnotationType() { getPackage().getName() = "javax.xml.bind.annotation" }
|
||||
JaxbAnnotationType() { this.getPackage().getName() = "javax.xml.bind.annotation" }
|
||||
}
|
||||
|
||||
class JaxbAnnotated extends Annotatable {
|
||||
JaxbAnnotated() { getAnAnnotation().getType() instanceof JaxbAnnotationType }
|
||||
JaxbAnnotated() { this.getAnAnnotation().getType() instanceof JaxbAnnotationType }
|
||||
|
||||
predicate hasJaxbAnnotation(string name) { hasJaxbAnnotation(this, name) }
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class JaxbType extends Class {
|
||||
this.getAnAnnotation() = a and
|
||||
a.getType().(JaxbAnnotationType).hasName("XmlAccessorType")
|
||||
|
|
||||
result.getAnAccess() = a.getValue("value").(VarAccess)
|
||||
result.getAnAccess() = a.getValue("value")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ class JaxbType extends Class {
|
||||
* Gets the `XmlAccessType` associated with this class.
|
||||
*/
|
||||
XmlAccessType getXmlAccessType() {
|
||||
if exists(getDeclaredAccessType())
|
||||
then result = getDeclaredAccessType()
|
||||
if exists(this.getDeclaredAccessType())
|
||||
then result = this.getDeclaredAccessType()
|
||||
else
|
||||
// Default access type, if not specified.
|
||||
result.isPublicMember()
|
||||
@@ -81,22 +81,22 @@ class XmlAccessType extends EnumConstant {
|
||||
/**
|
||||
* All public getter/setter pairs and public fields will be bound.
|
||||
*/
|
||||
predicate isPublicMember() { getName() = "PUBLIC_MEMBER" }
|
||||
predicate isPublicMember() { this.getName() = "PUBLIC_MEMBER" }
|
||||
|
||||
/**
|
||||
* All non-static, non-transient fields will be bound.
|
||||
*/
|
||||
predicate isField() { getName() = "FIELD" }
|
||||
predicate isField() { this.getName() = "FIELD" }
|
||||
|
||||
/**
|
||||
* All getter/setter pairs will be bound.
|
||||
*/
|
||||
predicate isProperty() { getName() = "PROPERTY" }
|
||||
predicate isProperty() { this.getName() = "PROPERTY" }
|
||||
|
||||
/**
|
||||
* Nothing will be bound automatically.
|
||||
*/
|
||||
predicate isNone() { getName() = "NONE" }
|
||||
predicate isNone() { this.getName() = "NONE" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,10 +105,10 @@ class XmlAccessType extends EnumConstant {
|
||||
*/
|
||||
class JaxbMemberAnnotation extends JaxbAnnotationType {
|
||||
JaxbMemberAnnotation() {
|
||||
hasName("XmlElement") or
|
||||
hasName("XmlAttribute") or
|
||||
hasName("XmlElementRefs") or
|
||||
hasName("XmlElements")
|
||||
this.hasName("XmlElement") or
|
||||
this.hasName("XmlAttribute") or
|
||||
this.hasName("XmlElementRefs") or
|
||||
this.hasName("XmlElements")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,14 +121,14 @@ private predicate isTransient(Member m) { hasJaxbAnnotation(m, "XmlTransient") }
|
||||
class JaxbBoundField extends Field {
|
||||
JaxbBoundField() {
|
||||
// Fields cannot be static, because JAXB creates instances.
|
||||
not isStatic() and
|
||||
not this.isStatic() and
|
||||
// Fields cannot be final, because JAXB instantiates the object, then sets the properties.
|
||||
not isFinal() and
|
||||
not this.isFinal() and
|
||||
// No transient fields are ever bound.
|
||||
not isTransient(this) and
|
||||
(
|
||||
// Explicitly annotated to be bound.
|
||||
exists(getAnAnnotation().getType().(JaxbMemberAnnotation))
|
||||
exists(this.getAnAnnotation().getType().(JaxbMemberAnnotation))
|
||||
or
|
||||
// Within a JAXB type which has an `XmlAcessType` that binds this field.
|
||||
exists(JaxbType type | this.getDeclaringType() = type |
|
||||
@@ -136,7 +136,7 @@ class JaxbBoundField extends Field {
|
||||
type.getXmlAccessType().isField()
|
||||
or
|
||||
// Only public fields are automatically bound in this access type.
|
||||
type.getXmlAccessType().isPublicMember() and isPublic()
|
||||
type.getXmlAccessType().isPublicMember() and this.isPublic()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -157,7 +157,7 @@ library class GetterOrSetterMethod extends Method {
|
||||
* Holds if this method has a "pair"ed method, e.g. whether there is an equivalent getter if this
|
||||
* is a setter, and vice versa.
|
||||
*/
|
||||
predicate isProperty() { exists(getPair()) }
|
||||
predicate isProperty() { exists(this.getPair()) }
|
||||
|
||||
/**
|
||||
* Gets the "pair" method, if one exists; that is, the getter if this is a setter, and vice versa.
|
||||
@@ -183,16 +183,16 @@ class JaxbBoundGetterSetter extends GetterOrSetterMethod {
|
||||
this.getField() instanceof JaxbBoundField
|
||||
or
|
||||
// An annotation on this method or the pair that indicate that it is a valid setter/getter.
|
||||
getThisOrPair().getAnAnnotation().getType() instanceof JaxbMemberAnnotation
|
||||
this.getThisOrPair().getAnAnnotation().getType() instanceof JaxbMemberAnnotation
|
||||
or
|
||||
// Within a JAXB type which has an `XmlAcessType` that binds this method.
|
||||
exists(JaxbType c | this.getDeclaringType() = c |
|
||||
// If this is a "property" - both a setter and getter present for the XML element or attribute
|
||||
// - the `XmlAccessType` of the declaring type may cause this property to be bound.
|
||||
isProperty() and
|
||||
this.isProperty() and
|
||||
(
|
||||
// In the `PUBLIC_MEMBER` case all public properties are considered bound.
|
||||
c.getXmlAccessType().isPublicMember() and isPublic()
|
||||
c.getXmlAccessType().isPublicMember() and this.isPublic()
|
||||
or
|
||||
// In "property" all properties are considered bound.
|
||||
c.getXmlAccessType().isProperty()
|
||||
|
||||
@@ -64,5 +64,5 @@ class RunWithAnnotation extends Annotation {
|
||||
/**
|
||||
* Gets the runner that will be used.
|
||||
*/
|
||||
Type getRunner() { result = getValue("value").(TypeLiteral).getReferencedType() }
|
||||
Type getRunner() { result = this.getValue("value").(TypeLiteral).getReferencedType() }
|
||||
}
|
||||
|
||||
@@ -7,31 +7,31 @@ private import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
private class ObjectMapper extends RefType {
|
||||
ObjectMapper() {
|
||||
getASupertype*().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper")
|
||||
this.getASupertype*().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper")
|
||||
}
|
||||
}
|
||||
|
||||
/** A builder for building Jackson's `JsonMapper`. */
|
||||
class MapperBuilder extends RefType {
|
||||
MapperBuilder() {
|
||||
hasQualifiedName("com.fasterxml.jackson.databind.cfg", "MapperBuilder<JsonMapper,Builder>")
|
||||
this.hasQualifiedName("com.fasterxml.jackson.databind.cfg", "MapperBuilder<JsonMapper,Builder>")
|
||||
}
|
||||
}
|
||||
|
||||
private class JsonFactory extends RefType {
|
||||
JsonFactory() { hasQualifiedName("com.fasterxml.jackson.core", "JsonFactory") }
|
||||
JsonFactory() { this.hasQualifiedName("com.fasterxml.jackson.core", "JsonFactory") }
|
||||
}
|
||||
|
||||
private class JsonParser extends RefType {
|
||||
JsonParser() { hasQualifiedName("com.fasterxml.jackson.core", "JsonParser") }
|
||||
JsonParser() { this.hasQualifiedName("com.fasterxml.jackson.core", "JsonParser") }
|
||||
}
|
||||
|
||||
/** A type descriptor in Jackson libraries. For example, `java.lang.Class`. */
|
||||
class JacksonTypeDescriptorType extends RefType {
|
||||
JacksonTypeDescriptorType() {
|
||||
this instanceof TypeClass or
|
||||
hasQualifiedName("com.fasterxml.jackson.databind", "JavaType") or
|
||||
hasQualifiedName("com.fasterxml.jackson.core.type", "TypeReference")
|
||||
this.hasQualifiedName("com.fasterxml.jackson.databind", "JavaType") or
|
||||
this.hasQualifiedName("com.fasterxml.jackson.core.type", "TypeReference")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,7 @@ string getAJaxRsPackage(string subpackage) { result = getAJaxRsPackage() + "." +
|
||||
class JaxWsEndpoint extends Class {
|
||||
JaxWsEndpoint() {
|
||||
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
|
||||
a.hasName("WebService") or
|
||||
a.hasName("WebServiceProvider") or
|
||||
a.hasName("WebServiceClient")
|
||||
a.hasName(["WebService", "WebServiceProvider", "WebServiceClient"])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -35,8 +33,7 @@ class JaxWsEndpoint extends Class {
|
||||
Callable getARemoteMethod() {
|
||||
result = this.getACallable() and
|
||||
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
|
||||
a.hasName("WebMethod") or
|
||||
a.hasName("WebEndpoint")
|
||||
a.hasName(["WebMethod", "WebEndpoint"])
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -62,12 +59,7 @@ class JaxRsResourceMethod extends Method {
|
||||
a = this.getAnAnnotation().getType() and
|
||||
a.getPackage().getName() = getAJaxRsPackage()
|
||||
|
|
||||
a.hasName("GET") or
|
||||
a.hasName("POST") or
|
||||
a.hasName("DELETE") or
|
||||
a.hasName("PUT") or
|
||||
a.hasName("OPTIONS") or
|
||||
a.hasName("HEAD")
|
||||
a.hasName(["GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD"])
|
||||
)
|
||||
or
|
||||
// A JaxRS resource method can also inherit these annotations from a supertype, but only if
|
||||
@@ -201,13 +193,10 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
|
||||
a = this.getType() and
|
||||
a.getPackage().getName() = getAJaxRsPackage()
|
||||
|
|
||||
a.hasName("BeanParam") or
|
||||
a.hasName("CookieParam") or
|
||||
a.hasName("FormParam") or
|
||||
a.hasName("HeaderParam") or
|
||||
a.hasName("MatrixParam") or
|
||||
a.hasName("PathParam") or
|
||||
a.hasName("QueryParam")
|
||||
a.hasName([
|
||||
"BeanParam", "CookieParam", "FormParam", "HeaderParam", "MatrixParam", "PathParam",
|
||||
"QueryParam"
|
||||
])
|
||||
)
|
||||
or
|
||||
this.getType().hasQualifiedName(getAJaxRsPackage("core"), "Context")
|
||||
|
||||
@@ -41,39 +41,39 @@ class TypeLdapName extends Class {
|
||||
/** A method with the name `addAll` declared in `javax.naming.ldap.LdapName`. */
|
||||
class MethodLdapNameAddAll extends Method {
|
||||
MethodLdapNameAddAll() {
|
||||
getDeclaringType() instanceof TypeLdapName and
|
||||
hasName("addAll")
|
||||
this.getDeclaringType() instanceof TypeLdapName and
|
||||
this.hasName("addAll")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `clone` declared in `javax.naming.ldap.LdapName`. */
|
||||
class MethodLdapNameClone extends Method {
|
||||
MethodLdapNameClone() {
|
||||
getDeclaringType() instanceof TypeLdapName and
|
||||
hasName("clone")
|
||||
this.getDeclaringType() instanceof TypeLdapName and
|
||||
this.hasName("clone")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `getAll` declared in `javax.naming.ldap.LdapName`. */
|
||||
class MethodLdapNameGetAll extends Method {
|
||||
MethodLdapNameGetAll() {
|
||||
getDeclaringType() instanceof TypeLdapName and
|
||||
hasName("getAll")
|
||||
this.getDeclaringType() instanceof TypeLdapName and
|
||||
this.hasName("getAll")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `getRdns` declared in `javax.naming.ldap.LdapName`. */
|
||||
class MethodLdapNameGetRdns extends Method {
|
||||
MethodLdapNameGetRdns() {
|
||||
getDeclaringType() instanceof TypeLdapName and
|
||||
hasName("getRdns")
|
||||
this.getDeclaringType() instanceof TypeLdapName and
|
||||
this.hasName("getRdns")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `toString` declared in `javax.naming.ldap.LdapName`. */
|
||||
class MethodLdapNameToString extends Method {
|
||||
MethodLdapNameToString() {
|
||||
getDeclaringType() instanceof TypeLdapName and
|
||||
hasName("toString")
|
||||
this.getDeclaringType() instanceof TypeLdapName and
|
||||
this.hasName("toString")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ private import semmle.code.java.dataflow.FlowSteps
|
||||
*/
|
||||
class Kryo extends RefType {
|
||||
Kryo() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class Kryo extends RefType {
|
||||
*/
|
||||
class KryoInput extends RefType {
|
||||
KryoInput() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ class KryoInput extends RefType {
|
||||
*/
|
||||
class KryoPool extends RefType {
|
||||
KryoPool() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ class KryoPool extends RefType {
|
||||
*/
|
||||
class KryoPoolBuilder extends RefType {
|
||||
KryoPoolBuilder() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
|
||||
this.hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ class KryoPoolBuilder extends RefType {
|
||||
*/
|
||||
class KryoPoolBuilderMethod extends Method {
|
||||
KryoPoolBuilderMethod() {
|
||||
getDeclaringType() instanceof KryoPoolBuilder and
|
||||
this.getDeclaringType() instanceof KryoPoolBuilder and
|
||||
(
|
||||
getReturnType() instanceof KryoPoolBuilder or
|
||||
getReturnType() instanceof KryoPool
|
||||
this.getReturnType() instanceof KryoPoolBuilder or
|
||||
this.getReturnType() instanceof KryoPool
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class KryoEnableWhiteListing extends MethodAccess {
|
||||
*/
|
||||
class KryoPoolRunMethod extends Method {
|
||||
KryoPoolRunMethod() {
|
||||
getDeclaringType() instanceof KryoPool and
|
||||
hasName("run")
|
||||
this.getDeclaringType() instanceof KryoPool and
|
||||
this.hasName("run")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import java
|
||||
*/
|
||||
class MockitoVerifyMethod extends Method {
|
||||
MockitoVerifyMethod() {
|
||||
getDeclaringType().getPackage().getName().matches("org.mockito%") and
|
||||
hasName("verify")
|
||||
this.getDeclaringType().getPackage().getName().matches("org.mockito%") and
|
||||
this.hasName("verify")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class MockitoVerifyMethod extends Method {
|
||||
*/
|
||||
class MockitoVerifiedMethodAccess extends MethodAccess {
|
||||
MockitoVerifiedMethodAccess() {
|
||||
getQualifier().(MethodAccess).getMethod() instanceof MockitoVerifyMethod
|
||||
this.getQualifier().(MethodAccess).getMethod() instanceof MockitoVerifyMethod
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ class MockitoMockableType extends ClassOrInterface {
|
||||
*/
|
||||
class MockitoInitMocks extends Method {
|
||||
MockitoInitMocks() {
|
||||
getDeclaringType().hasQualifiedName("org.mockito", "MockitoAnnotations") and
|
||||
hasName("initMocks")
|
||||
this.getDeclaringType().hasQualifiedName("org.mockito", "MockitoAnnotations") and
|
||||
this.hasName("initMocks")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ class MockitoInitedTest extends Class {
|
||||
or
|
||||
// Call to `MockitoAnnotations.initMocks()`, either by the constructor or by a `@Before` method.
|
||||
exists(MockitoInitMocks initMocks |
|
||||
getAConstructor().calls*(initMocks)
|
||||
this.getAConstructor().calls*(initMocks)
|
||||
or
|
||||
exists(Method m |
|
||||
m = getAnAncestor().getAMethod() and
|
||||
m = this.getAnAncestor().getAMethod() and
|
||||
(
|
||||
m.hasAnnotation("org.junit", "Before") or
|
||||
m.hasAnnotation("org.testng.annotations", "BeforeMethod")
|
||||
@@ -85,8 +85,8 @@ class MockitoInitedTest extends Class {
|
||||
*/
|
||||
class MockitoAnnotation extends Annotation {
|
||||
MockitoAnnotation() {
|
||||
getType().getPackage().getName().matches("org.mockito") or
|
||||
getType().getPackage().getName().matches("org.mockito.%")
|
||||
this.getType().getPackage().getName().matches("org.mockito") or
|
||||
this.getType().getPackage().getName().matches("org.mockito.%")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,11 +95,11 @@ class MockitoAnnotation extends Annotation {
|
||||
*/
|
||||
class MockitoExclusiveAnnotation extends MockitoAnnotation {
|
||||
MockitoExclusiveAnnotation() {
|
||||
getType().hasQualifiedName("org.mockito", "Mock") or
|
||||
getType().hasQualifiedName("org.mockito", "MockitoAnnotations$Mock") or
|
||||
getType().hasQualifiedName("org.mockito", "InjectMocks") or
|
||||
getType().hasQualifiedName("org.mockito", "Spy") or
|
||||
getType().hasQualifiedName("org.mockito", "Captor")
|
||||
this.getType().hasQualifiedName("org.mockito", "Mock") or
|
||||
this.getType().hasQualifiedName("org.mockito", "MockitoAnnotations$Mock") or
|
||||
this.getType().hasQualifiedName("org.mockito", "InjectMocks") or
|
||||
this.getType().hasQualifiedName("org.mockito", "Spy") or
|
||||
this.getType().hasQualifiedName("org.mockito", "Captor")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,16 +107,16 @@ class MockitoExclusiveAnnotation extends MockitoAnnotation {
|
||||
* A field which has a Mockito annotation.
|
||||
*/
|
||||
class MockitoAnnotatedField extends Field {
|
||||
MockitoAnnotatedField() { getAnAnnotation() instanceof MockitoAnnotation }
|
||||
MockitoAnnotatedField() { this.getAnAnnotation() instanceof MockitoAnnotation }
|
||||
|
||||
/**
|
||||
* Holds if this field will be processed by Mockito.
|
||||
*/
|
||||
predicate isValid() {
|
||||
// Mockito annotations are never parsed if the test isn't properly initialized.
|
||||
getDeclaringType() instanceof MockitoInitedTest and
|
||||
this.getDeclaringType() instanceof MockitoInitedTest and
|
||||
// There should only be one "exclusive" mockito annotation per field.
|
||||
count(getAnAnnotation().(MockitoExclusiveAnnotation)) = 1
|
||||
count(this.getAnAnnotation().(MockitoExclusiveAnnotation)) = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,16 +125,16 @@ class MockitoAnnotatedField extends Field {
|
||||
*/
|
||||
class MockitoMockedField extends MockitoAnnotatedField {
|
||||
MockitoMockedField() {
|
||||
hasAnnotation("org.mockito", "Mock")
|
||||
this.hasAnnotation("org.mockito", "Mock")
|
||||
or
|
||||
// Deprecated style.
|
||||
hasAnnotation("org.mockito", "MockitoAnnotations$Mock")
|
||||
this.hasAnnotation("org.mockito", "MockitoAnnotations$Mock")
|
||||
}
|
||||
|
||||
override predicate isValid() {
|
||||
super.isValid() and
|
||||
// The type must also be mockable, otherwise it will not be initialized.
|
||||
getType() instanceof MockitoMockableType
|
||||
this.getType() instanceof MockitoMockableType
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,12 +142,13 @@ class MockitoMockedField extends MockitoAnnotatedField {
|
||||
*/
|
||||
predicate isReferencedByInjection() {
|
||||
exists(MockitoInjectedField injectedField |
|
||||
injectedField.getDeclaringType() = getDeclaringType()
|
||||
injectedField.getDeclaringType() = this.getDeclaringType()
|
||||
|
|
||||
// A `@Mock` is injected if it is used in one of the invoked callables (constructor or
|
||||
// setter), or injected directly onto a field.
|
||||
getType().(RefType).getAnAncestor() = injectedField.getAnInvokedCallable().getAParamType() or
|
||||
getType().(RefType).getAnAncestor() = injectedField.getASetField().getType()
|
||||
this.getType().(RefType).getAnAncestor() =
|
||||
injectedField.getAnInvokedCallable().getAParamType() or
|
||||
this.getType().(RefType).getAnAncestor() = injectedField.getASetField().getType()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -156,25 +157,25 @@ class MockitoMockedField extends MockitoAnnotatedField {
|
||||
* A field annotated with `@InjectMocks`.
|
||||
*/
|
||||
class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
MockitoInjectedField() { hasAnnotation("org.mockito", "InjectMocks") }
|
||||
MockitoInjectedField() { this.hasAnnotation("org.mockito", "InjectMocks") }
|
||||
|
||||
override predicate isValid() {
|
||||
super.isValid() and
|
||||
(
|
||||
// If we need to initialize the field, it is only valid if the type is a `Class` that is not
|
||||
// local, is static if it is a nested class, and is not abstract.
|
||||
exists(getInitializer())
|
||||
exists(this.getInitializer())
|
||||
or
|
||||
exists(Class c | c = getType() |
|
||||
exists(Class c | c = this.getType() |
|
||||
not c.isLocal() and
|
||||
(getType() instanceof NestedClass implies c.(NestedClass).isStatic()) and
|
||||
(this.getType() instanceof NestedClass implies c.(NestedClass).isStatic()) and
|
||||
not c.isAbstract()
|
||||
)
|
||||
) and
|
||||
(
|
||||
// If neither of these is true, then mockito will fail to initialize this field.
|
||||
usingConstructorInjection() or
|
||||
usingPropertyInjection()
|
||||
this.usingConstructorInjection() or
|
||||
this.usingPropertyInjection()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,7 +185,8 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
* Note: this does not include the no-arg constructor.
|
||||
*/
|
||||
predicate usingConstructorInjection() {
|
||||
not exists(getInitializer()) and exists(getMockInjectedClass().getAMostMockableConstructor())
|
||||
not exists(this.getInitializer()) and
|
||||
exists(this.getMockInjectedClass().getAMostMockableConstructor())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,10 +196,10 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
* constructor, in addition to any property.
|
||||
*/
|
||||
predicate usingPropertyInjection() {
|
||||
not usingConstructorInjection() and
|
||||
not this.usingConstructorInjection() and
|
||||
(
|
||||
exists(getInitializer()) or
|
||||
exists(getMockInjectedClass().getNoArgsConstructor())
|
||||
exists(this.getInitializer()) or
|
||||
exists(this.getMockInjectedClass().getNoArgsConstructor())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -212,18 +214,18 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
Callable getAnInvokedCallable() {
|
||||
exists(MockitoMockInjectedClass mockInjectedClass |
|
||||
// This is the type we are constructing/injecting.
|
||||
mockInjectedClass = getType()
|
||||
mockInjectedClass = this.getType()
|
||||
|
|
||||
if usingConstructorInjection()
|
||||
if this.usingConstructorInjection()
|
||||
then
|
||||
// If there is no initializer for this field, and there is a most mockable constructor,
|
||||
// then we are doing a parameterized injection of mocks into a most mockable constructor.
|
||||
result = mockInjectedClass.getAMostMockableConstructor()
|
||||
else
|
||||
if usingPropertyInjection()
|
||||
if this.usingPropertyInjection()
|
||||
then
|
||||
// We will call the no-arg constructor if the field wasn't initialized.
|
||||
not exists(getInitializer()) and
|
||||
not exists(this.getInitializer()) and
|
||||
result = mockInjectedClass.getNoArgsConstructor()
|
||||
or
|
||||
// Perform property injection into setter fields, but only where there exists a mock
|
||||
@@ -249,9 +251,9 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
* Field injection only occurs if property injection and not constructor injection is used.
|
||||
*/
|
||||
Field getASetField() {
|
||||
if usingPropertyInjection()
|
||||
if this.usingPropertyInjection()
|
||||
then
|
||||
result = getMockInjectedClass().getASetField() and
|
||||
result = this.getMockInjectedClass().getASetField() and
|
||||
exists(MockitoMockedField mockedField |
|
||||
mockedField.getDeclaringType() = this.getDeclaringType() and
|
||||
mockedField.isValid()
|
||||
@@ -268,15 +270,15 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
* A field annotated with the Mockito `@Spy` annotation.
|
||||
*/
|
||||
class MockitoSpiedField extends MockitoAnnotatedField {
|
||||
MockitoSpiedField() { hasAnnotation("org.mockito", "Spy") }
|
||||
MockitoSpiedField() { this.hasAnnotation("org.mockito", "Spy") }
|
||||
|
||||
override predicate isValid() {
|
||||
super.isValid() and
|
||||
(
|
||||
exists(getInitializer())
|
||||
exists(this.getInitializer())
|
||||
or
|
||||
exists(Constructor c |
|
||||
c = getType().(RefType).getAConstructor() and c.getNumberOfParameters() = 0
|
||||
c = this.getType().(RefType).getAConstructor() and c.getNumberOfParameters() = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -284,7 +286,7 @@ class MockitoSpiedField extends MockitoAnnotatedField {
|
||||
/**
|
||||
* Holds if construction ever occurs.
|
||||
*/
|
||||
predicate isConstructed() { not exists(getInitializer()) }
|
||||
predicate isConstructed() { not exists(this.getInitializer()) }
|
||||
}
|
||||
|
||||
private int mockableParameterCount(Constructor constructor) {
|
||||
@@ -312,8 +314,8 @@ library class MockitoMockInjectedClass extends Class {
|
||||
* Mockito will call only one of them, but which one is dependent on the JVM...
|
||||
*/
|
||||
Constructor getAMostMockableConstructor() {
|
||||
result = getAConstructor() and
|
||||
mockableParameterCount(result) = max(mockableParameterCount(getAConstructor())) and
|
||||
result = this.getAConstructor() and
|
||||
mockableParameterCount(result) = max(mockableParameterCount(this.getAConstructor())) and
|
||||
result.getNumberOfParameters() > 0
|
||||
}
|
||||
|
||||
@@ -331,7 +333,7 @@ library class MockitoMockInjectedClass extends Class {
|
||||
* it sets.
|
||||
*/
|
||||
Method getASetterMethod() {
|
||||
result = getAMethod() and
|
||||
result = this.getAMethod() and
|
||||
exists(MockitoSettableField settableField | result = settableField.getSetterMethod())
|
||||
}
|
||||
|
||||
@@ -342,7 +344,7 @@ library class MockitoMockInjectedClass extends Class {
|
||||
* setter method.
|
||||
*/
|
||||
MockitoSettableField getASetField() {
|
||||
result = getAField() and
|
||||
result = this.getAField() and
|
||||
not exists(result.getSetterMethod())
|
||||
}
|
||||
}
|
||||
@@ -353,8 +355,8 @@ library class MockitoMockInjectedClass extends Class {
|
||||
*/
|
||||
class MockitoSettableField extends Field {
|
||||
MockitoSettableField() {
|
||||
not isFinal() and
|
||||
not isStatic() and
|
||||
not this.isFinal() and
|
||||
not this.isStatic() and
|
||||
exists(MockitoMockInjectedClass injectedClass | injectedClass = this.getDeclaringType())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,39 +6,39 @@ import semmle.code.java.Type
|
||||
|
||||
/** The type `java.net.URLConnection`. */
|
||||
class TypeUrlConnection extends RefType {
|
||||
TypeUrlConnection() { hasQualifiedName("java.net", "URLConnection") }
|
||||
TypeUrlConnection() { this.hasQualifiedName("java.net", "URLConnection") }
|
||||
}
|
||||
|
||||
/** The type `java.net.Socket`. */
|
||||
class TypeSocket extends RefType {
|
||||
TypeSocket() { hasQualifiedName("java.net", "Socket") }
|
||||
TypeSocket() { this.hasQualifiedName("java.net", "Socket") }
|
||||
}
|
||||
|
||||
/** The type `java.net.URL`. */
|
||||
class TypeUrl extends RefType {
|
||||
TypeUrl() { hasQualifiedName("java.net", "URL") }
|
||||
TypeUrl() { this.hasQualifiedName("java.net", "URL") }
|
||||
}
|
||||
|
||||
/** The type `java.net.URI`. */
|
||||
class TypeUri extends RefType {
|
||||
TypeUri() { hasQualifiedName("java.net", "URI") }
|
||||
TypeUri() { this.hasQualifiedName("java.net", "URI") }
|
||||
}
|
||||
|
||||
/** The method `java.net.URLConnection::getInputStream`. */
|
||||
class URLConnectionGetInputStreamMethod extends Method {
|
||||
URLConnectionGetInputStreamMethod() {
|
||||
getDeclaringType() instanceof TypeUrlConnection and
|
||||
hasName("getInputStream") and
|
||||
hasNoParameters()
|
||||
this.getDeclaringType() instanceof TypeUrlConnection and
|
||||
this.hasName("getInputStream") and
|
||||
this.hasNoParameters()
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `java.net.Socket::getInputStream`. */
|
||||
class SocketGetInputStreamMethod extends Method {
|
||||
SocketGetInputStreamMethod() {
|
||||
getDeclaringType() instanceof TypeSocket and
|
||||
hasName("getInputStream") and
|
||||
hasNoParameters()
|
||||
this.getDeclaringType() instanceof TypeSocket and
|
||||
this.hasName("getInputStream") and
|
||||
this.hasNoParameters()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,22 @@ private class OptionalModel extends SummaryModelCsv {
|
||||
s =
|
||||
[
|
||||
"java.util;Optional;false;filter;;;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util;Optional;false;filter;;;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Optional;false;flatMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Optional;false;flatMap;;;ReturnValue of Argument[0];ReturnValue;value",
|
||||
"java.util;Optional;false;get;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;Optional;false;ifPresent;;;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Optional;false;ifPresentOrElse;;;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Optional;false;map;;;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util;Optional;false;map;;;ReturnValue of Argument[0];Element of ReturnValue;value",
|
||||
"java.util;Optional;false;of;;;Argument[0];Element of ReturnValue;value",
|
||||
"java.util;Optional;false;ofNullable;;;Argument[0];Element of ReturnValue;value",
|
||||
"java.util;Optional;false;or;;;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util;Optional;false;or;;;ReturnValue of Argument[0];ReturnValue;value",
|
||||
"java.util;Optional;false;orElse;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;Optional;false;orElse;;;Argument[0];ReturnValue;value",
|
||||
"java.util;Optional;false;orElseGet;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value",
|
||||
"java.util;Optional;false;orElseThrow;;;Element of Argument[-1];ReturnValue;value",
|
||||
"java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value"
|
||||
]
|
||||
|
||||
@@ -30,7 +30,7 @@ class ProtobufMessageLite extends Interface {
|
||||
* Gets a static method named `parseFrom` (or similar) declared on a subtype of the `MessageLite` interface.
|
||||
*/
|
||||
Method getAParseFromMethod() {
|
||||
result = getASubtype+().getAMethod() and
|
||||
result = this.getASubtype+().getAMethod() and
|
||||
result.getName().matches("parse%From") and
|
||||
result.isStatic()
|
||||
}
|
||||
@@ -40,13 +40,7 @@ class ProtobufMessageLite extends Interface {
|
||||
*/
|
||||
Method getAGetterMethod() {
|
||||
exists(RefType decl | decl = result.getDeclaringType() and decl = this.getASubtype+() |
|
||||
exists(string name, string suffix |
|
||||
suffix = "" or
|
||||
suffix = "list" or
|
||||
suffix = "map" or
|
||||
suffix = "ordefault" or
|
||||
suffix = "orthrow"
|
||||
|
|
||||
exists(string name, string suffix | suffix = ["", "list", "map", "ordefault", "orthrow"] |
|
||||
exists(Field f | f.getDeclaringType() = decl |
|
||||
f.getName().toLowerCase().replaceAll("_", "") = name
|
||||
) and
|
||||
|
||||
@@ -74,7 +74,7 @@ library class HttpServletRequestGetQueryStringMethod extends Method {
|
||||
/**
|
||||
* The method `getPathInfo()` declared in `javax.servlet.http.HttpServletRequest`.
|
||||
*/
|
||||
library class HttpServletRequestGetPathMethod extends Method {
|
||||
class HttpServletRequestGetPathMethod extends Method {
|
||||
HttpServletRequestGetPathMethod() {
|
||||
getDeclaringType() instanceof HttpServletRequest and
|
||||
hasName("getPathInfo") and
|
||||
@@ -120,7 +120,7 @@ library class HttpServletRequestGetHeaderNamesMethod extends Method {
|
||||
/**
|
||||
* The method `getRequestURL()` declared in `javax.servlet.http.HttpServletRequest`.
|
||||
*/
|
||||
library class HttpServletRequestGetRequestURLMethod extends Method {
|
||||
class HttpServletRequestGetRequestURLMethod extends Method {
|
||||
HttpServletRequestGetRequestURLMethod() {
|
||||
getDeclaringType() instanceof HttpServletRequest and
|
||||
hasName("getRequestURL") and
|
||||
@@ -131,7 +131,7 @@ library class HttpServletRequestGetRequestURLMethod extends Method {
|
||||
/**
|
||||
* The method `getRequestURI()` declared in `javax.servlet.http.HttpServletRequest`.
|
||||
*/
|
||||
library class HttpServletRequestGetRequestURIMethod extends Method {
|
||||
class HttpServletRequestGetRequestURIMethod extends Method {
|
||||
HttpServletRequestGetRequestURIMethod() {
|
||||
getDeclaringType() instanceof HttpServletRequest and
|
||||
hasName("getRequestURI") and
|
||||
@@ -191,6 +191,16 @@ class HttpServletResponseSendErrorMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `getRequestDispatcher(String)` declared in `javax.servlet.http.HttpServletRequest` or `javax.servlet.ServletRequest`.
|
||||
*/
|
||||
class ServletRequestGetRequestDispatcherMethod extends Method {
|
||||
ServletRequestGetRequestDispatcherMethod() {
|
||||
getDeclaringType() instanceof ServletRequest and
|
||||
hasName("getRequestDispatcher")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `sendRedirect(String)` declared in `javax.servlet.http.HttpServletResponse`.
|
||||
*/
|
||||
|
||||
@@ -37,14 +37,14 @@ private class SafeYamlConstructionFlowConfig extends DataFlow2::Configuration {
|
||||
src.asExpr() instanceof SafeSnakeYamlConstruction
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink = yamlClassInstanceExprArgument(_) }
|
||||
override predicate isSink(DataFlow::Node sink) { sink = this.yamlClassInstanceExprArgument(_) }
|
||||
|
||||
private DataFlow::ExprNode yamlClassInstanceExprArgument(ClassInstanceExpr cie) {
|
||||
cie.getConstructedType() instanceof Yaml and
|
||||
result.getExpr() = cie.getArgument(0)
|
||||
}
|
||||
|
||||
ClassInstanceExpr getSafeYaml() { hasFlowTo(yamlClassInstanceExprArgument(result)) }
|
||||
ClassInstanceExpr getSafeYaml() { this.hasFlowTo(this.yamlClassInstanceExprArgument(result)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,13 +70,13 @@ private class SafeYamlFlowConfig extends DataFlow3::Configuration {
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink = yamlParseQualifier(_) }
|
||||
override predicate isSink(DataFlow::Node sink) { sink = this.yamlParseQualifier(_) }
|
||||
|
||||
private DataFlow::ExprNode yamlParseQualifier(SnakeYamlParse syp) {
|
||||
result.getExpr() = syp.getQualifier()
|
||||
}
|
||||
|
||||
SnakeYamlParse getASafeSnakeYamlParse() { hasFlowTo(yamlParseQualifier(result)) }
|
||||
SnakeYamlParse getASafeSnakeYamlParse() { this.hasFlowTo(this.yamlParseQualifier(result)) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,8 +77,8 @@ class TypeLdapOperations extends Interface {
|
||||
*/
|
||||
class MethodSpringLdapTemplateAuthenticate extends Method {
|
||||
MethodSpringLdapTemplateAuthenticate() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("authenticate")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("authenticate")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ class MethodSpringLdapTemplateAuthenticate extends Method {
|
||||
*/
|
||||
class MethodSpringLdapTemplateFind extends Method {
|
||||
MethodSpringLdapTemplateFind() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("find")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("find")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ class MethodSpringLdapTemplateFind extends Method {
|
||||
*/
|
||||
class MethodSpringLdapTemplateFindOne extends Method {
|
||||
MethodSpringLdapTemplateFindOne() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("findOne")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("findOne")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ class MethodSpringLdapTemplateFindOne extends Method {
|
||||
*/
|
||||
class MethodSpringLdapTemplateSearch extends Method {
|
||||
MethodSpringLdapTemplateSearch() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("search")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("search")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +121,8 @@ class MethodSpringLdapTemplateSearch extends Method {
|
||||
*/
|
||||
class MethodSpringLdapTemplateSearchForContext extends Method {
|
||||
MethodSpringLdapTemplateSearchForContext() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("searchForContext")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("searchForContext")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ class MethodSpringLdapTemplateSearchForContext extends Method {
|
||||
*/
|
||||
class MethodSpringLdapTemplateSearchForObject extends Method {
|
||||
MethodSpringLdapTemplateSearchForObject() {
|
||||
getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
hasName("searchForObject")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapTemplate and
|
||||
this.hasName("searchForObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +143,8 @@ class MethodSpringLdapTemplateSearchForObject extends Method {
|
||||
*/
|
||||
class MethodSpringLdapQueryBuilderFilter extends Method {
|
||||
MethodSpringLdapQueryBuilderFilter() {
|
||||
getDeclaringType() instanceof TypeSpringLdapQueryBuilder and
|
||||
hasName("filter")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapQueryBuilder and
|
||||
this.hasName("filter")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,8 +154,8 @@ class MethodSpringLdapQueryBuilderFilter extends Method {
|
||||
*/
|
||||
class MethodSpringLdapQueryBuilderBase extends Method {
|
||||
MethodSpringLdapQueryBuilderBase() {
|
||||
getDeclaringType() instanceof TypeSpringLdapQueryBuilder and
|
||||
hasName("base")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapQueryBuilder and
|
||||
this.hasName("base")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,8 +165,8 @@ class MethodSpringLdapQueryBuilderBase extends Method {
|
||||
*/
|
||||
class MethodSpringLdapNameBuilderNewInstance extends Method {
|
||||
MethodSpringLdapNameBuilderNewInstance() {
|
||||
getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
hasName("newInstance")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
this.hasName("newInstance")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,8 +176,8 @@ class MethodSpringLdapNameBuilderNewInstance extends Method {
|
||||
*/
|
||||
class MethodSpringLdapNameBuilderAdd extends Method {
|
||||
MethodSpringLdapNameBuilderAdd() {
|
||||
getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
hasName("add")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
this.hasName("add")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,8 +187,8 @@ class MethodSpringLdapNameBuilderAdd extends Method {
|
||||
*/
|
||||
class MethodSpringLdapNameBuilderBuild extends Method {
|
||||
MethodSpringLdapNameBuilderBuild() {
|
||||
getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
hasName("build")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapNameBuilder and
|
||||
this.hasName("build")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ class MethodSpringLdapNameBuilderBuild extends Method {
|
||||
*/
|
||||
class MethodSpringLdapUtilsNewLdapName extends Method {
|
||||
MethodSpringLdapUtilsNewLdapName() {
|
||||
getDeclaringType() instanceof TypeSpringLdapUtils and
|
||||
hasName("newLdapName")
|
||||
this.getDeclaringType() instanceof TypeSpringLdapUtils and
|
||||
this.hasName("newLdapName")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ private class StringSummaryCsv extends SummaryModelCsv {
|
||||
"java.lang;StringBuffer;true;StringBuffer;(CharSequence);;Argument[0];Argument[-1];taint",
|
||||
"java.lang;StringBuffer;true;StringBuffer;(String);;Argument[0];Argument[-1];taint",
|
||||
"java.lang;StringBuilder;true;StringBuilder;;;Argument[0];Argument[-1];taint",
|
||||
"java.lang;CharSequence;true;subSequence;;;Argument[-1];ReturnValue;taint"
|
||||
"java.lang;CharSequence;true;subSequence;;;Argument[-1];ReturnValue;taint",
|
||||
"java.lang;CharSequence;true;toString;;;Argument[-1];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class ThriftIface extends Interface {
|
||||
|
||||
Method getAnImplementingMethod() {
|
||||
result.getDeclaringType().(Class).getASupertype+() = this and
|
||||
result.overrides(getAMethod()) and
|
||||
result.overrides+(this.getAMethod()) and
|
||||
not result.getFile() = this.getFile()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,79 +35,79 @@ class TypeUnboundIdLDAPConnection extends Class {
|
||||
/** A method with the name `setBaseDN` declared in `com.unboundid.ldap.sdk.SearchRequest`. */
|
||||
class MethodUnboundIdSearchRequestSetBaseDN extends Method {
|
||||
MethodUnboundIdSearchRequestSetBaseDN() {
|
||||
getDeclaringType() instanceof TypeUnboundIdSearchRequest and
|
||||
hasName("setBaseDN")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdSearchRequest and
|
||||
this.hasName("setBaseDN")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `setFilter` declared in `com.unboundid.ldap.sdk.SearchRequest`. */
|
||||
class MethodUnboundIdSearchRequestSetFilter extends Method {
|
||||
MethodUnboundIdSearchRequestSetFilter() {
|
||||
getDeclaringType() instanceof TypeUnboundIdSearchRequest and
|
||||
hasName("setFilter")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdSearchRequest and
|
||||
this.hasName("setFilter")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `create` declared in `com.unboundid.ldap.sdk.Filter`. */
|
||||
class MethodUnboundIdFilterCreate extends Method {
|
||||
MethodUnboundIdFilterCreate() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
hasName("create")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
this.hasName("create")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `createANDFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
|
||||
class MethodUnboundIdFilterCreateANDFilter extends Method {
|
||||
MethodUnboundIdFilterCreateANDFilter() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
hasName("createANDFilter")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
this.hasName("createANDFilter")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `createORFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
|
||||
class MethodUnboundIdFilterCreateORFilter extends Method {
|
||||
MethodUnboundIdFilterCreateORFilter() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
hasName("createORFilter")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
this.hasName("createORFilter")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `createNOTFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
|
||||
class MethodUnboundIdFilterCreateNOTFilter extends Method {
|
||||
MethodUnboundIdFilterCreateNOTFilter() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
hasName("createNOTFilter")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
this.hasName("createNOTFilter")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `simplifyFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
|
||||
class MethodUnboundIdFilterSimplifyFilter extends Method {
|
||||
MethodUnboundIdFilterSimplifyFilter() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
hasName("simplifyFilter")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
|
||||
this.hasName("simplifyFilter")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `search` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */
|
||||
class MethodUnboundIdLDAPConnectionSearch extends Method {
|
||||
MethodUnboundIdLDAPConnectionSearch() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
hasName("search")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
this.hasName("search")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `asyncSearch` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */
|
||||
class MethodUnboundIdLDAPConnectionAsyncSearch extends Method {
|
||||
MethodUnboundIdLDAPConnectionAsyncSearch() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
hasName("asyncSearch")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
this.hasName("asyncSearch")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method with the name `searchForEntry` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */
|
||||
class MethodUnboundIdLDAPConnectionSearchForEntry extends Method {
|
||||
MethodUnboundIdLDAPConnectionSearchForEntry() {
|
||||
getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
hasName("searchForEntry")
|
||||
this.getDeclaringType() instanceof TypeUnboundIdLDAPConnection and
|
||||
this.hasName("searchForEntry")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,12 @@ class AndroidComponent extends Class {
|
||||
}
|
||||
|
||||
/** Holds if this Android component is configured as `exported` in an `AndroidManifest.xml` file. */
|
||||
predicate isExported() { getAndroidComponentXmlElement().isExported() }
|
||||
predicate isExported() { this.getAndroidComponentXmlElement().isExported() }
|
||||
|
||||
/** Holds if this Android component has an intent filter configured in an `AndroidManifest.xml` file. */
|
||||
predicate hasIntentFilter() { exists(getAndroidComponentXmlElement().getAnIntentFilterElement()) }
|
||||
predicate hasIntentFilter() {
|
||||
exists(this.getAndroidComponentXmlElement().getAnIntentFilterElement())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,10 +55,10 @@ class ExportableAndroidComponent extends AndroidComponent {
|
||||
* `AndroidManifest.xml` file.
|
||||
*/
|
||||
override predicate isExported() {
|
||||
getAndroidComponentXmlElement().isExported()
|
||||
this.getAndroidComponentXmlElement().isExported()
|
||||
or
|
||||
hasIntentFilter() and
|
||||
not getAndroidComponentXmlElement().isNotExported()
|
||||
this.hasIntentFilter() and
|
||||
not this.getAndroidComponentXmlElement().isNotExported()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ class AndroidContentProvider extends ExportableAndroidComponent {
|
||||
* in an `AndroidManifest.xml` file.
|
||||
*/
|
||||
predicate requiresPermissions() {
|
||||
getAndroidComponentXmlElement().(AndroidProviderXmlElement).requiresPermissions()
|
||||
this.getAndroidComponentXmlElement().(AndroidProviderXmlElement).requiresPermissions()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/** Provides classes and predicates to reason about `AsyncTask`s in Android. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
* Models the value-preserving step from `asyncTask.execute(params)` to `AsyncTask::doInBackground(params)`.
|
||||
*/
|
||||
private class AsyncTaskAdditionalValueStep extends AdditionalValueStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(ExecuteAsyncTaskMethodAccess ma, AsyncTaskRunInBackgroundMethod m |
|
||||
DataFlow::getInstanceArgument(ma).getType() = m.getDeclaringType() and
|
||||
node1.asExpr() = ma.getParamsArgument() and
|
||||
node2.asParameter() = m.getParameter(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Android class `android.os.AsyncTask`.
|
||||
*/
|
||||
private class AsyncTask extends RefType {
|
||||
AsyncTask() { this.hasQualifiedName("android.os", "AsyncTask") }
|
||||
}
|
||||
|
||||
/** A call to the `execute` or `executeOnExecutor` methods of the `android.os.AsyncTask` class. */
|
||||
private class ExecuteAsyncTaskMethodAccess extends MethodAccess {
|
||||
Argument paramsArgument;
|
||||
|
||||
ExecuteAsyncTaskMethodAccess() {
|
||||
exists(Method m |
|
||||
this.getMethod() = m and
|
||||
m.getDeclaringType().getSourceDeclaration().getASourceSupertype*() instanceof AsyncTask
|
||||
|
|
||||
m.getName() = "execute" and not m.isStatic() and paramsArgument = this.getArgument(0)
|
||||
or
|
||||
m.getName() = "executeOnExecutor" and paramsArgument = this.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns the `params` argument of this call. */
|
||||
Argument getParamsArgument() { result = paramsArgument }
|
||||
}
|
||||
|
||||
/** The `doInBackground` method of the `android.os.AsyncTask` class. */
|
||||
private class AsyncTaskRunInBackgroundMethod extends Method {
|
||||
AsyncTaskRunInBackgroundMethod() {
|
||||
this.getDeclaringType().getSourceDeclaration().getASourceSupertype*() instanceof AsyncTask and
|
||||
this.getName() = "doInBackground"
|
||||
}
|
||||
}
|
||||
@@ -7,35 +7,42 @@ import semmle.code.java.dataflow.ExternalFlow
|
||||
* The class `android.content.Intent`.
|
||||
*/
|
||||
class TypeIntent extends Class {
|
||||
TypeIntent() { hasQualifiedName("android.content", "Intent") }
|
||||
TypeIntent() { this.hasQualifiedName("android.content", "Intent") }
|
||||
}
|
||||
|
||||
/** The class `android.content.ComponentName`. */
|
||||
class TypeComponentName extends Class {
|
||||
TypeComponentName() { this.hasQualifiedName("android.content", "ComponentName") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.app.Activity`.
|
||||
*/
|
||||
class TypeActivity extends Class {
|
||||
TypeActivity() { hasQualifiedName("android.app", "Activity") }
|
||||
TypeActivity() { this.hasQualifiedName("android.app", "Activity") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.content.Context`.
|
||||
*/
|
||||
class TypeContext extends RefType {
|
||||
TypeContext() { hasQualifiedName("android.content", "Context") }
|
||||
TypeContext() { this.hasQualifiedName("android.content", "Context") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.content.BroadcastReceiver`.
|
||||
*/
|
||||
class TypeBroadcastReceiver extends Class {
|
||||
TypeBroadcastReceiver() { hasQualifiedName("android.content", "BroadcastReceiver") }
|
||||
TypeBroadcastReceiver() { this.hasQualifiedName("android.content", "BroadcastReceiver") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Activity.getIntent`
|
||||
*/
|
||||
class AndroidGetIntentMethod extends Method {
|
||||
AndroidGetIntentMethod() { hasName("getIntent") and getDeclaringType() instanceof TypeActivity }
|
||||
AndroidGetIntentMethod() {
|
||||
this.hasName("getIntent") and this.getDeclaringType() instanceof TypeActivity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +50,7 @@ class AndroidGetIntentMethod extends Method {
|
||||
*/
|
||||
class AndroidReceiveIntentMethod extends Method {
|
||||
AndroidReceiveIntentMethod() {
|
||||
hasName("onReceive") and getDeclaringType() instanceof TypeBroadcastReceiver
|
||||
this.hasName("onReceive") and this.getDeclaringType() instanceof TypeBroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +59,8 @@ class AndroidReceiveIntentMethod extends Method {
|
||||
*/
|
||||
class ContextStartActivityMethod extends Method {
|
||||
ContextStartActivityMethod() {
|
||||
(hasName("startActivity") or hasName("startActivities")) and
|
||||
getDeclaringType() instanceof TypeContext
|
||||
(this.hasName("startActivity") or this.hasName("startActivities")) and
|
||||
this.getDeclaringType() instanceof TypeContext
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +77,66 @@ private class IntentFieldsInheritTaint extends DataFlow::SyntheticFieldContent,
|
||||
*/
|
||||
class IntentGetParcelableExtraMethod extends Method {
|
||||
IntentGetParcelableExtraMethod() {
|
||||
hasName("getParcelableExtra") and
|
||||
getDeclaringType() instanceof TypeIntent
|
||||
this.hasName("getParcelableExtra") and
|
||||
this.getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `android.os.BaseBundle`, or a class that extends it. */
|
||||
class AndroidBundle extends Class {
|
||||
AndroidBundle() { this.getASupertype*().hasQualifiedName("android.os", "BaseBundle") }
|
||||
}
|
||||
|
||||
/** An `Intent` that explicitly sets a destination component. */
|
||||
class ExplicitIntent extends Expr {
|
||||
ExplicitIntent() {
|
||||
exists(MethodAccess ma, Method m |
|
||||
ma.getMethod() = m and
|
||||
m.getDeclaringType() instanceof TypeIntent and
|
||||
m.hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
|
||||
ma.getQualifier() = this
|
||||
)
|
||||
or
|
||||
exists(ConstructorCall cc, Argument classArg |
|
||||
cc.getConstructedType() instanceof TypeIntent and
|
||||
cc.getAnArgument() = classArg and
|
||||
classArg.getType() instanceof TypeClass and
|
||||
not exists(NullLiteral nullLiteral | DataFlow::localExprFlow(nullLiteral, classArg)) and
|
||||
cc = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for explicit intents.
|
||||
*
|
||||
* Use this when you want to work only with implicit intents
|
||||
* in a `DataFlow` or `TaintTracking` configuration.
|
||||
*/
|
||||
class ExplicitIntentSanitizer extends DataFlow::Node {
|
||||
ExplicitIntentSanitizer() {
|
||||
exists(ExplicitIntent explIntent | DataFlow::localExprFlow(explIntent, this.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
private class BundleExtrasSyntheticField extends SyntheticField {
|
||||
BundleExtrasSyntheticField() { this = "android.content.Intent.extras" }
|
||||
|
||||
override RefType getType() { result instanceof AndroidBundle }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if extras may be implicitly read from the Intent `node`.
|
||||
*/
|
||||
predicate allowIntentExtrasImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
node.getType() instanceof TypeIntent and
|
||||
(
|
||||
c instanceof DataFlow::MapValueContent
|
||||
or
|
||||
c.(DataFlow::SyntheticFieldContent).getType() instanceof AndroidBundle
|
||||
)
|
||||
}
|
||||
|
||||
private class IntentBundleFlowSteps extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
@@ -236,3 +298,34 @@ private class IntentBundleFlowSteps extends SummaryModelCsv {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private class IntentComponentTaintSteps extends SummaryModelCsv {
|
||||
override predicate row(string s) {
|
||||
s =
|
||||
[
|
||||
"android.content;Intent;true;Intent;(Intent);;Argument[0];Argument[-1];taint",
|
||||
"android.content;Intent;true;Intent;(Context,Class);;Argument[1];Argument[-1];taint",
|
||||
"android.content;Intent;true;Intent;(String,Uri,Context,Class);;Argument[3];Argument[-1];taint",
|
||||
"android.content;Intent;true;getIntent;(String);;Argument[0];ReturnValue;taint",
|
||||
"android.content;Intent;true;getIntentOld;(String);;Argument[0];ReturnValue;taint",
|
||||
"android.content;Intent;true;parseUri;(String,int);;Argument[0];ReturnValue;taint",
|
||||
"android.content;Intent;true;setPackage;;;Argument[0];Argument[-1];taint",
|
||||
"android.content;Intent;true;setClass;;;Argument[1];Argument[-1];taint",
|
||||
"android.content;Intent;true;setClassName;(Context,String);;Argument[1];Argument[-1];taint",
|
||||
"android.content;Intent;true;setClassName;(String,String);;Argument[0..1];Argument[-1];taint",
|
||||
"android.content;Intent;true;setComponent;;;Argument[0];Argument[-1];taint",
|
||||
"android.content;ComponentName;false;ComponentName;(String,String);;Argument[0..1];Argument[-1];taint",
|
||||
"android.content;ComponentName;false;ComponentName;(Context,String);;Argument[1];Argument[-1];taint",
|
||||
"android.content;ComponentName;false;ComponentName;(Context,Class);;Argument[1];Argument[-1];taint",
|
||||
"android.content;ComponentName;false;ComponentName;(Parcel);;Argument[0];Argument[-1];taint",
|
||||
"android.content;ComponentName;false;createRelative;(String,String);;Argument[0..1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;createRelative;(Context,String);;Argument[1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;flattenToShortString;;;Argument[-1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;flattenToString;;;Argument[-1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;getClassName;;;Argument[-1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;getPackageName;;;Argument[-1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;getShortClassName;;;Argument[-1];ReturnValue;taint",
|
||||
"android.content;ComponentName;false;unflattenFromString;;;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import java
|
||||
|
||||
class TypeWebView extends Class {
|
||||
TypeWebView() { hasQualifiedName("android.webkit", "WebView") }
|
||||
TypeWebView() { this.hasQualifiedName("android.webkit", "WebView") }
|
||||
}
|
||||
|
||||
class TypeWebViewClient extends Class {
|
||||
TypeWebViewClient() { hasQualifiedName("android.webkit", "WebViewClient") }
|
||||
TypeWebViewClient() { this.hasQualifiedName("android.webkit", "WebViewClient") }
|
||||
}
|
||||
|
||||
class TypeWebSettings extends Class {
|
||||
TypeWebSettings() { hasQualifiedName("android.webkit", "WebSettings") }
|
||||
TypeWebSettings() { this.hasQualifiedName("android.webkit", "WebSettings") }
|
||||
}
|
||||
|
||||
class WebViewGetSettingsMethod extends Method {
|
||||
|
||||
34
java/ql/lib/semmle/code/java/frameworks/apache/IO.qll
Normal file
34
java/ql/lib/semmle/code/java/frameworks/apache/IO.qll
Normal file
@@ -0,0 +1,34 @@
|
||||
/** Definitions related to the Apache Commons IO library. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
private class CommonsIOSummaryCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.io;IOUtils;false;buffer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;copy;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;copyLarge;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;read;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(ReadableByteChannel,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readLines;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedReader;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toByteArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toCharArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toString;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;write;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeChunked;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[0];Argument[2];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[1];Argument[2];taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,14 @@ private class TypeLiteralToParseAsFlowConfiguration extends DataFlowForSerializa
|
||||
)
|
||||
}
|
||||
|
||||
TypeLiteral getSourceWithFlowToParseAs() { hasFlow(DataFlow::exprNode(result), _) }
|
||||
TypeLiteral getSourceWithFlowToParseAs() { this.hasFlow(DataFlow::exprNode(result), _) }
|
||||
}
|
||||
|
||||
/** A field that is deserialized by `HttpResponse.parseAs`. */
|
||||
class HttpResponseParseAsDeserializableField extends DeserializableField {
|
||||
HttpResponseParseAsDeserializableField() {
|
||||
exists(RefType decltype, TypeLiteralToParseAsFlowConfiguration conf |
|
||||
decltype = getDeclaringType() and
|
||||
decltype = this.getDeclaringType() and
|
||||
conf.getSourceWithFlowToParseAs().getReferencedType() = decltype and
|
||||
decltype.fromSource()
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ class GwtEntryPointClass extends Class {
|
||||
isGwtXmlIncluded()
|
||||
implies
|
||||
// The entry point is live if it is specified in a `*.gwt.xml` file.
|
||||
exists(getAGwtXmlFile())
|
||||
exists(this.getAGwtXmlFile())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class GwtEntryPointClass extends Class {
|
||||
*/
|
||||
class GwtCompilationUnit extends CompilationUnit {
|
||||
GwtCompilationUnit() {
|
||||
exists(GwtXmlFile f | getRelativePath().matches(f.getARelativeSourcePath() + "%"))
|
||||
exists(GwtXmlFile f | this.getRelativePath().matches(f.getARelativeSourcePath() + "%"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,57 +12,62 @@ import GwtUiBinderXml
|
||||
* An annotation in the package `com.google.gwt.uibinder.client`.
|
||||
*/
|
||||
class GwtUiBinderClientAnnotation extends Annotation {
|
||||
GwtUiBinderClientAnnotation() { getType().getPackage().hasName("com.google.gwt.uibinder.client") }
|
||||
GwtUiBinderClientAnnotation() {
|
||||
this.getType().getPackage().hasName("com.google.gwt.uibinder.client")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `@com.google.gwt.uibinder.client.UiHandler` annotation.
|
||||
*/
|
||||
class GwtUiHandlerAnnotation extends GwtUiBinderClientAnnotation {
|
||||
GwtUiHandlerAnnotation() { getType().hasName("UiHandler") }
|
||||
GwtUiHandlerAnnotation() { this.getType().hasName("UiHandler") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `@com.google.gwt.uibinder.client.UiField` annotation.
|
||||
*/
|
||||
class GwtUiFieldAnnotation extends GwtUiBinderClientAnnotation {
|
||||
GwtUiFieldAnnotation() { getType().hasName("UiField") }
|
||||
GwtUiFieldAnnotation() { this.getType().hasName("UiField") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `@com.google.gwt.uibinder.client.UiTemplate` annotation.
|
||||
*/
|
||||
class GwtUiTemplateAnnotation extends GwtUiBinderClientAnnotation {
|
||||
GwtUiTemplateAnnotation() { getType().hasName("UiTemplate") }
|
||||
GwtUiTemplateAnnotation() { this.getType().hasName("UiTemplate") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `@com.google.gwt.uibinder.client.UiFactory` annotation.
|
||||
*/
|
||||
class GwtUiFactoryAnnotation extends GwtUiBinderClientAnnotation {
|
||||
GwtUiFactoryAnnotation() { getType().hasName("UiFactory") }
|
||||
GwtUiFactoryAnnotation() { this.getType().hasName("UiFactory") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `@com.google.gwt.uibinder.client.UiConstructor` annotation.
|
||||
*/
|
||||
class GwtUiConstructorAnnotation extends GwtUiBinderClientAnnotation {
|
||||
GwtUiConstructorAnnotation() { getType().hasName("UiConstructor") }
|
||||
GwtUiConstructorAnnotation() { this.getType().hasName("UiConstructor") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A field that is reflectively written to, and read from, by the GWT UiBinder framework.
|
||||
*/
|
||||
class GwtUiField extends Field {
|
||||
GwtUiField() { getAnAnnotation() instanceof GwtUiFieldAnnotation }
|
||||
GwtUiField() { this.getAnAnnotation() instanceof GwtUiFieldAnnotation }
|
||||
|
||||
/**
|
||||
* If true, the field must be filled before `UiBinder.createAndBindUi` is called.
|
||||
* If false, `UiBinder.createAndBindUi` will fill the field.
|
||||
*/
|
||||
predicate isProvided() {
|
||||
getAnAnnotation().(GwtUiFieldAnnotation).getValue("provided").(BooleanLiteral).getBooleanValue() =
|
||||
true
|
||||
this.getAnAnnotation()
|
||||
.(GwtUiFieldAnnotation)
|
||||
.getValue("provided")
|
||||
.(BooleanLiteral)
|
||||
.getBooleanValue() = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,14 +75,14 @@ class GwtUiField extends Field {
|
||||
* A method called as a handler for events thrown by GWT widgets.
|
||||
*/
|
||||
class GwtUiHandler extends Method {
|
||||
GwtUiHandler() { getAnAnnotation() instanceof GwtUiHandlerAnnotation }
|
||||
GwtUiHandler() { this.getAnAnnotation() instanceof GwtUiHandlerAnnotation }
|
||||
|
||||
/**
|
||||
* Gets the name of the field for which this handler is registered.
|
||||
*/
|
||||
string getFieldName() {
|
||||
result =
|
||||
getAnAnnotation()
|
||||
this.getAnAnnotation()
|
||||
.(GwtUiHandlerAnnotation)
|
||||
.getValue("value")
|
||||
.(CompileTimeConstantExpr)
|
||||
@@ -89,7 +94,7 @@ class GwtUiHandler extends Method {
|
||||
*/
|
||||
GwtUiField getField() {
|
||||
result = this.getDeclaringType().getAField() and
|
||||
result.getName() = getFieldName()
|
||||
result.getName() = this.getFieldName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +103,12 @@ class GwtUiHandler extends Method {
|
||||
* construct an instance of a class specified in a UiBinder XML file.
|
||||
*/
|
||||
class GwtUiFactory extends Method {
|
||||
GwtUiFactory() { getAnAnnotation() instanceof GwtUiFactoryAnnotation }
|
||||
GwtUiFactory() { this.getAnAnnotation() instanceof GwtUiFactoryAnnotation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that may be called by the UiBinder framework as a result of a `GWT.create()` call.
|
||||
*/
|
||||
class GwtUiConstructor extends Constructor {
|
||||
GwtUiConstructor() { getAnAnnotation() instanceof GwtUiConstructorAnnotation }
|
||||
GwtUiConstructor() { this.getAnAnnotation() instanceof GwtUiConstructorAnnotation }
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ class GwtComponentTemplateElement extends XMLElement {
|
||||
*/
|
||||
Class getClass() {
|
||||
exists(string namespace |
|
||||
namespace = getNamespace().getURI() and
|
||||
result.getQualifiedName() = namespace.substring(11, namespace.length()) + "." + getName()
|
||||
namespace = this.getNamespace().getURI() and
|
||||
result.getQualifiedName() = namespace.substring(11, namespace.length()) + "." + this.getName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user