@@ -149,11 +149,16 @@ private newtype TDefOrUseImpl =
149149private predicate isGlobalUse (
150150 GlobalLikeVariable v , IRFunction f , int indirection , int indirectionIndex
151151) {
152- exists ( VariableAddressInstruction vai |
153- vai .getEnclosingIRFunction ( ) = f and
154- vai .getAstVariable ( ) = v and
155- isDef ( _, _, _, vai , indirection , indirectionIndex )
156- )
152+ // Generate a "global use" at the end of the function body if there's a
153+ // direct definition somewhere in the body of the function
154+ indirection =
155+ min ( int cand , VariableAddressInstruction vai |
156+ vai .getEnclosingIRFunction ( ) = f and
157+ vai .getAstVariable ( ) = v and
158+ isDef ( _, _, _, vai , cand , indirectionIndex )
159+ |
160+ cand
161+ )
157162}
158163
159164private predicate isGlobalDefImpl (
@@ -447,6 +452,57 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
447452 }
448453}
449454
455+ /**
456+ * A use that models a synthetic "last use" of a global variable just before a
457+ * function returns.
458+ *
459+ * We model global variable flow by:
460+ * - Inserting a last use of any global variable that's modified by a function
461+ * - Flowing from the last use to the `VariableNode` that represents the global
462+ * variable.
463+ * - Flowing from the `VariableNode` to an "initial def" of the global variable
464+ * in any function that may read the global variable.
465+ * - Flowing from the initial definition to any subsequent uses of the global
466+ * variable in the function body.
467+ *
468+ * For example, consider the following pair of functions:
469+ * ```cpp
470+ * int global;
471+ * int source();
472+ * void sink(int);
473+ *
474+ * void set_global() {
475+ * global = source();
476+ * }
477+ *
478+ * void read_global() {
479+ * sink(global);
480+ * }
481+ * ```
482+ * we insert global uses and defs so that (from the point-of-view of dataflow)
483+ * the above scenario looks like:
484+ * ```cpp
485+ * int global; // (1)
486+ * int source();
487+ * void sink(int);
488+ *
489+ * void set_global() {
490+ * global = source();
491+ * __global_use(global); // (2)
492+ * }
493+ *
494+ * void read_global() {
495+ * global = __global_def; // (3)
496+ * sink(global); // (4)
497+ * }
498+ * ```
499+ * and flow from `source()` to the argument of `sink` is then modeled as
500+ * follows:
501+ * 1. Flow from `source()` to `(2)` (via SSA).
502+ * 2. Flow from `(2)` to `(1)` (via a `jumpStep`).
503+ * 3. Flow from `(1)` to `(3)` (via a `jumpStep`).
504+ * 4. Flow from `(3)` to `(4)` (via SSA).
505+ */
450506class GlobalUse extends UseImpl , TGlobalUse {
451507 GlobalLikeVariable global ;
452508 IRFunction f ;
@@ -494,6 +550,12 @@ class GlobalUse extends UseImpl, TGlobalUse {
494550 override BaseSourceVariableInstruction getBase ( ) { none ( ) }
495551}
496552
553+ /**
554+ * A definition that models a synthetic "initial definition" of a global
555+ * variable just after the function entry point.
556+ *
557+ * See the QLDoc for `GlobalUse` for how this is used.
558+ */
497559class GlobalDefImpl extends DefOrUseImpl , TGlobalDefImpl {
498560 GlobalLikeVariable global ;
499561 IRFunction f ;
0 commit comments