Merge branch 'main' into redsun82/swift-ios

This commit is contained in:
Paolo Tranquilli
2025-01-20 16:43:49 +01:00
38 changed files with 5302 additions and 100 deletions

View File

@@ -218,6 +218,7 @@ use_repo(
"kotlin-compiler-2.0.0-RC1", "kotlin-compiler-2.0.0-RC1",
"kotlin-compiler-2.0.20-Beta2", "kotlin-compiler-2.0.20-Beta2",
"kotlin-compiler-2.1.0-Beta1", "kotlin-compiler-2.1.0-Beta1",
"kotlin-compiler-2.1.20-Beta1",
"kotlin-compiler-embeddable-1.5.0", "kotlin-compiler-embeddable-1.5.0",
"kotlin-compiler-embeddable-1.5.10", "kotlin-compiler-embeddable-1.5.10",
"kotlin-compiler-embeddable-1.5.20", "kotlin-compiler-embeddable-1.5.20",
@@ -232,6 +233,7 @@ use_repo(
"kotlin-compiler-embeddable-2.0.0-RC1", "kotlin-compiler-embeddable-2.0.0-RC1",
"kotlin-compiler-embeddable-2.0.20-Beta2", "kotlin-compiler-embeddable-2.0.20-Beta2",
"kotlin-compiler-embeddable-2.1.0-Beta1", "kotlin-compiler-embeddable-2.1.0-Beta1",
"kotlin-compiler-embeddable-2.1.20-Beta1",
"kotlin-stdlib-1.5.0", "kotlin-stdlib-1.5.0",
"kotlin-stdlib-1.5.10", "kotlin-stdlib-1.5.10",
"kotlin-stdlib-1.5.20", "kotlin-stdlib-1.5.20",
@@ -246,6 +248,7 @@ use_repo(
"kotlin-stdlib-2.0.0-RC1", "kotlin-stdlib-2.0.0-RC1",
"kotlin-stdlib-2.0.20-Beta2", "kotlin-stdlib-2.0.20-Beta2",
"kotlin-stdlib-2.1.0-Beta1", "kotlin-stdlib-2.1.0-Beta1",
"kotlin-stdlib-2.1.20-Beta1",
) )
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")

View File

@@ -20,7 +20,7 @@
Java,"Java 7 to 22 [5]_","javac (OpenJDK and Oracle JDK), Java,"Java 7 to 22 [5]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [6]_",``.java`` Eclipse compiler for Java (ECJ) [6]_",``.java``
Kotlin,"Kotlin 1.5.0 to 2.1.0\ *x*","kotlinc",``.kt`` Kotlin,"Kotlin 1.5.0 to 2.1.2\ *x*","kotlinc",``.kt``
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_" JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_"
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py`` Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
Ruby [9]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" Ruby [9]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* By implementing `ImplicitFieldReadNode` it is now possible to declare a dataflow node that reads any content (fields, array members, map keys and values). For example, this is appropriate for modelling a serialization method that flattens a potentially deep data structure into a string or byte array.
* The `Template.Execute[Template]` methods of the `text/template` package now correctly convey taint from any nested fields to their result. This may produce more results from any taint-tracking query when the `text/template` package is in use.

View File

@@ -7,5 +7,5 @@ extensions:
- ["text/template", "", False, "HTMLEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["text/template", "", False, "HTMLEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["text/template", "", False, "JSEscape", "", "", "Argument[1]", "Argument[0]", "taint", "manual"] - ["text/template", "", False, "JSEscape", "", "", "Argument[1]", "Argument[0]", "taint", "manual"]
- ["text/template", "", False, "JSEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["text/template", "", False, "JSEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["text/template", "Template", True, "Execute", "", "", "Argument[1]", "Argument[0]", "taint", "manual"] # - ["text/template", "Template", True, "Execute", "", "", "Argument[1]", "Argument[0]", "taint", "manual"] # Implemented in QL to provide an arbitrary content read from the input.
- ["text/template", "Template", True, "ExecuteTemplate", "", "", "Argument[2]", "Argument[0]", "taint", "manual"] # - ["text/template", "Template", True, "ExecuteTemplate", "", "", "Argument[2]", "Argument[0]", "taint", "manual"] # Implemented in QL to provide an arbitrary content read from the input.

View File

@@ -143,7 +143,8 @@ predicate jumpStep(Node n1, Node n2) {
* Thus, `node2` references an object with a content `x` that contains the * Thus, `node2` references an object with a content `x` that contains the
* value of `node1`. * value of `node1`.
*/ */
predicate storeStep(Node node1, ContentSet c, Node node2) { predicate storeStep(Node node1, ContentSet cs, Node node2) {
exists(Content c | cs.asOneContent() = c |
// a write `(*p).f = rhs` is modeled as two store steps: `rhs` is flows into field `f` of `(*p)`, // a write `(*p).f = rhs` is modeled as two store steps: `rhs` is flows into field `f` of `(*p)`,
// which in turn flows into the pointer content of `p` // which in turn flows into the pointer content of `p`
exists(Write w, Field f, DataFlow::Node base, DataFlow::Node rhs | w.writesField(base, f, rhs) | exists(Write w, Field f, DataFlow::Node base, DataFlow::Node rhs | w.writesField(base, f, rhs) |
@@ -159,10 +160,11 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
node1 = node2.(AddressOperationNode).getOperand() and node1 = node2.(AddressOperationNode).getOperand() and
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType()) c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType())
or or
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
or
containerStoreStep(node1, node2, c) containerStoreStep(node1, node2, c)
)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
node2.(FlowSummaryNode).getSummaryNode())
} }
/** /**
@@ -170,7 +172,8 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
* Thus, `node1` references an object with a content `c` whose value ends up in * Thus, `node1` references an object with a content `c` whose value ends up in
* `node2`. * `node2`.
*/ */
predicate readStep(Node node1, ContentSet c, Node node2) { predicate readStep(Node node1, ContentSet cs, Node node2) {
exists(Content c | cs.asOneContent() = c |
node1 = node2.(PointerDereferenceNode).getOperand() and node1 = node2.(PointerDereferenceNode).getOperand() and
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType()) c = any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType())
or or
@@ -180,10 +183,15 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
c = any(DataFlow::FieldContent fc | fc.getField() = read.getField()) c = any(DataFlow::FieldContent fc | fc.getField() = read.getField())
) )
or or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c, containerReadStep(node1, node2, c)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
node2.(FlowSummaryNode).getSummaryNode()) node2.(FlowSummaryNode).getSummaryNode())
or or
containerReadStep(node1, node2, c) any(ImplicitFieldReadNode ifrn).shouldImplicitlyReadAllFields(node1) and
cs.isUniversalContent() and
node1 = node2
} }
/** /**

View File

@@ -7,6 +7,7 @@ private import semmle.go.dataflow.FunctionInputsAndOutputs
private import semmle.go.dataflow.ExternalFlow private import semmle.go.dataflow.ExternalFlow
private import DataFlowPrivate private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import codeql.util.Unit
import DataFlowNodes::Public import DataFlowNodes::Public
/** /**
@@ -50,6 +51,18 @@ abstract class FunctionModel extends Function {
} }
} }
/**
* A unit class for adding nodes that should implicitly read from all nested content.
*
* For example, this might be appropriate for the argument to a method that serializes a struct.
*/
class ImplicitFieldReadNode extends Unit {
/**
* Holds if the node `n` should implicitly read from all nested content in a taint-tracking context.
*/
abstract predicate shouldImplicitlyReadAllFields(DataFlow::Node n);
}
/** /**
* Gets the `Node` corresponding to `insn`. * Gets the `Node` corresponding to `insn`.
*/ */
@@ -169,6 +182,11 @@ class Content extends TContent {
) { ) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0 filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
} }
/**
* Gets the `ContentSet` contaning only this content.
*/
ContentSet asContentSet() { result.asOneContent() = this }
} }
/** A reference through a field. */ /** A reference through a field. */
@@ -236,21 +254,33 @@ class SyntheticFieldContent extends Content, TSyntheticFieldContent {
override string toString() { result = s.toString() } override string toString() { result = s.toString() }
} }
private newtype TContentSet =
TOneContent(Content c) or
TAllContent()
/** /**
* An entity that represents a set of `Content`s. * An entity that represents a set of `Content`s.
* *
* The set may be interpreted differently depending on whether it is * The set may be interpreted differently depending on whether it is
* stored into (`getAStoreContent`) or read from (`getAReadContent`). * stored into (`getAStoreContent`) or read from (`getAReadContent`).
*/ */
class ContentSet instanceof Content { class ContentSet instanceof TContentSet {
/** Gets a content that may be stored into when storing into this set. */ /** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { result = this } Content getAStoreContent() { this = TOneContent(result) }
/** Gets a content that may be read from when reading from this set. */ /** Gets a content that may be read from when reading from this set. */
Content getAReadContent() { result = this } Content getAReadContent() {
this = TOneContent(result)
or
this = TAllContent() and exists(result)
}
/** Gets a textual representation of this content set. */ /** Gets a textual representation of this content set. */
string toString() { result = super.toString() } string toString() {
exists(Content c | this = TOneContent(c) | result = c.toString())
or
this = TAllContent() and result = "all content"
}
/** /**
* Holds if this element is at the specified location. * Holds if this element is at the specified location.
@@ -262,8 +292,27 @@ class ContentSet instanceof Content {
predicate hasLocationInfo( predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) exists(Content c | this = TOneContent(c) |
c.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
this = TAllContent() and
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
} }
/**
* If this is a singleton content set, returns the content.
*/
Content asOneContent() { this = TOneContent(result) }
/**
* Holds if this is a universal content set.
*/
predicate isUniversalContent() { this = TAllContent() }
} }
/** /**

View File

@@ -61,26 +61,28 @@ module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
} }
string encodeContent(ContentSet cs, string arg) { string encodeContent(ContentSet cs, string arg) {
exists(Content c | cs.asOneContent() = c |
exists(Field f, string package, string className, string fieldName | exists(Field f, string package, string className, string fieldName |
f = cs.(FieldContent).getField() and f = c.(FieldContent).getField() and
f.hasQualifiedName(package, className, fieldName) and f.hasQualifiedName(package, className, fieldName) and
result = "Field" and result = "Field" and
arg = package + "." + className + "." + fieldName arg = package + "." + className + "." + fieldName
) )
or or
exists(SyntheticField f | exists(SyntheticField f |
f = cs.(SyntheticFieldContent).getField() and result = "SyntheticField" and arg = f f = c.(SyntheticFieldContent).getField() and result = "SyntheticField" and arg = f
) )
or or
cs instanceof ArrayContent and result = "ArrayElement" and arg = "" c instanceof ArrayContent and result = "ArrayElement" and arg = ""
or or
cs instanceof CollectionContent and result = "Element" and arg = "" c instanceof CollectionContent and result = "Element" and arg = ""
or or
cs instanceof MapKeyContent and result = "MapKey" and arg = "" c instanceof MapKeyContent and result = "MapKey" and arg = ""
or or
cs instanceof MapValueContent and result = "MapValue" and arg = "" c instanceof MapValueContent and result = "MapValue" and arg = ""
or or
cs instanceof PointerContent and result = "Dereference" and arg = "" c instanceof PointerContent and result = "Dereference" and arg = ""
)
} }
bindingset[token] bindingset[token]
@@ -523,7 +525,9 @@ module Private {
SummaryComponent qualifier() { result = argument(-1) } SummaryComponent qualifier() { result = argument(-1) }
/** Gets a summary component for field `f`. */ /** Gets a summary component for field `f`. */
SummaryComponent field(Field f) { result = content(any(FieldContent c | c.getField() = f)) } SummaryComponent field(Field f) {
result = content(any(FieldContent c | c.getField() = f).asContentSet())
}
/** Gets a summary component that represents the return value of a call. */ /** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = SC::return(_) } SummaryComponent return() { result = SC::return(_) }

View File

@@ -47,10 +47,11 @@ private Type getElementType(Type containerType) {
* of `c` at sinks and inputs to additional taint steps. * of `c` at sinks and inputs to additional taint steps.
*/ */
bindingset[node] bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet cs) {
exists(Type containerType | exists(Type containerType, DataFlow::Content c |
node instanceof DataFlow::ArgumentNode and node instanceof DataFlow::ArgumentNode and
getElementType*(node.getType()) = containerType getElementType*(node.getType()) = containerType and
cs.asOneContent() = c
| |
containerType instanceof ArrayType and containerType instanceof ArrayType and
c instanceof DataFlow::ArrayContent c instanceof DataFlow::ArrayContent
@@ -142,7 +143,7 @@ predicate elementWriteStep(DataFlow::Node pred, DataFlow::Node succ) {
any(DataFlow::Write w).writesElement(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, pred) any(DataFlow::Write w).writesElement(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, pred)
or or
FlowSummaryImpl::Private::Steps::summaryStoreStep(pred.(DataFlowPrivate::FlowSummaryNode) FlowSummaryImpl::Private::Steps::summaryStoreStep(pred.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), any(DataFlow::Content c | c instanceof DataFlow::ArrayContent), .getSummaryNode(), any(DataFlow::ArrayContent ac).asContentSet(),
succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode()) succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode())
} }

View File

@@ -122,7 +122,7 @@ module NetHttp {
| |
lastParamIndex = call.getCall().getCalleeType().getNumParameter() - 1 and lastParamIndex = call.getCall().getCalleeType().getNumParameter() - 1 and
varArgsSliceArgument = SummaryComponentStack::argument(lastParamIndex) and varArgsSliceArgument = SummaryComponentStack::argument(lastParamIndex) and
arrayContentSC = SummaryComponent::content(arrayContent) and arrayContentSC = SummaryComponent::content(arrayContent.asContentSet()) and
stack = SummaryComponentStack::push(arrayContentSC, varArgsSliceArgument) stack = SummaryComponentStack::push(arrayContentSC, varArgsSliceArgument)
) )
else stack = SummaryComponentStack::argument(n) else stack = SummaryComponentStack::argument(n)

View File

@@ -67,4 +67,45 @@ module TextTemplate {
input = inp and output = outp input = inp and output = outp
} }
} }
private class ExecuteTemplateMethod extends Method {
int inputArg;
ExecuteTemplateMethod() {
exists(string name |
this.hasQualifiedName("text/template", "Template", name) and
(
name = "Execute" and inputArg = 1
or
name = "ExecuteTemplate" and inputArg = 2
)
)
}
int getInputArgIdx() { result = inputArg }
}
private class ExecuteTemplateFieldReader extends DataFlow::ImplicitFieldReadNode {
override predicate shouldImplicitlyReadAllFields(DataFlow::Node n) {
exists(ExecuteTemplateMethod m, DataFlow::MethodCallNode cn |
cn.getTarget() = m and
n = cn.getArgument(m.getInputArgIdx())
)
}
}
private class ExecuteTemplateFunctionModels extends TaintTracking::FunctionModel,
ExecuteTemplateMethod
{
FunctionInput inp;
FunctionOutput outp;
ExecuteTemplateFunctionModels() {
inp.isParameter(this.getInputArgIdx()) and outp.isParameter(0)
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input = inp and output = outp
}
}
} }

View File

@@ -0,0 +1,9 @@
import go
import utils.test.InlineFlowTest
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
exists(sink) and
result = src.(DataFlow::CallNode).getArgument(0).getExactValue()
}
import TaintFlowTestArgString<DefaultFlowConfig, getArgString/2>

View File

@@ -0,0 +1,60 @@
package xyz
import (
"bytes"
"text/template"
)
type Inner1 struct {
Data string
}
type Inner2 struct {
Data string
}
type Inner3 struct {
Data string
}
type HasInner3Slice struct {
Slice []Inner3
}
type Outer struct {
SliceField []Inner1
PtrField *Inner2
MapField map[string]Inner3
DeepField HasInner3Slice
}
func source(n int) string { return "dummy" }
func sink(arg any) {}
func test() {
source1 := source(1)
source2 := source(2)
source3 := source(3)
source4 := source(4)
toSerialize := Outer{[]Inner1{{source1}}, &Inner2{source2}, map[string]Inner3{"key": {source3}},
HasInner3Slice{[]Inner3{{source4}}}}
buff1 := new(bytes.Buffer)
buff2 := new(bytes.Buffer)
bytes1 := make([]byte, 10)
bytes2 := make([]byte, 10)
tmpl, _ := template.New("test").Parse("Template text goes here (irrelevant for test)")
tmpl.ExecuteTemplate(buff1, "test", toSerialize)
buff1.Read(bytes1)
sink(bytes1) // $ hasTaintFlow=1 hasTaintFlow=2 hasTaintFlow=3 hasTaintFlow=4
// Read `buff2` via an `any`-typed variable, to ensure the static type of the argument to tmpl.Execute makes no difference to the result
var toSerializeAsAny any
toSerializeAsAny = toSerialize
tmpl.Execute(buff2, toSerializeAsAny)
buff2.Read(bytes2)
sink(bytes2) // $ hasTaintFlow=1 hasTaintFlow=2 hasTaintFlow=3 hasTaintFlow=4
}

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: Add databaseMetadata relation
compatibility: full
databaseMetadata.rel: delete

BIN
java/kotlin-extractor/deps/kotlin-compiler-2.1.20-Beta1.jar (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.1.20-Beta1.jar (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -25,7 +25,19 @@ import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.classFqName
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.types.typeWithArguments
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrStarProjection
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
@@ -2293,7 +2305,7 @@ open class KotlinFileExtractor(
// synthesised and inherit the annotation from the delegate (which given it has // synthesised and inherit the annotation from the delegate (which given it has
// @NotNull, is likely written in Java) // @NotNull, is likely written in Java)
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION.takeUnless { JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION.takeUnless {
t.isNullable() || t.isNullableCodeQL() ||
primitiveTypeMapping.getPrimitiveInfo(t) != null || primitiveTypeMapping.getPrimitiveInfo(t) != null ||
hasExistingAnnotation(it) hasExistingAnnotation(it)
} }
@@ -3975,7 +3987,7 @@ open class KotlinFileExtractor(
target.parent target.parent
} else { } else {
val st = extensionReceiverParameter.type as? IrSimpleType val st = extensionReceiverParameter.type as? IrSimpleType
if (isNullable != null && st?.isNullable() != isNullable) { if (isNullable != null && st?.isNullableCodeQL() != isNullable) {
verboseln("Nullablility of type didn't match") verboseln("Nullablility of type didn't match")
return false return false
} }
@@ -4621,9 +4633,9 @@ open class KotlinFileExtractor(
val isPrimitiveArrayCreation = !isBuiltinCallKotlin(c, "arrayOf") val isPrimitiveArrayCreation = !isBuiltinCallKotlin(c, "arrayOf")
val elementType = val elementType =
if (isPrimitiveArrayCreation) { if (isPrimitiveArrayCreation) {
c.type.getArrayElementType(pluginContext.irBuiltIns) c.type.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
} else { } else {
// TODO: is there any reason not to always use getArrayElementType? // TODO: is there any reason not to always use getArrayElementTypeCodeQL?
if (c.typeArgumentsCount == 1) { if (c.typeArgumentsCount == 1) {
c.getTypeArgument(0).also { c.getTypeArgument(0).also {
if (it == null) { if (it == null) {

View File

@@ -12,7 +12,24 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.addAnnotations
import org.jetbrains.kotlin.ir.types.classFqName
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.types.typeWithArguments
import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrStarProjection
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
@@ -679,7 +696,7 @@ open class KotlinUsesExtractor(
private fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType = private fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType =
if (arrayType.isPrimitiveArray()) arrayType if (arrayType.isPrimitiveArray()) arrayType
else { else {
val componentType = arrayType.getArrayElementType(pluginContext.irBuiltIns) val componentType = arrayType.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
val componentTypeBroadened = val componentTypeBroadened =
when (componentType) { when (componentType) {
is IrSimpleType -> is IrSimpleType ->
@@ -690,7 +707,7 @@ open class KotlinUsesExtractor(
val unchanged = val unchanged =
componentType == componentTypeBroadened && componentType == componentTypeBroadened &&
(arrayType.arguments[0] as? IrTypeProjection)?.variance == Variance.INVARIANT && (arrayType.arguments[0] as? IrTypeProjection)?.variance == Variance.INVARIANT &&
componentType.isNullable() componentType.isNullableCodeQL()
if (unchanged) arrayType if (unchanged) arrayType
else else
IrSimpleTypeImpl( IrSimpleTypeImpl(
@@ -705,7 +722,7 @@ open class KotlinUsesExtractor(
Kotlin arrays can be broken down as: Kotlin arrays can be broken down as:
isArray(t) isArray(t)
|- t.isBoxedArray |- t.isBoxedArrayCodeQL
| |- t.isArray() e.g. Array<Boolean>, Array<Boolean?> | |- t.isArray() e.g. Array<Boolean>, Array<Boolean?>
| |- t.isNullableArray() e.g. Array<Boolean>?, Array<Boolean?>? | |- t.isNullableArray() e.g. Array<Boolean>?, Array<Boolean?>?
|- t.isPrimitiveArray() e.g. BooleanArray |- t.isPrimitiveArray() e.g. BooleanArray
@@ -715,7 +732,7 @@ open class KotlinUsesExtractor(
Primitive arrays are represented as e.g. boolean[]. Primitive arrays are represented as e.g. boolean[].
*/ */
private fun isArray(t: IrType) = t.isBoxedArray || t.isPrimitiveArray() private fun isArray(t: IrType) = t.isBoxedArrayCodeQL || t.isPrimitiveArray()
data class ArrayInfo( data class ArrayInfo(
val elementTypeResults: TypeResults, val elementTypeResults: TypeResults,
@@ -756,7 +773,7 @@ open class KotlinUsesExtractor(
) { ) {
pluginContext.irBuiltIns.anyType pluginContext.irBuiltIns.anyType
} else { } else {
t.getArrayElementType(pluginContext.irBuiltIns) t.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
} }
val recInfo = useArrayType(elementType, t.isPrimitiveArray()) val recInfo = useArrayType(elementType, t.isPrimitiveArray())
@@ -844,7 +861,7 @@ open class KotlinUsesExtractor(
if ( if (
(context == TypeContext.RETURN || (context == TypeContext.RETURN ||
(context == TypeContext.OTHER && otherIsPrimitive)) && (context == TypeContext.OTHER && otherIsPrimitive)) &&
!s.isNullable() && !s.isNullableCodeQL() &&
getKotlinType(s)?.hasEnhancedNullability() != true && getKotlinType(s)?.hasEnhancedNullability() != true &&
primitiveName != null primitiveName != null
) { ) {
@@ -860,7 +877,7 @@ open class KotlinUsesExtractor(
val kotlinClassId = useClassInstance(kotlinClass, listOf()).typeResult.id val kotlinClassId = useClassInstance(kotlinClass, listOf()).typeResult.id
val kotlinResult = val kotlinResult =
if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") if (true) TypeResult(fakeKotlinType(), "TODO", "TODO")
else if (s.isNullable()) { else if (s.isNullableCodeQL()) {
val kotlinSignature = val kotlinSignature =
"$kotlinPackageName.$kotlinClassName?" // TODO: Is this right? "$kotlinPackageName.$kotlinClassName?" // TODO: Is this right?
val kotlinLabel = "@\"kt_type;nullable;$kotlinPackageName.$kotlinClassName\"" val kotlinLabel = "@\"kt_type;nullable;$kotlinPackageName.$kotlinClassName\""
@@ -902,21 +919,21 @@ open class KotlinUsesExtractor(
return extractErrorType() return extractErrorType()
} }
} }
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> { (s.isBoxedArrayCodeQL && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
val arrayInfo = useArrayType(s, false) val arrayInfo = useArrayType(s, false)
return arrayInfo.componentTypeResults return arrayInfo.componentTypeResults
} }
owner is IrClass -> { owner is IrClass -> {
val args = if (s.codeQlIsRawType()) null else s.arguments val args = if (s.codeQlIsRawType()) null else s.arguments
return useSimpleTypeClass(owner, args, s.isNullable()) return useSimpleTypeClass(owner, args, s.isNullableCodeQL())
} }
owner is IrTypeParameter -> { owner is IrTypeParameter -> {
val javaResult = useTypeParameter(owner) val javaResult = useTypeParameter(owner)
val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong
val kotlinResult = val kotlinResult =
if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") if (true) TypeResult(fakeKotlinType(), "TODO", "TODO")
else if (s.isNullable()) { else if (s.isNullableCodeQL()) {
val kotlinSignature = "${javaResult.signature}?" // TODO: Wrong val kotlinSignature = "${javaResult.signature}?" // TODO: Wrong
val kotlinLabel = "@\"kt_type;nullable;type_param\"" // TODO: Wrong val kotlinLabel = "@\"kt_type;nullable;type_param\"" // TODO: Wrong
val kotlinId: Label<DbKt_nullable_type> = val kotlinId: Label<DbKt_nullable_type> =
@@ -1200,7 +1217,7 @@ open class KotlinUsesExtractor(
} }
private fun extendsAdditionAllowed(t: IrType) = private fun extendsAdditionAllowed(t: IrType) =
if (t.isBoxedArray) { if (t.isBoxedArrayCodeQL) {
if (t is IrSimpleType) { if (t is IrSimpleType) {
arrayExtendsAdditionAllowed(t) arrayExtendsAdditionAllowed(t)
} else { } else {
@@ -1493,7 +1510,7 @@ open class KotlinUsesExtractor(
} }
} else { } else {
t.classOrNull?.let { tCls -> t.classOrNull?.let { tCls ->
if (t.isBoxedArray) { if (t.isBoxedArrayCodeQL) {
(t.arguments.singleOrNull() as? IrTypeProjection)?.let { elementTypeArg (t.arguments.singleOrNull() as? IrTypeProjection)?.let { elementTypeArg
-> ->
val elementType = elementTypeArg.type val elementType = elementTypeArg.type
@@ -1506,7 +1523,7 @@ open class KotlinUsesExtractor(
) )
return tCls return tCls
.typeWithArguments(listOf(newArg)) .typeWithArguments(listOf(newArg))
.codeQlWithHasQuestionMark(t.isNullable()) .codeQlWithHasQuestionMark(t.isNullableCodeQL())
} }
} }
} }
@@ -2086,12 +2103,12 @@ open class KotlinUsesExtractor(
} }
if (owner is IrClass) { if (owner is IrClass) {
if (t.isBoxedArray) { if (t.isBoxedArrayCodeQL) {
val elementType = t.getArrayElementType(pluginContext.irBuiltIns) val elementType = t.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
val erasedElementType = erase(elementType) val erasedElementType = erase(elementType)
return owner return owner
.typeWith(erasedElementType) .typeWith(erasedElementType)
.codeQlWithHasQuestionMark(t.isNullable()) .codeQlWithHasQuestionMark(t.isNullableCodeQL())
} }
return if (t.arguments.isNotEmpty()) return if (t.arguments.isNotEmpty())

View File

@@ -5,7 +5,7 @@ import com.github.codeql.utils.versions.*
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.fir.java.JavaBinarySourceElement import org.jetbrains.kotlin.fir.java.VirtualFileBasedSourceElement
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
@@ -89,8 +89,8 @@ fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? {
is BinaryJavaClass -> return element.virtualFile is BinaryJavaClass -> return element.virtualFile
} }
} }
is JavaBinarySourceElement -> { is VirtualFileBasedSourceElement -> {
return cSource.javaClass.virtualFile return cSource.virtualFile
} }
is KotlinJvmBinarySourceElement -> { is KotlinJvmBinarySourceElement -> {
val binaryClass = cSource.binaryClass val binaryClass = cSource.binaryClass

View File

@@ -5,6 +5,7 @@ import com.github.codeql.Logger
import com.github.codeql.getJavaEquivalentClassId import com.github.codeql.getJavaEquivalentClassId
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
import com.github.codeql.utils.versions.*
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
@@ -18,15 +19,18 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.addAnnotations
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrStarProjection
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.parents
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
@@ -57,7 +61,7 @@ private fun IrSimpleType.substituteTypeArguments(
} }
} }
return IrSimpleTypeImpl(classifier, isNullable(), newArguments, annotations) return IrSimpleTypeImpl(classifier, isNullableCodeQL(), newArguments, annotations)
} }
/** /**
@@ -96,7 +100,7 @@ private fun subProjectedType(
else { else {
val newProjectedType = val newProjectedType =
substitutedTypeArg.type.let { substitutedTypeArg.type.let {
if (t.isNullable()) it.codeQlWithHasQuestionMark(true) else it if (t.isNullableCodeQL()) it.codeQlWithHasQuestionMark(true) else it
} }
val newVariance = combineVariance(outerVariance, substitutedTypeArg.variance) val newVariance = combineVariance(outerVariance, substitutedTypeArg.variance)
makeTypeProjection(newProjectedType, newVariance) makeTypeProjection(newProjectedType, newVariance)
@@ -113,7 +117,7 @@ private fun IrTypeArgument.upperBound(context: IrPluginContext) =
when (this.variance) { when (this.variance) {
Variance.INVARIANT -> this.type Variance.INVARIANT -> this.type
Variance.IN_VARIANCE -> Variance.IN_VARIANCE ->
if (this.type.isNullable()) context.irBuiltIns.anyNType if (this.type.isNullableCodeQL()) context.irBuiltIns.anyNType
else context.irBuiltIns.anyType else context.irBuiltIns.anyType
Variance.OUT_VARIANCE -> this.type Variance.OUT_VARIANCE -> this.type
} }
@@ -128,7 +132,7 @@ private fun IrTypeArgument.lowerBound(context: IrPluginContext) =
Variance.INVARIANT -> this.type Variance.INVARIANT -> this.type
Variance.IN_VARIANCE -> this.type Variance.IN_VARIANCE -> this.type
Variance.OUT_VARIANCE -> Variance.OUT_VARIANCE ->
if (this.type.isNullable()) context.irBuiltIns.nothingNType if (this.type.isNullableCodeQL()) context.irBuiltIns.nothingNType
else context.irBuiltIns.nothingType else context.irBuiltIns.nothingType
} }
else -> context.irBuiltIns.nothingType else -> context.irBuiltIns.nothingType
@@ -211,7 +215,7 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument =
this.type.let { this.type.let {
when (it) { when (it) {
is IrSimpleType -> is IrSimpleType ->
if (it.isNullable() == b) this if (it.isNullableCodeQL() == b) this
else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance) else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance)
else -> this else -> this
} }

View File

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

View File

@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.fir.java package org.jetbrains.kotlin.fir.java
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
@@ -7,5 +8,6 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
We need this class to exist, but the compiler will never give us an We need this class to exist, but the compiler will never give us an
instance of it. instance of it.
*/ */
abstract class JavaBinarySourceElement private constructor(val javaClass: BinaryJavaClass) : abstract class VirtualFileBasedSourceElement private constructor(val javaClass: BinaryJavaClass) : SourceElement {
SourceElement {} abstract val virtualFile: VirtualFile
}

View File

@@ -0,0 +1,11 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.*
fun IrType.isNullableCodeQL(): Boolean =
this.isNullable()
val IrType.isBoxedArrayCodeQL: Boolean by IrType::isBoxedArray
fun IrType.getArrayElementTypeCodeQL(irBuiltIns: IrBuiltIns): IrType =
this.getArrayElementType(irBuiltIns)

View File

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

View File

@@ -1,3 +0,0 @@
/*
The compiler provides this class, so we don't have to do anything.
*/

View File

@@ -0,0 +1,3 @@
package org.jetbrains.kotlin.fir.java
typealias VirtualFileBasedSourceElement = JavaBinarySourceElement

View File

@@ -0,0 +1,12 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
fun IrType.isNullableCodeQL(): Boolean =
this.isNullable()
val IrType.isBoxedArrayCodeQL: Boolean by IrType::isBoxedArray
fun IrType.getArrayElementTypeCodeQL(irBuiltIns: IrBuiltIns): IrType =
this.getArrayElementType(irBuiltIns)

View File

@@ -14,6 +14,7 @@ VERSIONS = [
"2.0.0-RC1", "2.0.0-RC1",
"2.0.20-Beta2", "2.0.20-Beta2",
"2.1.0-Beta1", "2.1.0-Beta1",
"2.1.20-Beta1",
] ]
def _version_to_tuple(v): def _version_to_tuple(v):

View File

@@ -1,5 +1,5 @@
{ {
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.1.10.", "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.1.30.",
"severity": "error", "severity": "error",
"source": { "source": {
"extractorName": "java", "extractorName": "java",

View File

@@ -206,6 +206,11 @@ sourceLocationPrefix(
string prefix : string ref string prefix : string ref
); );
databaseMetadata(
string metadataKey : string ref,
string value : string ref
);
/* /*
* SMAP * SMAP
*/ */

View File

@@ -3968,6 +3968,21 @@
</columnsizes> </columnsizes>
<dependencies/> <dependencies/>
</relation> </relation>
<relation>
<name>databaseMetadata</name>
<cardinality>1</cardinality>
<columnsizes>
<e>
<k>metadataKey</k>
<v>1</v>
</e>
<e>
<k>value</k>
<v>1</v>
</e>
</columnsizes>
<dependencies/>
</relation>
<relation> <relation>
<name>smap_header</name> <name>smap_header</name>
<cardinality>1</cardinality> <cardinality>1</cardinality>

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 databaseMetadata relation
compatibility: full