Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ predicate intPlusConstantOld(BinaryExpr e) {
}
```

### Control flow:

_(qtil-cpp only)_ **BlockId**: This module assigns IDs to blocks or control flow nodes. It currently
assigns unique IDs to each block/node, except it can produce duplicates IDs in the presence of
switch/case statements. This module has a language-agnostic implementation but it is currently only
implemented for C/C++.

```ql
import qtil.cpp.BlockId

from BasicBlock b
select b, blockId(b)
```

### Query Formatting

**QlFormat** offers a way of formatting CodeQL query messages in a consistent way, with varying
Expand Down
1 change: 1 addition & 0 deletions cpp/src/qtil/Cpp.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Qtil {
// Importing qtil.Cpp should import all of Qtil.
import Common::Qtil
import qtil.cpp.ast.TwoOperands
import qtil.cpp.cfg.BlockId
import qtil.cpp.format.QlFormat
import qtil.cpp.graph.CustomPathProblem
}
41 changes: 41 additions & 0 deletions cpp/src/qtil/cpp/cfg/BlockId.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
private import cpp as cpp
private import qtil.cfg.BlockId
private import qtil.inheritance.Instance

/**
* Get an ID for a given block, which is typically(*) unique.
*
* (*) Current implementation of algorithm that assigns blocks will not give unique for results
* inside switch/case statements.
*/
int blockId(cpp::BasicBlock bb) { result = CppBlockId::blockId(bb) }

/**
* Get an ID for a given control flow node, which is typically(*) unique.
*
* (*) Current implementation of algorithm that assigns blocks will not give unique for results
* inside switch/case statements.
*/
int controlFlowNodeId(cpp::ControlFlowNode node) { result = CppBlockId::controlFlowNodeId(node) }

private module CppBlockIdConfig implements BlockIdConfigSig {
class BasicBlock extends Instance<cpp::BasicBlock>::Type {
BasicBlock getTrueSuccessor() { result = inst().getATrueSuccessor() }

BasicBlock getFalseSuccessor() { result = inst().getAFalseSuccessor() }

BasicBlock getASuccessor() { result = inst().getASuccessor() }

ControlFlowNode getNode(int index) { result = inst().getNode(index) }
}

class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { this instanceof cpp::EntryBasicBlock }
}

class ControlFlowNode extends Instance<cpp::ControlFlowNode>::Type {
BasicBlock getBasicBlock() { result = inst().getBasicBlock() }
}
}

private import BlockId<CppBlockIdConfig> as CppBlockId
43 changes: 43 additions & 0 deletions cpp/test/qtil/cpp/cfg/BlockIdTest.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
| test.cpp:2:1:1:7 | { ... } | 1 |
| test.cpp:7:1:9:10 | { ... } | 1 |
| test.cpp:10:5:11:10 | { ... } | 2 |
| test.cpp:14:5:15:10 | { ... } | 3 |
| test.cpp:18:5:6:7 | ExprStmt | 4 |
| test.cpp:22:1:27:5 | { ... } | 1 |
| test.cpp:24:12:24:13 | p1 | 2 |
| test.cpp:25:5:26:10 | { ... } | 3 |
| test.cpp:29:5:21:7 | ExprStmt | 4 |
| test.cpp:32:6:32:7 | f4 | 4 |
| test.cpp:33:1:35:10 | { ... } | 1 |
| test.cpp:36:5:38:15 | { ... } | 2 |
| test.cpp:41:5:42:10 | ExprStmt | 3 |
| test.cpp:43:5:45:15 | { ... } | 5 |
| test.cpp:48:5:49:1 | ExprStmt | 6 |
| test.cpp:52:1:54:10 | { ... } | 1 |
| test.cpp:55:5:57:14 | { ... } | 2 |
| test.cpp:58:9:59:14 | { ... } | 4 |
| test.cpp:62:9:63:14 | { ... } | 5 |
| test.cpp:67:5:68:10 | { ... } | 3 |
| test.cpp:71:5:51:7 | ExprStmt | 6 |
| test.cpp:75:1:77:12 | { ... } | 1 |
| test.cpp:78:5:79:17 | { ... } | 2 |
| test.cpp:84:9:85:14 | { ... } | 3 |
| test.cpp:93:5:74:7 | ExprStmt | 4 |
| test.cpp:97:1:99:18 | { ... } | 1 |
| test.cpp:99:21:99:26 | i | 2 |
| test.cpp:100:5:102:22 | { ... } | 3 |
| test.cpp:103:9:104:14 | { ... } | 5 |
| test.cpp:107:9:108:14 | { ... } | 6 |
| test.cpp:111:9:99:31 | ExprStmt | 7 |
| test.cpp:114:5:96:7 | ExprStmt | 4 |
| test.cpp:118:1:120:12 | { ... } | 1 |
| test.cpp:121:5:123:22 | { ... } | 2 |
| test.cpp:123:25:123:29 | i | 3 |
| test.cpp:124:9:123:34 | { ... } | 4 |
| test.cpp:128:9:128:10 | ExprStmt | 5 |
| test.cpp:135:5:117:7 | ExprStmt | 6 |
| test.cpp:139:1:151:5 | { ... } | 1 |
| test.cpp:141:12:141:15 | 1 | 2 |
| test.cpp:142:5:144:16 | { ... } | 3 |
| test.cpp:145:9:147:18 | { ... } | 4 |
| test.cpp:151:5:138:7 | label ...: | 5 |
5 changes: 5 additions & 0 deletions cpp/test/qtil/cpp/cfg/BlockIdTest.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import cpp
import qtil.cpp.cfg.BlockId

from BasicBlock b
select b, blockId(b)
154 changes: 154 additions & 0 deletions cpp/test/qtil/cpp/cfg/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
void f1()
{ // B1
// Single basic block function.
}

void f2(bool p1)
{ // B1
f1();
if (p1)
{ // B2
f1();
}
else
{ // B3
f1();
}
// B4
f1();
}

void f3(bool p1)
{ // B1
f1();
while (p1) // B2
{ // B3
f1();
}
// B4
f1();
}

void f4(bool p1) // B4 -- Not sure why this is assigned block 4
{ // B1
f1();
if (p1)
{ // B2
f1();
return;
}
// B3
f1();
if (p1)
{ // B5
f1();
return;
}
// B6
f1();
}

void f5(bool p1)
{ // B1
f1();
if (p1)
{ // B2
f1();
if (p1)
{ // B4
f1();
}
else
{ // B5
f1();
}
}
else
{ // B3
f1();
}
// B6
f1();
}

void f6()
{ // B1
f1();
if (true)
{ // B2
if (false)
{ // Unreachable, no ID.
f1();
}
else
{ // B3
f1();
}
}
else
{ // Unreachable, no ID.
f1();
}
// B4
f1();
}

void f7()
{ // B1
f1();
for (int i = 0; i < 10; i++) // B2
{ // B3
f1();
if (i % 2 == 0)
{ // B5
f1();
}
else
{ // B6
f1();
}
// B7
f1();
}
// B4
f1();
}

void f8()
{ // B1
f1();
if (true)
{ // B2
f1();
for (int i = 0; i < 5; i++) // B3
{ // B4
f1();
}
// B5
f1();
}
else
{ // unreachable
f1();
}
// B6
f1();
}

void f9()
{ // B1
f1();
while (true) // B2
{ // B3
f1();
if (true)
{ // B4
f1();
break;
}
// B5
f1();
}
// Unreachable, no block id
f1();
}
Loading