Skip to content

Commit 94d41b9

Browse files
committed
Ruby: add hook for adding type-tracking steps
fixup docs fixup docs fixup TypeTrackingStep
1 parent 96711b2 commit 94d41b9

File tree

1 file changed

+112
-1
lines changed

1 file changed

+112
-1
lines changed

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

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,11 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
106106
}
107107

108108
/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
109-
predicate levelStep(Node nodeFrom, Node nodeTo) { summarizedLocalStep(nodeFrom, nodeTo) }
109+
predicate levelStep(Node nodeFrom, Node nodeTo) {
110+
summarizedLocalStep(nodeFrom, nodeTo)
111+
or
112+
TypeTrackingStep::step(nodeFrom, nodeTo)
113+
}
110114

111115
pragma[noinline]
112116
private predicate argumentPositionMatch(
@@ -235,6 +239,8 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten
235239
not exists(pair.getKey().getConstantValue()) and
236240
contents.isAnyElement()
237241
)
242+
or
243+
TypeTrackingStep::storeStep(nodeFrom, nodeTo, contents)
238244
}
239245

240246
private predicate hashLiteralStore(DataFlow::CallNode hashCreation, DataFlow::Node argument) {
@@ -280,6 +286,8 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content
280286
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
281287
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
282288
)
289+
or
290+
TypeTrackingStep::loadStep(nodeFrom, nodeTo, contents)
283291
}
284292

285293
/**
@@ -298,6 +306,8 @@ predicate basicLoadStoreStep(
298306
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
299307
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
300308
)
309+
or
310+
TypeTrackingStep::loadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
301311
}
302312

303313
/**
@@ -314,6 +324,8 @@ predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filt
314324
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
315325
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
316326
)
327+
or
328+
TypeTrackingStep::withoutContentStep(nodeFrom, nodeTo, filter)
317329
}
318330

319331
/**
@@ -338,6 +350,8 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
338350
nodeFrom.asExpr() = node.asExpr().(Cfg::CfgNodes::ExprNodes::UnaryOperationCfgNode).getOperand() and
339351
filter = MkElementFilter()
340352
)
353+
or
354+
TypeTrackingStep::withContentStep(nodeFrom, nodeTo, filter)
341355
}
342356

343357
/**
@@ -562,3 +576,100 @@ private DataFlow::Node evaluateSummaryComponentStackLocal(
562576
)
563577
)
564578
}
579+
580+
private newtype TUnit = MkUnit()
581+
582+
/**
583+
* A data flow edge that should be followed by type tracking.
584+
*
585+
* This type of edge does not affect the local data flow graph, and is not used by data-flow configurations.
586+
*
587+
* Note: For performance reasons, all subclasses of this class should be part
588+
* of the standard library, and their implementations may not depend on API graphs.
589+
* For query-specific steps, consider including the custom steps in the type-tracking predicate itself.
590+
*/
591+
class TypeTrackingStep extends TUnit {
592+
/** Gets the string `"unit"`. */
593+
string toString() { result = "unit" }
594+
595+
/**
596+
* Holds if type-tracking should step from `pred` to `succ`.
597+
*/
598+
predicate step(Node pred, Node succ) { none() }
599+
600+
/**
601+
* Holds if type-tracking should step from `pred` into the `content` of `succ`.
602+
*/
603+
predicate storeStep(Node pred, TypeTrackingNode succ, TypeTrackerContent content) { none() }
604+
605+
/**
606+
* Holds if type-tracking should step from the `content` of `pred` to `succ`.
607+
*/
608+
predicate loadStep(Node pred, Node succ, TypeTrackerContent content) { none() }
609+
610+
/**
611+
* Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
612+
*/
613+
predicate loadStoreStep(
614+
Node pred, TypeTrackingNode succ, TypeTrackerContent loadContent,
615+
TypeTrackerContent storeContent
616+
) {
617+
none()
618+
}
619+
620+
/**
621+
* Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here.
622+
*/
623+
predicate withoutContentStep(Node pred, Node succ, ContentFilter filter) { none() }
624+
625+
/**
626+
* Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`.
627+
*/
628+
predicate withContentStep(Node pred, Node succ, ContentFilter filter) { none() }
629+
}
630+
631+
/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
632+
module TypeTrackingStep {
633+
/**
634+
* Holds if type-tracking should step from `pred` to `succ`.
635+
*/
636+
predicate step(Node pred, Node succ) { any(TypeTrackingStep st).step(pred, succ) }
637+
638+
/**
639+
* Holds if type-tracking should step from `pred` into the `content` of `succ`.
640+
*/
641+
predicate storeStep(Node pred, TypeTrackingNode succ, TypeTrackerContent content) {
642+
any(TypeTrackingStep st).storeStep(pred, succ, content)
643+
}
644+
645+
/**
646+
* Holds if type-tracking should step from the `content` of `pred` to `succ`.
647+
*/
648+
predicate loadStep(Node pred, Node succ, TypeTrackerContent content) {
649+
any(TypeTrackingStep st).loadStep(pred, succ, content)
650+
}
651+
652+
/**
653+
* Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
654+
*/
655+
predicate loadStoreStep(
656+
Node pred, TypeTrackingNode succ, TypeTrackerContent loadContent,
657+
TypeTrackerContent storeContent
658+
) {
659+
any(TypeTrackingStep st).loadStoreStep(pred, succ, loadContent, storeContent)
660+
}
661+
662+
/**
663+
* Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here.
664+
*/
665+
predicate withoutContentStep(Node pred, Node succ, ContentFilter filter) {
666+
any(TypeTrackingStep st).withoutContentStep(pred, succ, filter)
667+
}
668+
669+
/**
670+
* Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`.
671+
*/
672+
predicate withContentStep(Node pred, Node succ, ContentFilter filter) {
673+
any(TypeTrackingStep st).withContentStep(pred, succ, filter)
674+
}
675+
}

0 commit comments

Comments
 (0)