JS: Add test

This commit is contained in:
Asger F
2019-03-06 12:50:59 +00:00
parent e6a1374218
commit 3422fa328d
6 changed files with 212 additions and 4 deletions

View File

@@ -103,10 +103,11 @@ module StepSummary {
// Flow out of function
returnStep(predNode, succ) and
summary = return()
or
// Flow through an instance field between members of the same class
DataFlow::localFieldStep(predNode, succ) and
summary = level()
)
or
DataFlow::localFieldStep(pred, succ) and
summary = level()
}
/**
@@ -207,7 +208,7 @@ private newtype TTypeBackTracker = MkTypeBackTracker(boolean hasReturn) {
* ```
* DataFlow::SourceNode myCallback(DataFlow::TypeBackTracker t) {
* t.start() and
* result = (< some API call >).getParameter(< n >).getALocalSource()
* result = (< some API call >).getArgument(< n >).getALocalSource()
* or
* exists (DataFlow::TypeTracker t2 |
* result = myCallback(t2).backtrack(t2, t)

View File

@@ -0,0 +1,15 @@
test_ApiObject
| tst.js:3:11:3:21 | new myapi() |
| tst.js:15:10:15:21 | api.chain1() |
| tst.js:15:10:15:30 | api.cha ... hain2() |
test_Connection
| tst.js:6:15:6:18 | conn |
| tst.js:10:5:10:19 | this.connection |
| tst.js:15:10:15:49 | api.cha ... ction() |
| tst.js:18:7:18:21 | getConnection() |
test_DataCallback
| tst.js:9:11:9:12 | cb |
| tst.js:20:1:22:1 | functio ... ata);\\n} |
test_DataValue
| tst.js:20:18:20:21 | data |
| tst.js:24:19:24:22 | data |

View File

@@ -0,0 +1,91 @@
import javascript
string chainableMethod() {
result = "chain1" or
result = "chain2"
}
class ApiObject extends DataFlow::NewNode {
ApiObject() {
this = DataFlow::moduleImport("@test/myapi").getAnInstantiation()
}
DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
result = this
or
t.start() and
result = ref(_).getAMethodCall(chainableMethod())
or
exists(DataFlow::TypeTracker t2 |
result = ref(t2).track(t2, t)
)
}
DataFlow::SourceNode ref() {
result = ref(_)
}
}
class Connection extends DataFlow::SourceNode {
ApiObject api;
Connection() {
this = api.ref().getAMethodCall("createConnection")
}
DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
result = this
or
exists(DataFlow::TypeTracker t2 |
result = ref(t2).track(t2, t)
)
}
DataFlow::SourceNode ref() {
result = ref(_)
}
DataFlow::SourceNode getACallbackNode(DataFlow::TypeBackTracker t) {
t.start() and
result = ref().getAMethodCall("getData").getArgument(0).getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 |
result = getACallbackNode(t2).backtrack(t2, t)
)
}
DataFlow::FunctionNode getACallback() {
result = getACallbackNode(_).getAFunctionValue()
}
}
class DataValue extends DataFlow::SourceNode {
Connection connection;
DataValue() {
this = connection.getACallback().getParameter(0)
}
DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
result = this
or
exists(DataFlow::TypeTracker t2 |
result = ref(t2).track(t2, t)
)
}
DataFlow::SourceNode ref() {
result = ref(_)
}
}
query DataFlow::SourceNode test_ApiObject() { result = any(ApiObject obj).ref() }
query DataFlow::SourceNode test_Connection() { result = any(Connection c).ref() }
query DataFlow::SourceNode test_DataCallback() { result = any(Connection c).getACallbackNode(_) }
query DataFlow::SourceNode test_DataValue() { result = any(DataValue v).ref() }

View File

@@ -0,0 +1,15 @@
apiObject
| tst.js:3:11:3:21 | new myapi() |
| tst.js:15:10:15:21 | api.chain1() |
| tst.js:15:10:15:30 | api.cha ... hain2() |
connection
| type tracker with call steps | tst.js:6:15:6:18 | conn |
| type tracker with call steps | tst.js:10:5:10:19 | this.connection |
| type tracker without call steps | tst.js:15:10:15:49 | api.cha ... ction() |
| type tracker without call steps | tst.js:18:7:18:21 | getConnection() |
dataCallback
| tst.js:9:11:9:12 | cb |
| tst.js:20:1:22:1 | functio ... ata);\\n} |
dataValue
| tst.js:20:18:20:21 | data |
| tst.js:24:19:24:22 | data |

View File

@@ -0,0 +1,61 @@
import javascript
string chainableMethod() {
result = "chain1" or
result = "chain2"
}
DataFlow::SourceNode apiObject(DataFlow::TypeTracker t) {
t.start() and
result = DataFlow::moduleImport("@test/myapi").getAnInstantiation()
or
t.start() and
result = apiObject(_).getAMethodCall(chainableMethod())
or
exists(DataFlow::TypeTracker t2 |
result = apiObject(t2).track(t2, t)
)
}
query DataFlow::SourceNode apiObject() {
result = apiObject(_)
}
query DataFlow::SourceNode connection(DataFlow::TypeTracker t) {
t.start() and
result = apiObject().getAMethodCall("createConnection")
or
exists(DataFlow::TypeTracker t2 |
result = connection(t2).track(t2, t)
)
}
DataFlow::SourceNode connection() {
result = connection(_)
}
DataFlow::SourceNode dataCallback(DataFlow::TypeBackTracker t) {
t.start() and
result = connection().getAMethodCall("getData").getArgument(0).getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 |
result = dataCallback(t2).backtrack(t2, t)
)
}
query DataFlow::SourceNode dataCallback() {
result = dataCallback(_)
}
DataFlow::SourceNode dataValue(DataFlow::TypeTracker t) {
t.start() and
result = dataCallback().getAFunctionValue().getParameter(0)
or
exists(DataFlow::TypeTracker t2 |
result = dataValue(t2).track(t2, t)
)
}
query DataFlow::SourceNode dataValue() {
result = dataValue(_)
}

View File

@@ -0,0 +1,25 @@
import myapi from "@test/myapi";
let api = new myapi();
class C {
constructor(conn) {
this.connection = conn;
}
getData(cb) {
this.connection.getData(cb);
}
}
function getConnection() {
return api.chain1().chain2().createConnection();
}
new C(getConnection()).getData(useData);
function useData(data) {
useData2(data);
}
function useData2(data) {
}