@@ -118,6 +118,16 @@ module StepSummary {
118118 not ( type .hasCall ( ) = true and summary .hasReturn ( ) = true ) and
119119 result .hasCall ( ) = type .hasCall ( ) .booleanOr ( summary .hasCall ( ) )
120120 }
121+
122+ /**
123+ * INTERNAL. Do not use.
124+ *
125+ * Prepends a step summary before a backwards type-tracking summary.
126+ */
127+ TypeBackTracker prepend ( StepSummary summary , TypeBackTracker type ) {
128+ not ( type .hasReturn ( ) = true and summary .hasCall ( ) = true ) and
129+ result .hasReturn ( ) = type .hasReturn ( ) .booleanOr ( summary .hasReturn ( ) )
130+ }
121131}
122132
123133private newtype TTypeTracker = MkTypeTracker ( boolean hasCall ) {
@@ -147,9 +157,8 @@ private newtype TTypeTracker = MkTypeTracker(boolean hasCall) {
147157 * DataFlow::SourceNode myType() { result = myType(_) }
148158 * ```
149159 *
150- * This class can also be used to track values backwards, which can be useful for tracking
151- * the type of a callback. To do so, use the example above except with `.track`
152- * replaced with `.backtrack`.
160+ * To track values backwards, which can be useful for tracking
161+ * the type of a callback, use the `TypeBackTracker` class instead.
153162 */
154163class TypeTracker extends TTypeTracker {
155164 Boolean hasCall ;
@@ -178,3 +187,60 @@ class TypeTracker extends TTypeTracker {
178187 result = hasCall
179188 }
180189}
190+
191+ private newtype TTypeBackTracker = MkTypeBackTracker ( boolean hasReturn ) {
192+ hasReturn = true or hasReturn = false
193+ }
194+
195+ /**
196+ * Summary of the steps needed to back-track a use of a value to a given dataflow node.
197+ *
198+ * This can be used to track callbacks that are passed to a certian API call, and are
199+ * therefore expected to called with a certain type of value.
200+ *
201+ * Note that type back-tracking does not provide a source/sink relation, that is,
202+ * it may determine that a node will be used in an API call somwwhere, but it won't
203+ * determine exactly where that use was, or the path that led to the use.
204+ *
205+ * It is recommended that all uses of this type is written on the following form,
206+ * for back-tracking some callback type `myCallback`:
207+ * ```
208+ * DataFlow::SourceNode myCallback(DataFlow::TypeBackTracker t) {
209+ * t.start() and
210+ * result = (< some API call >).getParameter(< n >).getALocalSource()
211+ * or
212+ * exists (DataFlow::TypeTracker t2 |
213+ * result = myCallback(t2).backtrack(t2, t)
214+ * )
215+ * }
216+ *
217+ * DataFlow::SourceNode myCallback() { result = myCallback(_) }
218+ * ```
219+ */
220+ class TypeBackTracker extends TTypeBackTracker {
221+ Boolean hasReturn ;
222+
223+ TypeBackTracker ( ) { this = MkTypeBackTracker ( hasReturn ) }
224+
225+ string toString ( ) {
226+ hasReturn = true and result = "type back-tracker with return steps"
227+ or
228+ hasReturn = false and result = "type back-tracker without return steps"
229+ }
230+
231+ /**
232+ * Holds if this is the starting point of type tracking.
233+ */
234+ predicate start ( ) {
235+ hasReturn = false
236+ }
237+
238+ /**
239+ * INTERNAL. DO NOT USE.
240+ *
241+ * Holds if this type has been back-tracked into a call through return edge.
242+ */
243+ boolean hasReturn ( ) {
244+ result = hasReturn
245+ }
246+ }
0 commit comments