Skip to content

Commit e74c8f8

Browse files
committed
Shared: Disjunctive barrier guards for free
1 parent 8ad0273 commit e74c8f8

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

shared/ssa/codeql/ssa/Ssa.qll

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,133 @@ module Make<LocationSig Location, InputSig<Location> Input> {
12191219

12201220
/** Holds if the `i`th node of basic block `bb` evaluates this guard. */
12211221
predicate hasCfgNode(BasicBlock bb, int i);
1222+
1223+
/** Gets the location of this guard. */
1224+
Location getLocation();
1225+
}
1226+
1227+
/**
1228+
* A logical conjunction guard.
1229+
*
1230+
* Guards are automatically lifted to conjunctions:
1231+
*
1232+
* ```csharp
1233+
* // Example 1
1234+
* if (x == "safe" && x == "safe")
1235+
* {
1236+
* sink(x); // guarded
1237+
* }
1238+
* else
1239+
* {
1240+
* sink(x); // unguarded
1241+
* }
1242+
*
1243+
* // Example 2
1244+
* if (x == "safe" && x != "safe2")
1245+
* {
1246+
* sink(x); // guarded
1247+
* }
1248+
* else
1249+
* {
1250+
* sink(x); // unguarded
1251+
* }
1252+
*
1253+
* // Example 3
1254+
* if (x != "safe" && x == "safe2")
1255+
* {
1256+
* sink(x); // guarded
1257+
* }
1258+
* else
1259+
* {
1260+
* sink(x); // unguarded
1261+
* }
1262+
*
1263+
* // Example 4
1264+
* if (x != "safe1" && x != "safe2")
1265+
* {
1266+
* sink(x); // unguarded
1267+
* }
1268+
* else
1269+
* {
1270+
* sink(x); // guarded
1271+
* }
1272+
* ```
1273+
*
1274+
* Examples 1--3 should normally be handled via the control-flow graph (CFG)
1275+
* implementation, but they are included in our logic for completeness.
1276+
*
1277+
* Example 4, which does not come for free just from the CFG, requires that
1278+
* logical conjunctions be modeled post-order in the CFG, as they will
1279+
* otherwise not dominate their `else` branch.
1280+
*/
1281+
class AndGuard extends Guard {
1282+
/** Gets the left operand of this conjunction. */
1283+
Guard getLeftOperand();
1284+
1285+
/** Gets the right operand of this conjunction. */
1286+
Guard getRightOperand();
1287+
}
1288+
1289+
/**
1290+
* A logical disjunction guard.
1291+
*
1292+
* Guards are automatically lifted to disjunctions:
1293+
*
1294+
* ```csharp
1295+
* // Example 1
1296+
* if (x == "safe1" || x == "safe2")
1297+
* {
1298+
* sink(x); // guarded
1299+
* }
1300+
* else
1301+
* {
1302+
* sink(x); // unguarded
1303+
* }
1304+
*
1305+
* // Example 2
1306+
* if (x == "safe" || x != "safe2")
1307+
* {
1308+
* sink(x); // unguarded
1309+
* }
1310+
* else
1311+
* {
1312+
* sink(x); // guarded
1313+
* }
1314+
*
1315+
* // Example 3
1316+
* if (x != "safe" || x == "safe2")
1317+
* {
1318+
* sink(x); // unguarded
1319+
* }
1320+
* else
1321+
* {
1322+
* sink(x); // guarded
1323+
* }
1324+
*
1325+
* // Example 4
1326+
* if (x != "safe" || x != "safe")
1327+
* {
1328+
* sink(x); // unguarded
1329+
* }
1330+
* else
1331+
* {
1332+
* sink(x); // guarded
1333+
* }
1334+
* ```
1335+
*
1336+
* Examples 1--3 should normally be handled via the control-flow graph (CFG)
1337+
* implementation, but they are included in our logic for completeness.
1338+
*
1339+
* Example 4, which does not come for free just from the CFG, requires that
1340+
* logical disjunctions be modeled post-order in the CFG, as they will
1341+
* otherwise not dominate their `else` branch.
1342+
*/
1343+
class OrGuard extends Guard {
1344+
/** Gets the left operand of this disjunction. */
1345+
Guard getLeftOperand();
1346+
1347+
/** Gets the right operand of this disjunction. */
1348+
Guard getRightOperand();
12221349
}
12231350

12241351
/** Holds if `guard` controls block `bb` upon evaluating to `branch`. */
@@ -1641,6 +1768,24 @@ module Make<LocationSig Location, InputSig<Location> Input> {
16411768
pragma[nomagic]
16421769
private predicate guardChecksSsaDef(DfInput::Guard g, Definition def, boolean branch) {
16431770
guardChecks(g, DfInput::getARead(def), branch)
1771+
or
1772+
exists(boolean branchLeft, boolean branchRight |
1773+
// Automatically lift to conjunctions
1774+
g =
1775+
any(DfInput::AndGuard ag |
1776+
guardChecksSsaDef(ag.getLeftOperand(), def, branchLeft) and
1777+
guardChecksSsaDef(ag.getRightOperand(), def, branchRight) and
1778+
branch = branchLeft.booleanOr(branchRight)
1779+
)
1780+
or
1781+
// Automatically lift to disjunctions
1782+
g =
1783+
any(DfInput::OrGuard og |
1784+
guardChecksSsaDef(og.getLeftOperand(), def, branchLeft) and
1785+
guardChecksSsaDef(og.getRightOperand(), def, branchRight) and
1786+
branch = branchLeft.booleanAnd(branchRight)
1787+
)
1788+
)
16441789
}
16451790

16461791
/** Gets a node that is safely guarded by the given guard check. */

0 commit comments

Comments
 (0)