Skip to content

Java: Add manual overlay annotations & discard predicates #19813

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: kaspersv/overlay-java-annotations
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions java/ql/lib/java.qll
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import semmle.code.java.KotlinType
import semmle.code.java.Member
import semmle.code.java.Modifier
import semmle.code.java.Modules
import semmle.code.java.Overlay
import semmle.code.java.Package
import semmle.code.java.Statement
import semmle.code.java.Type
Expand Down
13 changes: 13 additions & 0 deletions java/ql/lib/semmle/code/Location.qll
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,16 @@ private predicate fixedHasLocation(Top l, Location loc, File f) {
not hasSourceLocation(l, _, _) and
locations_default(loc, f, _, _, _, _)
}

overlay[local]
private predicate discardableLocation(string file, @location l) {
not isOverlay() and
file = getRawFileForLoc(l) and
not exists(@file f | hasLocation(f, l))
}

/** Discard base locations in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardLocation(@location l) {
exists(string file | discardableLocation(file, l) and extractedInOverlay(file))
}
12 changes: 12 additions & 0 deletions java/ql/lib/semmle/code/java/Expr.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2701,3 +2701,15 @@ class RecordPatternExpr extends Expr, @recordpatternexpr {
)
}
}

overlay[local]
private predicate discardableExpr(string file, @expr e) {
not isOverlay() and
file = getRawFile(e)
}

/** Discard base expressions in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardExpr(@expr e) {
exists(string file | discardableExpr(file, e) and extractedInOverlay(file))
}
12 changes: 12 additions & 0 deletions java/ql/lib/semmle/code/java/Javadoc.qll
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,15 @@ class KtCommentSection extends @ktcommentsection {
/** Gets the string representation of this section. */
string toString() { result = this.getContent() }
}

overlay[local]
private predicate discardableJavadoc(string file, @javadoc d) {
not isOverlay() and
exists(@member m | file = getRawFile(m) and hasJavadoc(m, d))
}

/** Discard javadoc entities in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardJavadoc(@javadoc d) {
exists(string file | discardableJavadoc(file, d) and extractedInOverlay(file))
}
38 changes: 37 additions & 1 deletion java/ql/lib/semmle/code/java/Member.qll
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,13 @@ class SrcMethod extends Method {
then implementsInterfaceMethod(result, this)
else result.getASourceOverriddenMethod*() = this
) and
(exists(result.getBody()) or result.hasModifier("native"))
(
// We allow empty method bodies for the local overlay variant to allow
// calls to methods only fully extracted in base.
isOverlay() or
exists(result.getBody()) or
result.hasModifier("native")
)
}
}

Expand Down Expand Up @@ -897,3 +903,33 @@ class ExtensionMethod extends Method {
else result = 0
}
}

overlay[local]
private predicate discardableMethod(string file, @method m) {
not isOverlay() and
file = getRawFile(m) and
exists(@classorinterface c | methods(m, _, _, _, c, _) and isAnonymClass(c, _))
}

/** Discard base methods on anonymous classes in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardAnonMethod(@method m) {
exists(string file | discardableMethod(file, m) and extractedInOverlay(file))
}

overlay[local]
private predicate discardableBaseMethod(string file, @method m) {
not isOverlay() and
file = getRawFile(m)
}

overlay[local]
private predicate usedOverlayMethod(@method m) { isOverlay() and methods(m, _, _, _, _, _) }

/** Discard base methods in files fully extracted in the overlay that were not extracted in the overlay. */
overlay[discard_entity]
private predicate discardMethod(@method m) {
exists(string file |
discardableBaseMethod(file, m) and extractedInOverlay(file) and not usedOverlayMethod(m)
)
}
39 changes: 39 additions & 0 deletions java/ql/lib/semmle/code/java/Overlay.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
overlay[local?]
module;

import java

/**
* A local predicate that always holds for the overlay variant and
* never holds for the base variant. This is used to define local
* predicates that behave differently for the base and overlay variant.
*/
overlay[local]
predicate isOverlay() { databaseMetadata("isOverlay", "true") }

/** Gets the raw file for a locatable. */
overlay[local]
string getRawFile(@locatable el) {
exists(@location loc, @file file |
hasLocation(el, loc) and
locations_default(loc, file, _, _, _, _) and
files(file, result)
)
}

/** Gets the raw file for a location. */
overlay[local]
string getRawFileForLoc(@location l) {
exists(@file f | locations_default(l, f, _, _, _, _) and files(f, result))
}

/** Holds for files fully extracted in the overlay. */
overlay[local]
predicate extractedInOverlay(string file) {
isOverlay() and
// The incremental Java extractor extracts skeletons without method
// bodies for dependencies. To approximate fully extracted files in
// the overlay, we restrict attention to files that contain an expression
// with an enclosing callable.
exists(@expr e | callableEnclosingExpr(e, _) and file = getRawFile(e))
}
12 changes: 12 additions & 0 deletions java/ql/lib/semmle/code/java/Statement.qll
Original file line number Diff line number Diff line change
Expand Up @@ -987,3 +987,15 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr

override string getAPrimaryQlClass() { result = "SuperConstructorInvocationStmt" }
}

overlay[local]
private predicate discardableStmt(string file, @stmt s) {
not isOverlay() and
file = getRawFile(s)
}

/** Discard base statements in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardStmt(@stmt s) {
exists(string file | discardableStmt(file, s) and extractedInOverlay(file))
}
12 changes: 12 additions & 0 deletions java/ql/lib/semmle/code/java/Variable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,15 @@ class Parameter extends Element, @param, LocalScopeVariable {
/** Holds if this is an anonymous parameter, `_` */
predicate isAnonymous() { this.getName() = "" }
}

overlay[local]
private predicate discardableLocalVarDecl(string file, @localscopevariable l) {
not isOverlay() and
file = getRawFile(l)
}

/** Discard base local scoped variables in files fully extracted in the overlay. */
overlay[discard_entity]
private predicate discardLocalVarDecl(@localscopevariable l) {
exists(string file | discardableLocalVarDecl(file, l) and extractedInOverlay(file))
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Callable exactCallable(Call c) {
private predicate implCount(MethodCall m, int c) { strictcount(viableImpl(m)) = c }

/** Gets a viable implementation of the target of the given `Call`. */
overlay[local]
Callable viableCallable(Call c) {
result = viableImpl(c)
or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.security.Sanitizers
import Log4jInjectionFlow::PathGraph

overlay[local?]
deprecated private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "log4j-injection" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.ExternalFlow
import RemoteUrlToOpenStreamFlow::PathGraph

overlay[local?]
deprecated private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "openstream-called-on-tainted-url" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import semmle.code.java.security.PathSanitizer
private import semmle.code.java.security.Sanitizers
import InjectFilePathFlow::PathGraph

overlay[local?]
deprecated private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "file-path-injection" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import semmle.code.java.security.CommandLineQuery
import InputToArgumentToExecFlow::PathGraph
private import semmle.code.java.dataflow.ExternalFlow

overlay[local?]
deprecated private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "jsch-os-injection" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.frameworks.android.WebView

overlay[local?]
private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "android-web-resource-response" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import semmle.code.java.arithmetic.Overflow
import semmle.code.java.dataflow.FlowSteps
import semmle.code.java.controlflow.Guards

overlay[local?]
private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "thread-resource-abuse" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import semmle.code.java.controlflow.Guards
import semmle.code.java.security.UrlRedirect
import Regex

overlay[local?]
private class ActivateModels extends ActiveExperimentalModels {
ActivateModels() { this = "permissive-dot-regex-query" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
* callable of `lambdaCall`.
*/
overlay[global]
pragma[nomagic]
predicate revLambdaFlow(
Call lambdaCall, LambdaCallKind kind, Node node, Type t, boolean toReturn, boolean toJump,
Expand Down