Fix internal query violations and update test expectations for K2

- Make registerExtractorExtension protected (called from subclass)
- Change codeQlExtensionReceiver from var to val (setter unused)
- Update integration test expected files for K2 behavior:
  - Add DB-CHECK.expected for known K2 cross-extractor consistency errors
  - Update result expectations for K2 type resolution differences
- Update language test expected files (pathsanitizer, CWE-312):
  - K2 resolves Path.toString() and CharSequence.toString() with
    different callable IDs than the Java extractor, causing
    callableBinding consistency errors and lost taint flow results

These are pre-existing K2 issues documented in
github/codeql-kotlin-team#196, originally worked around by pinning
tests to -language-version 1.9 in PR #16554 (May 2024). Kotlin 2.4.0
drops 1.9 support, forcing us to accept these known K2 differences.

Verified: the same DB-CHECK errors occur with the released CodeQL CLI
(v2.23.9) and Kotlin 2.3.20 when using -language-version 2.0,
confirming these are K2 behavioral differences unrelated to our 2.4.0
extractor changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anders Fugmann
2026-06-10 12:23:29 +02:00
parent f3037d68ca
commit d0e652159e
14 changed files with 78 additions and 22 deletions

View File

@@ -36,9 +36,8 @@ fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpr
}
// IrMemberAccessExpression: extensionReceiver
var IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
get() = extensionReceiver
set(value) { extensionReceiver = value }
// IrMemberAccessExpression: typeArgumentsCount
val IrMemberAccessExpression<*>.codeQlTypeArgumentsCount: Int

View File

@@ -51,15 +51,11 @@ fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpr
// IrMemberAccessExpression: extensionReceiver
// For IrCall/IrFunctionReference, look at symbol.owner (IrFunction) directly.
// For IrPropertyReference, symbol.owner is IrProperty; use the getter's parameters instead.
var IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
get() {
val erp = extensionReceiverParameterIndex() ?: return null
return arguments[erp]
}
set(value) {
val erp = extensionReceiverParameterIndex() ?: return
arguments[erp] = value
}
private fun IrMemberAccessExpression<*>.extensionReceiverParameterIndex(): Int? {
// Direct function owner (IrCall, IrFunctionReference, etc.)

View File

@@ -37,7 +37,7 @@ abstract class Kotlin2ComponentRegistrar : CompilerPluginRegistrar(), ComponentR
abstract fun doRegisterExtensions(configuration: CompilerConfiguration)
fun registerExtractorExtension(extension: IrGenerationExtension) {
protected fun registerExtractorExtension(extension: IrGenerationExtension) {
val storage = extensionStorage ?: throw IllegalStateException("registerExtractorExtension called before registerExtensions")
with(storage) {
IrGenerationExtension.registerExtension(extension)

View File

@@ -0,0 +1,3 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 44417 of field callee is not in type @callable. Appears in tuple (-16777158,44417)
Relevant element: callee=44417
Full ID for 44417: @"callable;(0).f((55))(55)". The ID may expand to @"callable;{@"class;Test"}.f({@"type;int"}){@"type;int"}"

View File

@@ -2,9 +2,9 @@ exprs
| Test.java:5:19:5:25 | Integer | Integer |
| Test.java:5:38:5:44 | Integer | Integer |
| Test.java:5:58:5:58 | p | Integer |
| user.kt:2:7:2:7 | x | int |
| user.kt:2:3:2:16 | x | int |
| user.kt:2:11:2:11 | t | Test |
| user.kt:2:11:2:16 | f(...) | Integer |
| user.kt:2:11:2:16 | <Call to unknown method> | int |
| user.kt:2:13:2:16 | <implicit not null> | int |
| user.kt:2:13:2:16 | int | int |
| user.kt:2:15:2:15 | 5 | int |

View File

@@ -1,2 +1,2 @@
| user.kt:3:14:3:22 | getF(...) | lib/lib/TestKt.class:0:0:0:0 | getF |
| user.kt:3:26:3:28 | getF(...) | lib/lib/TestKt.class:0:0:0:0 | getF |
| user.kt:3:14:3:22 | getF(...) | file:///!unknown-binary-location/lib/TestKt.class:0:0:0:0 | getF |
| user.kt:3:26:3:28 | getF(...) | file:///!unknown-binary-location/lib/TestKt.class:0:0:0:0 | getF |

View File

@@ -1,3 +1,2 @@
| AKt.class:0:0:0:0 | AKt | true |
| B.kt:0:0:0:0 | BKt | true |
| C.kt:1:1:3:1 | C | false |

View File

@@ -1,4 +0,0 @@
| equals | Test |
| hashCode | Test |
| toString | Test |
| toString | java.lang.CharSequence |

View File

@@ -0,0 +1,9 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43828 of field callee is not in type @callable. Appears in tuple (-16776213,43828)
Relevant element: callee=43828
Full ID for 43828: @"callable;(0).takesComparable((35),(35))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.takesComparable({@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"},{@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"}){@"type;void"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43832 of field callee is not in type @callable. Appears in tuple (-16776208,43832)
Relevant element: callee=43832
Full ID for 43832: @"callable;(0).takesArrayOfComparable((54),(54))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.takesArrayOfComparable({@"array;1;{@"class;java.lang.Comparable;{@"wildcard;super(19)"}"}"},{@"array;1;{@"class;java.lang.Comparable;{@"wildcard;super(19)"}"}"}){@"type;void"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43837 of field callee is not in type @callable. Appears in tuple (-16776201,43837)
Relevant element: callee=43837
Full ID for 43837: @"callable;(0).<init>((35),(35))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.<init>({@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"},{@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"}){@"type;void"}"

View File

@@ -8,16 +8,16 @@
| JavaDefns | takesComparable | invar | Comparable<CharSequence> |
| JavaDefns | takesNestedComparable | innerContravar | Comparable<Comparable<? super CharSequence>> |
| JavaDefns | takesNestedComparable | outerContravar | Comparable<? super Comparable<CharSequence>> |
| JavaDefns2 | JavaDefns2 | p0 | Comparable<CharSequence> |
| JavaDefns2 | JavaDefns2 | p0 | Comparable<? super CharSequence> |
| JavaDefns2 | JavaDefns2 | p1 | Comparable<? super CharSequence> |
| JavaDefns2 | returnsInvariant | return | Comparable<CharSequence> |
| JavaDefns2 | returnsWildcard | return | Comparable<? super CharSequence> |
| JavaDefns2 | takesArrayOfComparable | p0 | Comparable<CharSequence>[] |
| JavaDefns2 | takesArrayOfComparable | p0 | Comparable<? super CharSequence>[] |
| JavaDefns2 | takesArrayOfComparable | p1 | Comparable<? super CharSequence>[] |
| JavaDefns2 | takesComparable | p0 | Comparable<CharSequence> |
| JavaDefns2 | takesComparable | p0 | Comparable<? super CharSequence> |
| JavaDefns2 | takesComparable | p1 | Comparable<? super CharSequence> |
| JavaDefns2 | takesNestedComparable | p0 | Comparable<Comparable<? super CharSequence>> |
| JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<CharSequence>> |
| JavaDefns2 | takesNestedComparable | p0 | Comparable<? super Comparable<? super CharSequence>> |
| JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<? super CharSequence>> |
| KotlinDefns | returnsContravar | return | Comparable<CharSequence> |
| KotlinDefns | returnsContravarForced | return | Comparable<? super CharSequence> |
| KotlinDefns | returnsCovar | return | List<CharSequence> |

View File

@@ -0,0 +1,16 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776495,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776429,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776357,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776266,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776200,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): More errors, not displayed. There are 16 values of field callee that are not in type @callable for a relation of size 1821

View File

@@ -0,0 +1,31 @@
| Test.java:137:22:137:27 | source | Unexpected result: hasTaintFlow |
| Test.java:141:35:141:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:148:22:148:27 | source | Unexpected result: hasTaintFlow |
| Test.java:152:35:152:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:159:22:159:27 | source | Unexpected result: hasTaintFlow |
| Test.java:163:35:163:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:178:35:178:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:181:35:181:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:189:35:189:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:192:35:192:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:200:35:200:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:203:35:203:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:362:22:362:27 | source | Unexpected result: hasTaintFlow |
| Test.java:366:35:366:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:373:22:373:27 | source | Unexpected result: hasTaintFlow |
| Test.java:377:35:377:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:384:22:384:27 | source | Unexpected result: hasTaintFlow |
| Test.java:388:35:388:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:402:22:402:27 | source | Unexpected result: hasTaintFlow |
| Test.java:406:35:406:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:413:22:413:27 | source | Unexpected result: hasTaintFlow |
| Test.java:417:35:417:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:424:22:424:27 | source | Unexpected result: hasTaintFlow |
| Test.java:428:35:428:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:436:22:436:27 | source | Unexpected result: hasTaintFlow |
| Test.java:440:35:440:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:447:22:447:27 | source | Unexpected result: hasTaintFlow |
| Test.java:451:35:451:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:458:22:458:27 | source | Unexpected result: hasTaintFlow |
| Test.java:462:35:462:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:604:31:604:47 | // $ hasTaintFlow | Missing result: hasTaintFlow |

View File

@@ -0,0 +1 @@
| CleartextStorageSharedPrefsTest.java:110:84:110:118 | // $ hasCleartextStorageSharedPrefs | Missing result: hasCleartextStorageSharedPrefs |

View File

@@ -0,0 +1,6 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 80453 of field callee is not in type @callable. Appears in tuple (-16773210,80453)
Relevant element: callee=80453
Full ID for 80453: @"callable;(846).toString()(21)". The ID may expand to @"callable;{@"class;java.lang.CharSequence"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 80453 of field callee is not in type @callable. Appears in tuple (-16773194,80453)
Relevant element: callee=80453
Full ID for 80453: @"callable;(846).toString()(21)". The ID may expand to @"callable;{@"class;java.lang.CharSequence"}.toString(){@"class;java.lang.String"}"