mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Java: Add proper support for variable capture flow.
This commit is contained in:
98
java/ql/test/library-tests/dataflow/capture/B.java
Normal file
98
java/ql/test/library-tests/dataflow/capture/B.java
Normal file
@@ -0,0 +1,98 @@
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
|
||||
public class B {
|
||||
static String source(String label) { return null; }
|
||||
|
||||
static void sink(String s) { }
|
||||
|
||||
static void test1() {
|
||||
List<String> l1 = new ArrayList<>();
|
||||
l1.add(source("L"));
|
||||
List<String> l2 = new ArrayList<>();
|
||||
l1.forEach(e -> l2.add(e));
|
||||
sink(l2.get(0)); // $ hasValueFlow=L
|
||||
}
|
||||
|
||||
String bf1;
|
||||
String bf2;
|
||||
|
||||
void test2() {
|
||||
B other = new B();
|
||||
Consumer<String> f = x -> { this.bf1 = x; bf2 = x; other.bf1 = x; };
|
||||
|
||||
// no flow
|
||||
sink(bf1);
|
||||
sink(this.bf2);
|
||||
sink(other.bf1);
|
||||
sink(other.bf2);
|
||||
|
||||
f.accept(source("T"));
|
||||
|
||||
sink(bf1); // $ MISSING: hasValueFlow=T
|
||||
sink(this.bf2); // $ MISSING: hasValueFlow=T
|
||||
sink(other.bf1); // $ hasValueFlow=T
|
||||
sink(other.bf2);
|
||||
}
|
||||
|
||||
static void convert(Map<String, String> inp, Map<String, String> out) {
|
||||
inp.forEach((key, value) -> { out.put(key, value); });
|
||||
}
|
||||
|
||||
void test3() {
|
||||
HashMap<String,String> m1 = new HashMap<>();
|
||||
HashMap<String,String> m2 = new HashMap<>();
|
||||
m1.put(source("Key"), source("Value"));
|
||||
convert(m1, m2);
|
||||
m2.forEach((k, v) -> {
|
||||
sink(k); // $ hasValueFlow=Key
|
||||
sink(v); // $ hasValueFlow=Value
|
||||
});
|
||||
}
|
||||
|
||||
String elem;
|
||||
|
||||
void testParamIn1() {
|
||||
elem = source("pin.This.elem");
|
||||
testParamIn2(source("pin.Arg"));
|
||||
}
|
||||
|
||||
void testParamIn2(String param) {
|
||||
Runnable r = () -> {
|
||||
sink(elem); // $ MISSING: hasValueFlow=pin.This.elem
|
||||
sink(this.elem); // $ MISSING: hasValueFlow=pin.This.elem
|
||||
sink(param); // $ hasValueFlow=pin.Arg
|
||||
};
|
||||
r.run();
|
||||
}
|
||||
|
||||
void testParamOut1() {
|
||||
B other = new B();
|
||||
testParamOut2(other);
|
||||
sink(elem); // $ MISSING: hasValueFlow=pout.This.elem
|
||||
sink(this.elem); // $ MISSING: hasValueFlow=pout.This.elem
|
||||
sink(other.elem); // $ hasValueFlow=pout.param
|
||||
}
|
||||
|
||||
void testParamOut2(B param) {
|
||||
Runnable r = () -> {
|
||||
this.elem = source("pout.This.elem");
|
||||
param.elem = source("pout.param");
|
||||
};
|
||||
r.run();
|
||||
}
|
||||
|
||||
void testCrossLambda() {
|
||||
B b = new B();
|
||||
Runnable sink1 = () -> { sink(b.elem); };
|
||||
Runnable sink2 = () -> { sink(b.elem); }; // $ hasValueFlow=src
|
||||
Runnable src = () -> { b.elem = source("src"); };
|
||||
doRun(sink1);
|
||||
doRun(src);
|
||||
doRun(sink2);
|
||||
}
|
||||
|
||||
void doRun(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import TestUtilities.InlineFlowTest
|
||||
@@ -1,6 +1,7 @@
|
||||
| A.java:14:14:14:16 | "A" | A.java:14:14:14:16 | "A" |
|
||||
| A.java:14:14:14:16 | "A" | A.java:15:16:15:22 | get(...) |
|
||||
| A.java:14:14:14:16 | "A" | A.java:18:8:18:15 | p |
|
||||
| A.java:14:14:14:16 | "A" | A.java:18:8:18:15 | p [post update] |
|
||||
| A.java:14:14:14:16 | "A" | A.java:32:26:32:26 | p |
|
||||
| A.java:21:11:21:13 | "B" | A.java:15:16:15:22 | get(...) |
|
||||
| A.java:21:11:21:13 | "B" | A.java:21:7:21:13 | ...=... |
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
StringLiteral src() { result.getCompilationUnit().fromSource() }
|
||||
StringLiteral src() {
|
||||
result.getCompilationUnit().fromSource() and
|
||||
result.getFile().toString() = "A"
|
||||
}
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() = src() }
|
||||
|
||||
Reference in New Issue
Block a user