Merge branch 'main' into java_nonce_reuse_tests

This commit is contained in:
Ben Rodes
2025-10-02 13:31:40 -04:00
committed by GitHub
2297 changed files with 124237 additions and 43864 deletions

View File

@@ -85,7 +85,7 @@ java.applet,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,11,
java.awt,1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,3
java.beans,1,,177,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,82,95
java.io,66,1,225,,,,,,,,,22,,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,,,,,1,,202,23
java.lang,38,3,783,,13,,,,,,1,,,,,,,,,,,,8,,,,11,,,4,,,1,,,,,,,,,,,,,,,,3,,,506,277
java.lang,38,3,790,,13,,,,,,1,,,,,,,,,,,,8,,,,11,,,4,,,1,,,,,,,,,,,,,,,,3,,,510,280
java.math,,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9
java.net,23,3,347,,,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,,,,,,,,,,,,,,,3,248,99
java.nio,47,,499,,,,,,,,,5,,,,,,,,,,,,,,,41,,,,,,,,,1,,,,,,,,,,,,,,,,302,197
@@ -99,7 +99,7 @@ javafx.scene.web,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,
javax.accessibility,,,63,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,28,35
javax.activation,2,,7,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,,,,,,,,,,,,,7,
javax.annotation.processing,,,28,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,3
javax.crypto,19,,114,,,12,3,,2,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,61,53
javax.crypto,19,,140,,,12,3,,2,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,76,64
javax.faces.context,4,7,,,,,,,,,,,,,,2,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,7,,
javax.imageio,1,,304,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,138,166
javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57,
1 package sink source summary sink:bean-validation sink:command-injection sink:credentials-key sink:credentials-password sink:credentials-username sink:encryption-iv sink:encryption-salt sink:environment-injection sink:file-content-store sink:fragment-injection sink:groovy-injection sink:hostname-verification sink:html-injection sink:information-leak sink:intent-redirection sink:jexl-injection sink:jndi-injection sink:js-injection sink:ldap-injection sink:log-injection sink:mvel-injection sink:notification sink:ognl-injection sink:path-injection sink:pending-intents sink:regex-use sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:request-forgery sink:response-splitting sink:sql-injection sink:template-injection sink:trust-boundary-violation sink:unsafe-deserialization sink:url-forward sink:url-redirection sink:xpath-injection sink:xslt-injection source:android-external-storage-dir source:contentprovider source:database source:environment source:file source:remote summary:taint summary:value
85 java.awt 1 3 1 3
86 java.beans 1 177 1 82 95
87 java.io 66 1 225 22 44 1 202 23
88 java.lang 38 3 783 790 13 1 8 11 4 1 3 506 510 277 280
89 java.math 9 9
90 java.net 23 3 347 1 1 21 3 248 99
91 java.nio 47 499 5 41 1 302 197
99 javax.accessibility 63 28 35
100 javax.activation 2 7 1 1 7
101 javax.annotation.processing 28 25 3
102 javax.crypto 19 114 140 12 3 2 2 61 76 53 64
103 javax.faces.context 4 7 2 2 7
104 javax.imageio 1 304 1 138 166
105 javax.jms 9 57 9 57

View File

@@ -18,10 +18,10 @@ Java framework & library support
`Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,43,9,,,,,
JBoss Logging,``org.jboss.logging``,,,324,,,,,,
`JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,
Java Standard Library,``java.*``,10,4621,260,99,,9,,,26
Java extensions,"``javax.*``, ``jakarta.*``",87,4159,90,10,4,2,1,1,4
Java Standard Library,``java.*``,10,4628,260,99,,9,,,26
Java extensions,"``javax.*``, ``jakarta.*``",87,4185,90,10,4,2,1,1,4
Kotlin Standard Library,``kotlin*``,,1849,16,14,,,,,2
`Spring <https://spring.io/>`_,``org.springframework.*``,38,486,143,26,,28,14,,35
Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.mongodb``, ``com.opensymphony.xwork2``, ``com.rabbitmq.client``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.struts.beanvalidation.validation.interceptor``, ``org.apache.struts2``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.hibernate``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.jooq``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",133,10525,927,140,6,22,18,,208
Totals,,330,26328,2656,404,16,128,33,1,409
Totals,,330,26361,2656,404,16,128,33,1,409

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Remove Java 25 compact source files support by removing `isImplicitClass` table
compatibility: partial
isImplicitClass.rel: delete

View File

@@ -1,6 +1,6 @@
diagnosticAttributes
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityCliSummaryTable | true |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityStatusPage | true |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityTelemetry | true |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code. Some metrics of the database quality are: Percentage of calls with call target: 20 % (threshold 85 %). Percentage of expressions with known type: 14 % (threshold 85 %). Ideally these metrics should be above their thresholds. Addressing these issues is advisable to avoid false-positives or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityCliSummaryTable | true |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code. Some metrics of the database quality are: Percentage of calls with call target: 20 % (threshold 85 %). Percentage of expressions with known type: 14 % (threshold 85 %). Ideally these metrics should be above their thresholds. Addressing these issues is advisable to avoid false-positives or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityStatusPage | true |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code. Some metrics of the database quality are: Percentage of calls with call target: 20 % (threshold 85 %). Percentage of expressions with known type: 14 % (threshold 85 %). Ideally these metrics should be above their thresholds. Addressing these issues is advisable to avoid false-positives or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | visibilityTelemetry | true |
#select
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | 1 |
| Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code. Some metrics of the database quality are: Percentage of calls with call target: 20 % (threshold 85 %). Percentage of expressions with known type: 14 % (threshold 85 %). Ideally these metrics should be above their thresholds. Addressing these issues is advisable to avoid false-positives or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | Scanning Java code completed successfully, but the scan encountered issues. This may be caused by problems identifying dependencies or use of generated source code. Some metrics of the database quality are: Percentage of calls with call target: 20 % (threshold 85 %). Percentage of expressions with known type: 14 % (threshold 85 %). Ideally these metrics should be above their thresholds. Addressing these issues is advisable to avoid false-positives or missing results. If they cannot be addressed, consider scanning Java using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes). | 1 |

View File

@@ -1,4 +1,4 @@
| Annotation processors enabled: true | 1 |
| Annotation processors enabled: false | 1 |
| Number of calls with call target | 1 |
| Number of calls with missing call target | 4 |
| Number of diagnostics from CodeQL Java extractor with severity 5 | 10 |
@@ -15,5 +15,3 @@
| Total number of diagnostics from CodeQL Java extractor | 12 |
| Total number of lines | 13 |
| Total number of lines with extension java | 13 |
| Used annotation processor: lombok.launch.AnnotationProcessorHider$AnnotationProcessor | 1 |
| Used annotation processor: lombok.launch.AnnotationProcessorHider$ClaimingProcessor | 1 |

View File

@@ -0,0 +1,2 @@
query: Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,7 @@
class Test {
public static void updateFlashlights(Minecraft mc){
if(mc.world != null){
}
}
}

View File

@@ -0,0 +1,2 @@
def test(codeql, java):
codeql.database.create(build_mode="none")

View File

@@ -1,61 +1,117 @@
ql/java/ql/src/Advisory/Declarations/MissingOverrideAnnotation.ql
ql/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql
ql/java/ql/src/Advisory/Declarations/NonPrivateField.ql
ql/java/ql/src/Advisory/Documentation/ImpossibleJavadocThrows.ql
ql/java/ql/src/Advisory/Documentation/SpuriousJavadocParam.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneMethodAccess.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneOverride.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneableInterface.ql
ql/java/ql/src/Advisory/Java Objects/AvoidFinalizeOverride.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsConstants.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsMethods.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsPackages.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsRefTypes.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsVariables.ql
ql/java/ql/src/Advisory/Statements/MissingDefaultInSwitch.ql
ql/java/ql/src/Advisory/Statements/OneStatementPerLine.ql
ql/java/ql/src/Advisory/Statements/TerminateIfElseIfWithElse.ql
ql/java/ql/src/Advisory/Types/GenericsConstructor.ql
ql/java/ql/src/Advisory/Types/GenericsReturnType.ql
ql/java/ql/src/Advisory/Types/GenericsVariable.ql
ql/java/ql/src/Compatibility/JDK9/JdkInternalAccess.ql
ql/java/ql/src/Compatibility/JDK9/UnderscoreIdentifier.ql
ql/java/ql/src/DeadCode/DeadClass.ql
ql/java/ql/src/DeadCode/DeadEnumConstant.ql
ql/java/ql/src/DeadCode/DeadField.ql
ql/java/ql/src/DeadCode/DeadMethod.ql
ql/java/ql/src/DeadCode/UselessParameter.ql
ql/java/ql/src/Language Abuse/EmptyMethod.ql
ql/java/ql/src/Language Abuse/IterableIterator.ql
ql/java/ql/src/Language Abuse/LabelInSwitch.ql
ql/java/ql/src/Language Abuse/OverridePackagePrivate.ql
ql/java/ql/src/Language Abuse/TypeVarExtendsFinalType.ql
ql/java/ql/src/Language Abuse/TypeVariableHidesType.ql
ql/java/ql/src/Language Abuse/UselessNullCheck.ql
ql/java/ql/src/Language Abuse/UselessTypeTest.ql
ql/java/ql/src/Language Abuse/WrappedIterator.ql
ql/java/ql/src/Likely Bugs/Arithmetic/BadAbsOfRandom.ql
ql/java/ql/src/Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql
ql/java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
ql/java/ql/src/Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql
ql/java/ql/src/Likely Bugs/Arithmetic/MultiplyRemainder.ql
ql/java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql
ql/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
ql/java/ql/src/Likely Bugs/Cloning/MissingCallToSuperClone.ql
ql/java/ql/src/Likely Bugs/Cloning/MissingMethodClone.ql
ql/java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql
ql/java/ql/src/Likely Bugs/Collections/ContainsTypeMismatch.ql
ql/java/ql/src/Likely Bugs/Collections/IteratorRemoveMayFail.ql
ql/java/ql/src/Likely Bugs/Collections/ReadOnlyContainer.ql
ql/java/ql/src/Likely Bugs/Collections/RemoveTypeMismatch.ql
ql/java/ql/src/Likely Bugs/Collections/WriteOnlyContainer.ql
ql/java/ql/src/Likely Bugs/Comparison/CompareIdenticalValues.ql
ql/java/ql/src/Likely Bugs/Comparison/CovariantCompareTo.ql
ql/java/ql/src/Likely Bugs/Comparison/CovariantEquals.ql
ql/java/ql/src/Likely Bugs/Comparison/EqualsArray.ql
ql/java/ql/src/Likely Bugs/Comparison/HashedButNoHash.ql
ql/java/ql/src/Likely Bugs/Comparison/IncomparableEquals.ql
ql/java/ql/src/Likely Bugs/Comparison/InconsistentCompareTo.ql
ql/java/ql/src/Likely Bugs/Comparison/InconsistentEqualsHashCode.ql
ql/java/ql/src/Likely Bugs/Comparison/MissingInstanceofInEquals.ql
ql/java/ql/src/Likely Bugs/Comparison/RefEqBoxed.ql
ql/java/ql/src/Likely Bugs/Comparison/StringComparison.ql
ql/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql
ql/java/ql/src/Likely Bugs/Comparison/WrongNanComparison.ql
ql/java/ql/src/Likely Bugs/Concurrency/CallsToConditionWait.ql
ql/java/ql/src/Likely Bugs/Concurrency/CallsToRunnableRun.ql
ql/java/ql/src/Likely Bugs/Concurrency/DateFormatThreadUnsafe.ql
ql/java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLocking.ql
ql/java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLockingWithInitRace.ql
ql/java/ql/src/Likely Bugs/Concurrency/FutileSynchOnField.ql
ql/java/ql/src/Likely Bugs/Concurrency/NonSynchronizedOverride.ql
ql/java/ql/src/Likely Bugs/Concurrency/NotifyNotNotifyAll.ql
ql/java/ql/src/Likely Bugs/Concurrency/ScheduledThreadPoolExecutorZeroThread.ql
ql/java/ql/src/Likely Bugs/Concurrency/SleepWithLock.ql
ql/java/ql/src/Likely Bugs/Concurrency/StartInConstructor.ql
ql/java/ql/src/Likely Bugs/Concurrency/SynchOnBoxedType.ql
ql/java/ql/src/Likely Bugs/Concurrency/SynchSetUnsynchGet.ql
ql/java/ql/src/Likely Bugs/Concurrency/SynchWriteObject.ql
ql/java/ql/src/Likely Bugs/Finalization/NullifiedSuperFinalize.ql
ql/java/ql/src/Likely Bugs/Frameworks/JUnit/BadSuiteMethod.ql
ql/java/ql/src/Likely Bugs/Frameworks/JUnit/JUnit5MissingNestedAnnotation.ql
ql/java/ql/src/Likely Bugs/Frameworks/Swing/BadlyOverriddenAdapter.ql
ql/java/ql/src/Likely Bugs/Inheritance/NoNonFinalInConstructor.ql
ql/java/ql/src/Likely Bugs/Likely Typos/ContainerSizeCmpZero.ql
ql/java/ql/src/Likely Bugs/Likely Typos/ContradictoryTypeChecks.ql
ql/java/ql/src/Likely Bugs/Likely Typos/DangerousNonCircuitLogic.ql
ql/java/ql/src/Likely Bugs/Likely Typos/EqualsTypo.ql
ql/java/ql/src/Likely Bugs/Likely Typos/HashCodeTypo.ql
ql/java/ql/src/Likely Bugs/Likely Typos/MissingFormatArg.ql
ql/java/ql/src/Likely Bugs/Likely Typos/MissingSpaceTypo.ql
ql/java/ql/src/Likely Bugs/Likely Typos/SelfAssignment.ql
ql/java/ql/src/Likely Bugs/Likely Typos/StringBufferCharInit.ql
ql/java/ql/src/Likely Bugs/Likely Typos/SuspiciousDateFormat.ql
ql/java/ql/src/Likely Bugs/Likely Typos/ToStringTypo.ql
ql/java/ql/src/Likely Bugs/Likely Typos/UnusedFormatArg.ql
ql/java/ql/src/Likely Bugs/Nullness/NullAlways.ql
ql/java/ql/src/Likely Bugs/Nullness/NullExprDeref.ql
ql/java/ql/src/Likely Bugs/Nullness/NullMaybe.ql
ql/java/ql/src/Likely Bugs/Reflection/AnnotationPresentCheck.ql
ql/java/ql/src/Likely Bugs/Resource Leaks/CloseReader.ql
ql/java/ql/src/Likely Bugs/Resource Leaks/CloseSql.ql
ql/java/ql/src/Likely Bugs/Resource Leaks/CloseWriter.ql
ql/java/ql/src/Likely Bugs/Serialization/IncorrectSerialVersionUID.ql
ql/java/ql/src/Likely Bugs/Serialization/IncorrectSerializableMethods.ql
ql/java/ql/src/Likely Bugs/Serialization/MissingVoidConstructorOnExternalizable.ql
ql/java/ql/src/Likely Bugs/Serialization/MissingVoidConstructorsOnSerializable.ql
ql/java/ql/src/Likely Bugs/Serialization/NonSerializableInnerClass.ql
ql/java/ql/src/Likely Bugs/Serialization/ReadResolveObject.ql
ql/java/ql/src/Likely Bugs/Statements/ContinueInFalseLoop.ql
ql/java/ql/src/Likely Bugs/Statements/MissingEnumInSwitch.ql
ql/java/ql/src/Likely Bugs/Statements/PartiallyMaskedCatch.ql
ql/java/ql/src/Likely Bugs/Statements/UseBraces.ql
ql/java/ql/src/Likely Bugs/Termination/ConstantLoopCondition.ql
ql/java/ql/src/Likely Bugs/Termination/SpinOnField.ql
ql/java/ql/src/Performance/InefficientEmptyStringTest.ql
ql/java/ql/src/Performance/InefficientKeySetIterator.ql
ql/java/ql/src/Performance/InefficientOutputStream.ql
@@ -64,6 +120,7 @@ ql/java/ql/src/Performance/InnerClassCouldBeStatic.ql
ql/java/ql/src/Performance/NewStringString.ql
ql/java/ql/src/Performance/StringReplaceAllWithNonRegex.ql
ql/java/ql/src/Violations of Best Practice/Boxed Types/BoxedVariable.ql
ql/java/ql/src/Violations of Best Practice/Dead Code/CreatesEmptyZip.ql
ql/java/ql/src/Violations of Best Practice/Dead Code/DeadRefTypes.ql
ql/java/ql/src/Violations of Best Practice/Dead Code/InterfaceCannotBeImplemented.ql
ql/java/ql/src/Violations of Best Practice/Dead Code/UnreadLocal.ql
@@ -73,14 +130,21 @@ ql/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalR
ql/java/ql/src/Violations of Best Practice/Exception Handling/NumberFormatException.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/GetClassGetResource.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/VisibleForTestingAbuse.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/AmbiguousOuterSuper.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingMethodNames.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/FieldMasksSuperField.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsFieldConfusing.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
ql/java/ql/src/Violations of Best Practice/Testing/ExcessivePublicMethodMocking.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToRunFinalizersOnExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/NextFromIterator.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/PrintLnArray.ql

View File

@@ -71,6 +71,7 @@ ql/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalR
ql/java/ql/src/Violations of Best Practice/Exception Handling/NumberFormatException.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql
ql/java/ql/src/Violations of Best Practice/Implementation Hiding/VisibleForTestingAbuse.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/AmbiguousOuterSuper.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingMethodNames.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql
@@ -78,6 +79,7 @@ ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsFieldC
ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
ql/java/ql/src/Violations of Best Practice/Testing/ExcessivePublicMethodMocking.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql

View File

@@ -27,6 +27,7 @@ ql/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
ql/java/ql/src/Security/CWE/CWE-1204/StaticInitializationVector.ql
ql/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
ql/java/ql/src/Security/CWE/CWE-266/IntentUriPermissionManipulation.ql

View File

@@ -143,6 +143,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

View File

@@ -46,6 +46,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

View File

@@ -1,25 +1,8 @@
ql/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql
ql/java/ql/src/Advisory/Declarations/NonPrivateField.ql
ql/java/ql/src/Advisory/Documentation/MissingJavadocMethods.ql
ql/java/ql/src/Advisory/Documentation/MissingJavadocParameters.ql
ql/java/ql/src/Advisory/Documentation/MissingJavadocReturnValues.ql
ql/java/ql/src/Advisory/Documentation/MissingJavadocThrows.ql
ql/java/ql/src/Advisory/Documentation/MissingJavadocTypes.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneMethodAccess.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneOverride.ql
ql/java/ql/src/Advisory/Java Objects/AvoidCloneableInterface.ql
ql/java/ql/src/Advisory/Java Objects/AvoidFinalizeOverride.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsConstants.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsMethods.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsPackages.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsRefTypes.ql
ql/java/ql/src/Advisory/Naming/NamingConventionsVariables.ql
ql/java/ql/src/Advisory/Statements/MissingDefaultInSwitch.ql
ql/java/ql/src/Advisory/Statements/OneStatementPerLine.ql
ql/java/ql/src/Advisory/Statements/TerminateIfElseIfWithElse.ql
ql/java/ql/src/Advisory/Types/GenericsConstructor.ql
ql/java/ql/src/Advisory/Types/GenericsReturnType.ql
ql/java/ql/src/Advisory/Types/GenericsVariable.ql
ql/java/ql/src/AlertSuppression.ql
ql/java/ql/src/AlertSuppressionAnnotations.ql
ql/java/ql/src/Architecture/Dependencies/MutualDependency.ql
@@ -31,10 +14,6 @@ ql/java/ql/src/Architecture/Refactoring Opportunities/HubClasses.ql
ql/java/ql/src/Architecture/Refactoring Opportunities/InappropriateIntimacy.ql
ql/java/ql/src/Complexity/BlockWithTooManyStatements.ql
ql/java/ql/src/Complexity/ComplexCondition.ql
ql/java/ql/src/DeadCode/DeadClass.ql
ql/java/ql/src/DeadCode/DeadEnumConstant.ql
ql/java/ql/src/DeadCode/DeadField.ql
ql/java/ql/src/DeadCode/DeadMethod.ql
ql/java/ql/src/DeadCode/FLinesOfDeadCode.ql
ql/java/ql/src/Frameworks/JavaEE/EJB/EjbContainerInterference.ql
ql/java/ql/src/Frameworks/JavaEE/EJB/EjbFileIO.ql
@@ -66,7 +45,6 @@ ql/java/ql/src/Frameworks/Spring/XML Configuration Errors/MissingSetters.ql
ql/java/ql/src/Language Abuse/CastThisToTypeParameter.ql
ql/java/ql/src/Language Abuse/DubiousDowncastOfThis.ql
ql/java/ql/src/Language Abuse/DubiousTypeTestOfThis.ql
ql/java/ql/src/Language Abuse/EmptyStatement.ql
ql/java/ql/src/Language Abuse/EnumIdentifier.ql
ql/java/ql/src/Language Abuse/ImplementsAnnotation.ql
ql/java/ql/src/Language Abuse/MissedTernaryOpportunity.ql
@@ -187,7 +165,6 @@ ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConsta
ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverridesNames.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsField.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/GarbageCollection.ql
ql/java/ql/src/Violations of Best Practice/legacy/AutoBoxing.ql
ql/java/ql/src/Violations of Best Practice/legacy/FinallyMayNotComplete.ql
@@ -196,7 +173,6 @@ ql/java/ql/src/Violations of Best Practice/legacy/ParameterAssignment.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryCast.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryImport.ql
ql/java/ql/src/definitions.ql
ql/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql
ql/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql
ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql

View File

@@ -1,3 +1,36 @@
## 7.7.1
No user-facing changes.
## 7.7.0
### New Features
* The Java extractor and QL libraries now support Java 25.
* Added support for Java 25 compact source files (JEP 512). The new predicate `Class.isImplicit()` identifies classes that are implicitly declared when using compact source files, and the new predicate `CompilationUnit.isCompactSourceFile()` identifies compilation units that contain compact source files.
* Added support for Java 25 module import declarations.
* Add `ModuleImportDeclaration` class.
### Minor Analysis Improvements
* Improved support for various assertion libraries, in particular JUnit. This affects the control-flow graph slightly, and in turn affects several queries (mainly quality queries). Most queries should see improved precision (new true positives and fewer false positives), in particular `java/constant-comparison`, `java/index-out-of-bounds`, `java/dereferenced-value-may-be-null`, and `java/useless-null-check`. Some medium precision queries like `java/toctou-race-condition` and `java/unreleased-lock` may see mixed result changes (both slight improvements and slight regressions).
* Added taint flow model for `java.crypto.KDF`.
* Added taint flow model for `java.lang.ScopedValue`.
## 7.6.1
No user-facing changes.
## 7.6.0
### Major Analysis Improvements
* Added library models for the relevant method calls under `jakarta.servlet.ServletRequest` and `jakarta.servlet.http.HttpServletRequest` as remote flow sources.
### Minor Analysis Improvements
* Guard implication logic involving wrapper methods has been improved. In particular, this means fewer false positives for `java/dereferenced-value-may-be-null`.
## 7.5.0
### New Features

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Guard implication logic involving wrapper methods has been improved. In particular, this means fewer false positives for `java/dereferenced-value-may-be-null`.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* Added library models for the relevant method calls under `jakarta.servlet.ServletRequest` and `jakarta.servlet.http.HttpServletRequest` as remote flow sources.

View File

@@ -0,0 +1,9 @@
## 7.6.0
### Major Analysis Improvements
* Added library models for the relevant method calls under `jakarta.servlet.ServletRequest` and `jakarta.servlet.http.HttpServletRequest` as remote flow sources.
### Minor Analysis Improvements
* Guard implication logic involving wrapper methods has been improved. In particular, this means fewer false positives for `java/dereferenced-value-may-be-null`.

View File

@@ -0,0 +1,3 @@
## 7.6.1
No user-facing changes.

View File

@@ -0,0 +1,14 @@
## 7.7.0
### New Features
* The Java extractor and QL libraries now support Java 25.
* Added support for Java 25 compact source files (JEP 512). The new predicate `Class.isImplicit()` identifies classes that are implicitly declared when using compact source files, and the new predicate `CompilationUnit.isCompactSourceFile()` identifies compilation units that contain compact source files.
* Added support for Java 25 module import declarations.
* Add `ModuleImportDeclaration` class.
### Minor Analysis Improvements
* Improved support for various assertion libraries, in particular JUnit. This affects the control-flow graph slightly, and in turn affects several queries (mainly quality queries). Most queries should see improved precision (new true positives and fewer false positives), in particular `java/constant-comparison`, `java/index-out-of-bounds`, `java/dereferenced-value-may-be-null`, and `java/useless-null-check`. Some medium precision queries like `java/toctou-race-condition` and `java/unreleased-lock` may see mixed result changes (both slight improvements and slight regressions).
* Added taint flow model for `java.crypto.KDF`.
* Added taint flow model for `java.lang.ScopedValue`.

View File

@@ -0,0 +1,3 @@
## 7.7.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 7.5.0
lastReleaseVersion: 7.7.1

View File

@@ -537,6 +537,10 @@ isLocalClassOrInterface(
int parent: @localtypedeclstmt ref
);
isImplicitClass(
unique int classid: @classorinterface ref
);
isDefConstr(
int constructorid: @constructor ref
);

View File

@@ -13986,6 +13986,17 @@
</dep>
</dependencies>
</relation>
<relation>
<name>isImplicitClass</name>
<cardinality>4</cardinality>
<columnsizes>
<e>
<k>classid</k>
<v>4</v>
</e>
</columnsizes>
<dependencies/>
</relation>
<relation>
<name>isDefConstr</name>
<cardinality>139376</cardinality>

View File

@@ -119,15 +119,15 @@ module JCAModel {
bindingset[name]
Crypto::HashType hash_name_to_type_known(string name, int digestLength) {
name = "SHA-1" and result instanceof Crypto::SHA1 and digestLength = 160
name in ["SHA-1", "SHA1"] and result instanceof Crypto::SHA1 and digestLength = 160
or
name = ["SHA-256", "SHA-384", "SHA-512"] and
name in ["SHA-256", "SHA-384", "SHA-512", "SHA256", "SHA384", "SHA512"] and
result instanceof Crypto::SHA2 and
digestLength = name.splitAt("-", 1).toInt()
digestLength = name.replaceAll("-", "").splitAt("SHA", 1).toInt()
or
name = ["SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512"] and
name in ["SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHA3256", "SHA3384", "SHA3512"] and
result instanceof Crypto::SHA3 and
digestLength = name.splitAt("-", 1).toInt()
digestLength = name.replaceAll("-", "").splitAt("SHA3", 1).toInt()
or
(
name.matches("BLAKE2b%") and
@@ -205,12 +205,6 @@ module JCAModel {
)
}
bindingset[name]
predicate mac_name_to_mac_type_known(Crypto::TMacType type, string name) {
type = Crypto::HMAC() and
name.toUpperCase().matches("HMAC%")
}
bindingset[name]
predicate key_agreement_name_to_type_known(Crypto::TKeyAgreementType type, string name) {
type = Crypto::DH() and
@@ -269,7 +263,7 @@ module JCAModel {
}
/**
* Data-flow configuration modelling flow from a cipher string literal to a cipher algorithm consumer.
* Data-flow configuration modeling flow from a cipher string literal to a cipher algorithm consumer.
*/
private module CipherAlgorithmStringToCipherConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CipherStringLiteral }
@@ -404,9 +398,7 @@ module JCAModel {
* For example, in `Cipher.getInstance(algorithm)`, this class represents `algorithm`.
*/
class CipherGetInstanceAlgorithmArg extends CipherAlgorithmValueConsumer instanceof Expr {
CipherGetInstanceCall call;
CipherGetInstanceAlgorithmArg() { this = call.getAlgorithmArg() }
CipherGetInstanceAlgorithmArg() { this = any(CipherGetInstanceCall call).getAlgorithmArg() }
override Crypto::ConsumerInputDataFlowNode getInputNode() { result.asExpr() = this }
@@ -659,27 +651,19 @@ module JCAModel {
class IvParameterSpecInstance extends NonceParameterInstantiation {
IvParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("javax.crypto.spec", "IvParameterSpec")
super.getConstructedType().hasQualifiedName("javax.crypto.spec", "IvParameterSpec")
}
override DataFlow::Node getInputNode() {
result.asExpr() = this.(ClassInstanceExpr).getArgument(0)
}
override DataFlow::Node getInputNode() { result.asExpr() = super.getArgument(0) }
}
// TODO: this also specifies the tag length for GCM
class GCMParameterSpecInstance extends NonceParameterInstantiation {
GCMParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("javax.crypto.spec", "GCMParameterSpec")
super.getConstructedType().hasQualifiedName("javax.crypto.spec", "GCMParameterSpec")
}
override DataFlow::Node getInputNode() {
result.asExpr() = this.(ClassInstanceExpr).getArgument(1)
}
override DataFlow::Node getInputNode() { result.asExpr() = super.getArgument(1) }
}
class IvParameterSpecGetIvCall extends MethodCall {
@@ -819,14 +803,14 @@ module JCAModel {
HashAlgorithmValueConsumer consumer;
KnownHashAlgorithm() {
hash_names(this.getValue()) and
hash_names(super.getValue()) and
KnownHashAlgorithmLiteralToMessageDigestFlow::flow(DataFlow::exprNode(this),
consumer.getInputNode())
}
HashAlgorithmValueConsumer getConsumer() { result = consumer }
override string getRawHashAlgorithmName() { result = this.(StringLiteral).getValue() }
override string getRawHashAlgorithmName() { result = super.getValue() }
override Crypto::THashType getHashFamily() {
result = hash_name_to_type_known(this.getRawHashAlgorithmName(), _)
@@ -925,9 +909,7 @@ module JCAModel {
class DHGenParameterSpecInstance extends KeyGeneratorParameterSpecClassInstanceExpr {
DHGenParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec")
super.getConstructedType().hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec")
}
Expr getPrimeSizeArg() { result = this.getArgument(0) }
@@ -937,9 +919,7 @@ module JCAModel {
class DSAParameterSpecInstance extends KeyGeneratorParameterSpecClassInstanceExpr {
DSAParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("java.security.spec", "DSAParameterSpec")
super.getConstructedType().hasQualifiedName("java.security.spec", "DSAParameterSpec")
}
Expr getPArg() { result = this.getArgument(0) }
@@ -951,9 +931,7 @@ module JCAModel {
class ECGenParameterSpecInstance extends KeyGeneratorParameterSpecClassInstanceExpr {
ECGenParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("java.security.spec", "ECGenParameterSpec")
super.getConstructedType().hasQualifiedName("java.security.spec", "ECGenParameterSpec")
}
Expr getCurveNameArg() { result = this.getArgument(0) }
@@ -963,9 +941,7 @@ module JCAModel {
class RSAGenParameterSpecInstance extends KeyGeneratorParameterSpecClassInstanceExpr {
RSAGenParameterSpecInstance() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("java.security.spec", "RSAGenParameterSpec")
super.getConstructedType().hasQualifiedName("java.security.spec", "RSAGenParameterSpec")
}
Expr getKeySizeArg() { result = this.getArgument(0) }
@@ -989,9 +965,7 @@ module JCAModel {
class ECGenParameterSpecClassInstanceExpr extends KeyGeneratorParameterSpecClassInstanceExpr {
ECGenParameterSpecClassInstanceExpr() {
this.(ClassInstanceExpr)
.getConstructedType()
.hasQualifiedName("java.security.spec", "ECGenParameterSpec")
super.getConstructedType().hasQualifiedName("java.security.spec", "ECGenParameterSpec")
}
Expr getAlgorithmArg() { result = this.getArgument(0) }
@@ -1228,37 +1202,86 @@ module JCAModel {
SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer() { result = consumer }
}
class Pbkdf2AlgorithmStringLiteral extends KdfAlgorithmStringLiteral,
Crypto::Pbkdf2AlgorithmInstance, Crypto::HmacAlgorithmInstance, Crypto::HashAlgorithmInstance,
Crypto::AlgorithmValueConsumer
class Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral extends Crypto::KeyOperationAlgorithmInstance instanceof KdfAlgorithmStringLiteral
{
Pbkdf2AlgorithmStringLiteral() { super.getKdfType() instanceof Crypto::PBKDF2 }
override Crypto::ConsumerInputDataFlowNode getInputNode() { none() }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { result = this }
override Crypto::THashType getHashFamily() {
result = hash_name_to_type_known(this.getRawHashAlgorithmName(), _)
Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral() {
this.(StringLiteral).getValue().toUpperCase().matches("PBKDF2WithHmac%".toUpperCase())
}
override int getFixedDigestLength() {
exists(hash_name_to_type_known(this.getRawHashAlgorithmName(), result))
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
result = KeyOpAlg::TMac(KeyOpAlg::HMAC())
}
override string getRawMacAlgorithmName() {
result = super.getRawKdfAlgorithmName().splitAt("PBKDF2With", 1)
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
// TODO: trace to any key size initializer?
none()
}
override string getRawHashAlgorithmName() {
result = super.getRawKdfAlgorithmName().splitAt("WithHmac", 1)
override int getKeySizeFixed() {
// TODO: are there known fixed key sizes to consider?
none()
}
override Crypto::MacType getMacType() { result = Crypto::HMAC() }
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
override Crypto::AlgorithmValueConsumer getHmacAlgorithmValueConsumer() { result = this }
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() { result = this }
override string getRawAlgorithmName() { result = this.(StringLiteral).getValue() }
}
class Pbkdf2WithHmac_HashAlgorithmStringLiteral extends Crypto::HashAlgorithmInstance instanceof Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral
{
string hashName;
Pbkdf2WithHmac_HashAlgorithmStringLiteral() {
hashName = this.(StringLiteral).getValue().splitAt("WithHmac", 1)
}
override string getRawHashAlgorithmName() { result = this.(StringLiteral).getValue() }
override Crypto::THashType getHashFamily() { result = hash_name_to_type_known(hashName, _) }
override int getFixedDigestLength() { exists(hash_name_to_type_known(hashName, result)) }
}
//TODO: handle PBE "with" cases
class Pbkdf2WithHmac_Pbkdf2AlgorithmInstance extends Crypto::Pbkdf2AlgorithmInstance,
KdfAlgorithmStringLiteral, // this is a parent already, but extending to have immediate access to 'getConsumer()'
Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral
{
override Crypto::AlgorithmValueConsumer getHmacAlgorithmValueConsumer() {
result = this.getConsumer()
}
}
// NOTE: must use instanceof to avoid non-monotonic recursion
class Pbkdf2WithHmac_HmacAlgorithmInstance extends Crypto::HmacAlgorithmInstance instanceof Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral
{
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
result = this.(KdfAlgorithmStringLiteral).getConsumer()
}
override int getKeySizeFixed() {
// already defined by parent key operation algorithm, but extending an instance
// still requires we override this method
result = super.getKeySizeFixed()
}
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
// already defined by parent key operation algorithm, but extending an instance
// still requires we override this method
result = super.getKeySizeConsumer()
}
override string getRawAlgorithmName() {
// already defined by parent key operation algorithm, but extending an instance
// still requires we override this method
result = super.getRawAlgorithmName()
}
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
result = KeyOpAlg::TMac(KeyOpAlg::HMAC())
}
}
class SecretKeyFactoryKDFAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer instanceof Expr
@@ -1333,7 +1356,7 @@ module JCAModel {
}
/**
* Data-flow configuration modelling flow from a key agreement string literal to a key agreement algorithm consumer.
* Data-flow configuration modeling flow from a key agreement string literal to a key agreement algorithm consumer.
*/
private module KeyAgreementAlgorithmStringToConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KeyAgreementStringLiteral }
@@ -1480,7 +1503,7 @@ module JCAModel {
module MacInitCallToMacOperationFlow = DataFlow::Global<MacInitCallToMacOperationFlowConfig>;
class KnownMacAlgorithm extends Crypto::MacAlgorithmInstance instanceof StringLiteral {
class KnownMacAlgorithm extends Crypto::KeyOperationAlgorithmInstance instanceof StringLiteral {
MacGetInstanceAlgorithmValueConsumer consumer;
KnownMacAlgorithm() {
@@ -1490,13 +1513,30 @@ module JCAModel {
MacGetInstanceAlgorithmValueConsumer getConsumer() { result = consumer }
override string getRawMacAlgorithmName() { result = super.getValue() }
override string getRawAlgorithmName() { result = super.getValue() }
override Crypto::MacType getMacType() {
if mac_name_to_mac_type_known(_, super.getValue())
then mac_name_to_mac_type_known(result, super.getValue())
else result = Crypto::OtherMacType()
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
if super.getValue().toUpperCase().matches("HMAC%")
then result = KeyOpAlg::TMac(KeyOpAlg::HMAC())
else
if super.getValue().toUpperCase().matches("CMAC%")
then result = KeyOpAlg::TMac(KeyOpAlg::CMAC())
else result = KeyOpAlg::TMac(KeyOpAlg::OtherMacAlgorithmType())
}
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
// TODO: trace to any key size initializer?
none()
}
override int getKeySizeFixed() {
// TODO: are there known fixed key sizes to consider?
none()
}
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
}
class MacGetInstanceCall extends MethodCall {
@@ -1566,10 +1606,22 @@ module JCAModel {
)
}
override Crypto::ConsumerInputDataFlowNode getMessageConsumer() {
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result.asExpr() = super.getArgument(0) and
super.getMethod().getParameterType(0).hasName("byte[]")
}
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result.asExpr() = output }
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() { none() }
override predicate hasHashAlgorithmConsumer() { none() }
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
result instanceof Crypto::TMacMode
}
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() { none() }
}
/*

View File

@@ -113,7 +113,7 @@ private class ConstantDataSource extends Crypto::GenericConstantSourceInstance i
}
/**
* An instance of random number generation, modelled as the expression
* An instance of random number generation, modeled as the expression
* tied to an output node (i.e., the result of the source of randomness)
*/
abstract class RandomnessInstance extends Crypto::RandomNumberGenerationInstance {

View File

@@ -0,0 +1,19 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["java.lang", "ScopedValue", False, "where", "(ScopedValue,Object)", "", "Argument[1]", "Argument[0].SyntheticField[java.lang.ScopedValue.boundValue]", "value", "manual"]
- ["java.lang", "ScopedValue", True, "get", "()", "", "Argument[this].SyntheticField[java.lang.ScopedValue.boundValue]", "ReturnValue", "value", "manual"]
- ["java.lang", "ScopedValue", False, "where", "(ScopedValue,Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "ScopedValue$Carrier", False, "where", "(ScopedValue,Object)", "", "Argument[1]", "Argument[0].SyntheticField[java.lang.ScopedValue.boundValue]", "value", "manual"]
- ["java.lang", "ScopedValue$Carrier", False, "where", "(ScopedValue,Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "ScopedValue$Carrier", False, "run", "(Runnable)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.lang", "ScopedValue$Carrier", False, "call", "(Callable)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["java.lang", "ScopedValue", "newInstance", "()", "summary", "manual"]
- ["java.lang", "ScopedValue", "isBound", "()", "summary", "manual"]

View File

@@ -7,6 +7,21 @@ extensions:
- ["javax.crypto", "Cipher", True, "init", "(int,Key,AlgorithmParameterSpec,SecureRandom)", "", "Argument[2]", "encryption-iv", "manual"]
- ["javax.crypto", "Cipher", False, "unwrap", "(byte[],String,int)", "", "Argument[0]", "credentials-key", "hq-generated"]
- ["javax.crypto", "CipherSpi", True, "engineUnwrap", "(byte[],String,int)", "", "Argument[0]", "credentials-key", "hq-generated"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["javax.crypto", "KDF", False, "getInstance", "(String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", False, "getInstance", "(String,Provider)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", False, "getInstance", "(String,String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,Provider)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"]
- ["javax.crypto", "KDF", True, "getAlgorithm", "()", "", "Argument[this].SyntheticField[javax.crypto.KDF.algorithm]", "ReturnValue", "value", "manual"]
- ["javax.crypto", "KDF", True, "getProvider", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["javax.crypto", "KDF", True, "deriveKey", "(String,AlgorithmParameterSpec)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["javax.crypto", "KDF", True, "deriveData", "(AlgorithmParameterSpec)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["javax.crypto", "SecretKey", True, "getEncoded", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel

View File

@@ -7,6 +7,21 @@ extensions:
- ["javax.crypto.spec", "GCMParameterSpec", True, "GCMParameterSpec", "", "", "Argument[1]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "RC2ParameterSpec", True, "RC2ParameterSpec", "", "", "Argument[1]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "RC5ParameterSpec", True, "RC5ParameterSpec", "", "", "Argument[3]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],int,int,String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- addsTo:
pack: codeql/java-all
extensible: sinkModel

View File

@@ -18,8 +18,8 @@ external string selectedSourceFile();
class PrintAstConfigurationOverride extends PrintAstConfiguration {
/**
* Holds if the location matches the selected file in the VS Code extension and
* the element is `fromSource`.
* Holds if the location `l` matches the selected file in the VS Code extension and
* the element `e` is `fromSource`.
*/
override predicate shouldPrint(Element e, Location l) {
super.shouldPrint(e, l) and

View File

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

View File

@@ -70,7 +70,12 @@ class ConfigValue extends @configValue, ConfigLocatable {
override string toString() { result = this.getValue() }
}
/** A `.properties` file. */
class PropertiesFile extends File {
PropertiesFile() { this.getExtension() = "properties" }
}
/** A Java property is a name-value pair in a `.properties` file. */
class JavaProperty extends ConfigPair {
JavaProperty() { this.getFile().getExtension() = "properties" }
JavaProperty() { this.getFile() instanceof PropertiesFile }
}

View File

@@ -33,5 +33,13 @@ class CompilationUnit extends Element, File {
*/
Module getModule() { cumodule(this, result) }
/**
* Holds if this compilation unit represents a compact source file.
* A compact source file contains an implicitly declared top-level class.
*/
predicate isCompactSourceFile() {
exists(Class c | c.getCompilationUnit() = this and c.isImplicit())
}
override string getAPrimaryQlClass() { result = "CompilationUnit" }
}

View File

@@ -26,7 +26,8 @@ predicate locallySynchronizedOnThis(Expr e, RefType thisType) {
}
/**
* Holds if `e` is synchronized by a `synchronized` modifier on the enclosing (static) method.
* Holds if `e` is synchronized by a `synchronized` modifier on the enclosing (static) method
* declared in the type `classType`.
*/
predicate locallySynchronizedOnClass(Expr e, RefType classType) {
exists(SynchronizedCallable c | c = e.getEnclosingCallable() |

View File

@@ -82,6 +82,7 @@ module;
*/
import java
private import codeql.controlflow.SuccessorType
private import codeql.util.Boolean
private import Completion
private import controlflow.internal.Preconditions
@@ -124,6 +125,28 @@ module ControlFlow {
result = succ(this, NormalCompletion())
}
/** Gets an immediate successor of this node of a given type, if any. */
Node getASuccessor(SuccessorType t) {
result = branchSuccessor(this, t.(BooleanSuccessor).getValue())
or
exists(Completion completion |
result = succ(this, completion) and
not result = branchSuccessor(this, _)
|
completion = NormalCompletion() and t instanceof DirectSuccessor
or
completion = ReturnCompletion() and t instanceof ReturnSuccessor
or
completion = BreakCompletion(_) and t instanceof BreakSuccessor
or
completion = YieldCompletion(_) and t instanceof BreakSuccessor
or
completion = ContinueCompletion(_) and t instanceof ContinueSuccessor
or
completion = ThrowCompletion(_) and t instanceof ExceptionSuccessor
)
}
/** Gets the basic block that contains this node. */
BasicBlock getBasicBlock() { result.getANode() = this }
@@ -365,10 +388,10 @@ private module ControlFlowGraphImpl {
* Bind `t` to an unchecked exception that may occur in a precondition check or guard wrapper.
*/
private predicate uncheckedExceptionFromMethod(MethodCall ma, ThrowableType t) {
conditionCheckArgument(ma, _, _) and
(methodCallChecksArgument(ma) or methodCallUnconditionallyThrows(ma)) and
(t instanceof TypeError or t instanceof TypeRuntimeException)
or
methodMayThrow(ma.getMethod(), t)
methodMayThrow(ma.getMethod().getSourceDeclaration(), t)
}
/**
@@ -586,6 +609,7 @@ private module ControlFlowGraphImpl {
* Gets a `MethodCall` that always throws an exception or calls `exit`.
*/
private MethodCall nonReturningMethodCall() {
methodCallUnconditionallyThrows(result) or
result.getMethod().getSourceDeclaration() = nonReturningMethod() or
result = likelyNonReturningMethod().getAnAccess()
}

View File

@@ -100,12 +100,12 @@ class InvocationConversionContext extends ConversionSite {
* See the Java Language Specification, Section 5.4.
*/
class StringConversionContext extends ConversionSite {
AddExpr a;
StringConversionContext() {
a.getAnOperand() = this and
not this.getType() instanceof TypeString and
a.getAnOperand().getType() instanceof TypeString
exists(AddExpr a |
a.getAnOperand() = this and
not this.getType() instanceof TypeString and
a.getAnOperand().getType() instanceof TypeString
)
}
override Type getConversionTarget() { result instanceof TypeString }

View File

@@ -154,3 +154,35 @@ class ImportStaticTypeMember extends Import {
override string getAPrimaryQlClass() { result = "ImportStaticTypeMember" }
}
/**
* A module import declaration, which imports an entire module.
*
* For example, `import module java.base;` makes all packages exported
* by the `java.base` module available, and through those packages,
* the types they declare become accessible.
*/
class ModuleImportDeclaration extends Import {
ModuleImportDeclaration() { imports(this, _, _, 6) }
/** Gets the name of the imported module. */
string getModuleName() { imports(this, _, result, _) }
/** Gets the imported module. */
Module getModule() { result.getName() = this.getModuleName() }
/** Gets an exported package from the imported module. */
Package getAnImportedPackage() {
exists(ExportsDirective exports |
exports = this.getModule().getADirective() and
result = exports.getExportedPackage()
)
}
/** Gets a type from a package that is accessible through this module import. */
RefType getAnImportedType() { result.getPackage() = this.getAnImportedPackage() }
override string toString() { result = "import module " + this.getModuleName() }
override string getAPrimaryQlClass() { result = "ModuleImportDeclaration" }
}

View File

@@ -848,6 +848,9 @@ class Field extends Member, ExprParent, @field, Variable {
override string getAPrimaryQlClass() { result = "Field" }
}
overlay[local]
private class DiscardableField extends DiscardableReferableLocatable, @field { }
/** An instance field. */
class InstanceField extends Field {
InstanceField() { not this.isStatic() }

View File

@@ -18,7 +18,7 @@ predicate isOverlay() { databaseMetadata("isOverlay", "true") }
overlay[local]
string getRawFile(@locatable el) {
exists(@location loc, @file file |
hasLocation(el, loc) and
(hasLocation(el, loc) or xmllocations(el, loc)) and
locations_default(loc, file, _, _, _, _) and
files(file, result)
)
@@ -73,40 +73,60 @@ private predicate discardReferableLocatable(@locatable el) {
)
}
/** Gets the raw file for a configLocatable. */
overlay[local]
private predicate baseConfigLocatable(@configLocatable l) { not isOverlay() and exists(l) }
private string getRawFileForConfig(@configLocatable el) {
exists(@location loc, @file file |
configLocations(el, loc) and
locations_default(loc, file, _, _, _, _) and
files(file, result)
)
}
overlay[local]
private predicate overlayHasConfigLocatables() {
private string baseConfigLocatable(@configLocatable el) {
not isOverlay() and result = getRawFileForConfig(el)
}
overlay[local]
private predicate overlayConfigExtracted(string file) {
isOverlay() and
exists(@configLocatable el)
exists(@configLocatable el | file = getRawFileForConfig(el))
}
overlay[discard_entity]
private predicate discardBaseConfigLocatable(@configLocatable el) {
// The properties extractor is currently not incremental, so if
// the overlay contains any config locatables, the overlay should
// contain a full extraction and all config locatables from base
// should be discarded.
baseConfigLocatable(el) and overlayHasConfigLocatables()
overlayChangedFiles(baseConfigLocatable(el))
or
// The config extractor is currently not incremental and may extract more
// property files than those included in overlayChangedFiles.
overlayConfigExtracted(baseConfigLocatable(el))
}
/**
* An `@xmllocatable` that should be discarded in the base variant if its file is
* extracted in the overlay variant.
*/
overlay[local]
abstract class DiscardableXmlLocatable extends @xmllocatable {
/** Gets the raw file for an xmllocatable in base. */
string getRawFileInBase() { not isOverlay() and result = getRawFile(this) }
/** Gets a textual representation of this discardable xmllocatable. */
string toString() { none() }
}
overlay[local]
private predicate baseXmlLocatable(@xmllocatable l) {
not isOverlay() and not files(l, _) and not xmlNs(l, _, _, _)
}
overlay[local]
private predicate overlayHasXmlLocatable() {
private predicate overlayXmlExtracted(string file) {
isOverlay() and
exists(@xmllocatable l | not files(l, _) and not xmlNs(l, _, _, _))
exists(@xmllocatable el | not files(el, _) and not xmlNs(el, _, _, _) and file = getRawFile(el))
}
overlay[discard_entity]
private predicate discardBaseXmlLocatable(@xmllocatable el) {
// The XML extractor is currently not incremental, so if
// the overlay contains any XML locatables, the overlay should
// contain a full extraction and all XML locatables from base
// should be discarded.
baseXmlLocatable(el) and overlayHasXmlLocatable()
private predicate discardXmlLocatable(@xmllocatable el) {
overlayChangedFiles(el.(DiscardableXmlLocatable).getRawFileInBase())
or
// The XML extractor is currently not incremental and may extract more
// XML files than those included in overlayChangedFiles.
overlayXmlExtracted(el.(DiscardableXmlLocatable).getRawFileInBase())
}

View File

@@ -291,7 +291,7 @@ class TryStmt extends Stmt, @trystmt {
CatchClause getACatchClause() { result.getParent() = this }
/**
* Gets the `catch` clause at the specified (zero-based) position
* Gets the `catch` clause at the specified (zero-based) position `index`
* in this `try` statement.
*/
CatchClause getCatchClause(int index) {
@@ -305,7 +305,7 @@ class TryStmt extends Stmt, @trystmt {
/** Gets a resource variable declaration, if any. */
LocalVariableDeclStmt getAResourceDecl() { result.getParent() = this and result.getIndex() <= -3 }
/** Gets the resource variable declaration at the specified position in this `try` statement. */
/** Gets the resource variable declaration at the specified position `index` in this `try` statement. */
LocalVariableDeclStmt getResourceDecl(int index) {
result = this.getAResourceDecl() and
index = -3 - result.getIndex()
@@ -314,7 +314,7 @@ class TryStmt extends Stmt, @trystmt {
/** Gets a resource expression, if any. */
VarAccess getAResourceExpr() { result.getParent() = this and result.getIndex() <= -3 }
/** Gets the resource expression at the specified position in this `try` statement. */
/** Gets the resource expression at the specified position `index` in this `try` statement. */
VarAccess getResourceExpr(int index) {
result = this.getAResourceExpr() and
index = -3 - result.getIndex()
@@ -323,7 +323,7 @@ class TryStmt extends Stmt, @trystmt {
/** Gets a resource in this `try` statement, if any. */
ExprParent getAResource() { result = this.getAResourceDecl() or result = this.getAResourceExpr() }
/** Gets the resource at the specified position in this `try` statement. */
/** Gets the resource at the specified position `index` in this `try` statement. */
ExprParent getResource(int index) {
result = this.getResourceDecl(index) or result = this.getResourceExpr(index)
}

View File

@@ -15,6 +15,7 @@ module;
import Member
import Modifier
import JDK
private import semmle.code.java.Overlay
/**
* Holds if reference type `t` is an immediate super-type of `sub`.
@@ -699,6 +700,15 @@ class Class extends ClassOrInterface {
/** Holds if this class is an anonymous class. */
predicate isAnonymous() { isAnonymClass(this.getSourceDeclaration(), _) }
/** Holds if this class is an implicit class (compact source file). */
predicate isImplicit() { isImplicitClass(this.getSourceDeclaration()) }
/** Holds if this is an auxiliary program element generated by the compiler. */
override predicate isCompilerGenerated() {
super.isCompilerGenerated() or
this.isImplicit()
}
/**
* Gets an annotation that applies to this class.
*
@@ -998,6 +1008,10 @@ class ClassOrInterface extends RefType, @classorinterface {
CompanionObject getCompanionObject() { type_companion_object(this, _, result) }
}
overlay[local]
private class DiscardableClassOrInterface extends DiscardableReferableLocatable, @classorinterface {
}
private string getAPublicObjectMethodSignature() {
exists(Method m |
m.getDeclaringType() instanceof TypeObject and

View File

@@ -7,10 +7,9 @@ module;
import java
import Dominance
private import codeql.controlflow.BasicBlock as BB
private import codeql.controlflow.SuccessorType
private module Input implements BB::InputSig<Location> {
import SuccessorType
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t) { none() }
@@ -23,20 +22,8 @@ private module Input implements BB::InputSig<Location> {
/** Gets the CFG scope in which this node occurs. */
CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result }
private Node getASpecificSuccessor(Node node, SuccessorType t) {
node.(ConditionNode).getABranchSuccessor(t.(BooleanSuccessor).getValue()) = result
or
node.getAnExceptionSuccessor() = result and t instanceof ExceptionSuccessor
}
/** Gets an immediate successor of this node. */
Node nodeGetASuccessor(Node node, SuccessorType t) {
result = getASpecificSuccessor(node, t)
or
node.getASuccessor() = result and
t instanceof NormalSuccessor and
not result = getASpecificSuccessor(node, _)
}
Node nodeGetASuccessor(Node node, SuccessorType t) { result = node.getASuccessor(t) }
/**
* Holds if `node` represents an entry node to be used when calculating
@@ -96,7 +83,17 @@ class BasicBlock extends BbImpl::BasicBlock {
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
/** Gets an immediate successor of this basic block of a given type, if any. */
BasicBlock getASuccessor(Input::SuccessorType t) { result = super.getASuccessor(t) }
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor(t) }
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) }
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
/**
* DEPRECATED: Use `getASuccessor` instead.
@@ -145,3 +142,15 @@ class BasicBlock extends BbImpl::BasicBlock {
class ExitBlock extends BasicBlock {
ExitBlock() { this.getLastNode() instanceof ControlFlow::ExitNode }
}
private class BasicBlockAlias = BasicBlock;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = BbImpl::ControlFlowNode;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock extends BasicBlock instanceof BbImpl::EntryBasicBlock { }
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { BbImpl::dominatingEdge(bb1, bb2) }
}

View File

@@ -0,0 +1,60 @@
/**
* Provides an implementation of local (intraprocedural) control flow reachability.
*/
overlay[local?]
module;
import java
private import codeql.controlflow.ControlFlow
private import semmle.code.java.dataflow.SSA as SSA
private import semmle.code.java.controlflow.Guards as Guards
private module ControlFlowInput implements InputSig<Location, ControlFlowNode, BasicBlock> {
private import java as J
AstNode getEnclosingAstNode(ControlFlowNode node) { node.getAstNode() = result }
class AstNode = ExprParent;
AstNode getParent(AstNode node) {
result = node.(Expr).getParent() or
result = node.(Stmt).getParent()
}
class FinallyBlock extends AstNode {
FinallyBlock() { any(TryStmt try).getFinally() = this }
}
class Expr = J::Expr;
class SourceVariable = SSA::SsaSourceVariable;
class SsaDefinition = SSA::SsaVariable;
class SsaWriteDefinition extends SsaDefinition instanceof SSA::SsaExplicitUpdate {
Expr getDefinition() {
super.getDefiningExpr().(VariableAssign).getSource() = result or
super.getDefiningExpr().(AssignOp) = result
}
}
class SsaPhiNode = SSA::SsaPhiNode;
class SsaUncertainDefinition extends SsaDefinition instanceof SSA::SsaUncertainImplicitUpdate {
SsaDefinition getPriorDefinition() { result = super.getPriorDef() }
}
class GuardValue = Guards::GuardValue;
predicate ssaControlsBranchEdge(SsaDefinition def, BasicBlock bb1, BasicBlock bb2, GuardValue v) {
Guards::Guards_v3::ssaControlsBranchEdge(def, bb1, bb2, v)
}
predicate ssaControls(SsaDefinition def, BasicBlock bb, GuardValue v) {
Guards::Guards_v3::ssaControls(def, bb, v)
}
import Guards::Guards_v3::InternalUtil
}
module ControlFlow = Make<Location, Cfg, ControlFlowInput>;

View File

@@ -139,19 +139,13 @@ private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pre
)
}
private module GuardsInput implements SharedGuards::InputSig<Location> {
private module GuardsInput implements SharedGuards::InputSig<Location, ControlFlowNode, BasicBlock> {
private import java as J
private import semmle.code.java.dataflow.internal.BaseSSA
private import semmle.code.java.dataflow.NullGuards as NullGuards
import SuccessorType
class ControlFlowNode = J::ControlFlowNode;
class NormalExitNode = ControlFlow::NormalExitNode;
class BasicBlock = J::BasicBlock;
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { J::dominatingEdge(bb1, bb2) }
class AstNode = ExprParent;
class Expr = J::Expr;
@@ -216,6 +210,12 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
f.isFinal() and
f.getInitializer() = NullGuards::baseNotNullExpr()
)
or
exists(CatchClause cc, LocalVariableDeclExpr decl, BaseSsaUpdate v |
decl = cc.getVariable() and
decl = v.getDefiningExpr() and
this = v.getAUse()
)
}
}
@@ -375,7 +375,7 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
}
}
private module GuardsImpl = SharedGuards::Make<Location, GuardsInput>;
private module GuardsImpl = SharedGuards::Make<Location, Cfg, GuardsInput>;
private module LogicInputCommon {
private import semmle.code.java.dataflow.NullGuards as NullGuards
@@ -395,11 +395,13 @@ private module LogicInputCommon {
predicate additionalImpliesStep(
GuardsImpl::PreGuard g1, GuardValue v1, GuardsImpl::PreGuard g2, GuardValue v2
) {
exists(MethodCall check, int argIndex |
exists(MethodCall check |
g1 = check and
v1.getDualValue().isThrowsException() and
conditionCheckArgument(check, argIndex, v2.asBooleanValue()) and
g2 = check.getArgument(argIndex)
v1.getDualValue().isThrowsException()
|
methodCallChecksBoolean(check, g2, v2.asBooleanValue())
or
methodCallChecksNotNull(check, g2) and v2.isNonNullValue()
)
}
}

View File

@@ -1,74 +0,0 @@
/**
* Provides different types of control flow successor types.
*/
overlay[local?]
module;
import java
private import codeql.util.Boolean
private newtype TSuccessorType =
TNormalSuccessor() or
TBooleanSuccessor(Boolean branch) or
TExceptionSuccessor()
/** The type of a control flow successor. */
class SuccessorType extends TSuccessorType {
/** Gets a textual representation of successor type. */
string toString() { result = "SuccessorType" }
}
/** A normal control flow successor. */
class NormalSuccessor extends SuccessorType, TNormalSuccessor { }
/**
* An exceptional control flow successor.
*
* This marks control flow edges that are taken when an exception is thrown.
*/
class ExceptionSuccessor extends SuccessorType, TExceptionSuccessor { }
/**
* A conditional control flow successor.
*
* This currently only includes boolean successors (`BooleanSuccessor`).
*/
class ConditionalSuccessor extends SuccessorType, TBooleanSuccessor {
/** Gets the Boolean value of this successor. */
boolean getValue() { this = TBooleanSuccessor(result) }
}
/**
* A Boolean control flow successor.
*
* For example, this program fragment:
*
* ```java
* if (x < 0)
* return 0;
* else
* return 1;
* ```
*
* has a control flow graph containing Boolean successors:
*
* ```
* if
* |
* x < 0
* / \
* / \
* / \
* true false
* | \
* return 0 return 1
* ```
*/
class BooleanSuccessor = ConditionalSuccessor;
/**
* A nullness control flow successor. This is currently unused for Java.
*/
class NullnessSuccessor extends ConditionalSuccessor {
NullnessSuccessor() { none() }
}

View File

@@ -1,5 +1,5 @@
/**
* Provides predicates for identifying precondition checks like
* Provides predicates for identifying precondition and assertion checks like
* `com.google.common.base.Preconditions` and
* `org.apache.commons.lang3.Validate`.
*/
@@ -9,99 +9,150 @@ module;
import java
/**
* Holds if `m` is a method that checks that its argument at position `arg` is
* equal to true and throws otherwise.
*/
private predicate methodCheckTrue(Method m, int arg) {
arg = 0 and
(
m.hasQualifiedName("com.google.common.base", "Preconditions", ["checkArgument", "checkState"]) or
m.hasQualifiedName("com.google.common.base", "Verify", "verify") or
m.hasQualifiedName("org.apache.commons.lang3", "Validate", ["isTrue", "validState"]) or
m.hasQualifiedName("org.junit.jupiter.api", "Assertions", "assertTrue") or
m.hasQualifiedName("org.junit.jupiter.api", "Assumptions", "assumeTrue") or
m.hasQualifiedName("org.testng", "Assert", "assertTrue")
)
or
m.getParameter(arg).getType() instanceof BooleanType and
(
m.hasQualifiedName("org.junit", "Assert", "assertTrue") or
m.hasQualifiedName("org.junit", "Assume", "assumeTrue") or
m.hasQualifiedName("junit.framework", _, "assertTrue")
)
}
/**
* Holds if `m` is a method that checks that its argument at position `arg` is
* equal to false and throws otherwise.
*/
private predicate methodCheckFalse(Method m, int arg) {
arg = 0 and
(
m.hasQualifiedName("org.junit.jupiter.api", "Assertions", "assertFalse") or
m.hasQualifiedName("org.junit.jupiter.api", "Assumptions", "assumeFalse") or
m.hasQualifiedName("org.testng", "Assert", "assertFalse")
)
or
m.getParameter(arg).getType() instanceof BooleanType and
(
m.hasQualifiedName("org.junit", "Assert", "assertFalse") or
m.hasQualifiedName("org.junit", "Assume", "assumeFalse") or
m.hasQualifiedName("junit.framework", _, "assertFalse")
)
}
/**
* Holds if `m` is a method that checks that its argument at position `arg` is
* not null and throws otherwise.
*/
private predicate methodCheckNotNull(Method m, int arg) {
arg = 0 and
(
m.hasQualifiedName("com.google.common.base", "Preconditions", "checkNotNull") or
m.hasQualifiedName("com.google.common.base", "Verify", "verifyNotNull") or
m.hasQualifiedName("org.apache.commons.lang3", "Validate", "notNull") or
m.hasQualifiedName("java.util", "Objects", "requireNonNull") or
m.hasQualifiedName("org.junit.jupiter.api", "Assertions", "assertNotNull") or
m.hasQualifiedName("org.junit", "Assume", "assumeNotNull") or // vararg
m.hasQualifiedName("org.testng", "Assert", "assertNotNull")
)
or
arg = m.getNumberOfParameters() - 1 and
(
m.hasQualifiedName("org.junit", "Assert", "assertNotNull") or
m.hasQualifiedName("junit.framework", _, "assertNotNull")
)
}
/**
* Holds if `m` is a method that checks that its argument at position `arg`
* satisfies a property specified by another argument and throws otherwise.
*/
private predicate methodCheckThat(Method m, int arg) {
m.getParameter(arg).getType().getErasure() instanceof TypeObject and
(
m.hasQualifiedName("org.hamcrest", "MatcherAssert", "assertThat") or
m.hasQualifiedName("org.junit", "Assert", "assertThat") or
m.hasQualifiedName("org.junit", "Assume", "assumeThat")
)
}
/** Holds if `m` is a method that unconditionally throws. */
private predicate methodUnconditionallyThrows(Method m) {
m.hasQualifiedName("org.junit.jupiter.api", "Assertions", "fail") or
m.hasQualifiedName("org.junit", "Assert", "fail") or
m.hasQualifiedName("junit.framework", _, "fail") or
m.hasQualifiedName("org.testng", "Assert", "fail")
}
/**
* Holds if `mc` is a call to a method that checks that its argument `arg` is
* equal to `checkTrue` and throws otherwise.
*/
predicate methodCallChecksBoolean(MethodCall mc, Expr arg, boolean checkTrue) {
exists(int pos | mc.getArgument(pos) = arg |
methodCheckTrue(mc.getMethod().getSourceDeclaration(), pos) and checkTrue = true
or
methodCheckFalse(mc.getMethod().getSourceDeclaration(), pos) and checkTrue = false
)
}
/**
* Holds if `mc` is a call to a method that checks that its argument `arg` is
* not null and throws otherwise.
*/
predicate methodCallChecksNotNull(MethodCall mc, Expr arg) {
exists(int pos | mc.getArgument(pos) = arg |
methodCheckNotNull(mc.getMethod().getSourceDeclaration(), pos)
or
methodCheckThat(mc.getMethod().getSourceDeclaration(), pos) and
mc.getAnArgument().(MethodCall).getMethod().getName() = "notNullValue"
)
}
/**
* Holds if `mc` is a call to a method that checks one of its arguments in some
* way and possibly throws.
*/
predicate methodCallChecksArgument(MethodCall mc) {
methodCallChecksBoolean(mc, _, _) or
methodCallChecksNotNull(mc, _)
}
/** Holds if `mc` is a call to a method that unconditionally throws. */
predicate methodCallUnconditionallyThrows(MethodCall mc) {
methodUnconditionallyThrows(mc.getMethod().getSourceDeclaration()) or
exists(BooleanLiteral b | methodCallChecksBoolean(mc, b, b.getBooleanValue().booleanNot()))
}
/**
* DEPRECATED: Use `methodCallChecksBoolean` instead.
*
* Holds if `m` is a non-overridable method that checks that its zero-indexed `argument`
* is equal to `checkTrue` and throws otherwise.
*/
predicate conditionCheckMethodArgument(Method m, int argument, boolean checkTrue) {
condtionCheckMethodGooglePreconditions(m, checkTrue) and argument = 0
deprecated predicate conditionCheckMethodArgument(Method m, int argument, boolean checkTrue) {
methodCheckTrue(m, argument) and checkTrue = true
or
conditionCheckMethodApacheCommonsLang3Validate(m, checkTrue) and argument = 0
or
condtionCheckMethodTestingFramework(m, argument, checkTrue)
or
exists(Parameter p, MethodCall ma, int argIndex, boolean ct, Expr arg |
p = m.getParameter(argument) and
not m.isOverridable() and
m.getBody().getStmt(0).(ExprStmt).getExpr() = ma and
conditionCheckArgument(ma, argIndex, ct) and
ma.getArgument(argIndex) = arg and
(
arg.(LogNotExpr).getExpr().(VarAccess).getVariable() = p and
checkTrue = ct.booleanNot()
or
arg.(VarAccess).getVariable() = p and checkTrue = ct
)
)
or
exists(Parameter p, IfStmt ifstmt, Expr cond |
p = m.getParameter(argument) and
not m.isOverridable() and
p.getType() instanceof BooleanType and
m.getBody().getStmt(0) = ifstmt and
ifstmt.getCondition() = cond and
(
cond.(LogNotExpr).getExpr().(VarAccess).getVariable() = p and checkTrue = true
or
cond.(VarAccess).getVariable() = p and checkTrue = false
) and
(
ifstmt.getThen() instanceof ThrowStmt or
ifstmt.getThen().(SingletonBlock).getStmt() instanceof ThrowStmt
)
)
}
private predicate condtionCheckMethodGooglePreconditions(Method m, boolean checkTrue) {
m.getDeclaringType().hasQualifiedName("com.google.common.base", "Preconditions") and
checkTrue = true and
(m.hasName("checkArgument") or m.hasName("checkState"))
}
private predicate conditionCheckMethodApacheCommonsLang3Validate(Method m, boolean checkTrue) {
m.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "Validate") and
checkTrue = true and
(m.hasName("isTrue") or m.hasName("validState"))
}
/**
* Holds if `m` is a non-overridable testing framework method that checks that its first argument
* is equal to `checkTrue` and throws otherwise.
*/
private predicate condtionCheckMethodTestingFramework(Method m, int argument, boolean checkTrue) {
argument = 0 and
(
m.getDeclaringType().hasQualifiedName("org.junit", "Assume") and
checkTrue = true and
m.hasName("assumeTrue")
or
m.getDeclaringType().hasQualifiedName("org.junit.jupiter.api", "Assertions") and
(
checkTrue = true and m.hasName("assertTrue")
or
checkTrue = false and m.hasName("assertFalse")
)
or
m.getDeclaringType().hasQualifiedName("org.junit.jupiter.api", "Assumptions") and
(
checkTrue = true and m.hasName("assumeTrue")
or
checkTrue = false and m.hasName("assumeFalse")
)
)
or
m.getDeclaringType().hasQualifiedName(["org.junit", "org.testng"], "Assert") and
m.getParameter(argument).getType() instanceof BooleanType and
(
checkTrue = true and m.hasName("assertTrue")
or
checkTrue = false and m.hasName("assertFalse")
)
methodCheckFalse(m, argument) and checkTrue = false
}
/**
* DEPRECATED: Use `methodCallChecksBoolean` instead.
*
* Holds if `ma` is an access to a non-overridable method that checks that its
* zero-indexed `argument` is equal to `checkTrue` and throws otherwise.
*/
predicate conditionCheckArgument(MethodCall ma, int argument, boolean checkTrue) {
deprecated predicate conditionCheckArgument(MethodCall ma, int argument, boolean checkTrue) {
conditionCheckMethodArgument(ma.getMethod().getSourceDeclaration(), argument, checkTrue)
}

View File

@@ -10,7 +10,7 @@ private import RangeUtils
private import RangeAnalysis
/** Gets an expression that might have the value `i`. */
private Expr exprWithIntValue(int i) {
deprecated private Expr exprWithIntValue(int i) {
result.(ConstantIntegerExpr).getIntValue() = i or
result.(ChooseExpr).getAResultExpr() = exprWithIntValue(i)
}
@@ -19,11 +19,11 @@ private Expr exprWithIntValue(int i) {
* An expression for which the predicate `integerGuard` is relevant.
* This includes `VarRead` and `MethodCall`.
*/
class IntComparableExpr extends Expr {
deprecated class IntComparableExpr extends Expr {
IntComparableExpr() { this instanceof VarRead or this instanceof MethodCall }
/** Gets an integer that is directly assigned to the expression in case of a variable; or zero. */
int relevantInt() {
deprecated int relevantInt() {
exists(SsaExplicitUpdate ssa, SsaSourceVariable v |
this = v.getAnAccess() and
ssa.getSourceVariable() = v and
@@ -55,6 +55,9 @@ private predicate comparison(ComparisonExpr comp, boolean branch, Expr e1, Expr
* Holds if `guard` evaluating to `branch` ensures that:
* `e <= k` when `upper = true`
* `e >= k` when `upper = false`
*
* Does _not_ include the constant comparison case where the guard directly
* ensures `e == k`.
*/
pragma[nomagic]
predicate rangeGuard(Expr guard, boolean branch, Expr e, int k, boolean upper) {
@@ -62,7 +65,8 @@ predicate rangeGuard(Expr guard, boolean branch, Expr e, int k, boolean upper) {
eqtest = guard and
eqtest.hasOperands(e, c) and
bounded(c, any(ZeroBound zb), k, upper, _) and
branch = eqtest.polarity()
branch = eqtest.polarity() and
not c instanceof ConstantIntegerExpr
)
or
exists(Expr c, int val, boolean strict, int d |
@@ -87,6 +91,30 @@ predicate rangeGuard(Expr guard, boolean branch, Expr e, int k, boolean upper) {
}
/**
* Gets an expression that directly tests whether a given expression, `e`, is
* non-zero.
*/
Expr nonZeroGuard(Expr e, boolean branch) {
exists(EqualityTest eqtest, boolean polarity, int k |
eqtest = result and
eqtest.hasOperands(e, any(ConstantIntegerExpr c | c.getIntValue() = k)) and
polarity = eqtest.polarity()
|
k = 0 and branch = polarity.booleanNot()
or
k != 0 and branch = polarity
)
or
exists(int val, boolean upper | rangeGuard(result, branch, e, val, upper) |
upper = true and val < 0 // e <= val < 0 ==> e != 0
or
upper = false and val > 0 // e >= val > 0 ==> e != 0
)
}
/**
* DEPRECATED.
*
* An expression that directly tests whether a given expression is equal to `k` or not.
* The set of `k`s is restricted to those that are relevant for the expression or
* have a direct comparison with the expression.
@@ -95,7 +123,7 @@ predicate rangeGuard(Expr guard, boolean branch, Expr e, int k, boolean upper) {
* is true, and different from `k` if `is_k` is false.
*/
pragma[nomagic]
Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) {
deprecated Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) {
exists(EqualityTest eqtest, boolean polarity |
eqtest = result and
eqtest.hasOperands(e, any(ConstantIntegerExpr c | c.getIntValue() = k)) and
@@ -119,13 +147,15 @@ Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) {
}
/**
* DEPRECATED: Use `rangeGuard` instead.
*
* A guard that splits the values of a variable into one range with an upper bound of `k-1`
* and one with a lower bound of `k`.
*
* If `branch_with_lower_bound_k` is true then `result` is equivalent to `k <= x`
* and if it is false then `result` is equivalent to `k > x`.
*/
Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, int k) {
deprecated Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, int k) {
exists(ComparisonExpr comp, ConstantIntegerExpr c, int val |
comp = result and
comp.hasOperands(x, c) and

View File

@@ -9,49 +9,31 @@
overlay[local?]
module;
/*
* Implementation details:
*
* The three exported predicates, `nullDeref`, `alwaysNullDeref`, and
* `superfluousNullGuard`, compute potential null dereferences, definite null
* dereferences, and superfluous null checks, respectively. The bulk of the
* library supports `nullDeref`, while the latter two are fairly simple in
* comparison.
*
* The NPE (NullPointerException) candidates are computed by
* `nullDerefCandidate` and consist of three parts: A variable definition that
* might be null as computed by `varMaybeNull`, a dereference that can cause a
* NPE as computed by `firstVarDereferenceInBlock`, and a control flow path
* between the two points. The path is computed by `varMaybeNullInBlock`,
* which is the transitive closure of the step relation `nullVarStep`
* originating in a definition given by `varMaybeNull`. The step relation
* `nullVarStep` is essentially just the successor relation on basic blocks
* restricted to exclude edges along which the variable cannot be null.
*
* The step relation `nullVarStep` is then reused twice to produce two
* refinements of the path reachability predicate `varMaybeNullInBlock` in
* order to prune impossible paths that would otherwise lead to a potential
* NPE. These two refinements are `varMaybeNullInBlock_corrCond` and
* `varMaybeNullInBlock_trackVar` and are described in further detail below.
*/
import java
private import SSA
private import semmle.code.java.controlflow.Guards
private import RangeUtils
private import IntegerGuards
private import NullGuards
private import semmle.code.java.Collections
private import semmle.code.java.frameworks.Assertions
private import semmle.code.java.controlflow.internal.Preconditions
private import semmle.code.java.controlflow.ControlFlow as Cf
/** Gets an expression that may be `null`. */
Expr nullExpr() {
result instanceof NullLiteral or
result.(ChooseExpr).getAResultExpr() = nullExpr() or
result.(AssignExpr).getSource() = nullExpr() or
result.(CastExpr).getExpr() = nullExpr() or
result.(ImplicitCastExpr).getExpr() = nullExpr() or
result instanceof SafeCastExpr
Expr nullExpr() { result = nullExpr(_) }
/** Gets an expression that may be `null`. */
private Expr nullExpr(Expr reason) {
result instanceof NullLiteral and reason = result
or
result.(ChooseExpr).getAResultExpr() = nullExpr(reason)
or
result.(AssignExpr).getSource() = nullExpr(reason)
or
result.(CastExpr).getExpr() = nullExpr(reason)
or
result.(ImplicitCastExpr).getExpr() = nullExpr(reason)
or
result instanceof SafeCastExpr and reason = result
}
/** An expression of a boxed type that is implicitly unboxed. */
@@ -137,58 +119,29 @@ private ControlFlowNode varDereference(SsaVariable v, VarAccess va) {
}
/**
* A `ControlFlowNode` that ensures that the SSA variable is not null in any
* subsequent use, either by dereferencing it or by an assertion.
*/
private ControlFlowNode ensureNotNull(SsaVariable v) {
result = varDereference(v, _)
or
exists(AssertTrueMethod m | result.asCall() = m.getACheck(directNullGuard(v, true, false)))
or
exists(AssertFalseMethod m | result.asCall() = m.getACheck(directNullGuard(v, false, false)))
or
exists(AssertNotNullMethod m | result.asCall() = m.getACheck(v.getAUse()))
or
exists(AssertThatMethod m, MethodCall ma |
result.asCall() = m.getACheck(v.getAUse()) and ma.getControlFlowNode() = result
|
ma.getAnArgument().(MethodCall).getMethod().getName() = "notNullValue"
)
}
/**
* A variable dereference that cannot be reached by a `null` value, because of an earlier
* dereference or assertion in the same `BasicBlock`.
*/
private predicate unreachableVarDereference(BasicBlock bb, SsaVariable v, ControlFlowNode varDeref) {
exists(ControlFlowNode n, int i, int j |
(n = ensureNotNull(v) or assertFail(bb, n)) and
varDeref = varDereference(v, _) and
bb.getNode(i) = n and
bb.getNode(j) = varDeref and
i < j
)
}
/**
* The first dereference of a variable in a given `BasicBlock` excluding those dereferences
* that are preceded by a not-null assertion or a trivially failing assertion.
* The first dereference of a variable in a given `BasicBlock`.
*/
private predicate firstVarDereferenceInBlock(BasicBlock bb, SsaVariable v, VarAccess va) {
exists(ControlFlowNode n |
varDereference(v, va) = n and
n.getBasicBlock() = bb and
not unreachableVarDereference(bb, v, n)
n =
min(ControlFlowNode n0, int i |
varDereference(v, _) = n0 and bb.getNode(i) = n0
|
n0 order by i
)
)
}
/** A variable suspected of being `null`. */
private predicate varMaybeNull(SsaVariable v, string msg, Expr reason) {
private predicate varMaybeNull(SsaVariable v, ControlFlowNode node, string msg, Expr reason) {
// A variable compared to null might be null.
exists(Expr e |
reason = e and
msg = "as suggested by $@ null guard" and
guardSuggestsVarMaybeNull(e, v) and
node = v.getCfgNode() and
not v instanceof SsaPhiNode and
not clearlyNotNull(v) and
// Comparisons in finally blocks are excluded since missing exception edges in the CFG could otherwise yield FPs.
@@ -204,6 +157,7 @@ private predicate varMaybeNull(SsaVariable v, string msg, Expr reason) {
// A parameter might be null if there is a null argument somewhere.
exists(Parameter p, Expr arg |
v.(SsaImplicitInit).isParameterDefinition(p) and
node = v.getCfgNode() and
p.getAnArgument() = arg and
reason = arg and
msg = "because of $@ null argument" and
@@ -214,7 +168,7 @@ private predicate varMaybeNull(SsaVariable v, string msg, Expr reason) {
// If the source of a variable is null then the variable may be null.
exists(VariableAssign def |
v.(SsaExplicitUpdate).getDefiningExpr() = def and
def.getSource() = nullExpr() and
def.getSource() = nullExpr(node.asExpr()) and
reason = def and
msg = "because of $@ assignment"
)
@@ -236,7 +190,7 @@ private Expr nonEmptyExpr() {
// ...or it is guarded by a condition proving its length to be non-zero.
exists(ConditionBlock cond, boolean branch, FieldAccess length |
cond.controls(result.getBasicBlock(), branch) and
cond.getCondition() = integerGuard(length, branch, 0, false) and
cond.getCondition() = nonZeroGuard(length, branch) and
length.getField().hasName("length") and
length.getQualifier() = v.getAUse()
)
@@ -266,7 +220,7 @@ private Expr nonEmptyExpr() {
or
// ...or a check on its `size`.
exists(MethodCall size |
c = integerGuard(size, branch, 0, false) and
c = nonZeroGuard(size, branch) and
size.getMethod().hasName("size") and
size.getQualifier() = v.getAUse()
)
@@ -294,536 +248,29 @@ private predicate impossibleEdge(BasicBlock bb1, BasicBlock bb2) {
)
}
/** A control flow edge that leaves a finally-block. */
private predicate leavingFinally(BasicBlock bb1, BasicBlock bb2, boolean normaledge) {
exists(TryStmt try, BlockStmt finally |
try.getFinally() = finally and
bb1.getASuccessor() = bb2 and
bb1.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
not bb2.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
if bb1.getLastNode().getANormalSuccessor() = bb2.getFirstNode()
then normaledge = true
else normaledge = false
)
private module NullnessConfig implements Cf::ControlFlow::ConfigSig {
predicate source(ControlFlowNode node, SsaVariable def) { varMaybeNull(def, node, _, _) }
predicate sink(ControlFlowNode node, SsaVariable def) { varDereference(def, _) = node }
predicate barrierValue(GuardValue gv) { gv.isNullness(false) }
predicate barrierEdge(BasicBlock bb1, BasicBlock bb2) { impossibleEdge(bb1, bb2) }
predicate uncertainFlow() { none() }
}
private predicate ssaSourceVarMaybeNull(SsaSourceVariable v) {
varMaybeNull(v.getAnSsaVariable(), _, _)
}
private module NullnessFlow = Cf::ControlFlow::Flow<NullnessConfig>;
/**
* The step relation for propagating that a given SSA variable might be `null` in a given `BasicBlock`.
*
* If `midssa` is null in `mid` then `ssa` might be null in `bb`. The SSA variables share the same
* `SsaSourceVariable`.
*
* A boolean flag tracks whether a non-normal completion is waiting to resume upon the exit of a finally-block.
* If the flag is set, then the normal edge out of the finally-block is prohibited, but if it is not set then
* no knowledge is assumed of any potentially waiting completions. `midstoredcompletion` is the flag before
* the step and `storedcompletion` is the flag after the step.
*/
private predicate nullVarStep(
SsaVariable midssa, BasicBlock mid, boolean midstoredcompletion, SsaVariable ssa, BasicBlock bb,
boolean storedcompletion
) {
exists(SsaSourceVariable v |
ssaSourceVarMaybeNull(v) and
midssa.getSourceVariable() = v
|
ssa.(SsaPhiNode).getAPhiInput() = midssa and ssa.getBasicBlock() = bb
or
ssa = midssa and
not exists(SsaPhiNode phi | phi.getSourceVariable() = v and phi.getBasicBlock() = bb)
) and
(midstoredcompletion = true or midstoredcompletion = false) and
midssa.isLiveAtEndOfBlock(mid) and
not ensureNotNull(midssa).getBasicBlock() = mid and
not assertFail(mid, _) and
bb = mid.getASuccessor() and
not impossibleEdge(mid, bb) and
not nullGuardControlsBranchEdge(midssa, false, mid, bb) and
not (leavingFinally(mid, bb, true) and midstoredcompletion = true) and
if bb.getFirstNode().asStmt() = any(TryStmt try | | try.getFinally())
then
if bb.getFirstNode() = mid.getLastNode().getANormalSuccessor()
then storedcompletion = false
else storedcompletion = true
else
if leavingFinally(mid, bb, _)
then storedcompletion = false
else storedcompletion = midstoredcompletion
}
/**
* The transitive closure of `nullVarStep` originating from `varMaybeNull`. That is, those `BasicBlock`s
* for which the SSA variable is suspected of being `null`.
*/
private predicate varMaybeNullInBlock(
SsaVariable ssa, SsaSourceVariable v, BasicBlock bb, boolean storedcompletion
) {
varMaybeNull(ssa, _, _) and
bb = ssa.getBasicBlock() and
storedcompletion = false and
v = ssa.getSourceVariable()
or
exists(BasicBlock mid, SsaVariable midssa, boolean midstoredcompletion |
varMaybeNullInBlock(midssa, v, mid, midstoredcompletion) and
nullVarStep(midssa, mid, midstoredcompletion, ssa, bb, storedcompletion)
)
}
/**
* Holds if `v` is a source variable that might reach a potential `null`
* dereference.
*/
private predicate nullDerefCandidateVariable(SsaSourceVariable v) {
exists(SsaVariable ssa, BasicBlock bb |
firstVarDereferenceInBlock(bb, ssa, _) and
varMaybeNullInBlock(ssa, v, bb, _)
)
}
private predicate varMaybeNullInBlock_origin(
SsaVariable origin, SsaVariable ssa, BasicBlock bb, boolean storedcompletion
) {
nullDerefCandidateVariable(ssa.getSourceVariable()) and
varMaybeNull(ssa, _, _) and
bb = ssa.getBasicBlock() and
storedcompletion = false and
origin = ssa
or
exists(BasicBlock mid, SsaVariable midssa, boolean midstoredcompletion |
varMaybeNullInBlock_origin(origin, midssa, mid, midstoredcompletion) and
nullVarStep(midssa, mid, midstoredcompletion, ssa, bb, storedcompletion)
)
}
/**
* A potential `null` dereference. That is, the first dereference of a variable in a block
* where it is suspected of being `null`.
*/
private predicate nullDerefCandidate(SsaVariable origin, VarAccess va) {
exists(SsaVariable ssa, BasicBlock bb |
firstVarDereferenceInBlock(bb, ssa, va) and
varMaybeNullInBlock_origin(origin, ssa, bb, _)
)
}
/*
* In the following, the potential `null` dereference candidates are pruned by proving that
* a `NullPointerException` (NPE) cannot occur. This is done by pruning the control-flow paths
* that lead to the NPE candidate in two ways:
*
* 1. For each set of correlated conditions that are passed by the path, consistent
* branches must be taken. For example, the following code is safe due to the two tests on
* `flag` begin correlated.
* ```
* x = null;
* if (flag) x = new A();
* if (flag) x.m();
* ```
*
* 2. For each other variable that changes its value alongside the potential NPE candidate,
* the passed conditions must be consistent with its value. For example, the following
* code is safe due to the value of `t`.
* ```
* x = null;
* t = null;
* if (...) { x = new A(); t = new B(); }
* if (t != null) x.m();
* ```
* We call such a variable a _tracking variable_ as it tracks the null-ness of `x`.
*/
/** A variable that is assigned `null` if the given condition takes the given branch. */
private predicate varConditionallyNull(SsaExplicitUpdate v, ConditionBlock cond, boolean branch) {
exists(ConditionalExpr condexpr |
v.getDefiningExpr().(VariableAssign).getSource() = condexpr and
condexpr.getCondition() = cond.getCondition()
|
condexpr.getBranchExpr(branch) = nullExpr() and
not condexpr.getBranchExpr(branch.booleanNot()) = nullExpr()
)
or
v.getDefiningExpr().(VariableAssign).getSource() = nullExpr() and
cond.controls(v.getBasicBlock(), branch)
}
/**
* A condition that might be useful in proving an NPE candidate safe.
*
* This is a condition along the path that found the NPE candidate.
*/
private predicate interestingCond(SsaSourceVariable npecand, ConditionBlock cond) {
nullDerefCandidateVariable(npecand) and
(
varMaybeNullInBlock(_, npecand, cond, _) or
varConditionallyNull(npecand.getAnSsaVariable(), cond, _)
) and
not cond.getCondition().(Expr).getAChildExpr*() = npecand.getAnAccess()
}
pragma[nomagic]
private ConditionBlock ssaIntegerGuard(SsaVariable v, boolean branch, int k, boolean is_k) {
result.getCondition() = integerGuard(v.getAUse(), branch, k, is_k)
}
pragma[nomagic]
private ConditionBlock ssaIntBoundGuard(SsaVariable v, boolean branch_with_lower_bound_k, int k) {
result.getCondition() = intBoundGuard(v.getAUse(), branch_with_lower_bound_k, k)
}
pragma[nomagic]
private ConditionBlock ssaEnumConstEquality(SsaVariable v, boolean polarity, EnumConstant c) {
result.getCondition() = enumConstEquality(v.getAUse(), polarity, c)
}
private predicate conditionChecksNull(ConditionBlock cond, SsaVariable v, boolean branchIsNull) {
nullGuardControlsBranchEdge(v, true, cond, cond.getTestSuccessor(branchIsNull)) and
nullGuardControlsBranchEdge(v, false, cond, cond.getTestSuccessor(branchIsNull.booleanNot()))
}
/** A pair of correlated conditions for a given NPE candidate. */
private predicate correlatedConditions(
SsaSourceVariable npecand, ConditionBlock cond1, ConditionBlock cond2, boolean inverted
) {
interestingCond(npecand, cond1) and
interestingCond(npecand, cond2) and
cond1 != cond2 and
(
exists(SsaVariable v |
cond1.getCondition() = v.getAUse() and
cond2.getCondition() = v.getAUse() and
inverted = false
)
or
exists(SsaVariable v, boolean branch1, boolean branch2 |
conditionChecksNull(cond1, v, branch1) and
conditionChecksNull(cond2, v, branch2) and
inverted = branch1.booleanXor(branch2)
)
or
exists(SsaVariable v, int k, boolean branch1, boolean branch2 |
cond1 = ssaIntegerGuard(v, branch1, k, true) and
cond1 = ssaIntegerGuard(v, branch1.booleanNot(), k, false) and
cond2 = ssaIntegerGuard(v, branch2, k, true) and
cond2 = ssaIntegerGuard(v, branch2.booleanNot(), k, false) and
inverted = branch1.booleanXor(branch2)
)
or
exists(SsaVariable v, int k, boolean branch1, boolean branch2 |
cond1 = ssaIntBoundGuard(v, branch1, k) and
cond2 = ssaIntBoundGuard(v, branch2, k) and
inverted = branch1.booleanXor(branch2)
)
or
exists(SsaVariable v, EnumConstant c, boolean pol1, boolean pol2 |
cond1 = ssaEnumConstEquality(v, pol1, c) and
cond2 = ssaEnumConstEquality(v, pol2, c) and
inverted = pol1.booleanXor(pol2)
)
or
exists(SsaVariable v, RefType type |
cond1.getCondition() = instanceofExpr(v, type) and
cond2.getCondition() = instanceofExpr(v, type) and
inverted = false
)
or
exists(SsaVariable v1, SsaVariable v2, boolean branch1, boolean branch2 |
cond1.getCondition() = varEqualityTestExpr(v1, v2, branch1) and
cond2.getCondition() = varEqualityTestExpr(v1, v2, branch2) and
inverted = branch1.booleanXor(branch2)
)
)
}
/**
* This is again the transitive closure of `nullVarStep` similarly to `varMaybeNullInBlock`, but
* this time restricted based on pairs of correlated conditions consistent with `cond1`
* evaluating to `branch`.
*/
private predicate varMaybeNullInBlock_corrCond(
SsaVariable origin, SsaVariable ssa, BasicBlock bb, boolean storedcompletion,
ConditionBlock cond1, boolean branch
) {
exists(SsaSourceVariable npecand | npecand = ssa.getSourceVariable() |
nullDerefCandidateVariable(npecand) and correlatedConditions(npecand, cond1, _, _)
) and
(
varConditionallyNull(ssa, cond1, branch)
or
not varConditionallyNull(ssa, cond1, _) and
(branch = true or branch = false)
) and
varMaybeNull(ssa, _, _) and
bb = ssa.getBasicBlock() and
storedcompletion = false and
origin = ssa
or
exists(BasicBlock mid, SsaVariable midssa, boolean midstoredcompletion |
varMaybeNullInBlock_corrCond(origin, midssa, mid, midstoredcompletion, cond1, branch) and
(
cond1 = mid and cond1.getTestSuccessor(branch) = bb
or
exists(ConditionBlock cond2, boolean inverted, boolean branch2 |
cond2 = mid and
correlatedConditions(_, cond1, cond2, inverted) and
cond2.getTestSuccessor(branch2) = bb and
branch = branch2.booleanXor(inverted)
)
or
cond1 != mid and
not exists(ConditionBlock cond2 | cond2 = mid and correlatedConditions(_, cond1, cond2, _))
) and
nullVarStep(midssa, mid, midstoredcompletion, ssa, bb, storedcompletion)
)
}
/*
* A tracking variable has its possible values divided into two sets, A and B, for
* which we can attribute at least one direct assignment to be contained in either
* A or B.
* Four kinds are supported:
* - null: A means null and B means non-null.
* - boolean: A means true and B means false.
* - enum: A means a specific enum constant and B means any other value.
* - int: A means a specific integer value and B means any other value.
*/
private newtype TrackVarKind =
TrackVarKindNull() or
TrackVarKindBool() or
TrackVarKindEnum() or
TrackVarKindInt()
/** A variable that might be relevant as a tracking variable for the NPE candidate. */
private predicate trackingVar(
SsaSourceVariable npecand, SsaExplicitUpdate trackssa, SsaSourceVariable trackvar,
TrackVarKind kind, Expr init
) {
exists(ConditionBlock cond |
interestingCond(npecand, cond) and
varMaybeNullInBlock(_, npecand, cond, _) and
cond.getCondition().(Expr).getAChildExpr*() = trackvar.getAnAccess() and
trackssa.getSourceVariable() = trackvar and
trackssa.getDefiningExpr().(VariableAssign).getSource() = init
|
init instanceof NullLiteral and kind = TrackVarKindNull()
or
init = clearlyNotNullExpr() and kind = TrackVarKindNull()
or
init instanceof BooleanLiteral and kind = TrackVarKindBool()
or
init.(VarAccess).getVariable() instanceof EnumConstant and kind = TrackVarKindEnum()
or
exists(init.(ConstantIntegerExpr).getIntValue()) and kind = TrackVarKindInt()
)
}
/** Gets an expression that tests the value of a given tracking variable. */
private Expr trackingVarGuard(
SsaVariable trackssa, SsaSourceVariable trackvar, TrackVarKind kind, boolean branch, boolean isA
) {
exists(Expr init | trackingVar(_, trackssa, trackvar, kind, init) |
result = basicNullGuard(trackvar.getAnAccess(), branch, isA) and
kind = TrackVarKindNull()
or
result = trackvar.getAnAccess() and
kind = TrackVarKindBool() and
(branch = true or branch = false) and
isA = branch
or
exists(boolean polarity, EnumConstant c, EnumConstant initc |
initc.getAnAccess() = init and
kind = TrackVarKindEnum() and
result = enumConstEquality(trackvar.getAnAccess(), polarity, c) and
(
initc = c and branch = polarity.booleanNot() and isA = false
or
initc = c and branch = polarity and isA = true
or
initc != c and branch = polarity and isA = false
)
)
or
exists(int k |
init.(ConstantIntegerExpr).getIntValue() = k and
kind = TrackVarKindInt()
|
result = integerGuard(trackvar.getAnAccess(), branch, k, isA)
or
exists(int k2 |
result = integerGuard(trackvar.getAnAccess(), branch.booleanNot(), k2, true) and
isA = false and
k2 != k
)
or
exists(int bound, boolean branch_with_lower_bound |
result = intBoundGuard(trackvar.getAnAccess(), branch_with_lower_bound, bound) and
isA = false
|
branch = branch_with_lower_bound and k < bound
or
branch = branch_with_lower_bound.booleanNot() and bound <= k
)
)
)
or
exists(EqualityTest eqtest, boolean branch0, boolean polarity, BooleanLiteral boollit |
eqtest = result and
eqtest.hasOperands(trackingVarGuard(trackssa, trackvar, kind, branch0, isA), boollit) and
eqtest.polarity() = polarity and
branch = branch0.booleanXor(polarity).booleanXor(boollit.getBooleanValue())
)
}
/** An update to a tracking variable that is contained fully in either A or B. */
private predicate isReset(
SsaVariable trackssa, SsaSourceVariable trackvar, TrackVarKind kind, SsaExplicitUpdate update,
boolean isA
) {
exists(Expr init, Expr e |
trackingVar(_, trackssa, trackvar, kind, init) and
update.getSourceVariable() = trackvar and
e = update.getDefiningExpr().(VariableAssign).getSource()
|
e instanceof NullLiteral and kind = TrackVarKindNull() and isA = true
or
e = clearlyNotNullExpr() and kind = TrackVarKindNull() and isA = false
or
e.(BooleanLiteral).getBooleanValue() = isA and kind = TrackVarKindBool()
or
e.(VarAccess).getVariable().(EnumConstant) = init.(VarAccess).getVariable() and
kind = TrackVarKindEnum() and
isA = true
or
e.(VarAccess).getVariable().(EnumConstant) != init.(VarAccess).getVariable() and
kind = TrackVarKindEnum() and
isA = false
or
e.(ConstantIntegerExpr).getIntValue() = init.(ConstantIntegerExpr).getIntValue() and
kind = TrackVarKindInt() and
isA = true
or
e.(ConstantIntegerExpr).getIntValue() != init.(ConstantIntegerExpr).getIntValue() and
kind = TrackVarKindInt() and
isA = false
)
}
/** The abstract value of the tracked variable. */
private newtype TrackedValue =
TrackedValueA() or
TrackedValueB() or
TrackedValueUnknown()
private TrackedValue trackValAorB(boolean isA) {
isA = true and result = TrackedValueA()
or
isA = false and result = TrackedValueB()
}
/** A control flow edge passing through a condition that implies a specific value for a tracking variable. */
private predicate stepImplies(
BasicBlock bb1, BasicBlock bb2, SsaVariable trackssa, SsaSourceVariable trackvar,
TrackVarKind kind, boolean isA
) {
exists(ConditionBlock cond, boolean branch |
cond = bb1 and
cond.getTestSuccessor(branch) = bb2 and
cond.getCondition() = trackingVarGuard(trackssa, trackvar, kind, branch, isA)
)
}
/**
* This is again the transitive closure of `nullVarStep` similarly to `varMaybeNullInBlock`, but
* this time restricted based on a tracking variable.
*/
private predicate varMaybeNullInBlock_trackVar(
SsaVariable origin, SsaVariable ssa, BasicBlock bb, boolean storedcompletion,
SsaVariable trackssa, SsaSourceVariable trackvar, TrackVarKind kind, TrackedValue trackvalue
) {
exists(SsaSourceVariable npecand | npecand = ssa.getSourceVariable() |
nullDerefCandidateVariable(npecand) and trackingVar(npecand, trackssa, trackvar, kind, _)
) and
(
exists(SsaVariable init, boolean isA |
init.getSourceVariable() = trackvar and
init.isLiveAtEndOfBlock(bb) and
isReset(trackssa, trackvar, kind, init, isA) and
trackvalue = trackValAorB(isA)
)
or
trackvalue = TrackedValueUnknown() and
not exists(SsaVariable init |
init.getSourceVariable() = trackvar and
init.isLiveAtEndOfBlock(bb) and
isReset(trackssa, trackvar, kind, init, _)
)
) and
varMaybeNull(ssa, _, _) and
bb = ssa.getBasicBlock() and
storedcompletion = false and
origin = ssa
or
exists(BasicBlock mid, SsaVariable midssa, boolean midstoredcompletion, TrackedValue trackvalue0 |
varMaybeNullInBlock_trackVar(origin, midssa, mid, midstoredcompletion, trackssa, trackvar, kind,
trackvalue0) and
nullVarStep(midssa, mid, midstoredcompletion, ssa, bb, storedcompletion) and
(
trackvalue0 = TrackedValueUnknown()
or
// A step that implies a value that contradicts the current value is not allowed.
exists(boolean isA | trackvalue0 = trackValAorB(isA) |
not stepImplies(mid, bb, trackssa, trackvar, kind, isA.booleanNot())
)
) and
(
// If no update occurs then the tracked value is unchanged unless the step implies a given value via a condition.
not exists(SsaUpdate update |
update.getSourceVariable() = trackvar and
update.getBasicBlock() = bb
) and
(
exists(boolean isA | stepImplies(mid, bb, trackssa, trackvar, kind, isA) |
trackvalue = trackValAorB(isA)
)
or
not stepImplies(mid, bb, trackssa, trackvar, kind, _) and trackvalue = trackvalue0
)
or
// If an update occurs then the tracked value is set accordingly.
exists(SsaUpdate update |
update.getSourceVariable() = trackvar and
update.getBasicBlock() = bb
|
exists(boolean isA | isReset(trackssa, trackvar, kind, update, isA) |
trackvalue = trackValAorB(isA)
)
or
not isReset(trackssa, trackvar, kind, update, _) and trackvalue = TrackedValueUnknown()
)
)
)
}
/**
* A potential `null` dereference that has not been proven safe.
* Holds if the dereference of `v` at `va` might be `null`.
*/
predicate nullDeref(SsaSourceVariable v, VarAccess va, string msg, Expr reason) {
exists(SsaVariable origin, SsaVariable ssa, BasicBlock bb |
nullDerefCandidate(origin, va) and
varMaybeNull(origin, msg, reason) and
exists(SsaVariable origin, SsaVariable ssa, ControlFlowNode src, ControlFlowNode sink |
varMaybeNull(origin, src, msg, reason) and
NullnessFlow::flow(src, origin, sink, ssa) and
ssa.getSourceVariable() = v and
firstVarDereferenceInBlock(bb, ssa, va) and
forall(ConditionBlock cond | correlatedConditions(v, cond, _, _) |
varMaybeNullInBlock_corrCond(origin, ssa, bb, _, cond, _)
) and
forall(SsaVariable guardssa, SsaSourceVariable guardvar, TrackVarKind kind |
trackingVar(v, guardssa, guardvar, kind, _)
|
varMaybeNullInBlock_trackVar(origin, ssa, bb, _, guardssa, guardvar, kind, _)
)
varDereference(ssa, va) = sink
)
}

View File

@@ -253,17 +253,18 @@ class SsaImplicitUpdate extends SsaUpdate {
or
if this.hasImplicitQualifierUpdate()
then
if exists(this.getANonLocalUpdate())
if isNonLocal(this)
then result = "nonlocal + nonlocal qualifier"
else result = "nonlocal qualifier"
else (
exists(this.getANonLocalUpdate()) and result = "nonlocal"
isNonLocal(this) and result = "nonlocal"
)
}
/**
* Gets a reachable `FieldWrite` that might represent this ssa update, if any.
*/
overlay[global]
FieldWrite getANonLocalUpdate() {
exists(SsaSourceField f, Callable setter |
relevantFieldUpdate(setter, f.getField(), result) and
@@ -287,6 +288,11 @@ class SsaImplicitUpdate extends SsaUpdate {
}
}
overlay[global]
private predicate isNonLocalImpl(SsaImplicitUpdate su) { exists(su.getANonLocalUpdate()) }
private predicate isNonLocal(SsaImplicitUpdate su) = forceLocal(isNonLocalImpl/1)(su)
/**
* An SSA variable that represents an uncertain implicit update of the value.
* This is a `Call` that might reach a non-local update of the field or one of

View File

@@ -157,17 +157,7 @@ private module BaseSsaImpl {
private import BaseSsaImpl
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
class SourceVariable = BaseSsaSourceVariable;
/**
@@ -199,7 +189,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
}
}
private module Impl = SsaImplCommon::Make<Location, SsaInput>;
private module Impl = SsaImplCommon::Make<Location, Cfg, SsaInput>;
private import Cached

View File

@@ -470,7 +470,8 @@ private predicate enhancedForStmtStep(Node node1, Node node2, Type containerType
}
/**
* Holds if the step from `node1` to `node2` reads a value from an array.
* Holds if the step from `node1` to `node2` reads a value from an array, where
* the elements are of type `elemType`.
* This covers ordinary array reads as well as array iteration through enhanced
* `for` statements.
*/

View File

@@ -69,28 +69,10 @@ private predicate closureFlowStep(Expr e1, Expr e2) {
)
}
private module CaptureInput implements VariableCapture::InputSig<Location> {
private module CaptureInput implements VariableCapture::InputSig<Location, BasicBlock> {
private import java as J
class BasicBlock instanceof J::BasicBlock {
string toString() { result = super.toString() }
ControlFlowNode getNode(int i) { result = super.getNode(i) }
int length() { result = super.length() }
Callable getEnclosingCallable() { result = super.getEnclosingCallable() }
Location getLocation() { result = super.getLocation() }
}
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
result.(J::BasicBlock).immediatelyDominates(bb)
}
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.(J::BasicBlock).getASuccessor() }
Callable basicBlockGetEnclosingCallable(BasicBlock bb) { result = bb.getEnclosingCallable() }
//TODO: support capture of `this` in lambdas
class CapturedVariable instanceof LocalScopeVariable {
@@ -165,7 +147,7 @@ class CapturedVariable = CaptureInput::CapturedVariable;
class CapturedParameter = CaptureInput::CapturedParameter;
module CaptureFlow = VariableCapture::Flow<Location, CaptureInput>;
module CaptureFlow = VariableCapture::Flow<Location, Cfg, CaptureInput>;
private CaptureFlow::ClosureNode asClosureNode(Node n) {
result = n.(CaptureNode).getSynthesizedCaptureNode()

View File

@@ -83,6 +83,7 @@ overlay[caller?]
pragma[inline]
predicate localFlow(Node node1, Node node2) { node1 = node2 or localFlowStepPlus(node1, node2) }
overlay[caller?]
private predicate localFlowStepPlus(Node node1, Node node2) = fastTC(localFlowStep/2)(node1, node2)
/**
@@ -263,8 +264,8 @@ class Content extends TContent {
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* The location spans column `sc` of line `sl` to
* column `ec` of line `el` in file `path`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
@@ -362,8 +363,8 @@ class ContentSet instanceof Content {
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* The location spans column `sc` of line `sl` to
* column `ec` of line `el` in file `path`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/

View File

@@ -132,7 +132,7 @@ private module TypesInput implements Impl::Private::TypesInputSig {
exists(rk)
}
DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
none()
}
@@ -144,7 +144,9 @@ private module StepsInput implements Impl::Private::StepsInputSig {
sc = viableCallable(result).asSummarizedCallable()
}
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() }
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
}

View File

@@ -157,26 +157,21 @@ private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
}
/** Holds if `n` might update the locally tracked variable `v`. */
overlay[global]
pragma[nomagic]
private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
private predicate uncertainVariableUpdateImpl(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
exists(Call c | c = n.asCall() | updatesNamedField(c, v, _)) and
b.getNode(i) = n and
hasDominanceInformation(b)
or
uncertainVariableUpdate(v.getQualifier(), n, b, i)
uncertainVariableUpdateImpl(v.getQualifier(), n, b, i)
}
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
/** Holds if `n` might update the locally tracked variable `v`. */
predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) =
forceLocal(uncertainVariableUpdateImpl/4)(v, n, b, i)
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
class SourceVariable = SsaSourceVariable;
/**
@@ -218,7 +213,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
}
}
import SsaImplCommon::Make<Location, SsaInput> as Impl
import SsaImplCommon::Make<Location, Cfg, SsaInput> as Impl
final class Definition = Impl::Definition;
@@ -345,6 +340,7 @@ private module Cached {
* Constructor --(intraInstanceCallEdge)-->+ Method(setter of this.f)
* ```
*/
overlay[global]
private predicate intraInstanceCallEdge(Callable c1, Method m2) {
exists(MethodCall ma, RefType t1 |
ma.getCaller() = c1 and
@@ -365,6 +361,7 @@ private module Cached {
)
}
overlay[global]
private Callable tgt(Call c) {
result = viableImpl_v2(c)
or
@@ -374,11 +371,13 @@ private module Cached {
}
/** Holds if `(c1,c2)` is an edge in the call graph. */
overlay[global]
private predicate callEdge(Callable c1, Callable c2) {
exists(Call c | c.getCaller() = c1 and c2 = tgt(c))
}
/** Holds if `(c1,c2)` is an edge in the call graph excluding `intraInstanceCallEdge`. */
overlay[global]
private predicate crossInstanceCallEdge(Callable c1, Callable c2) {
callEdge(c1, c2) and not intraInstanceCallEdge(c1, c2)
}
@@ -392,6 +391,7 @@ private module Cached {
relevantFieldUpdate(_, f.getField(), _)
}
overlay[global]
private predicate source(Call call, TrackedField f, Field field, Callable c, boolean fresh) {
relevantCall(call, f) and
field = f.getField() and
@@ -405,9 +405,11 @@ private module Cached {
* `fresh` indicates whether the instance `this` in `c` has been freshly
* allocated along the call-chain.
*/
overlay[global]
private newtype TCallableNode =
MkCallableNode(Callable c, boolean fresh) { source(_, _, _, c, fresh) or edge(_, c, fresh) }
overlay[global]
private predicate edge(TCallableNode n, Callable c2, boolean f2) {
exists(Callable c1, boolean f1 | n = MkCallableNode(c1, f1) |
intraInstanceCallEdge(c1, c2) and f2 = f1
@@ -417,6 +419,7 @@ private module Cached {
)
}
overlay[global]
private predicate edge(TCallableNode n1, TCallableNode n2) {
exists(Callable c2, boolean f2 |
edge(n1, c2, f2) and
@@ -424,6 +427,7 @@ private module Cached {
)
}
overlay[global]
pragma[noinline]
private predicate source(Call call, TrackedField f, Field field, TCallableNode n) {
exists(Callable c, boolean fresh |
@@ -432,24 +436,28 @@ private module Cached {
)
}
overlay[global]
private predicate sink(Callable c, Field f, TCallableNode n) {
setsOwnField(c, f) and n = MkCallableNode(c, false)
or
setsOtherField(c, f) and n = MkCallableNode(c, _)
}
overlay[global]
private predicate prunedNode(TCallableNode n) {
sink(_, _, n)
or
exists(TCallableNode mid | edge(n, mid) and prunedNode(mid))
}
overlay[global]
private predicate prunedEdge(TCallableNode n1, TCallableNode n2) {
prunedNode(n1) and
prunedNode(n2) and
edge(n1, n2)
}
overlay[global]
private predicate edgePlus(TCallableNode c1, TCallableNode c2) = fastTC(prunedEdge/2)(c1, c2)
/**
@@ -457,6 +465,7 @@ private module Cached {
* where `f` and `call` share the same enclosing callable in which a
* `FieldRead` of `f` is reachable from `call`.
*/
overlay[global]
pragma[noopt]
private predicate updatesNamedFieldImpl(Call call, TrackedField f, Callable setter) {
exists(TCallableNode src, TCallableNode sink, Field field |
@@ -467,11 +476,13 @@ private module Cached {
}
bindingset[call, f]
overlay[global]
pragma[inline_late]
private predicate updatesNamedField0(Call call, TrackedField f, Callable setter) {
updatesNamedField(call, f, setter)
}
overlay[global]
cached
predicate defUpdatesNamedField(SsaImplicitUpdate def, TrackedField f, Callable setter) {
f = def.getSourceVariable() and

View File

@@ -278,21 +278,23 @@ private predicate inputStreamWrapper(Constructor c, int argi) {
/** An object construction that preserves the data flow status of any of its arguments. */
private predicate constructorStep(Expr tracked, ConstructorCall sink, string model) {
exists(int argi | sink.getArgument(argi) = tracked |
exists(int argi | sink.getArgument(pragma[only_bind_into](argi)) = tracked |
// wrappers constructed by extension
exists(Constructor c, Parameter p, SuperConstructorInvocationStmt sup |
c = sink.getConstructor() and
p = c.getParameter(argi) and
p = c.getParameter(pragma[only_bind_into](argi)) and
sup.getEnclosingCallable() = c and
constructorStep(p.getAnAccess(), sup, model)
)
or
// a custom InputStream that wraps a tainted data source is tainted
model = "inputStreamWrapper" and
inputStreamWrapper(sink.getConstructor(), argi)
inputStreamWrapper(sink.getConstructor(), pragma[only_bind_into](argi))
or
model = "TaintPreservingCallable" and
sink.getConstructor().(TaintPreservingCallable).returnsTaintFrom(argToParam(sink, argi))
sink.getConstructor()
.(TaintPreservingCallable)
.returnsTaintFrom(argToParam(sink, pragma[only_bind_into](argi)))
)
}

View File

@@ -204,7 +204,7 @@ private module Impl {
/** Gets the character value of expression `e`. */
string getCharValue(Expr e) { result = e.(CharacterLiteral).getValue() }
/** Gets the constant `float` value of non-`ConstantIntegerExpr` expressions. */
/** Gets the constant `float` value of non-`ConstantIntegerExpr` expression `e`. */
float getNonIntegerValue(Expr e) {
result = e.(LongLiteral).getValue().toFloat() or
result = e.(FloatLiteral).getValue().toFloat() or
@@ -256,12 +256,12 @@ private module Impl {
exists(EnhancedForStmt for | def = for.getVariable())
}
/** Returns the operand of the operation if `def` is a decrement. */
/** Returns the operand of the operation if `e` is a decrement. */
Expr getDecrementOperand(Element e) {
result = e.(PostDecExpr).getExpr() or result = e.(PreDecExpr).getExpr()
}
/** Returns the operand of the operation if `def` is an increment. */
/** Returns the operand of the operation if `e` is an increment. */
Expr getIncrementOperand(Element e) {
result = e.(PostIncExpr).getExpr() or result = e.(PreIncExpr).getExpr()
}

View File

@@ -5,8 +5,6 @@
* data flow check for lambdas, anonymous classes, and other sufficiently
* private classes where all object instantiations are accounted for.
*/
overlay[local?]
module;
import java
private import VirtualDispatch

View File

@@ -6,8 +6,6 @@
* The set of dispatch targets for `Object.toString()` calls are reduced based
* on possible data flow from objects of more specific types to the qualifier.
*/
overlay[local?]
module;
import java
private import VirtualDispatch

View File

@@ -2,8 +2,6 @@
* Provides predicates for reasoning about runtime call targets through virtual
* dispatch.
*/
overlay[local?]
module;
import java
import semmle.code.java.dataflow.TypeFlow

View File

@@ -1,8 +1,6 @@
/**
* Provides a module to check whether two `ParameterizedType`s are unifiable.
*/
overlay[local?]
module;
import java

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED.
*
* A library providing uniform access to various assertion frameworks.
*
* Currently supports `org.junit.Assert`, `junit.framework.*`,
@@ -6,7 +8,7 @@
* and `java.util.Objects`.
*/
overlay[local?]
module;
deprecated module;
import java

View File

@@ -223,10 +223,10 @@ class MockitoInjectedField extends MockitoAnnotatedField {
// 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 this.usingPropertyInjection()
then
// We will call the no-arg constructor if the field wasn't initialized.
else (
this.usingPropertyInjection() and
// We will call the no-arg constructor if the field wasn't initialized.
(
not exists(this.getInitializer()) and
result = mockInjectedClass.getNoArgsConstructor()
or
@@ -241,9 +241,8 @@ class MockitoInjectedField extends MockitoAnnotatedField {
// once, but we instead assume that there are sufficient mocks to go around.
mockedField.getType().(RefType).getAnAncestor() = result.getParameterType(0)
)
else
// There's no instance, and no no-arg constructor we can call, so injection fails.
none()
)
)
)
}
@@ -253,18 +252,16 @@ class MockitoInjectedField extends MockitoAnnotatedField {
* Field injection only occurs if property injection and not constructor injection is used.
*/
Field getASetField() {
if this.usingPropertyInjection()
then
result = this.getMockInjectedClass().getASetField() and
exists(MockitoMockedField mockedField |
mockedField.getDeclaringType() = this.getDeclaringType() and
mockedField.isValid()
|
// We make a simplifying assumption here - in theory, each mock can only be injected
// once, but we instead assume that there are sufficient mocks to go around.
mockedField.getType().(RefType).getAnAncestor() = result.getType()
)
else none()
this.usingPropertyInjection() and
result = this.getMockInjectedClass().getASetField() and
exists(MockitoMockedField mockedField |
mockedField.getDeclaringType() = this.getDeclaringType() and
mockedField.isValid()
|
// We make a simplifying assumption here - in theory, each mock can only be injected
// once, but we instead assume that there are sufficient mocks to go around.
mockedField.getType().(RefType).getAnAncestor() = result.getType()
)
}
}

View File

@@ -20,8 +20,10 @@ private predicate externalStorageFlowStep(DataFlow::Node node1, DataFlow::Node n
node2.asExpr().(FieldRead).getField().getInitializer() = node1.asExpr()
}
private predicate externalStorageFlow(DataFlow::Node node1, DataFlow::Node node2) {
externalStorageFlowStep*(node1, node2)
private predicate externalStorageDirFlowsTo(DataFlow::Node n) {
sourceNode(n, "android-external-storage-dir")
or
exists(DataFlow::Node mid | externalStorageDirFlowsTo(mid) and externalStorageFlowStep(mid, n))
}
/**
@@ -29,9 +31,8 @@ private predicate externalStorageFlow(DataFlow::Node node1, DataFlow::Node node2
* This is controllable by third-party applications, so is treated as a remote flow source.
*/
predicate androidExternalStorageSource(DataFlow::Node n) {
exists(DataFlow::Node externalDir, DirectFileReadExpr read |
sourceNode(externalDir, "android-external-storage-dir") and
exists(DirectFileReadExpr read |
n.asExpr() = read and
externalStorageFlow(externalDir, DataFlow::exprNode(read.getFileExpr()))
externalStorageDirFlowsTo(DataFlow::exprNode(read.getFileExpr()))
)
}

View File

@@ -35,14 +35,14 @@ class SessionEjb extends EJB {
// Either the EJB does not declare any business interfaces explicitly
// and implements a single interface candidate,
// which is then considered to be the business interface...
count(this.getAnExplicitBusinessInterface()) = 0 and
not exists(this.getAnExplicitBusinessInterface()) and
count(this.getAnImplementedBusinessInterfaceCandidate()) = 1 and
result = this.getAnImplementedBusinessInterfaceCandidate()
or
// ...or each business interface needs to be declared explicitly.
(
count(this.getAnImplementedBusinessInterfaceCandidate()) != 1 or
count(this.getAnExplicitBusinessInterface()) != 0
exists(this.getAnExplicitBusinessInterface())
) and
result = this.getAnExplicitBusinessInterface()
}

View File

@@ -163,6 +163,12 @@ private module RegexFlowConfig implements DataFlow::ConfigSig {
private module RegexFlow = DataFlow::Global<RegexFlowConfig>;
private predicate usedAsRegexImpl(StringLiteral regex, string mode, boolean match_full_string) {
RegexFlow::flow(DataFlow::exprNode(regex), _) and
mode = "None" and // TODO: proper mode detection
(if matchesFullString(regex) then match_full_string = true else match_full_string = false)
}
/**
* Holds if `regex` is used as a regex, with the mode `mode` (if known).
* If regex mode is not known, `mode` will be `"None"`.
@@ -170,11 +176,9 @@ private module RegexFlow = DataFlow::Global<RegexFlowConfig>;
* As an optimisation, only regexes containing an infinite repitition quatifier (`+`, `*`, or `{x,}`)
* and therefore may be relevant for ReDoS queries are considered.
*/
predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) {
RegexFlow::flow(DataFlow::exprNode(regex), _) and
mode = "None" and // TODO: proper mode detection
(if matchesFullString(regex) then match_full_string = true else match_full_string = false)
}
overlay[local]
predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) =
forceLocal(usedAsRegexImpl/3)(regex, mode, match_full_string)
/**
* Holds if `regex` is used as a regular expression that is matched against a full string,

View File

@@ -55,7 +55,7 @@ private predicate isVarargs(Argument arg, DataFlow::ImplicitVarargsArray varargs
arg.isVararg() and arg.getCall() = varargs.getCall()
}
/** Holds if `store` closes `file`. */
/** Holds if `closeCall` closes `file`. */
private predicate closesFile(DataFlow::Node file, Call closeCall) {
closeCall.getCallee() instanceof CloseFileMethod and
if closeCall.getCallee().isStatic()

View File

@@ -89,7 +89,7 @@ private VarAccess getFileForPathConversion(Expr pathExpr) {
}
/**
* Holds if `fileAccess` is used in the `setWorldWritableExpr` to set the file to be world writable.
* Holds if `fileAccess` is used in the `setWorldWritable` to set the file to be world writable.
*/
private predicate fileSetWorldWritable(VarAccess fileAccess, Expr setWorldWritable) {
// Calls to `File.setWritable(.., false)`.

View File

@@ -0,0 +1,128 @@
/** Provides classes and predicates to reason about Spring Boot actuators exposed in configuration files. */
overlay[local?]
module;
import java
private import semmle.code.configfiles.ConfigFiles
private import semmle.code.xml.MavenPom
/** The parent node of the `org.springframework.boot` group. */
private class SpringBootParent extends Parent {
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
}
/** A `Pom` with a Spring Boot parent node. */
private class SpringBootPom extends Pom {
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
/** Holds if the Spring Boot Security module is used in the project. */
predicate isSpringBootSecurityUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
}
}
/** A dependency with artifactId `spring-boot-starter-actuator`. */
class SpringBootStarterActuatorDependency extends Dependency {
SpringBootStarterActuatorDependency() {
this.getArtifact().getValue() = "spring-boot-starter-actuator"
}
}
/** The Spring Boot configuration property `management.security.enabled`. */
private class ManagementSecurityEnabledProperty extends JavaProperty {
ManagementSecurityEnabledProperty() {
this.getNameElement().getName() = "management.security.enabled"
}
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
/** Holds if `management.security.enabled` is set to `false`. */
predicate hasSecurityDisabled() { this.getValue() = "false" }
}
/**
* The Spring Boot configuration property `management.endpoints.web.exposure.include`
* or `management.endpoints.web.expose`.
*/
private class ManagementEndpointsExposeProperty extends JavaProperty {
ManagementEndpointsExposeProperty() {
this.getNameElement().getName() = "management.endpoints.web." + ["exposure.include", "expose"]
}
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
}
private newtype TOption =
TNone() or
TSome(JavaProperty jp)
/**
* An option type that is either a singleton `None` or a `Some` wrapping
* the `JavaProperty` type.
*/
class JavaPropertyOption extends TOption {
/** Gets a textual representation of this element. */
string toString() {
this = TNone() and result = "(none)"
or
result = this.asSome().toString()
}
/** Gets the location of this element. */
Location getLocation() { result = this.asSome().getLocation() }
/** Gets the wrapped element, if any. */
JavaProperty asSome() { this = TSome(result) }
/** Holds if this option is the singleton `None`. */
predicate isNone() { this = TNone() }
}
/**
* Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
* d exposes sensitive Spring Boot Actuator endpoints.
*/
predicate exposesSensitiveEndpoint(
SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
) {
exists(PropertiesFile propFile, SpringBootPom pom |
d = pom.getADependency() and
not pom.isSpringBootSecurityUsed() and
propFile
.getParentContainer()
.getAbsolutePath()
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
exists(string springBootVersion |
springBootVersion = pom.getParentElement().getVersionString()
|
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
not exists(ManagementSecurityEnabledProperty ep | ep.getFile() = propFile) and
jpOption.isNone()
or
springBootVersion.regexpMatch("1\\.[0-5].*") and // version 1.0, 1.1, ..., 1.5
exists(ManagementSecurityEnabledProperty ep |
ep.hasSecurityDisabled() and ep.getFile() = propFile and ep = jpOption.asSome()
)
or
springBootVersion.matches(["2.%", "3.%"]) and //version 2.x and 3.x
exists(ManagementEndpointsExposeProperty ep |
ep.getFile() = propFile and
ep = jpOption.asSome() and
(
// all endpoints are exposed
ep.getValue() = "*"
or
// version 2.x: exposes health and info only by default
springBootVersion.matches("2.%") and
not ep.getValue() = ["health", "info"]
or
// version 3.x: exposes health only by default
springBootVersion.matches("3.%") and
not ep.getValue() = "health"
)
)
)
)
}

View File

@@ -26,7 +26,8 @@ class MethodFileCreateTempFile extends Method {
}
/**
* Holds if `expDest` is some constructor call `new java.io.File(expSource)`, where the specific `File` constructor being used has `paramCount` parameters.
* Holds if `expSource` is an argument to a constructor call `exprDest` (constructor from `java.io.File`), where
* the specific `File` constructor being used has `paramCount` parameters.
*/
predicate isFileConstructorArgument(Expr expSource, Expr exprDest, int paramCount) {
exists(ConstructorCall construtorCall |

View File

@@ -552,7 +552,7 @@ private DataFlow::Node getASafelyConfiguredParser() {
}
/**
* Holds if `parseMethodQualifierExpr` is a `jodd.json.JsonParser` instance that is configured unsafely
* Holds if `parserExpr` is a `jodd.json.JsonParser` instance that is configured unsafely
* and which never appears to be configured safely.
*/
private predicate joddJsonParserConfiguredUnsafely(Expr parserExpr) {

View File

@@ -6,6 +6,7 @@ module;
import semmle.files.FileSystem
private import codeql.xml.Xml
private import semmle.code.java.Overlay
private module Input implements InputSig<File, Location> {
class XmlLocatableBase = @xmllocatable or @xmlnamespaceable;
@@ -69,3 +70,13 @@ private module Input implements InputSig<File, Location> {
}
import Make<File, Location, Input>
private class DiscardableXmlAttribute extends DiscardableXmlLocatable, @xmlattribute { }
private class DiscardableXmlElement extends DiscardableXmlLocatable, @xmlelement { }
private class DiscardableXmlComment extends DiscardableXmlLocatable, @xmlcomment { }
private class DiscardableXmlCharacters extends DiscardableXmlLocatable, @xmlcharacters { }
private class DiscardableXmlDtd extends DiscardableXmlLocatable, @xmldtd { }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add support for Java 25 compact source files by introducing isImplicitClass table
compatibility: full

View File

@@ -7,7 +7,10 @@
* @problem.severity recommendation
* @precision medium
* @id java/non-final-immutable-field
* @tags reliability
* @tags quality
* reliability
* correctness
* readability
*/
import java

View File

@@ -6,7 +6,10 @@
* @problem.severity recommendation
* @precision medium
* @id java/non-private-field
* @tags maintainability
* @tags quality
* maintainability
* readability
* complexity
*/
import java

View File

@@ -7,6 +7,7 @@
* @precision medium
* @id java/undocumented-function
* @tags maintainability
* readability
*/
import java

View File

@@ -7,6 +7,7 @@
* @precision medium
* @id java/undocumented-parameter
* @tags maintainability
* readability
*/
import java

View File

@@ -7,6 +7,7 @@
* @precision medium
* @id java/undocumented-return-value
* @tags maintainability
* readability
*/
import java

View File

@@ -7,6 +7,8 @@
* @precision medium
* @id java/undocumented-exception
* @tags maintainability
* readability
* error-handling
*/
import java

View File

@@ -7,6 +7,7 @@
* @precision medium
* @id java/undocumented-type
* @tags maintainability
* readability
*/
import java

View File

@@ -6,7 +6,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/use-of-clone-method
* @tags reliability
* @tags quality
* reliability
* correctness
*/
import java

View File

@@ -6,7 +6,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/override-of-clone-method
* @tags reliability
* @tags quality
* reliability
* correctness
*/
import java

View File

@@ -6,7 +6,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/use-of-cloneable-interface
* @tags reliability
* @tags quality
* reliability
* correctness
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/override-of-finalize-method
* @tags reliability
* @tags quality
* reliability
* correctness
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/misnamed-constant
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/misnamed-function
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/misnamed-package
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/misnamed-type
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/misnamed-variable
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -6,7 +6,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/missing-default-in-switch
* @tags reliability
* @tags quality
* reliability
* correctness
* external/cwe/cwe-478
*/

View File

@@ -5,7 +5,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/multiple-statements-on-same-line
* @tags maintainability
* @tags quality
* maintainability
* readability
*/
import java

View File

@@ -6,7 +6,9 @@
* @problem.severity recommendation
* @precision medium
* @id java/non-terminated-if-else-if-chain
* @tags reliability
* @tags quality
* reliability
* correctness
*/
import java

View File

@@ -6,7 +6,10 @@
* @problem.severity recommendation
* @precision medium
* @id java/raw-constructor-invocation
* @tags maintainability
* @tags quality
* maintainability
* readability
* correctness
*/
import java

View File

@@ -6,7 +6,10 @@
* @problem.severity recommendation
* @precision medium
* @id java/raw-return-type
* @tags maintainability
* @tags quality
* maintainability
* readability
* correctness
*/
import java

View File

@@ -6,7 +6,10 @@
* @problem.severity recommendation
* @precision medium
* @id java/raw-variable
* @tags maintainability
* @tags quality
* maintainability
* readability
* correctness
*/
import java

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