mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Java: Use the instance argument type in call contexts.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
private import java
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import semmle.code.java.dataflow.InstanceAccess
|
||||
import semmle.code.java.dispatch.VirtualDispatch
|
||||
|
||||
private module DispatchImpl {
|
||||
@@ -17,6 +19,13 @@ private module DispatchImpl {
|
||||
not p.isVarargs() and
|
||||
c = ma.getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
exists(OwnInstanceAccess ia |
|
||||
2 <= strictcount(viableImpl(ma)) and
|
||||
(ia.isExplicit(ma.getQualifier()) or ia.isImplicitMethodQualifier(ma)) and
|
||||
i = -1 and
|
||||
c = ma.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,18 +46,32 @@ private module DispatchImpl {
|
||||
* relevant call context.
|
||||
*/
|
||||
private predicate contextArgHasType(Call ctx, int i, RefType t, boolean exact) {
|
||||
exists(Expr arg, Expr src |
|
||||
relevantContext(ctx, i) and
|
||||
ctx.getArgument(i) = arg and
|
||||
src = variableTrack(arg) and
|
||||
exists(RefType srctype | srctype = src.getType() |
|
||||
exists(TypeVariable v | v = srctype |
|
||||
t = v.getUpperBoundType+() and not t instanceof TypeVariable
|
||||
)
|
||||
relevantContext(ctx, i) and
|
||||
exists(RefType srctype |
|
||||
exists(Expr arg, Expr src |
|
||||
i = -1 and
|
||||
ctx.getQualifier() = arg
|
||||
or
|
||||
t = srctype and not srctype instanceof TypeVariable
|
||||
) and
|
||||
if src instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
ctx.getArgument(i) = arg
|
||||
|
|
||||
src = variableTrack(arg) and
|
||||
srctype = src.getType() and
|
||||
if src instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
or
|
||||
exists(Node arg |
|
||||
i = -1 and
|
||||
not exists(ctx.getQualifier()) and
|
||||
getInstanceArgument(ctx) = arg and
|
||||
arg.getTypeBound() = srctype and
|
||||
if ctx instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
|
|
||||
exists(TypeVariable v | v = srctype |
|
||||
t = v.getUpperBoundType+() and not t instanceof TypeVariable
|
||||
)
|
||||
or
|
||||
t = srctype and not srctype instanceof TypeVariable
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
63
java/ql/test/library-tests/dataflow/callctx/A.java
Normal file
63
java/ql/test/library-tests/dataflow/callctx/A.java
Normal file
@@ -0,0 +1,63 @@
|
||||
public class A {
|
||||
static void sink(Object x) { }
|
||||
|
||||
static Object source() { return null; }
|
||||
|
||||
static class C1 {
|
||||
C1() { }
|
||||
|
||||
C1(Object x) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
void wrapFoo1(Object x) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
void wrapFoo2(Object x) {
|
||||
this.foo(x);
|
||||
}
|
||||
|
||||
void foo(Object x) {
|
||||
Object c1 = x;
|
||||
sink(c1);
|
||||
}
|
||||
}
|
||||
|
||||
static class C2 extends C1 {
|
||||
C2() { }
|
||||
|
||||
C2(Object x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
void foo(Object x) {
|
||||
Object c2 = x;
|
||||
sink(c2);
|
||||
}
|
||||
|
||||
void callWrapFoo2() {
|
||||
wrapFoo2(source());
|
||||
}
|
||||
}
|
||||
|
||||
static void wrapFoo3(C1 c1, Object x) {
|
||||
c1.foo(x);
|
||||
}
|
||||
|
||||
void test(C1 c) {
|
||||
c.wrapFoo1(source());
|
||||
c.wrapFoo2(source());
|
||||
wrapFoo3(c, source());
|
||||
|
||||
new C1(source());
|
||||
new C1().wrapFoo1(source());
|
||||
new C1().wrapFoo2(source());
|
||||
wrapFoo3(new C1(), source());
|
||||
|
||||
new C2(source());
|
||||
new C2().wrapFoo1(source());
|
||||
new C2().wrapFoo2(source());
|
||||
wrapFoo3(new C2(), source());
|
||||
}
|
||||
}
|
||||
15
java/ql/test/library-tests/dataflow/callctx/test.expected
Normal file
15
java/ql/test/library-tests/dataflow/callctx/test.expected
Normal file
@@ -0,0 +1,15 @@
|
||||
| A.java:40:16:40:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:49:16:49:23 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:49:16:49:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:50:16:50:23 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:50:16:50:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:51:17:51:24 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:51:17:51:24 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:53:12:53:19 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:54:23:54:30 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:55:23:55:30 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:56:24:56:31 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:58:12:58:19 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:59:23:59:30 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:60:23:60:30 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:61:24:61:31 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
15
java/ql/test/library-tests/dataflow/callctx/test.ql
Normal file
15
java/ql/test/library-tests/dataflow/callctx/test.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "qqconf" }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") }
|
||||
|
||||
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
}
|
||||
|
||||
from Node src, Node sink, Conf c
|
||||
where c.hasFlow(src, sink)
|
||||
select src, sink
|
||||
Reference in New Issue
Block a user