Skip to content

Commit 80fad34

Browse files
committed
Swift: Implement CFG for property reads, writes, and observers.
1 parent 67cc1b5 commit 80fad34

File tree

2 files changed

+333
-127
lines changed

2 files changed

+333
-127
lines changed

swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 219 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -887,13 +887,96 @@ module Decls {
887887
}
888888

889889
module Exprs {
890-
private class AssignExprTree extends AstStandardPostOrderTree {
891-
override AssignExpr ast;
890+
module AssignExprs {
891+
/**
892+
* The control-flow of an assignment operation.
893+
*
894+
* There are two implementation of this base class:
895+
* - One where the left-hand side has direct-to-storage-access semantics
896+
* - One where the left-hand side has direct-to-implementation-access semantics
897+
*/
898+
abstract private class AssignExprTree extends AstControlFlowTree {
899+
override AssignExpr ast;
892900

893-
final override ControlFlowTree getChildElement(int i) {
894-
result.asAstNode() = ast.getDest().getFullyConverted() and i = 0
895-
or
896-
result.asAstNode() = ast.getSource().getFullyConverted() and i = 1
901+
final override predicate first(ControlFlowElement first) {
902+
astFirst(ast.getDest().getFullyConverted(), first)
903+
}
904+
905+
abstract predicate isSet(ControlFlowElement n);
906+
907+
abstract predicate isLast(ControlFlowElement n, Completion c);
908+
909+
final override predicate propagatesAbnormal(ControlFlowElement child) {
910+
child.asAstNode() = ast.getDest().getFullyConverted() or
911+
child.asAstNode() = ast.getSource().getFullyConverted()
912+
}
913+
914+
predicate hasWillSetObserver() { isPropertyObserverElement(any(WillSetObserver obs), ast) }
915+
916+
predicate hasDidSetObserver() { isPropertyObserverElement(any(WillSetObserver obs), ast) }
917+
918+
final override predicate last(ControlFlowElement last, Completion c) {
919+
isPropertyObserverElement(last, any(DidSetObserver obs), ast) and
920+
completionIsValidFor(c, last)
921+
or
922+
not this.hasDidSetObserver() and
923+
this.isLast(last, c)
924+
}
925+
926+
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
927+
// Flow from the destination to the source
928+
astLast(ast.getDest().getFullyConverted(), pred, c) and
929+
c instanceof NormalCompletion and
930+
astFirst(ast.getSource().getFullyConverted(), succ)
931+
or
932+
// Flow from the source to the `willSet` observer, if any. Otherwise, flow to the set operation
933+
astLast(ast.getSource().getFullyConverted(), pred, c) and
934+
c instanceof NormalCompletion and
935+
(
936+
if this.hasWillSetObserver()
937+
then isPropertyObserverElement(succ, any(WillSetObserver obs), ast)
938+
else this.isSet(succ)
939+
)
940+
or
941+
// Flow from the set operation to the `didSet` observer, if any
942+
this.isSet(pred) and
943+
completionIsValidFor(c, pred) and
944+
isPropertyObserverElement(succ, any(DidSetObserver obs), ast)
945+
}
946+
}
947+
948+
/**
949+
* The control-flow for assignments where the left-hand side has
950+
* direct-to-implmentation-access semantics.
951+
*/
952+
class PropertyAssignExpr extends AssignExprTree {
953+
AccessorDecl accessorDecl;
954+
955+
PropertyAssignExpr() { isPropertySetterElement(accessorDecl, ast) }
956+
957+
final override predicate isLast(ControlFlowElement last, Completion c) {
958+
isPropertySetterElement(last, accessorDecl, ast) and
959+
completionIsValidFor(c, last)
960+
}
961+
962+
final override predicate isSet(ControlFlowElement node) {
963+
isPropertySetterElement(node, _, ast)
964+
}
965+
}
966+
967+
/**
968+
* The control-flow for assignments where the left-hand side has
969+
* direct-to-storage-access semantics.
970+
*/
971+
class DirectAssignExpr extends AssignExprTree {
972+
DirectAssignExpr() { not this instanceof PropertyAssignExpr }
973+
974+
final override predicate isLast(ControlFlowElement last, Completion c) {
975+
last.asAstNode() = ast and
976+
completionIsValidFor(c, last)
977+
}
978+
979+
final override predicate isSet(ControlFlowElement node) { node.asAstNode() = ast }
897980
}
898981
}
899982

@@ -1122,15 +1205,139 @@ module Exprs {
11221205
}
11231206
}
11241207

1125-
private class DeclRefExprTree extends AstLeafTree {
1126-
override DeclRefExpr ast;
1208+
module DeclRefExprs {
1209+
class DeclRefExprLValueTree extends AstLeafTree {
1210+
override DeclRefExpr ast;
1211+
1212+
DeclRefExprLValueTree() { isLValue(ast) }
1213+
}
1214+
1215+
abstract class DeclRefExprRValueTree extends AstControlFlowTree {
1216+
override DeclRefExpr ast;
1217+
1218+
DeclRefExprRValueTree() { isRValue(ast) }
1219+
1220+
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1221+
none()
1222+
}
1223+
1224+
override predicate propagatesAbnormal(ControlFlowElement child) { none() }
1225+
}
1226+
1227+
private class PropertyDeclRefRValueTree extends DeclRefExprRValueTree {
1228+
AccessorDecl accessor;
1229+
1230+
PropertyDeclRefRValueTree() { isPropertyGetterElement(accessor, ast) }
1231+
1232+
final override predicate first(ControlFlowElement first) {
1233+
isPropertyGetterElement(first, accessor, ast)
1234+
}
1235+
1236+
final override predicate last(ControlFlowElement last, Completion c) {
1237+
isPropertyGetterElement(last, accessor, ast) and
1238+
completionIsValidFor(c, last)
1239+
}
1240+
}
1241+
1242+
private class DirectDeclRefRValueTree extends DeclRefExprRValueTree {
1243+
DirectDeclRefRValueTree() { not this instanceof PropertyDeclRefRValueTree }
1244+
1245+
final override predicate first(ControlFlowElement first) { first.asAstNode() = ast }
1246+
1247+
final override predicate last(ControlFlowElement last, Completion c) {
1248+
last.asAstNode() = ast and
1249+
completionIsValidFor(c, last)
1250+
}
1251+
}
11271252
}
11281253

1129-
private class MemberRefTree extends AstStandardPostOrderTree {
1130-
override MemberRefExpr ast;
1254+
module MemberRefs {
1255+
/**
1256+
* The control-flow of a member reference expression.
1257+
*
1258+
* There are two implementation of this base class:
1259+
* - One for lvalues
1260+
* - One for rvalues
1261+
*/
1262+
abstract private class MemberRefTreeBase extends AstControlFlowTree {
1263+
override MemberRefExpr ast;
1264+
1265+
final override predicate propagatesAbnormal(ControlFlowElement child) {
1266+
child.asAstNode() = ast.getBaseExpr().getFullyConverted()
1267+
}
1268+
1269+
final override predicate first(ControlFlowElement first) {
1270+
astFirst(ast.getBaseExpr().getFullyConverted(), first)
1271+
}
1272+
}
1273+
1274+
/**
1275+
* The lvalue implementation of `MemberRefTreeBase`
1276+
*/
1277+
private class MemberRefLValueTree extends MemberRefTreeBase {
1278+
MemberRefLValueTree() { isLValue(ast) }
11311279

1132-
final override AstNode getChildElement(int i) {
1133-
result = ast.getBaseExpr().getFullyConverted() and i = 0
1280+
final override predicate last(ControlFlowElement last, Completion c) {
1281+
last.asAstNode() = ast and
1282+
completionIsValidFor(c, last)
1283+
}
1284+
1285+
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1286+
astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and
1287+
c instanceof NormalCompletion and
1288+
succ.asAstNode() = ast
1289+
}
1290+
}
1291+
1292+
/**
1293+
* The rvalue base implementation of `MemberRefTreeBase`.
1294+
*
1295+
* There are two implementations of this class:
1296+
* - One for direct-storage semantics
1297+
* - One for calls to getters
1298+
*/
1299+
abstract private class MemberRefRValueTree extends MemberRefTreeBase {
1300+
MemberRefRValueTree() { isRValue(ast) }
1301+
}
1302+
1303+
/**
1304+
* Control-flow for rvalue member accesses with direct-to-storage semantics
1305+
* or ordinary semantics without a getter.
1306+
*/
1307+
private class DirectMemberRefRValue extends MemberRefRValueTree {
1308+
DirectMemberRefRValue() { not this instanceof PropertyMemberRefRValue }
1309+
1310+
final override predicate last(ControlFlowElement last, Completion c) {
1311+
last.asAstNode() = ast and
1312+
completionIsValidFor(c, last)
1313+
}
1314+
1315+
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1316+
astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and
1317+
c instanceof NormalCompletion and
1318+
succ.asAstNode() = ast
1319+
}
1320+
}
1321+
1322+
/**
1323+
* Control-flow for rvalue member accesses with direct-to-implementation semantics
1324+
* or ordinary semantics that includes a getter.
1325+
*/
1326+
private class PropertyMemberRefRValue extends MemberRefRValueTree {
1327+
AccessorDecl accessor;
1328+
1329+
PropertyMemberRefRValue() { isPropertyGetterElement(accessor, ast) }
1330+
1331+
final override predicate last(ControlFlowElement last, Completion c) {
1332+
isPropertyGetterElement(last, accessor, ast) and
1333+
completionIsValidFor(c, last)
1334+
}
1335+
1336+
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1337+
astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and
1338+
c instanceof NormalCompletion and
1339+
isPropertyGetterElement(succ, accessor, ast)
1340+
}
11341341
}
11351342
}
11361343

0 commit comments

Comments
 (0)