-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathVariableWithFields.qll
More file actions
205 lines (186 loc) · 6.87 KB
/
VariableWithFields.qll
File metadata and controls
205 lines (186 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/** Provides the `VariableWithFields` class, for working with variables with a chain of field or element accesses chained to it. */
overlay[local]
module;
import go
private newtype TVariableWithFields =
TVariableRoot(Variable v) or
TVariableFieldStep(VariableWithFields base, Field f) {
exists(fieldAccessPathAux(base, f)) or exists(fieldWriteAccessPathAux(base, f))
} or
TVariableElementStep(VariableWithFields base, string e) {
exists(elementAccessPathAux(base, e)) or exists(elementWriteAccessPathAux(base, e))
}
/**
* Gets a representation of the write target `wt` as a variable with fields value if there is one.
*/
private TVariableWithFields writeAccessPath(IR::WriteTarget wt) {
exists(Variable v | wt = v.getAWrite().getLhs() | result = TVariableRoot(v))
or
exists(VariableWithFields base, Field f | wt = fieldWriteAccessPathAux(base, f) |
result = TVariableFieldStep(base, f)
)
or
exists(VariableWithFields base, string e | wt = elementWriteAccessPathAux(base, e) |
result = TVariableElementStep(base, e)
)
}
/**
* Gets a representation of `insn` as a variable with fields value if there is one.
*/
private TVariableWithFields accessPath(IR::Instruction insn) {
exists(Variable v | insn = v.getARead().asInstruction() | result = TVariableRoot(v))
or
exists(VariableWithFields base, Field f | insn = fieldAccessPathAux(base, f) |
result = TVariableFieldStep(base, f)
)
or
exists(VariableWithFields base, string e | insn = elementAccessPathAux(base, e) |
result = TVariableElementStep(base, e)
)
}
/**
* Gets an IR instruction that reads a field `f` from a node that is represented
* by variable with fields value `base`.
*/
private IR::Instruction fieldAccessPathAux(TVariableWithFields base, Field f) {
exists(IR::FieldReadInstruction fr, IR::Instruction frb |
fr.getBase() = frb or
fr.getBase() = IR::implicitDerefInstruction(frb.(IR::EvalInstruction).getExpr())
|
base = accessPath(frb) and
f = fr.getField() and
result = fr
)
}
/**
* Gets an IR write target that represents a field `f` from a node that is represented
* by variable with fields value `base`.
*/
private IR::WriteTarget fieldWriteAccessPathAux(TVariableWithFields base, Field f) {
exists(IR::FieldTarget ft, IR::Instruction ftb |
ft.getBase() = ftb or
ft.getBase() = IR::implicitDerefInstruction(ftb.(IR::EvalInstruction).getExpr())
|
base = accessPath(ftb) and
ft.getField() = f and
result = ft
)
}
/**
* Gets an IR instruction that reads an element `e` from a node that is represented
* by variable with fields value `base`.
*/
private IR::Instruction elementAccessPathAux(TVariableWithFields base, string e) {
exists(IR::ElementReadInstruction er, IR::EvalInstruction erb |
er.getBase() = erb or
er.getBase() = IR::implicitDerefInstruction(erb.getExpr())
|
base = accessPath(erb) and
e = er.getIndex().getExactValue() and
result = er
)
}
/**
* Gets an IR write target that represents an element `e` from a node that is represented
* by variable with fields value `base`.
*/
private IR::WriteTarget elementWriteAccessPathAux(TVariableWithFields base, string e) {
exists(IR::ElementTarget et, IR::EvalInstruction etb |
et.getBase() = etb or
et.getBase() = IR::implicitDerefInstruction(etb.getExpr())
|
base = accessPath(etb) and
e = et.getIndex().getExactValue() and
result = et
)
}
/** A variable with zero or more fields or elements read from it. */
class VariableWithFields extends TVariableWithFields {
/**
* Gets the variable corresponding to the base of this variable with fields.
*
* For example, the variable corresponding to `a` for the variable with fields
* corresponding to `a.b[c]`.
*/
Variable getBaseVariable() { this.getParent*() = TVariableRoot(result) }
/**
* Gets the variable with fields corresponding to the parent of this variable with fields.
*
* For example, the variable with fields corresponding to `a.b` for the variable with fields
* corresponding to `a.b[c]`.
*/
VariableWithFields getParent() {
exists(VariableWithFields base |
this = TVariableFieldStep(base, _) or this = TVariableElementStep(base, _)
|
result = base
)
}
/** Gets a use that refers to this variable with fields. */
DataFlow::Node getAUse() { this = accessPath(result.asInstruction()) }
/** Gets the type of this variable with fields. */
Type getType() {
exists(IR::Instruction acc | this = accessPath(acc) | result = acc.getResultType())
}
/** Gets a textual representation of this element. */
string toString() {
exists(Variable var | this = TVariableRoot(var) | result = "(" + var + ")")
or
exists(VariableWithFields base, Field f | this = TVariableFieldStep(base, f) |
result = base + "." + f.getName()
)
or
exists(VariableWithFields base, string e | this = TVariableElementStep(base, e) |
result = base + "[" + e + "]"
)
}
/**
* Gets the qualified name of the source variable or variable and fields that this represents.
*
* For example, for the variable with fields that represents the field `a.b[c]`, this would get the string
* `"a.b.c"`.
*/
string getQualifiedName() {
exists(Variable v | this = TVariableRoot(v) | result = v.getName())
or
exists(VariableWithFields base, Field f | this = TVariableFieldStep(base, f) |
result = base.getQualifiedName() + "." + f.getName()
)
or
exists(VariableWithFields base, string e | this = TVariableElementStep(base, e) |
result = base.getQualifiedName() + "." + e.replaceAll(".", "\\.")
)
}
/**
* Gets a write of this variable with fields.
*/
Write getAWrite() { this = writeAccessPath(result.getLhs()) }
/**
* Gets the field that is the last step of this variable with fields, if any.
*
* For example, the field `c` for the variable with fields `a.b.c`.
*/
Field getField() { this = TVariableFieldStep(_, result) }
/**
* Gets the element that this variable with fields reads, if any.
*
* For example, the string value of `c` for the variable with fields `a.b[c]`.
*/
string getElement() { this = TVariableElementStep(_, result) }
/** Gets the location of this variable with fields. */
Location getLocation() { result = this.getBaseVariable().getLocation() }
/**
* DEPRECATED: Use `getLocation()` instead.
*
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
deprecated predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}