Skip to content

Commit a07d03f

Browse files
committed
C++: Use the 'StoreInstruction' instead of the 'ReturnValueInstruction' when detecting return expressions.
1 parent 26a8a4b commit a07d03f

File tree

6 files changed

+39
-8
lines changed

6 files changed

+39
-8
lines changed

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,30 @@ module GuardsInput implements SharedGuards::InputSig<Cpp::Location, Instruction,
361361

362362
/** Gets an expression returned from this function. */
363363
GuardsInput::Expr getAReturnExpr() {
364-
exists(ReturnValueInstruction ret |
365-
ret.getEnclosingFunction() = this and
366-
result = ret.getReturnValue()
364+
exists(StoreInstruction store |
365+
// We use the `Store` instruction that writes the return value instead of the
366+
// `ReturnValue` instruction since the `ReturnValue` instruction is not always
367+
// dominated by certain guards. For example:
368+
// ```
369+
// if(b) {
370+
// return true;
371+
// } else {
372+
// return false;
373+
// }
374+
// ```
375+
// this will be translated into IR like:
376+
// ```
377+
// if(b) {
378+
// x = true;
379+
// } else {
380+
// x = false;
381+
// }
382+
// return x;
383+
// ```
384+
store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof
385+
IRReturnVariable and
386+
store.getEnclosingFunction() = this and
387+
result = store
367388
)
368389
}
369390
}

cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,11 @@
381381
| test.cpp:372:10:372:13 | flag | false | test.cpp:372:35:372:49 | FAILURE |
382382
| test.cpp:372:10:372:13 | flag | true | test.cpp:372:17:372:31 | SUCCESS |
383383
| test.cpp:375:25:375:25 | p | not null | test.cpp:376:24:377:7 | { ... } |
384+
| test.cpp:375:25:375:25 | p | not null | test.cpp:382:24:383:7 | { ... } |
384385
| test.cpp:375:25:375:25 | p | null | test.cpp:378:10:379:7 | { ... } |
386+
| test.cpp:375:25:375:25 | p | null | test.cpp:384:10:385:7 | { ... } |
385387
| test.cpp:375:33:375:33 | i | not null | test.cpp:390:10:391:7 | { ... } |
388+
| test.cpp:375:42:375:42 | s | not null | test.cpp:396:10:397:7 | { ... } |
386389
| test.cpp:375:50:375:50 | b | false | test.cpp:404:5:406:12 | case ...: |
387390
| test.cpp:375:50:375:50 | b | true | test.cpp:401:5:403:12 | case ...: |
388391
| test.cpp:376:7:376:18 | call to testNotNull1 | false | test.cpp:378:10:379:7 | { ... } |
@@ -391,6 +394,8 @@
391394
| test.cpp:376:20:376:20 | p | null | test.cpp:378:10:379:7 | { ... } |
392395
| test.cpp:382:7:382:18 | call to testNotNull2 | false | test.cpp:384:10:385:7 | { ... } |
393396
| test.cpp:382:7:382:18 | call to testNotNull2 | true | test.cpp:382:24:383:7 | { ... } |
397+
| test.cpp:382:20:382:20 | p | not null | test.cpp:382:24:383:7 | { ... } |
398+
| test.cpp:382:20:382:20 | p | null | test.cpp:384:10:385:7 | { ... } |
394399
| test.cpp:388:7:388:29 | ... == ... | false | test.cpp:390:10:391:7 | { ... } |
395400
| test.cpp:388:7:388:29 | ... == ... | true | test.cpp:388:32:389:7 | { ... } |
396401
| test.cpp:388:12:388:26 | call to getNumOrDefault | 0 | test.cpp:388:32:389:7 | { ... } |
@@ -400,6 +405,8 @@
400405
| test.cpp:394:7:394:47 | ... == ... | true | test.cpp:394:50:395:7 | { ... } |
401406
| test.cpp:394:15:394:34 | call to returnAIfNoneAreNull | 0 | test.cpp:394:50:395:7 | { ... } |
402407
| test.cpp:394:15:394:34 | call to returnAIfNoneAreNull | not 0 | test.cpp:396:10:397:7 | { ... } |
408+
| test.cpp:394:36:394:36 | s | not null | test.cpp:396:10:397:7 | { ... } |
409+
| test.cpp:394:39:394:46 | suffix | not null | test.cpp:396:10:397:7 | { ... } |
403410
| test.cpp:400:11:400:25 | call to testEnumWrapper | 1 | test.cpp:401:5:403:12 | case ...: |
404411
| test.cpp:400:11:400:25 | call to testEnumWrapper | 2 | test.cpp:404:5:406:12 | case ...: |
405412
| test.cpp:400:27:400:27 | b | false | test.cpp:404:5:406:12 | case ...: |

cpp/ql/test/library-tests/controlflow/guards/GuardsInline.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
| test.cpp:379:5:379:7 | Call: call to chk | 'call to testNotNull1:false' |
1010
| test.cpp:379:5:379:7 | Call: call to chk | p:null |
1111
| test.cpp:383:5:383:7 | Call: call to chk | 'call to testNotNull2:true' |
12+
| test.cpp:383:5:383:7 | Call: call to chk | 'p:not null' |
1213
| test.cpp:385:5:385:7 | Call: call to chk | 'call to testNotNull2:false' |
14+
| test.cpp:385:5:385:7 | Call: call to chk | p:null |
1315
| test.cpp:389:5:389:7 | Call: call to chk | '0 == call to getNumOrDefault:true' |
1416
| test.cpp:389:5:389:7 | Call: call to chk | 'call to getNumOrDefault:0' |
1517
| test.cpp:391:5:391:7 | Call: call to chk | '0 == call to getNumOrDefault:false' |
@@ -19,6 +21,8 @@
1921
| test.cpp:395:5:395:7 | Call: call to chk | 'call to returnAIfNoneAreNull:0' |
2022
| test.cpp:397:5:397:7 | Call: call to chk | '0 == call to returnAIfNoneAreNull:false' |
2123
| test.cpp:397:5:397:7 | Call: call to chk | 'call to returnAIfNoneAreNull:not 0' |
24+
| test.cpp:397:5:397:7 | Call: call to chk | 's:not null' |
25+
| test.cpp:397:5:397:7 | Call: call to chk | 'suffix:not null' |
2226
| test.cpp:402:7:402:9 | Call: call to chk | 'call to testEnumWrapper:1' |
2327
| test.cpp:402:7:402:9 | Call: call to chk | 'call to testEnumWrapper=SUCCESS:true' |
2428
| test.cpp:402:7:402:9 | Call: call to chk | b:true |

cpp/ql/test/library-tests/controlflow/guards/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,9 @@ void testWrappers(void* p, int* i, char* s, bool b) {
380380
}
381381

382382
if (testNotNull2(p)) {
383-
chk(); // $ guarded='call to testNotNull2:true' MISSING: guarded='p:not null'
383+
chk(); // $ guarded='call to testNotNull2:true' guarded='p:not null'
384384
} else {
385-
chk(); // $ guarded='call to testNotNull2:false'
385+
chk(); // $ guarded='call to testNotNull2:false' guarded=p:null
386386
}
387387

388388
if (0 == getNumOrDefault(i)) {
@@ -394,7 +394,7 @@ void testWrappers(void* p, int* i, char* s, bool b) {
394394
if ('\0' == returnAIfNoneAreNull(s, "suffix")) {
395395
chk(); // $ guarded='0 == call to returnAIfNoneAreNull:true' guarded='call to returnAIfNoneAreNull:0'
396396
} else {
397-
chk(); // $ guarded='0 == call to returnAIfNoneAreNull:false' guarded='call to returnAIfNoneAreNull:not 0' MISSING: guarded='s:not null'
397+
chk(); // $ guarded='0 == call to returnAIfNoneAreNull:false' guarded='call to returnAIfNoneAreNull:not 0' guarded='s:not null' guarded='suffix:not null'
398398
}
399399

400400
switch (testEnumWrapper(b)) {

cpp/ql/test/library-tests/dataflow/dataflow-tests/BarrierGuard.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void test_guarded_wrapper() {
139139
int x = source();
140140

141141
if(guarded_wrapper(x)) {
142-
sink(x); // $ SPURIOUS: ast,ir
142+
sink(x); // $ SPURIOUS: ast
143143
} else {
144144
sink(x); // $ ast,ir
145145
}

cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ irFlow
158158
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
159159
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
160160
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
161-
| BarrierGuard.cpp:139:11:139:16 | call to source | BarrierGuard.cpp:142:10:142:10 | x |
162161
| BarrierGuard.cpp:139:11:139:16 | call to source | BarrierGuard.cpp:144:10:144:10 | x |
163162
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
164163
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |

0 commit comments

Comments
 (0)