|
5 | 5 | private import javascript |
6 | 6 | private import semmle.javascript.dataflow.internal.StepSummary |
7 | 7 | private import semmle.javascript.dataflow.internal.PreCallGraphStep |
| 8 | +private import semmle.javascript.dataflow.internal.FlowSteps |
8 | 9 | private import semmle.javascript.internal.NameResolution |
9 | 10 |
|
10 | 11 | cached |
11 | 12 | module CallGraph { |
| 13 | + pragma[nomagic] |
| 14 | + private predicate shouldBackTrack(DataFlow::SourceNode node) { |
| 15 | + exists(DataFlow::Node rhs | rhs = node.getAPropertyWrite().getRhs().getALocalSource() | |
| 16 | + track(_) = rhs |
| 17 | + ) |
| 18 | + } |
| 19 | + |
| 20 | + pragma[nomagic] |
| 21 | + private DataFlow::SourceNode backtrackStoreTarget() { |
| 22 | + shouldBackTrack(result) |
| 23 | + or |
| 24 | + AccessPath::step(result.getALocalUse(), backtrackStoreTarget()) |
| 25 | + or |
| 26 | + propertyFlowStep(result.getALocalUse(), backtrackStoreTarget()) |
| 27 | + or |
| 28 | + storeReadStep(result, backtrackStoreTarget()) |
| 29 | + } |
| 30 | + |
| 31 | + pragma[nomagic] |
| 32 | + private predicate shouldTrack(DataFlow::SourceNode node) { |
| 33 | + node instanceof DataFlow::FunctionNode |
| 34 | + or |
| 35 | + node instanceof DataFlow::ClassNode |
| 36 | + or |
| 37 | + ( |
| 38 | + node instanceof DataFlow::ObjectLiteralNode or |
| 39 | + node instanceof DataFlow::InvokeNode or |
| 40 | + node instanceof DataFlow::ArrayLiteralNode |
| 41 | + ) and |
| 42 | + backtrackStoreTarget() = node |
| 43 | + } |
| 44 | + |
| 45 | + pragma[nomagic] |
| 46 | + private predicate deepStore(DataFlow::SourceNode node1, string prop, DataFlow::SourceNode node2) { |
| 47 | + track(node2).getAPropertyWrite(prop).getRhs().getALocalSource() = node1 |
| 48 | + } |
| 49 | + |
| 50 | + pragma[nomagic] |
| 51 | + private predicate deepRead(DataFlow::SourceNode node1, string prop, DataFlow::SourceNode node2) { |
| 52 | + track(node1).getAPropertyRead(prop) = node2 |
| 53 | + } |
| 54 | + |
| 55 | + pragma[nomagic] |
| 56 | + private predicate storeReadStep(DataFlow::SourceNode node1, DataFlow::SourceNode node2) { |
| 57 | + exists(DataFlow::SourceNode base, string name | |
| 58 | + deepStore(node1, name, base) and |
| 59 | + deepRead(base, name, node2) |
| 60 | + ) |
| 61 | + } |
| 62 | + |
| 63 | + pragma[nomagic] |
| 64 | + private DataFlow::SourceNode track(DataFlow::SourceNode source) { |
| 65 | + shouldTrack(source) and |
| 66 | + ( |
| 67 | + result = source |
| 68 | + or |
| 69 | + AccessPath::step(track(source).getALocalUse(), result) |
| 70 | + or |
| 71 | + propertyFlowStep(track(source).getALocalUse(), result) |
| 72 | + or |
| 73 | + storeReadStep(track(source), result) |
| 74 | + ) |
| 75 | + } |
| 76 | + |
12 | 77 | /** Gets the function referenced by `node`, as determined by the type inference. */ |
13 | 78 | cached |
14 | 79 | Function getAFunctionValue(AnalyzedNode node) { |
15 | | - result = node.getAValue().(AbstractCallable).getFunction() |
16 | | - or |
17 | | - node = NameResolution::trackFunctionValue(result).toDataFlowNodeOut() |
| 80 | + exists(DataFlow::FunctionNode func | |
| 81 | + result = func.getFunction() and |
| 82 | + track(func).getALocalUse() = node |
| 83 | + ) |
18 | 84 | or |
19 | | - exists(DataFlow::Node pred | |
20 | | - AccessPath::step(pred, node) and |
21 | | - result = getAFunctionValue(pred) |
| 85 | + exists(DataFlow::ClassNode cls | |
| 86 | + result = cls.getConstructor().getFunction() and |
| 87 | + track(cls).getALocalUse() = node |
22 | 88 | ) |
23 | 89 | } |
24 | 90 |
|
|
0 commit comments