Skip to content

Commit 245cd5c

Browse files
authored
Merge pull request github#15760 from asgerf/js/summarised-tt-store-steps
JS: Summarise store steps for type tracking
2 parents a9bab18 + fc5b9e2 commit 245cd5c

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ private module Cached {
4545
CopyStep(PropertyName prop) or
4646
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
4747
SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp)
48+
or
49+
summarizedLoadStoreStep(_, _, fromProp, toProp)
4850
} or
4951
WithoutPropStep(PropertySet props) { SharedTypeTrackingStep::withoutPropStep(_, _, props) }
5052
}
@@ -69,6 +71,26 @@ private module Cached {
6971
AccessPath::isAssignedInUniqueFile(global)
7072
}
7173

74+
bindingset[fun]
75+
pragma[inline_late]
76+
private DataFlow::PropRead getStoredPropRead(DataFlow::FunctionNode fun, string storeProp) {
77+
result = fun.getAReturn().getALocalSource().getAPropertySource(storeProp)
78+
}
79+
80+
/**
81+
* Holds if `loadProp` of `param` is stored in the `storeProp` property of the return value of `fun`.
82+
*/
83+
pragma[nomagic]
84+
private predicate summarizedLoadStoreStep(
85+
DataFlow::ParameterNode param, DataFlow::FunctionNode fun, string loadProp, string storeProp
86+
) {
87+
exists(DataFlow::PropRead read |
88+
read = getStoredPropRead(fun, storeProp) and
89+
read.getBase().getALocalSource() = param and
90+
read.getPropertyName() = loadProp
91+
)
92+
}
93+
7294
/**
7395
* INTERNAL: Use `TypeBackTracker.smallstep()` instead.
7496
*/
@@ -156,6 +178,14 @@ private module Cached {
156178
exists(string prop |
157179
param.getAPropertyRead(prop).flowsTo(fun.getAReturn()) and
158180
summary = LoadStep(prop)
181+
or
182+
fun.getAReturn().getALocalSource().getAPropertySource(prop) = param and
183+
summary = StoreStep(prop)
184+
)
185+
or
186+
exists(string loadProp, string storeProp |
187+
summarizedLoadStoreStep(param, fun, loadProp, storeProp) and
188+
summary = LoadStoreStep(loadProp, storeProp)
159189
)
160190
) and
161191
if param = fun.getAParameter()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'dummy';
2+
3+
function identity(x) {
4+
return x;
5+
}
6+
function load(x) {
7+
return x.loadProp;
8+
}
9+
function store(x) {
10+
return { storeProp: x };
11+
}
12+
function loadStore(x) {
13+
return { storeProp: x.loadProp };
14+
}
15+
function loadStore2(x) {
16+
let mid = x.loadProp;
17+
return { storeProp: mid };
18+
}
19+
20+
identity({});
21+
load({});
22+
store({});
23+
loadStore({});
24+
loadStore2({});
25+
26+
const obj = {}; // name: obj
27+
28+
let x = identity(obj);
29+
x; // track: obj
30+
31+
x = load({ loadProp: obj });
32+
x; // track: obj
33+
34+
x = store(obj);
35+
x.storeProp; // track: obj
36+
37+
x = loadStore({ loadProp: obj });
38+
x.storeProp; // track: obj
39+
40+
x = loadStore2({ loadProp: obj });
41+
x.storeProp; // track: obj

0 commit comments

Comments
 (0)