|
| 1 | +/** |
| 2 | + * INTERNAL: Do not use. |
| 3 | + * |
| 4 | + * The purpose of this file is to control which cached predicates belong to the same stage. |
| 5 | + * |
| 6 | + * Combining stages can improve performance as we are more likely to reuse shared, non-cached predicates. |
| 7 | + * |
| 8 | + * To make a predicate `p` belong to a stage `A`: |
| 9 | + * - make `p` depend on `A::ref()`, and |
| 10 | + * - make `A::backref()` depend on `p`. |
| 11 | + * |
| 12 | + * Since `A` is a cached module, `ref` and `backref` must be in the same stage, and the dependency |
| 13 | + * chain above thus forces `p` to be in that stage as well. |
| 14 | + * |
| 15 | + * With these two predicates in a `cached module` we ensure that all the cached predicates will be in a single stage at runtime. |
| 16 | + * |
| 17 | + * Grouping stages can cause unnecessary computation, as a concrete query might not depend on |
| 18 | + * all the cached predicates in a stage. |
| 19 | + * Care should therefore be taken not to combine two stages, if it is likely that a query only depend |
| 20 | + * on some but not all the cached predicates in the combined stage. |
| 21 | + */ |
| 22 | + |
| 23 | +import python |
| 24 | + |
| 25 | +/** |
| 26 | + * Contains a `cached module` for each stage. |
| 27 | + * Each `cached module` ensures that predicates that are supposed to be in the same stage, are in the same stage. |
| 28 | + * |
| 29 | + * Each `cached module` contain two predicates: |
| 30 | + * The first, `ref`, always holds, and is referenced from `cached` predicates. |
| 31 | + * The second, `backref`, contains references to the same `cached` predicates. |
| 32 | + * The `backref` predicate starts with `1 = 1 or` to ensure that the predicate will be optimized down to a constant by the optimizer. |
| 33 | + */ |
| 34 | +module Stages { |
| 35 | + /** |
| 36 | + * The `SSA` stage. |
| 37 | + */ |
| 38 | + cached |
| 39 | + module SSA { |
| 40 | + /** |
| 41 | + * Always holds. |
| 42 | + * Ensures that a predicate is evaluated as part of the Ast stage. |
| 43 | + */ |
| 44 | + cached |
| 45 | + predicate ref() { 1 = 1 } |
| 46 | + |
| 47 | + private import semmle.python.essa.SsaDefinitions as SsaDefinitions |
| 48 | + private import semmle.python.essa.SsaCompute as SsaCompute |
| 49 | + private import semmle.python.essa.Essa as Essa |
| 50 | + |
| 51 | + /** |
| 52 | + * DONT USE! |
| 53 | + * Contains references to each predicate that use the above `ref` predicate. |
| 54 | + */ |
| 55 | + cached |
| 56 | + predicate backref() { |
| 57 | + 1 = 1 |
| 58 | + or |
| 59 | + SsaDefinitions::SsaSource::method_call_refinement(_, _, _) |
| 60 | + or |
| 61 | + SsaCompute::SsaDefinitions::reachesEndOfBlock(_, _, _, _) |
| 62 | + or |
| 63 | + exists(any(Essa::PhiFunction p).getInput(_)) |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * The `dataflow` stage. |
| 69 | + */ |
| 70 | + cached |
| 71 | + module DataFlow { |
| 72 | + /** |
| 73 | + * Always holds. |
| 74 | + * Ensures that a predicate is evaluated as part of the DataFlow stage. |
| 75 | + */ |
| 76 | + cached |
| 77 | + predicate ref() { 1 = 1 } |
| 78 | + |
| 79 | + private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic |
| 80 | + private import semmle.python.dataflow.new.internal.LocalSources as LocalSources |
| 81 | + private import semmle.python.internal.Awaited as Awaited |
| 82 | + private import semmle.python.pointsto.Base as PointsToBase |
| 83 | + private import semmle.python.types.Object as TypeObject |
| 84 | + private import semmle.python.objects.TObject as TObject |
| 85 | + private import semmle.python.Flow as Flow |
| 86 | + |
| 87 | + /** |
| 88 | + * DONT USE! |
| 89 | + * Contains references to each predicate that use the above `ref` predicate. |
| 90 | + */ |
| 91 | + cached |
| 92 | + predicate backref() { |
| 93 | + 1 = 1 |
| 94 | + or |
| 95 | + exists(any(DataFlowPublic::Node node).toString()) |
| 96 | + or |
| 97 | + any(DataFlowPublic::Node node).hasLocationInfo(_, _, _, _, _) |
| 98 | + or |
| 99 | + any(LocalSources::LocalSourceNode n).flowsTo(_) |
| 100 | + or |
| 101 | + exists(Awaited::awaited(_)) |
| 102 | + or |
| 103 | + PointsToBase::BaseFlow::scope_entry_value_transfer_from_earlier(_, _, _, _) |
| 104 | + or |
| 105 | + exists(TypeObject::Object a) |
| 106 | + or |
| 107 | + exists(TObject::TObject f) |
| 108 | + or |
| 109 | + exists(any(Flow::ControlFlowNode c).toString()) |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + /** |
| 114 | + * The `taint` stage. |
| 115 | + */ |
| 116 | + cached |
| 117 | + module Taint { |
| 118 | + /** |
| 119 | + * Always holds. |
| 120 | + * Ensures that a predicate is evaluated as part of the DataFlow stage. |
| 121 | + */ |
| 122 | + cached |
| 123 | + predicate ref() { 1 = 1 } |
| 124 | + |
| 125 | + private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TaintTrackingPrivate |
| 126 | + |
| 127 | + /** |
| 128 | + * DONT USE! |
| 129 | + * Contains references to each predicate that use the above `ref` predicate. |
| 130 | + */ |
| 131 | + cached |
| 132 | + predicate backref() { |
| 133 | + 1 = 1 |
| 134 | + or |
| 135 | + TaintTrackingPrivate::localAdditionalTaintStep(_, _) |
| 136 | + or |
| 137 | + TaintTrackingPrivate::defaultAdditionalTaintStep(_, _) |
| 138 | + } |
| 139 | + } |
| 140 | +} |
0 commit comments