@@ -149,11 +149,16 @@ private newtype TDefOrUseImpl =
149
149
private predicate isGlobalUse (
150
150
GlobalLikeVariable v , IRFunction f , int indirection , int indirectionIndex
151
151
) {
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
+ )
157
162
}
158
163
159
164
private predicate isGlobalDefImpl (
@@ -447,6 +452,57 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
447
452
}
448
453
}
449
454
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
+ */
450
506
class GlobalUse extends UseImpl , TGlobalUse {
451
507
GlobalLikeVariable global ;
452
508
IRFunction f ;
@@ -494,6 +550,12 @@ class GlobalUse extends UseImpl, TGlobalUse {
494
550
override BaseSourceVariableInstruction getBase ( ) { none ( ) }
495
551
}
496
552
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
+ */
497
559
class GlobalDefImpl extends DefOrUseImpl , TGlobalDefImpl {
498
560
GlobalLikeVariable global ;
499
561
IRFunction f ;
0 commit comments