Skip to content

Commit 40b0f68

Browse files
committed
Add backward dataflow edges through modelled function invocations.
Also add convenience abstract classes for easily modelling new functions as fluent or value-preserving.
1 parent fe07630 commit 40b0f68

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,36 @@ predicate hasNonlocalValue(FieldRead fr) {
368368
*/
369369
predicate localFlowStep(Node node1, Node node2) { simpleLocalFlowStep(node1, node2) }
370370

371+
/**
372+
* A method or constructor that returns the exact value of one of its parameters or the qualifier.
373+
*
374+
* Extend this class and override `returnsValue` to add additional value-preserving steps through a
375+
* method that should be added to the basic local flow step relation.
376+
*
377+
* These steps will be visible for all global data-flow purposes, as well as via
378+
* `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
379+
*/
380+
abstract class ValuePreservingCallable extends Callable {
381+
/**
382+
* Holds if this callable returns precisely the value passed into argument `arg`.
383+
* `arg` is a parameter index, or is -1 to indicate the qualifier.
384+
*/
385+
abstract predicate returnsValue(int arg);
386+
}
387+
388+
/**
389+
* A method or constructor that returns the exact value of its qualifier (e.g., `return this;`)
390+
*
391+
* Extend this class and override `returnsValue` to add additional value-preserving steps through a
392+
* method that should be added to the basic local flow step relation.
393+
*
394+
* These steps will be visible for all global data-flow purposes, as well as via
395+
* `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
396+
*/
397+
abstract class FluentMethod extends ValuePreservingCallable {
398+
override predicate returnsValue(int arg) { arg = -1 }
399+
}
400+
371401
/**
372402
* INTERNAL: do not use.
373403
*
@@ -408,6 +438,17 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
408438
or
409439
summaryStep(node1, node2, "value")
410440
or
441+
exists(MethodAccess ma, ValuePreservingCallable c, int argNo |
442+
ma.getCallee() = c and c.returnsValue(argNo)
443+
|
444+
node2.asExpr() = ma and
445+
(
446+
node1.asExpr() = ma.getArgument(argNo)
447+
or
448+
argNo = -1 and node1.asExpr() = ma.getQualifier()
449+
)
450+
)
451+
or
411452
exists(MethodAccess ma, Method m |
412453
ma = node2.asExpr() and
413454
m = ma.getMethod() and

java/ql/test/library-tests/dataflow/fluent-methods/Test.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ public Test fluentNoop() {
66
return this;
77
}
88

9+
public Test modelledFluentMethod() {
10+
// A model in the accompanying .ql file will indicate that the qualifier flows to the return value.
11+
return null;
12+
}
13+
14+
public static Test modelledIdentity(Test t) {
15+
// A model in the accompanying .ql file will indicate that the argument flows to the return value.
16+
return null;
17+
}
18+
919
public Test indirectlyFluentNoop() {
1020
return this.fluentNoop();
1121
}
@@ -47,4 +57,16 @@ public static void test3() {
4757
sink(t.get()); // $hasTaintFlow=y
4858
}
4959

60+
public static void testModel1() {
61+
Test t = new Test();
62+
t.indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
63+
sink(t.get()); // $hasTaintFlow=y
64+
}
65+
66+
public static void testModel2() {
67+
Test t = new Test();
68+
Test.modelledIdentity(t).indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
69+
sink(t.get()); // $hasTaintFlow=y
70+
}
71+
5072
}

java/ql/test/library-tests/dataflow/fluent-methods/flow.ql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import java
22
import semmle.code.java.dataflow.DataFlow
3+
import semmle.code.java.dataflow.FlowSteps
34
import TestUtilities.InlineExpectationsTest
45

56
class Conf extends DataFlow::Configuration {
@@ -14,6 +15,16 @@ class Conf extends DataFlow::Configuration {
1415
}
1516
}
1617

18+
class Model extends DataFlow::FluentMethod {
19+
Model() { this.getName() = "modelledFluentMethod" }
20+
}
21+
22+
class IdentityModel extends DataFlow::ValuePreservingCallable {
23+
IdentityModel() { this.getName() = "modelledIdentity" }
24+
25+
override predicate returnsValue(int arg) { arg = 0 }
26+
}
27+
1728
class HasFlowTest extends InlineExpectationsTest {
1829
HasFlowTest() { this = "HasFlowTest" }
1930

0 commit comments

Comments
 (0)