Skip to content

Commit 072e2ed

Browse files
committed
Merge branch 'main' into redsun82/kotlin
2 parents aaa29d8 + 3592e76 commit 072e2ed

File tree

205 files changed

+4326
-2514
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

205 files changed

+4326
-2514
lines changed

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ predicate knownSourceModel(Node source, string model) { none() }
290290

291291
predicate knownSinkModel(Node sink, string model) { none() }
292292

293+
class DataFlowSecondLevelScope = Unit;
294+
293295
/**
294296
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
295297
* side-effect, resulting in a summary from `p` to itself.

cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,24 @@ class CoAwaitExpr extends UnaryOperation, @co_await {
13381338
override string getOperator() { result = "co_await" }
13391339

13401340
override int getPrecedence() { result = 16 }
1341+
1342+
/**
1343+
* Gets the Boolean expression that is used to decide if the enclosing
1344+
* coroutine should be suspended.
1345+
*/
1346+
Expr getAwaitReady() { result = this.getChild(1) }
1347+
1348+
/**
1349+
* Gets the expression that represents the resume point if the enclosing
1350+
* coroutine was suspended.
1351+
*/
1352+
Expr getAwaitResume() { result = this.getChild(2) }
1353+
1354+
/**
1355+
* Gets the expression that is evaluated when the enclosing coroutine is
1356+
* suspended.
1357+
*/
1358+
Expr getAwaitSuspend() { result = this.getChild(3) }
13411359
}
13421360

13431361
/**
@@ -1352,6 +1370,24 @@ class CoYieldExpr extends UnaryOperation, @co_yield {
13521370
override string getOperator() { result = "co_yield" }
13531371

13541372
override int getPrecedence() { result = 2 }
1373+
1374+
/**
1375+
* Gets the Boolean expression that is used to decide if the enclosing
1376+
* coroutine should be suspended.
1377+
*/
1378+
Expr getAwaitReady() { result = this.getChild(1) }
1379+
1380+
/**
1381+
* Gets the expression that represents the resume point if the enclosing
1382+
* coroutine was suspended.
1383+
*/
1384+
Expr getAwaitResume() { result = this.getChild(2) }
1385+
1386+
/**
1387+
* Gets the expression that is evaluated when the enclosing coroutine is
1388+
* suspended.
1389+
*/
1390+
Expr getAwaitSuspend() { result = this.getChild(3) }
13551391
}
13561392

13571393
/**

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplSpecific.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module CppDataFlow implements InputSig<Location> {
2222

2323
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
2424

25+
predicate getSecondLevelScope = Private::getSecondLevelScope/1;
26+
2527
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
2628

2729
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,3 +1583,85 @@ predicate validParameterAliasStep(Node node1, Node node2) {
15831583
)
15841584
)
15851585
}
1586+
1587+
private predicate isTopLevel(Cpp::Stmt s) { any(Function f).getBlock().getAStmt() = s }
1588+
1589+
private Cpp::Stmt getAChainedBranch(Cpp::IfStmt s) {
1590+
result = s.getThen()
1591+
or
1592+
exists(Cpp::Stmt elseBranch | s.getElse() = elseBranch |
1593+
result = getAChainedBranch(elseBranch)
1594+
or
1595+
result = elseBranch and not elseBranch instanceof Cpp::IfStmt
1596+
)
1597+
}
1598+
1599+
private Instruction getAnInstruction(Node n) {
1600+
result = n.asInstruction()
1601+
or
1602+
not n instanceof InstructionNode and
1603+
result = n.asOperand().getUse()
1604+
or
1605+
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
1606+
or
1607+
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
1608+
or
1609+
not n instanceof IndirectInstruction and
1610+
exists(Operand operand |
1611+
n.(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and
1612+
result = operand.getUse()
1613+
)
1614+
or
1615+
result = getAnInstruction(n.(PostUpdateNode).getPreUpdateNode())
1616+
}
1617+
1618+
private newtype TDataFlowSecondLevelScope =
1619+
TTopLevelIfBranch(Cpp::Stmt s) {
1620+
exists(Cpp::IfStmt ifstmt | s = getAChainedBranch(ifstmt) and isTopLevel(ifstmt))
1621+
} or
1622+
TTopLevelSwitchCase(Cpp::SwitchCase s) {
1623+
exists(Cpp::SwitchStmt switchstmt | s = switchstmt.getASwitchCase() and isTopLevel(switchstmt))
1624+
}
1625+
1626+
/**
1627+
* A second-level control-flow scope in a `switch` or a chained `if` statement.
1628+
*
1629+
* This is a `switch` case or a branch of a chained `if` statement, given that
1630+
* the `switch` or `if` statement is top level, that is, it is not nested inside
1631+
* other CFG constructs.
1632+
*/
1633+
class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
1634+
/** Gets a textual representation of this element. */
1635+
string toString() {
1636+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.toString())
1637+
or
1638+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.toString())
1639+
}
1640+
1641+
/** Gets the primary location of this element. */
1642+
Cpp::Location getLocation() {
1643+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.getLocation())
1644+
or
1645+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getLocation())
1646+
}
1647+
1648+
/**
1649+
* Gets a statement directly contained in this scope. For an `if` branch, this
1650+
* is the branch itself, and for a `switch case`, this is one the statements
1651+
* of that case branch.
1652+
*/
1653+
private Cpp::Stmt getAStmt() {
1654+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s)
1655+
or
1656+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getAStmt())
1657+
}
1658+
1659+
/** Gets a data-flow node nested within this scope. */
1660+
Node getANode() {
1661+
getAnInstruction(result).getAst().(Cpp::ControlFlowNode).getEnclosingStmt().getParentStmt*() =
1662+
this.getAStmt()
1663+
}
1664+
}
1665+
1666+
/** Gets the second-level scope containing the node `n`, if any. */
1667+
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ newtype TInstructionTag =
8989
ImplicitDestructorTag(int index) {
9090
exists(Expr e | exists(e.getImplicitDestructorCall(index))) or
9191
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
92-
}
92+
} or
93+
CoAwaitBranchTag()
9394

9495
class InstructionTag extends TInstructionTag {
9596
final string toString() { result = getInstructionTagId(this) }
@@ -186,6 +187,8 @@ string getInstructionTagId(TInstructionTag tag) {
186187
or
187188
tag = BoolConversionCompareTag() and result = "BoolConvComp"
188189
or
190+
tag = ResultCopyTag() and result = "ResultCopy"
191+
or
189192
tag = LoadTag() and result = "Load" // Implicit load due to lvalue-to-rvalue conversion
190193
or
191194
tag = CatchTag() and result = "Catch"
@@ -263,4 +266,6 @@ string getInstructionTagId(TInstructionTag tag) {
263266
exists(int index |
264267
tag = ImplicitDestructorTag(index) and result = "ImplicitDestructor(" + index + ")"
265268
)
269+
or
270+
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
266271
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 141 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,9 +1259,7 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
12591259
expr instanceof NotExpr or
12601260
expr instanceof ComplementExpr or
12611261
expr instanceof UnaryPlusExpr or
1262-
expr instanceof UnaryMinusExpr or
1263-
expr instanceof CoAwaitExpr or
1264-
expr instanceof CoYieldExpr
1262+
expr instanceof UnaryMinusExpr
12651263
}
12661264

12671265
final override Instruction getFirstInstruction(EdgeKind kind) {
@@ -1301,19 +1299,153 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
13011299
expr instanceof UnaryPlusExpr and result instanceof Opcode::CopyValue
13021300
or
13031301
expr instanceof UnaryMinusExpr and result instanceof Opcode::Negate
1304-
or
1305-
// TODO: Use a new opcode to represent "awaiting the value"
1306-
expr instanceof CoAwaitExpr and result instanceof Opcode::CopyValue
1307-
or
1308-
// TODO: Use a new opcode to represent "awaiting the value"
1309-
expr instanceof CoYieldExpr and result instanceof Opcode::CopyValue
13101302
}
13111303

13121304
private TranslatedExpr getOperand() {
13131305
result = getTranslatedExpr(expr.(UnaryOperation).getOperand().getFullyConverted())
13141306
}
13151307
}
13161308

1309+
/**
1310+
* IR translation of a `co_await` or `co_yield` expression.
1311+
*
1312+
* The translation of `x = co_await ...` is essentially:
1313+
* ```cpp
1314+
* if (!awaiter.await_ready()) {
1315+
* awaiter.await_suspend();
1316+
* }
1317+
* x = awaiter.await_resume();
1318+
* ```
1319+
* where `awaiter` is an object constructed from programmer-supplied
1320+
* input, and for IR construction purposes these are resolved by the C/C++
1321+
* front-end.
1322+
*
1323+
* See https://en.cppreference.com/w/cpp/language/coroutines#co_await for the
1324+
* specification on how `awaiter` is obtained.
1325+
*/
1326+
abstract private class TranslatedCoExpr extends TranslatedNonConstantExpr {
1327+
/** Gets the operand of this operation. */
1328+
abstract Expr getOperand();
1329+
1330+
/**
1331+
* Gets the expression that decides if the enclosing coroutine should be
1332+
* suspended.
1333+
*/
1334+
abstract Expr getAwaitReady();
1335+
1336+
/**
1337+
* Gets the expression that is evaluated when the enclosing coroutine is
1338+
* suspended.
1339+
*/
1340+
abstract Expr getAwaitSuspend();
1341+
1342+
/**
1343+
* Gets the expression that represents the resume point if the enclosing
1344+
* coroutine was suspended.
1345+
*/
1346+
abstract Expr getAwaitResume();
1347+
1348+
final override Instruction getFirstInstruction(EdgeKind kind) {
1349+
result = this.getTranslatedOperand().getFirstInstruction(kind)
1350+
}
1351+
1352+
override Instruction getALastInstructionInternal() {
1353+
result = this.getTranslatedAwaitResume().getALastInstruction()
1354+
}
1355+
1356+
final override TranslatedElement getChildInternal(int id) {
1357+
id = 0 and result = this.getTranslatedOperand()
1358+
or
1359+
id = 1 and result = this.getTranslatedAwaitReady()
1360+
or
1361+
id = 2 and result = this.getTranslatedAwaitResume()
1362+
or
1363+
id = 3 and result = this.getTranslatedAwaitSuspend()
1364+
}
1365+
1366+
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
1367+
tag = CoAwaitBranchTag() and
1368+
(
1369+
kind instanceof TrueEdge and
1370+
result = this.getTranslatedAwaitResume().getFirstInstruction(any(GotoEdge goto))
1371+
or
1372+
kind instanceof FalseEdge and
1373+
result = this.getTranslatedAwaitSuspend().getFirstInstruction(any(GotoEdge goto))
1374+
)
1375+
}
1376+
1377+
override Instruction getResult() { result = this.getTranslatedAwaitResume().getResult() }
1378+
1379+
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
1380+
child = this.getTranslatedOperand() and
1381+
result = this.getTranslatedAwaitReady().getFirstInstruction(kind)
1382+
or
1383+
child = this.getTranslatedAwaitReady() and
1384+
kind instanceof GotoEdge and
1385+
result = this.getInstruction(CoAwaitBranchTag())
1386+
or
1387+
child = this.getTranslatedAwaitSuspend() and
1388+
result = this.getTranslatedAwaitResume().getFirstInstruction(kind)
1389+
or
1390+
child = this.getTranslatedAwaitResume() and
1391+
result = this.getParent().getChildSuccessor(this, kind)
1392+
}
1393+
1394+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
1395+
tag = CoAwaitBranchTag() and
1396+
opcode instanceof Opcode::ConditionalBranch and
1397+
resultType = getVoidType()
1398+
}
1399+
1400+
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
1401+
tag = CoAwaitBranchTag() and
1402+
operandTag instanceof ConditionOperandTag and
1403+
result = this.getTranslatedAwaitReady().getResult()
1404+
}
1405+
1406+
private TranslatedExpr getTranslatedOperand() {
1407+
result = getTranslatedExpr(this.getOperand().getFullyConverted())
1408+
}
1409+
1410+
private TranslatedExpr getTranslatedAwaitReady() {
1411+
result = getTranslatedExpr(this.getAwaitReady().getFullyConverted())
1412+
}
1413+
1414+
private TranslatedExpr getTranslatedAwaitResume() {
1415+
result = getTranslatedExpr(this.getAwaitResume().getFullyConverted())
1416+
}
1417+
1418+
private TranslatedExpr getTranslatedAwaitSuspend() {
1419+
result = getTranslatedExpr(this.getAwaitSuspend().getFullyConverted())
1420+
}
1421+
}
1422+
1423+
/** IR translation of `co_await`. */
1424+
class TranslatedCoAwaitExpr extends TranslatedCoExpr {
1425+
override CoAwaitExpr expr;
1426+
1427+
final override Expr getOperand() { result = expr.getOperand() }
1428+
1429+
final override Expr getAwaitReady() { result = expr.getAwaitReady() }
1430+
1431+
final override Expr getAwaitSuspend() { result = expr.getAwaitSuspend() }
1432+
1433+
final override Expr getAwaitResume() { result = expr.getAwaitResume() }
1434+
}
1435+
1436+
/** IR translation of `co_yield`. */
1437+
class TranslatedCoYieldxpr extends TranslatedCoExpr {
1438+
override CoYieldExpr expr;
1439+
1440+
final override Expr getOperand() { result = expr.getOperand() }
1441+
1442+
final override Expr getAwaitReady() { result = expr.getAwaitReady() }
1443+
1444+
final override Expr getAwaitSuspend() { result = expr.getAwaitSuspend() }
1445+
1446+
final override Expr getAwaitResume() { result = expr.getAwaitResume() }
1447+
}
1448+
13171449
abstract class TranslatedConversion extends TranslatedNonConstantExpr {
13181450
override Conversion expr;
13191451

cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void test_copy_assignment_operator()
8484

8585
swap(z1, z2);
8686

87-
sink(z2.data1); // $ ir MISSING: ast
87+
sink(z2.data1); // $ ir ast
8888
sink(z1.data1); // $ SPURIOUS: ir ast=81:27 ast=82:16
8989
}
9090

0 commit comments

Comments
 (0)