Skip to content

Commit 38a3476

Browse files
committed
Ruby: add local field step to type tracking
fixup local field steps
1 parent d55925d commit 38a3476

File tree

1 file changed

+61
-1
lines changed

1 file changed

+61
-1
lines changed

ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,67 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
102102
}
103103

104104
/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
105-
predicate levelStep(Node nodeFrom, Node nodeTo) { summarizedLocalStep(nodeFrom, nodeTo) }
105+
predicate levelStep(Node nodeFrom, Node nodeTo) {
106+
summarizedLocalStep(nodeFrom, nodeTo)
107+
or
108+
localFieldStep(nodeFrom, nodeTo)
109+
}
110+
111+
/**
112+
* Gets a method of `mod`, with `instance` indicating if this is an instance method.
113+
*
114+
* Does not take inheritance or the various forms of inclusion into account.
115+
*/
116+
pragma[nomagic]
117+
private MethodBase getAMethod(ModuleBase mod, boolean instance) {
118+
not mod instanceof SingletonClass and
119+
result = mod.getAMethod() and
120+
if result instanceof SingletonMethod then instance = false else instance = true
121+
or
122+
exists(SingletonClass cls |
123+
cls.getValue().(SelfVariableAccess).getCfgScope() = mod and
124+
result = cls.getAMethod().(Method) and
125+
instance = false
126+
)
127+
}
128+
129+
/**
130+
* Gets a value flowing into `field` in `mod`, with `instance` indicating if it's
131+
* a field on an instance of `mod` (as opposed to the module object itself).
132+
*/
133+
pragma[nomagic]
134+
private Node fieldPredecessor(ModuleBase mod, boolean instance, string field) {
135+
exists(InstanceVariableWriteAccess access, AssignExpr assign |
136+
access.getReceiver().getCfgScope() = getAMethod(mod, instance) and
137+
field = access.getVariable().getName() and
138+
assign.getLeftOperand() = access and
139+
result.asExpr().getExpr() = assign.getRightOperand()
140+
)
141+
}
142+
143+
/**
144+
* Gets a reference to `field` in `mod`, with `instance` indicating if it's
145+
* a field on an instance of `mod` (as opposed to the module object itself).
146+
*/
147+
pragma[nomagic]
148+
private Node fieldSuccessor(ModuleBase mod, boolean instance, string field) {
149+
exists(InstanceVariableReadAccess access |
150+
access.getReceiver().getCfgScope() = getAMethod(mod, instance) and
151+
result.asExpr().getExpr() = access and
152+
field = access.getVariable().getName()
153+
)
154+
}
155+
156+
/**
157+
* Holds if `pred -> succ` should be used a level step, from a field assignment to
158+
* a read within the same class.
159+
*/
160+
private predicate localFieldStep(Node pred, Node succ) {
161+
exists(ModuleBase mod, boolean instance, string field |
162+
pred = fieldPredecessor(mod, instance, field) and
163+
succ = fieldSuccessor(mod, instance, field)
164+
)
165+
}
106166

107167
pragma[noinline]
108168
private predicate argumentPositionMatch(

0 commit comments

Comments
 (0)