Summary
When a CodeQL Java database is built with buildMode: none and a lambda expression targets a method from a third-party library not on the classpath, the lambda's synthetic public method is not modelled as overriding the functional interface's abstract method. m.overrides(_) returns false for it, making it an unexpected match for any query that uses not m.overrides(_) to exclude interface implementations.
Environment
- CodeQL CLI: 2.25.6
- Language: Java
- Build mode:
none
Minimal reproduction
Directory layout:
lambda-override-bug/
├── qlpack.yml
├── LambdaNotOverride.ql
├── src/
│ └── Example.java ← source root for CodeQL
└── stub/
└── com/example/
└── ThirdParty.java ← only needed for the control case
Note: The stub must be outside src/ so that buildMode:none does not extract it. If it were inside src/, CodeQL would resolve com.example.ThirdParty from source and the bug would not reproduce.
qlpack.yml
name: lambda-bug-repro
version: 0.0.1
dependencies:
codeql/java-all: "*"
src/Example.java
class Example {
// Lambda targeting an unresolved third-party type.
void useThirdParty(com.example.ThirdParty obj) {
obj.onSuccess(result -> System.out.println(result));
}
// Lambda targeting a JDK type (always resolved — control).
void useJdk() {
java.util.stream.Stream.of("x").filter(s -> !s.isEmpty());
}
}
stub/com/example/ThirdParty.java
package com.example;
import java.util.function.Consumer;
public class ThirdParty {
public void onSuccess(Consumer<String> consumer) {}
}
LambdaNotOverride.ql
import java
from Method m
where
m.fromSource() and
m.isPublic() and
m.getDeclaringType() instanceof AnonymousClass and
not m.overrides(_)
select m, "Lambda synthetic method not modelled as override: " + m.getDeclaringType()
Steps to reproduce
cd lambda-override-bug
codeql pack install
# Bug: build without the stub (com.example.ThirdParty is unresolved)
codeql database create db-none --language=java --build-mode=none --source-root=src --overwrite
codeql query run --database db-none -- LambdaNotOverride.ql
# → 1 result: the lambda in useThirdParty() is returned
# Control: compile with the stub so ThirdParty resolves correctly
javac stub/com/example/ThirdParty.java -d stub-classes
mkdir -p classes
codeql database create db-compiled \
--language=java \
--command="javac -cp $(pwd)/stub-classes $(pwd)/src/Example.java -d $(pwd)/classes" \
--source-root=src --overwrite
codeql query run --database db-compiled -- LambdaNotOverride.ql
# → 0 results
Actual vs expected behaviour
| Scenario |
useThirdParty lambda overrides(_) |
useJdk lambda overrides(_) |
buildMode:none, ThirdParty unresolved |
false |
true |
Compiled, ThirdParty resolved via stub |
true |
true |
When the functional interface type cannot be resolved, CodeQL creates an anonymous class extending <TypeAccess of ErrorType>. With no known parent type, no override link is established and the synthetic public method leaks through guards like not m.overrides(_).
Impact
Any query that uses not m.overrides(_) to restrict results to non-overriding methods will produce false positives on lambda expressions in buildMode:none databases containing calls into third-party libraries.
Summary
When a CodeQL Java database is built with
buildMode: noneand a lambda expression targets a method from a third-party library not on the classpath, the lambda's syntheticpublicmethod is not modelled as overriding the functional interface's abstract method.m.overrides(_)returnsfalsefor it, making it an unexpected match for any query that usesnot m.overrides(_)to exclude interface implementations.Environment
noneMinimal reproduction
Directory layout:
qlpack.ymlsrc/Example.javastub/com/example/ThirdParty.javaLambdaNotOverride.qlSteps to reproduce
Actual vs expected behaviour
useThirdPartylambdaoverrides(_)useJdklambdaoverrides(_)buildMode:none,ThirdPartyunresolvedfalsetrueThirdPartyresolved via stubtruetrueWhen the functional interface type cannot be resolved, CodeQL creates an anonymous class extending
<TypeAccess of ErrorType>. With no known parent type, no override link is established and the syntheticpublicmethod leaks through guards likenot m.overrides(_).Impact
Any query that uses
not m.overrides(_)to restrict results to non-overriding methods will produce false positives on lambda expressions inbuildMode:nonedatabases containing calls into third-party libraries.