Merge branch 'main' into log-injection-mad

This commit is contained in:
Jeongsoo Lee
2023-07-31 09:55:35 -07:00
committed by GitHub
42 changed files with 943 additions and 299 deletions

View File

@@ -171,11 +171,9 @@ private predicate invalidPointerToDerefSource(
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
// and the instruction computing the address for which we will search for a dereference.
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, rhsSizeDelta) and
// pai <= derefSource + deltaDerefSourceAndPai and deltaDerefSourceAndPai <= 0 is equivalent to
// derefSource >= pai + deltaDerefSourceAndPai and deltaDerefSourceAndPai >= 0
bounded1(pai, derefSource.asInstruction(), deltaDerefSourceAndPai) and
deltaDerefSourceAndPai <= 0 and
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
deltaDerefSourceAndPai >= 0 and
// TODO: This condition will go away once #13725 is merged, and then we can make `SizeBarrier`
// private to `AllocationToInvalidPointer.qll`.
not derefSource.getBasicBlock() =
AllocToInvalidPointer::SizeBarrier::getABarrierBlock(rhsSizeDelta)

View File

@@ -35,5 +35,14 @@ bindingset[i]
pragma[inline_late]
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
/**
* Holds if `i <= b + delta`.
*
* This predicate enforces a join-order that ensures that `b` has already been bound.
*/
bindingset[b]
pragma[inline_late]
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
/** Holds if `i <= b + delta`. */
predicate bounded = boundedImpl/3;

View File

@@ -132,6 +132,8 @@ edges
| test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | ... = ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | * ... |
| test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
@@ -139,46 +141,93 @@ edges
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | * ... |
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
| test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | * ... |
| test.cpp:381:5:381:9 | ... ++ | test.cpp:381:5:381:9 | ... ++ |
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:13:384:16 | * ... |
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
| test.cpp:410:14:410:27 | new[] | test.cpp:415:7:415:15 | ... = ... |
| test.cpp:411:15:411:23 | & ... | test.cpp:411:15:411:23 | & ... |
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
| test.cpp:413:5:413:8 | ... ++ | test.cpp:413:5:413:8 | ... ++ |
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
| test.cpp:421:14:421:27 | new[] | test.cpp:426:7:426:15 | ... = ... |
| test.cpp:422:15:422:23 | & ... | test.cpp:422:15:422:23 | & ... |
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
| test.cpp:424:5:424:8 | ... ++ | test.cpp:424:5:424:8 | ... ++ |
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
| test.cpp:432:14:432:27 | new[] | test.cpp:438:7:438:15 | ... = ... |
| test.cpp:433:15:433:23 | & ... | test.cpp:433:15:433:23 | & ... |
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
| test.cpp:436:5:436:8 | ... ++ | test.cpp:436:5:436:8 | ... ++ |
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
| test.cpp:444:14:444:27 | new[] | test.cpp:450:7:450:15 | ... = ... |
| test.cpp:445:15:445:23 | & ... | test.cpp:445:15:445:23 | & ... |
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
| test.cpp:448:5:448:8 | ... ++ | test.cpp:448:5:448:8 | ... ++ |
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
| test.cpp:480:14:480:27 | new[] | test.cpp:486:7:486:15 | ... = ... |
| test.cpp:481:15:481:23 | & ... | test.cpp:481:15:481:23 | & ... |
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
| test.cpp:484:5:484:8 | ... ++ | test.cpp:484:5:484:8 | ... ++ |
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
| test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... |
| test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... |
| test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... |
| test.cpp:652:14:652:27 | new[] | test.cpp:656:3:656:6 | ... ++ |
| test.cpp:652:14:652:27 | new[] | test.cpp:656:3:656:6 | ... ++ |
| test.cpp:652:14:652:27 | new[] | test.cpp:662:3:662:11 | ... = ... |
| test.cpp:656:3:656:6 | ... ++ | test.cpp:656:3:656:6 | ... ++ |
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
| test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... |
| test.cpp:695:13:695:26 | new[] | test.cpp:698:5:698:10 | ... += ... |
| test.cpp:698:5:698:10 | ... += ... | test.cpp:701:15:701:16 | * ... |
| test.cpp:705:18:705:18 | q | test.cpp:705:18:705:18 | q |
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
| test.cpp:711:13:711:26 | new[] | test.cpp:714:11:714:11 | q |
| test.cpp:714:11:714:11 | q | test.cpp:705:18:705:18 | q |
nodes
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
@@ -276,31 +325,45 @@ nodes
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:358:14:358:26 | * ... | semmle.label | * ... |
| test.cpp:359:14:359:32 | * ... | semmle.label | * ... |
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
| test.cpp:384:13:384:16 | * ... | semmle.label | * ... |
| test.cpp:410:14:410:27 | new[] | semmle.label | new[] |
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:415:7:415:15 | ... = ... | semmle.label | ... = ... |
| test.cpp:421:14:421:27 | new[] | semmle.label | new[] |
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:426:7:426:15 | ... = ... | semmle.label | ... = ... |
| test.cpp:432:14:432:27 | new[] | semmle.label | new[] |
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:438:7:438:15 | ... = ... | semmle.label | ... = ... |
| test.cpp:444:14:444:27 | new[] | semmle.label | new[] |
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:450:7:450:15 | ... = ... | semmle.label | ... = ... |
| test.cpp:480:14:480:27 | new[] | semmle.label | new[] |
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
| test.cpp:486:7:486:15 | ... = ... | semmle.label | ... = ... |
| test.cpp:543:14:543:27 | new[] | semmle.label | new[] |
| test.cpp:548:5:548:19 | ... = ... | semmle.label | ... = ... |
@@ -308,8 +371,20 @@ nodes
| test.cpp:559:5:559:19 | ... = ... | semmle.label | ... = ... |
| test.cpp:642:14:642:31 | new[] | semmle.label | new[] |
| test.cpp:647:5:647:19 | ... = ... | semmle.label | ... = ... |
| test.cpp:652:14:652:27 | new[] | semmle.label | new[] |
| test.cpp:656:3:656:6 | ... ++ | semmle.label | ... ++ |
| test.cpp:656:3:656:6 | ... ++ | semmle.label | ... ++ |
| test.cpp:662:3:662:11 | ... = ... | semmle.label | ... = ... |
| test.cpp:667:14:667:31 | new[] | semmle.label | new[] |
| test.cpp:675:7:675:23 | ... = ... | semmle.label | ... = ... |
| test.cpp:695:13:695:26 | new[] | semmle.label | new[] |
| test.cpp:698:5:698:10 | ... += ... | semmle.label | ... += ... |
| test.cpp:701:15:701:16 | * ... | semmle.label | * ... |
| test.cpp:705:18:705:18 | q | semmle.label | q |
| test.cpp:705:18:705:18 | q | semmle.label | q |
| test.cpp:706:12:706:13 | * ... | semmle.label | * ... |
| test.cpp:711:13:711:26 | new[] | semmle.label | new[] |
| test.cpp:714:11:714:11 | q | semmle.label | q |
subpaths
#select
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
@@ -343,4 +418,7 @@ subpaths
| test.cpp:548:5:548:19 | ... = ... | test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:543:14:543:27 | new[] | new[] | test.cpp:548:8:548:14 | src_pos | src_pos |
| test.cpp:559:5:559:19 | ... = ... | test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:554:14:554:27 | new[] | new[] | test.cpp:559:8:559:14 | src_pos | src_pos |
| test.cpp:647:5:647:19 | ... = ... | test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:642:14:642:31 | new[] | new[] | test.cpp:647:8:647:14 | src_pos | src_pos |
| test.cpp:662:3:662:11 | ... = ... | test.cpp:652:14:652:27 | new[] | test.cpp:662:3:662:11 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:652:14:652:27 | new[] | new[] | test.cpp:653:19:653:22 | size | size |
| test.cpp:675:7:675:23 | ... = ... | test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:667:14:667:31 | new[] | new[] | test.cpp:675:10:675:18 | ... ++ | ... ++ |
| test.cpp:701:15:701:16 | * ... | test.cpp:695:13:695:26 | new[] | test.cpp:701:15:701:16 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:695:13:695:26 | new[] | new[] | test.cpp:696:19:696:22 | size | size |
| test.cpp:706:12:706:13 | * ... | test.cpp:711:13:711:26 | new[] | test.cpp:706:12:706:13 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:711:13:711:26 | new[] | new[] | test.cpp:712:19:712:22 | size | size |

View File

@@ -17,7 +17,7 @@ void test2(int size) {
char* q = p + size - 1; // $ alloc=L16
char a = *q; // GOOD
char b = *(q - 1); // GOOD
char c = *(q + 1); // $ deref=L17->L20 // BAD
char c = *(q + 1); // $ deref=L20 // BAD
char d = *(q + size); // BAD [NOT DETECTED]
char e = *(q - size); // GOOD
char f = *(q + size + 1); // BAD [NOT DETECTED]
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
return;
}
p[index] = '\0'; // $ deref=L195->L201 deref=L197->L201 // BAD
p[index] = '\0'; // $ deref=L201 // BAD
}
void test13(unsigned len, unsigned index) {
@@ -210,7 +210,7 @@ void test13(unsigned len, unsigned index) {
return;
}
*q = '\0'; // $ deref=L206->L213 deref=L209->L213 // BAD
*q = '\0'; // $ deref=L213 // BAD
}
bool unknown();
@@ -261,7 +261,7 @@ void test17(unsigned len)
int *end = xs + len; // $ alloc=L260
for (int *x = xs; x <= end; x++)
{
int i = *x; // $ deref=L261->L264 deref=L262->L264 // BAD
int i = *x; // $ deref=L264 // BAD
}
}
@@ -271,7 +271,7 @@ void test18(unsigned len)
int *end = xs + len; // $ alloc=L270
for (int *x = xs; x <= end; x++)
{
*x = 0; // $ deref=L271->L274 deref=L272->L274 // BAD
*x = 0; // $ deref=L274 // BAD
}
}
@@ -355,8 +355,8 @@ void test25(unsigned size) {
char *xs = new char[size];
char *end = xs + size; // $ alloc=L355
char *end_plus_one = end + 1;
int val1 = *end_plus_one; // $ deref=L356->L358+1 deref=L357->L358+1 // BAD
int val2 = *(end_plus_one + 1); // $ deref=L356->L359+2 deref=L357->L359+2 // BAD
int val1 = *end_plus_one; // $ deref=L358+1 // BAD
int val2 = *(end_plus_one + 1); // $ deref=L359+2 // BAD
}
void test26(unsigned size) {
@@ -381,7 +381,7 @@ void test27(unsigned size, bool b) {
end++;
}
int val = *end; // $ deref=L378->L384+1 deref=L381->L384+1 // BAD
int val = *end; // $ deref=L384+1 // BAD
}
void test28(unsigned size) {
@@ -412,7 +412,7 @@ void test28_simple2(unsigned size) {
if (xs < end) {
xs++;
if (xs < end + 1) {
xs[0] = 0; // $ deref=L411->L415 deref=L412->L415 deref=L414->L415 // BAD
xs[0] = 0; // $ deref=L415 // BAD
}
}
}
@@ -423,7 +423,7 @@ void test28_simple3(unsigned size) {
if (xs < end) {
xs++;
if (xs - 1 < end) {
xs[0] = 0; // $ deref=L422->L426 deref=L423->L426 deref=L425->L426 // BAD
xs[0] = 0; // $ deref=L426 // BAD
}
}
}
@@ -435,7 +435,7 @@ void test28_simple4(unsigned size) {
end++;
xs++;
if (xs < end) {
xs[0] = 0; // $ deref=L433->L438 deref=L434->L438 deref=L435->L438 // BAD
xs[0] = 0; // $ deref=L438 // BAD
}
}
}
@@ -447,7 +447,7 @@ void test28_simple5(unsigned size) {
if (xs < end) {
xs++;
if (xs < end) {
xs[0] = 0; // $ deref=L445->L450 deref=L446->L450 // BAD
xs[0] = 0; // $ deref=L450 // BAD
}
}
}
@@ -483,7 +483,7 @@ void test28_simple8(unsigned size) {
if (xs < end) {
xs++;
if (xs < end - 1) {
xs[0] = 0; // $ deref=L481->L486+498 deref=L482->L486+498 // BAD
xs[0] = 0; // $ deref=L486+498 // BAD
}
}
}
@@ -659,7 +659,7 @@ void test32(unsigned size) {
xs++;
if (xs >= end)
return;
xs[0] = 0; // $ GOOD
xs[0] = 0; // $ deref=L656->L662+1 deref=L657->L662+1 GOOD [FALSE POSITIVE]
}
void test33(unsigned size, unsigned src_pos)
@@ -698,12 +698,12 @@ void test34(unsigned size) {
p += 1;
}
if (p + 1 < end) {
int val = *p; // GOOD
int val = *p; // $ deref=L698->L700->L701 // GOOD [FALSE POSITIVE]
}
}
void deref(char* q) {
char x = *q; // $ MISSING: deref=L712->L706 deref=L713->L706
char x = *q; // $ deref=L714->L705->L706 // BAD
}
void test35(unsigned long size, char* q)

View File

@@ -15030,25 +15030,28 @@ ir.cpp:
# 1999| Value = [Literal] 5
# 1999| ValueCategory = prvalue
# 2000| getStmt(3): [ExprStmt] ExprStmt
# 2000| getExpr(): [ConditionalExpr] ... ? ... : ...
# 2000| getExpr(): [AssignExpr] ... = ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getCondition(): [VariableAccess] a
# 2000| Type = [BoolType] bool
# 2000| ValueCategory = prvalue(load)
# 2000| getThen(): [VariableAccess] x
# 2000| getLValue(): [ConditionalExpr] ... ? ... : ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getElse(): [AssignExpr] ... = ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getLValue(): [VariableAccess] y
# 2000| getCondition(): [VariableAccess] a
# 2000| Type = [BoolType] bool
# 2000| ValueCategory = prvalue(load)
# 2000| getThen(): [VariableAccess] x
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getRValue(): [Literal] 7
# 2000| getElse(): [VariableAccess] y
# 2000| Type = [IntType] int
# 2000| Value = [Literal] 7
# 2000| ValueCategory = prvalue
# 2000| ValueCategory = lvalue
# 2000| getRValue(): [Literal] 7
# 2000| Type = [IntType] int
# 2000| Value = [Literal] 7
# 2000| ValueCategory = prvalue
# 2000| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2001| getStmt(4): [ReturnStmt] return ...
# 2003| [CopyAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj const&)
# 2003| <params>:
@@ -15151,31 +15154,34 @@ ir.cpp:
# 2010| getExpr(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getLValue(): [VariableAccess] z
# 2010| getLValue(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue
# 2010| getCondition(): [VariableAccess] a
# 2010| Type = [BoolType] bool
# 2010| ValueCategory = prvalue(load)
# 2010| getThen(): [VariableAccess] x
# 2010| getLValue(): [VariableAccess] z
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2010| getElse(): [AssignExpr] ... = ...
# 2010| ValueCategory = lvalue
# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue
# 2010| getLValue(): [VariableAccess] y
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getRValue(): [Literal] 0
# 2010| Type = [Struct] TernaryPodObj
# 2010| Value = [Literal] 0
# 2010| ValueCategory = prvalue
# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2010| getCondition(): [VariableAccess] a
# 2010| Type = [BoolType] bool
# 2010| ValueCategory = prvalue(load)
# 2010| getThen(): [VariableAccess] x
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2010| getElse(): [VariableAccess] y
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2010| getRValue(): [Literal] 0
# 2010| Type = [Struct] TernaryPodObj
# 2010| Value = [Literal] 0
# 2010| ValueCategory = prvalue
# 2010| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2011| getStmt(4): [ReturnStmt] return ...
# 2013| [CopyAssignmentOperator] TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
# 2013| <params>:
@@ -15339,38 +15345,38 @@ ir.cpp:
# 2021| getExpr(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getQualifier(): [VariableAccess] z
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getCondition(): [VariableAccess] a
# 2021| Type = [BoolType] bool
# 2021| ValueCategory = prvalue(load)
# 2021| getThen(): [VariableAccess] x
# 2021| getQualifier(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getQualifier(): [VariableAccess] z
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getElse(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getQualifier(): [VariableAccess] y
# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getCondition(): [VariableAccess] a
# 2021| Type = [BoolType] bool
# 2021| ValueCategory = prvalue(load)
# 2021| getThen(): [VariableAccess] x
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
# 2021| Type = [VoidType] void
# 2021| ValueCategory = prvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr(): [TemporaryObjectExpr] temporary object
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getElse().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| getElse(): [VariableAccess] y
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
# 2021| Type = [VoidType] void
# 2021| ValueCategory = prvalue
# 2021| getQualifier().getFullyConverted(): [ParenthesisExpr] (...)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
@@ -15380,6 +15386,9 @@ ir.cpp:
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr(): [TemporaryObjectExpr] temporary object
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue

View File

@@ -1997,7 +1997,7 @@ void TernaryTestInt(bool a, int x, int y, int z) {
z = a ? x : y;
z = a ? x : 5;
z = a ? 3 : 5;
a ? x : y = 7;
(a ? x : y) = 7;
}
struct TernaryPodObj {
@@ -2007,7 +2007,7 @@ void TernaryTestPodObj(bool a, TernaryPodObj x, TernaryPodObj y, TernaryPodObj z
z = a ? x : y;
z = a ? x : TernaryPodObj();
z = a ? TernaryPodObj() : TernaryPodObj();
z = a ? x : y = TernaryPodObj();
(z = a ? x : y) = TernaryPodObj();
}
struct TernaryNonPodObj {
@@ -2018,7 +2018,7 @@ void TernaryTestNonPodObj(bool a, TernaryNonPodObj x, TernaryNonPodObj y, Ternar
z = a ? x : y;
z = a ? x : TernaryNonPodObj();
z = a ? TernaryNonPodObj() : TernaryNonPodObj();
z = a ? x : y = TernaryNonPodObj();
(z = a ? x : y) = TernaryNonPodObj();
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -9078,7 +9078,7 @@
| ir.cpp:1993:13:1993:32 | StoreValue | r1993_2 |
| ir.cpp:1996:6:1996:19 | ChiPartial | partial:m1996_3 |
| ir.cpp:1996:6:1996:19 | ChiTotal | total:m1996_2 |
| ir.cpp:1996:6:1996:19 | SideEffect | m1996_3 |
| ir.cpp:1996:6:1996:19 | SideEffect | ~m2000_9 |
| ir.cpp:1996:26:1996:26 | Address | &:r1996_5 |
| ir.cpp:1996:33:1996:33 | Address | &:r1996_7 |
| ir.cpp:1996:40:1996:40 | Address | &:r1996_9 |
@@ -9128,20 +9128,21 @@
| ir.cpp:1999:9:1999:17 | StoreValue | r1999_6 |
| ir.cpp:1999:13:1999:13 | StoreValue | r1999_9 |
| ir.cpp:1999:17:1999:17 | StoreValue | r1999_12 |
| ir.cpp:2000:5:2000:5 | Address | &:r2000_1 |
| ir.cpp:2000:5:2000:5 | Condition | r2000_2 |
| ir.cpp:2000:5:2000:5 | Load | m1996_6 |
| ir.cpp:2000:5:2000:17 | Address | &:r2000_5 |
| ir.cpp:2000:5:2000:17 | Address | &:r2000_8 |
| ir.cpp:2000:5:2000:17 | Address | &:r2000_14 |
| ir.cpp:2000:5:2000:17 | Load | m2000_4 |
| ir.cpp:2000:5:2000:17 | Phi | from 11:m2000_9 |
| ir.cpp:2000:5:2000:17 | Phi | from 12:m2000_15 |
| ir.cpp:2000:9:2000:9 | StoreValue | r2000_7 |
| ir.cpp:2000:13:2000:13 | Address | &:r2000_11 |
| ir.cpp:2000:13:2000:13 | Unary | r2000_11 |
| ir.cpp:2000:13:2000:17 | StoreValue | r2000_13 |
| ir.cpp:2000:17:2000:17 | StoreValue | r2000_10 |
| ir.cpp:2000:5:2000:19 | ChiPartial | partial:m2000_8 |
| ir.cpp:2000:5:2000:19 | ChiTotal | total:m1996_4 |
| ir.cpp:2000:6:2000:6 | Address | &:r2000_2 |
| ir.cpp:2000:6:2000:6 | Condition | r2000_3 |
| ir.cpp:2000:6:2000:6 | Load | m1996_6 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_6 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_7 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_11 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_14 |
| ir.cpp:2000:6:2000:14 | Load | m2000_5 |
| ir.cpp:2000:6:2000:14 | Phi | from 11:m2000_12 |
| ir.cpp:2000:6:2000:14 | Phi | from 12:m2000_15 |
| ir.cpp:2000:10:2000:10 | StoreValue | r2000_10 |
| ir.cpp:2000:14:2000:14 | StoreValue | r2000_13 |
| ir.cpp:2000:19:2000:19 | StoreValue | r2000_1 |
| ir.cpp:2006:6:2006:22 | ChiPartial | partial:m2006_3 |
| ir.cpp:2006:6:2006:22 | ChiTotal | total:m2006_2 |
| ir.cpp:2006:6:2006:22 | SideEffect | m2006_3 |
@@ -9218,28 +9219,30 @@
| ir.cpp:2009:31:2009:45 | Load | m2009_20 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_19 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_21 |
| ir.cpp:2010:5:2010:5 | Address | &:r2010_7 |
| ir.cpp:2010:9:2010:9 | Address | &:r2010_1 |
| ir.cpp:2010:9:2010:9 | Condition | r2010_2 |
| ir.cpp:2010:9:2010:9 | Load | m2006_6 |
| ir.cpp:2010:9:2010:35 | Address | &:r2010_5 |
| ir.cpp:2010:9:2010:35 | Address | &:r2010_11 |
| ir.cpp:2010:9:2010:35 | Address | &:r2010_20 |
| ir.cpp:2010:9:2010:35 | Load | m2010_4 |
| ir.cpp:2010:9:2010:35 | Phi | from 11:m2010_12 |
| ir.cpp:2010:9:2010:35 | Phi | from 12:m2010_21 |
| ir.cpp:2010:9:2010:35 | StoreValue | r2010_6 |
| ir.cpp:2010:13:2010:13 | Address | &:r2010_9 |
| ir.cpp:2010:13:2010:13 | Load | m2006_8 |
| ir.cpp:2010:13:2010:13 | StoreValue | r2010_10 |
| ir.cpp:2010:17:2010:17 | Address | &:r2010_17 |
| ir.cpp:2010:17:2010:35 | StoreValue | r2010_19 |
| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
| ir.cpp:2010:21:2010:35 | Load | m2010_15 |
| ir.cpp:2010:21:2010:35 | StoreValue | r2010_14 |
| ir.cpp:2010:21:2010:35 | StoreValue | r2010_16 |
| ir.cpp:2010:21:2010:35 | Unary | r2010_16 |
| ir.cpp:2010:6:2010:6 | Address | &:r2010_11 |
| ir.cpp:2010:6:2010:6 | Unary | r2010_11 |
| ir.cpp:2010:6:2010:18 | Address | &:r2010_13 |
| ir.cpp:2010:10:2010:10 | Address | &:r2010_5 |
| ir.cpp:2010:10:2010:10 | Condition | r2010_6 |
| ir.cpp:2010:10:2010:10 | Load | m2006_6 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_9 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_17 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_21 |
| ir.cpp:2010:10:2010:18 | Load | m2010_8 |
| ir.cpp:2010:10:2010:18 | Phi | from 11:m2010_18 |
| ir.cpp:2010:10:2010:18 | Phi | from 12:m2010_22 |
| ir.cpp:2010:10:2010:18 | StoreValue | r2010_10 |
| ir.cpp:2010:14:2010:14 | Address | &:r2010_15 |
| ir.cpp:2010:14:2010:14 | Load | m2006_8 |
| ir.cpp:2010:14:2010:14 | StoreValue | r2010_16 |
| ir.cpp:2010:18:2010:18 | Address | &:r2010_19 |
| ir.cpp:2010:18:2010:18 | Load | m2006_10 |
| ir.cpp:2010:18:2010:18 | StoreValue | r2010_20 |
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
| ir.cpp:2010:23:2010:37 | Load | m2010_3 |
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_2 |
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_4 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
@@ -9280,7 +9283,7 @@
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_8 |
| ir.cpp:2017:6:2017:25 | ChiPartial | partial:m2017_3 |
| ir.cpp:2017:6:2017:25 | ChiTotal | total:m2017_2 |
| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_14 |
| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_32 |
| ir.cpp:2017:32:2017:32 | Address | &:r2017_5 |
| ir.cpp:2017:52:2017:52 | Address | &:r2017_7 |
| ir.cpp:2017:72:2017:72 | Address | &:r2017_9 |
@@ -9423,60 +9426,58 @@
| ir.cpp:2020:34:2020:51 | Load | m2020_40 |
| ir.cpp:2020:34:2020:51 | SideEffect | ~m2019_16 |
| ir.cpp:2020:34:2020:51 | StoreValue | r2020_41 |
| ir.cpp:2021:5:2021:5 | Address | &:r2021_1 |
| ir.cpp:2021:5:2021:5 | Address | &:r2021_1 |
| ir.cpp:2021:5:2021:5 | Arg(this) | this:r2021_1 |
| ir.cpp:2021:5:2021:5 | ChiPartial | partial:m2021_17 |
| ir.cpp:2021:5:2021:5 | ChiTotal | total:m2020_20 |
| ir.cpp:2021:5:2021:5 | SideEffect | m2020_20 |
| ir.cpp:2021:7:2021:7 | CallTarget | func:r2021_2 |
| ir.cpp:2021:7:2021:7 | ChiPartial | partial:m2021_13 |
| ir.cpp:2021:7:2021:7 | ChiTotal | total:m2021_6 |
| ir.cpp:2021:7:2021:7 | SideEffect | ~m2021_6 |
| ir.cpp:2021:7:2021:7 | Unary | r2021_12 |
| ir.cpp:2021:9:2021:9 | Address | &:r2021_3 |
| ir.cpp:2021:9:2021:9 | Condition | r2021_4 |
| ir.cpp:2021:9:2021:9 | Load | m2017_6 |
| ir.cpp:2021:9:2021:38 | Address | &:r2021_8 |
| ir.cpp:2021:9:2021:38 | Address | &:r2021_11 |
| ir.cpp:2021:9:2021:38 | Address | &:r2021_21 |
| ir.cpp:2021:9:2021:38 | Address | &:r2021_43 |
| ir.cpp:2021:9:2021:38 | Arg(0) | 0:r2021_11 |
| ir.cpp:2021:9:2021:38 | Load | m2021_7 |
| ir.cpp:2021:9:2021:38 | Phi | from 11:m2021_22 |
| ir.cpp:2021:9:2021:38 | Phi | from 11:~m2020_16 |
| ir.cpp:2021:9:2021:38 | Phi | from 12:m2021_44 |
| ir.cpp:2021:9:2021:38 | Phi | from 12:~m2021_37 |
| ir.cpp:2021:9:2021:38 | SideEffect | ~m2021_14 |
| ir.cpp:2021:9:2021:38 | Unary | r2021_9 |
| ir.cpp:2021:9:2021:38 | Unary | r2021_10 |
| ir.cpp:2021:13:2021:13 | StoreValue | r2021_20 |
| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
| ir.cpp:2021:17:2021:17 | Arg(this) | this:r2021_23 |
| ir.cpp:2021:17:2021:17 | ChiPartial | partial:m2021_40 |
| ir.cpp:2021:17:2021:17 | ChiTotal | total:m2017_10 |
| ir.cpp:2021:17:2021:17 | SideEffect | m2017_10 |
| ir.cpp:2021:19:2021:19 | CallTarget | func:r2021_24 |
| ir.cpp:2021:19:2021:19 | ChiPartial | partial:m2021_36 |
| ir.cpp:2021:19:2021:19 | ChiTotal | total:m2021_30 |
| ir.cpp:2021:19:2021:19 | SideEffect | ~m2021_30 |
| ir.cpp:2021:19:2021:19 | Unary | r2021_35 |
| ir.cpp:2021:19:2021:39 | StoreValue | r2021_42 |
| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
| ir.cpp:2021:21:2021:38 | Address | &:r2021_34 |
| ir.cpp:2021:21:2021:38 | Arg(0) | 0:r2021_34 |
| ir.cpp:2021:21:2021:38 | Arg(this) | this:r2021_25 |
| ir.cpp:2021:21:2021:38 | CallTarget | func:r2021_27 |
| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_29 |
| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_31 |
| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2020_16 |
| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2021_26 |
| ir.cpp:2021:21:2021:38 | SideEffect | ~m2020_16 |
| ir.cpp:2021:21:2021:38 | SideEffect | ~m2021_32 |
| ir.cpp:2021:21:2021:38 | Unary | r2021_25 |
| ir.cpp:2021:21:2021:38 | Unary | r2021_33 |
| ir.cpp:2021:5:2021:19 | ChiPartial | partial:m2021_35 |
| ir.cpp:2021:5:2021:19 | ChiTotal | total:m2021_17 |
| ir.cpp:2021:5:2021:19 | SideEffect | m2021_17 |
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
| ir.cpp:2021:6:2021:6 | Arg(this) | this:r2021_1 |
| ir.cpp:2021:6:2021:6 | ChiPartial | partial:m2021_16 |
| ir.cpp:2021:6:2021:6 | ChiTotal | total:m2020_20 |
| ir.cpp:2021:6:2021:6 | SideEffect | m2020_20 |
| ir.cpp:2021:8:2021:8 | CallTarget | func:r2021_2 |
| ir.cpp:2021:8:2021:8 | ChiPartial | partial:m2021_12 |
| ir.cpp:2021:8:2021:8 | ChiTotal | total:m2020_16 |
| ir.cpp:2021:8:2021:8 | SideEffect | ~m2020_16 |
| ir.cpp:2021:8:2021:8 | Unary | r2021_11 |
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
| ir.cpp:2021:8:2021:19 | Arg(this) | this:r2021_18 |
| ir.cpp:2021:10:2021:10 | Address | &:r2021_3 |
| ir.cpp:2021:10:2021:10 | Condition | r2021_4 |
| ir.cpp:2021:10:2021:10 | Load | m2017_6 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_7 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_10 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_39 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_42 |
| ir.cpp:2021:10:2021:18 | Arg(0) | 0:r2021_10 |
| ir.cpp:2021:10:2021:18 | Load | m2021_6 |
| ir.cpp:2021:10:2021:18 | Phi | from 11:m2021_40 |
| ir.cpp:2021:10:2021:18 | Phi | from 12:m2021_43 |
| ir.cpp:2021:10:2021:18 | SideEffect | ~m2021_13 |
| ir.cpp:2021:10:2021:18 | Unary | r2021_8 |
| ir.cpp:2021:10:2021:18 | Unary | r2021_9 |
| ir.cpp:2021:14:2021:14 | StoreValue | r2021_38 |
| ir.cpp:2021:18:2021:18 | StoreValue | r2021_41 |
| ir.cpp:2021:21:2021:21 | CallTarget | func:r2021_19 |
| ir.cpp:2021:21:2021:21 | ChiPartial | partial:m2021_31 |
| ir.cpp:2021:21:2021:21 | ChiTotal | total:m2021_25 |
| ir.cpp:2021:21:2021:21 | SideEffect | ~m2021_25 |
| ir.cpp:2021:21:2021:21 | Unary | r2021_30 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_29 |
| ir.cpp:2021:23:2021:40 | Arg(0) | 0:r2021_29 |
| ir.cpp:2021:23:2021:40 | Arg(this) | this:r2021_20 |
| ir.cpp:2021:23:2021:40 | CallTarget | func:r2021_22 |
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_24 |
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_26 |
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_13 |
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_21 |
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_13 |
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_27 |
| ir.cpp:2021:23:2021:40 | Unary | r2021_20 |
| ir.cpp:2021:23:2021:40 | Unary | r2021_28 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -10529,9 +10529,10 @@ ir.cpp:
# 1999| r1999_5(int) = Load[#temp1999:9] : &:r1999_4, ~m?
# 1999| r1999_6(glval<int>) = VariableAddress[z] :
# 1999| mu1999_7(int) = Store[z] : &:r1999_6, r1999_5
# 2000| r2000_1(glval<bool>) = VariableAddress[a] :
# 2000| r2000_2(bool) = Load[a] : &:r2000_1, ~m?
# 2000| v2000_3(void) = ConditionalBranch : r2000_2
# 2000| r2000_1(int) = Constant[7] :
# 2000| r2000_2(glval<bool>) = VariableAddress[a] :
# 2000| r2000_3(bool) = Load[a] : &:r2000_2, ~m?
# 2000| v2000_4(void) = ConditionalBranch : r2000_3
#-----| False -> Block 12
#-----| True -> Block 11
@@ -10548,26 +10549,24 @@ ir.cpp:
#-----| Goto -> Block 7
# 2000| Block 10
# 2000| r2000_4(glval<unknown>) = VariableAddress[#temp2000:5] :
# 2000| r2000_5(glval<int>) = Load[#temp2000:5] : &:r2000_4, ~m?
# 2000| r2000_5(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| r2000_6(glval<int>) = Load[#temp2000:6] : &:r2000_5, ~m?
# 2000| mu2000_7(int) = Store[?] : &:r2000_6, r2000_1
# 2001| v2001_1(void) = NoOp :
# 1996| v1996_12(void) = ReturnVoid :
# 1996| v1996_13(void) = AliasedUse : ~m?
# 1996| v1996_14(void) = ExitFunction :
# 2000| Block 11
# 2000| r2000_6(glval<int>) = VariableAddress[x] :
# 2000| r2000_7(glval<unknown>) = VariableAddress[#temp2000:5] :
# 2000| mu2000_8(glval<int>) = Store[#temp2000:5] : &:r2000_7, r2000_6
# 2000| r2000_8(glval<int>) = VariableAddress[x] :
# 2000| r2000_9(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| mu2000_10(glval<int>) = Store[#temp2000:6] : &:r2000_9, r2000_8
#-----| Goto -> Block 10
# 2000| Block 12
# 2000| r2000_9(int) = Constant[7] :
# 2000| r2000_10(glval<int>) = VariableAddress[y] :
# 2000| mu2000_11(int) = Store[y] : &:r2000_10, r2000_9
# 2000| r2000_12(glval<int>) = CopyValue : r2000_10
# 2000| r2000_13(glval<unknown>) = VariableAddress[#temp2000:5] :
# 2000| mu2000_14(glval<int>) = Store[#temp2000:5] : &:r2000_13, r2000_12
# 2000| r2000_11(glval<int>) = VariableAddress[y] :
# 2000| r2000_12(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| mu2000_13(glval<int>) = Store[#temp2000:6] : &:r2000_12, r2000_11
#-----| Goto -> Block 10
# 2006| void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
@@ -10649,15 +10648,19 @@ ir.cpp:
#-----| Goto -> Block 4
# 2009| Block 7
# 2009| r2009_5(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
# 2009| r2009_9(glval<TernaryPodObj>) = VariableAddress[z] :
# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
# 2010| r2010_1(glval<bool>) = VariableAddress[a] :
# 2010| r2010_2(bool) = Load[a] : &:r2010_1, ~m?
# 2010| v2010_3(void) = ConditionalBranch : r2010_2
# 2009| r2009_5(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
# 2009| r2009_9(glval<TernaryPodObj>) = VariableAddress[z] :
# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
# 2010| r2010_1(glval<TernaryPodObj>) = VariableAddress[#temp2010:23] :
# 2010| r2010_2(TernaryPodObj) = Constant[0] :
# 2010| mu2010_3(TernaryPodObj) = Store[#temp2010:23] : &:r2010_1, r2010_2
# 2010| r2010_4(TernaryPodObj) = Load[#temp2010:23] : &:r2010_1, ~m?
# 2010| r2010_5(glval<bool>) = VariableAddress[a] :
# 2010| r2010_6(bool) = Load[a] : &:r2010_5, ~m?
# 2010| v2010_7(void) = ConditionalBranch : r2010_6
#-----| False -> Block 12
#-----| True -> Block 11
@@ -10680,32 +10683,29 @@ ir.cpp:
#-----| Goto -> Block 7
# 2010| Block 10
# 2010| r2010_4(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
# 2010| r2010_5(TernaryPodObj) = Load[#temp2010:9] : &:r2010_4, ~m?
# 2010| r2010_6(glval<TernaryPodObj>) = VariableAddress[z] :
# 2010| mu2010_7(TernaryPodObj) = Store[z] : &:r2010_6, r2010_5
# 2011| v2011_1(void) = NoOp :
# 2006| v2006_12(void) = ReturnVoid :
# 2006| v2006_13(void) = AliasedUse : ~m?
# 2006| v2006_14(void) = ExitFunction :
# 2010| r2010_8(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| r2010_9(TernaryPodObj) = Load[#temp2010:10] : &:r2010_8, ~m?
# 2010| r2010_10(glval<TernaryPodObj>) = VariableAddress[z] :
# 2010| mu2010_11(TernaryPodObj) = Store[z] : &:r2010_10, r2010_9
# 2010| r2010_12(glval<TernaryPodObj>) = CopyValue : r2010_10
# 2010| mu2010_13(TernaryPodObj) = Store[?] : &:r2010_12, r2010_4
# 2011| v2011_1(void) = NoOp :
# 2006| v2006_12(void) = ReturnVoid :
# 2006| v2006_13(void) = AliasedUse : ~m?
# 2006| v2006_14(void) = ExitFunction :
# 2010| Block 11
# 2010| r2010_8(glval<TernaryPodObj>) = VariableAddress[x] :
# 2010| r2010_9(TernaryPodObj) = Load[x] : &:r2010_8, ~m?
# 2010| r2010_10(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
# 2010| mu2010_11(TernaryPodObj) = Store[#temp2010:9] : &:r2010_10, r2010_9
# 2010| r2010_14(glval<TernaryPodObj>) = VariableAddress[x] :
# 2010| r2010_15(TernaryPodObj) = Load[x] : &:r2010_14, ~m?
# 2010| r2010_16(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| mu2010_17(TernaryPodObj) = Store[#temp2010:10] : &:r2010_16, r2010_15
#-----| Goto -> Block 10
# 2010| Block 12
# 2010| r2010_12(glval<TernaryPodObj>) = VariableAddress[#temp2010:21] :
# 2010| r2010_13(TernaryPodObj) = Constant[0] :
# 2010| mu2010_14(TernaryPodObj) = Store[#temp2010:21] : &:r2010_12, r2010_13
# 2010| r2010_15(TernaryPodObj) = Load[#temp2010:21] : &:r2010_12, ~m?
# 2010| r2010_16(glval<TernaryPodObj>) = VariableAddress[y] :
# 2010| mu2010_17(TernaryPodObj) = Store[y] : &:r2010_16, r2010_15
# 2010| r2010_18(TernaryPodObj) = CopyValue : r2010_15
# 2010| r2010_19(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
# 2010| mu2010_20(TernaryPodObj) = Store[#temp2010:9] : &:r2010_19, r2010_18
# 2010| r2010_18(glval<TernaryPodObj>) = VariableAddress[y] :
# 2010| r2010_19(TernaryPodObj) = Load[y] : &:r2010_18, ~m?
# 2010| r2010_20(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| mu2010_21(TernaryPodObj) = Store[#temp2010:10] : &:r2010_20, r2010_19
#-----| Goto -> Block 10
# 2013| TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
@@ -10931,46 +10931,46 @@ ir.cpp:
#-----| Goto -> Block 7
# 2021| Block 10
# 2021| r2021_6(glval<unknown>) = VariableAddress[#temp2021:9] :
# 2021| r2021_7(glval<TernaryNonPodObj>) = Load[#temp2021:9] : &:r2021_6, ~m?
# 2021| r2021_8(glval<TernaryNonPodObj>) = Convert : r2021_7
# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
# 2021| r2021_15(glval<TernaryNonPodObj>) = CopyValue : r2021_10
# 2022| v2022_1(void) = NoOp :
# 2017| v2017_12(void) = ReturnVoid :
# 2017| v2017_13(void) = AliasedUse : ~m?
# 2017| v2017_14(void) = ExitFunction :
# 2021| r2021_6(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| r2021_7(glval<TernaryNonPodObj>) = Load[#temp2021:10] : &:r2021_6, ~m?
# 2021| r2021_8(glval<TernaryNonPodObj>) = Convert : r2021_7
# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
# 2021| r2021_15(glval<TernaryNonPodObj>) = CopyValue : r2021_10
# 2021| r2021_16(glval<unknown>) = FunctionAddress[operator=] :
# 2021| r2021_17(glval<TernaryNonPodObj>) = VariableAddress[#temp2021:23] :
# 2021| mu2021_18(TernaryNonPodObj) = Uninitialized[#temp2021:23] : &:r2021_17
# 2021| r2021_19(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2021| v2021_20(void) = Call[TernaryNonPodObj] : func:r2021_19, this:r2021_17
# 2021| mu2021_21(unknown) = ^CallSideEffect : ~m?
# 2021| mu2021_22(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_17
# 2021| r2021_23(glval<TernaryNonPodObj>) = Convert : r2021_17
# 2021| r2021_24(TernaryNonPodObj &) = CopyValue : r2021_23
# 2021| r2021_25(TernaryNonPodObj &) = Call[operator=] : func:r2021_16, this:r2021_15, 0:r2021_24
# 2021| mu2021_26(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_27(void) = ^IndirectReadSideEffect[-1] : &:r2021_15, ~m?
# 2021| v2021_28(void) = ^BufferReadSideEffect[0] : &:r2021_24, ~m?
# 2021| mu2021_29(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_15
# 2021| r2021_30(glval<TernaryNonPodObj>) = CopyValue : r2021_25
# 2022| v2022_1(void) = NoOp :
# 2017| v2017_12(void) = ReturnVoid :
# 2017| v2017_13(void) = AliasedUse : ~m?
# 2017| v2017_14(void) = ExitFunction :
# 2021| Block 11
# 2021| r2021_16(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2021| r2021_17(glval<unknown>) = VariableAddress[#temp2021:9] :
# 2021| mu2021_18(glval<TernaryNonPodObj>) = Store[#temp2021:9] : &:r2021_17, r2021_16
# 2021| r2021_31(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2021| r2021_32(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| mu2021_33(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_32, r2021_31
#-----| Goto -> Block 10
# 2021| Block 12
# 2021| r2021_19(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2021| r2021_20(glval<unknown>) = FunctionAddress[operator=] :
# 2021| r2021_21(glval<TernaryNonPodObj>) = VariableAddress[#temp2021:21] :
# 2021| mu2021_22(TernaryNonPodObj) = Uninitialized[#temp2021:21] : &:r2021_21
# 2021| r2021_23(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2021| v2021_24(void) = Call[TernaryNonPodObj] : func:r2021_23, this:r2021_21
# 2021| mu2021_25(unknown) = ^CallSideEffect : ~m?
# 2021| mu2021_26(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_21
# 2021| r2021_27(glval<TernaryNonPodObj>) = Convert : r2021_21
# 2021| r2021_28(TernaryNonPodObj &) = CopyValue : r2021_27
# 2021| r2021_29(TernaryNonPodObj &) = Call[operator=] : func:r2021_20, this:r2021_19, 0:r2021_28
# 2021| mu2021_30(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_31(void) = ^IndirectReadSideEffect[-1] : &:r2021_19, ~m?
# 2021| v2021_32(void) = ^BufferReadSideEffect[0] : &:r2021_28, ~m?
# 2021| mu2021_33(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_19
# 2021| r2021_34(glval<TernaryNonPodObj>) = CopyValue : r2021_29
# 2021| r2021_35(glval<unknown>) = VariableAddress[#temp2021:9] :
# 2021| mu2021_36(glval<TernaryNonPodObj>) = Store[#temp2021:9] : &:r2021_35, r2021_34
# 2021| r2021_34(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2021| r2021_35(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| mu2021_36(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_35, r2021_34
#-----| Goto -> Block 10
perf-regression.cpp:

View File

@@ -2,7 +2,7 @@
.. pull-quote:: Note
The data flow library described here is available from CodeQL 2.12.5 onwards. For information on the previous version of the library, see :ref:`Analyzing data flow in C and C++ <analyzing-data-flow-in-cpp>`.
The data flow library described here is available from CodeQL 2.12.5 onwards. With the release of CodeQL 2.13.0 the library uses the new modular API for data flow. For information on the previous version of the library, see :ref:`Analyzing data flow in C and C++ <analyzing-data-flow-in-cpp>` and for information about the new modular API and how to migrate any existing queries to the updated data flow library, see `New dataflow API for CodeQL query writing <https://gh.io/codeql-new-dataflow-api>`__.
Analyzing data flow in C and C++ (new)
======================================

View File

@@ -2,7 +2,7 @@
.. pull-quote:: Note
The data flow library used in this article has been replaced with an improved library which is available from CodeQL 2.12.5 onwards, see :ref:`Analyzing data flow in C and C++ (new) <analyzing-data-flow-in-cpp-new>`. The old library has been deprecated in CodeQL 2.14.1 and will be removed in a later release.
The data flow library used in this article has been replaced with an improved library which is available from CodeQL 2.12.5 onwards, see :ref:`Analyzing data flow in C and C++ (new) <analyzing-data-flow-in-cpp-new>`. The old library has been deprecated in CodeQL 2.14.1 and will be removed in a later release. With the release of CodeQL 2.13.0 both libraries use the new modular API for data flow.
Analyzing data flow in C and C++
================================

View File

@@ -12,6 +12,8 @@ This article describes how data flow analysis is implemented in the CodeQL libra
The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking.
For a more general introduction to modeling data flow, see ":ref:`About data flow analysis <about-data-flow-analysis>`."
.. include:: ../reusables/new-data-flow-api.rst
Local data flow
---------------

View File

@@ -17,6 +17,8 @@ The following sections describe how to use the libraries for local data flow, gl
For a more general introduction to modeling data flow, see ":ref:`About data flow analysis <about-data-flow-analysis>`."
.. include:: ../reusables/new-data-flow-api.rst
Local data flow
---------------

View File

@@ -12,6 +12,8 @@ This article describes how data flow analysis is implemented in the CodeQL libra
The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking.
For a more general introduction to modeling data flow, see ":ref:`About data flow analysis <about-data-flow-analysis>`."
.. include:: ../reusables/new-data-flow-api.rst
Local data flow
---------------

View File

@@ -12,6 +12,8 @@ This article describes how data flow analysis is implemented in the CodeQL libra
The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking.
For a more general introduction to modeling data flow, see ":ref:`About data flow analysis <about-data-flow-analysis>`."
.. include:: ../reusables/new-data-flow-api.rst
Local data flow
---------------

View File

@@ -0,0 +1,4 @@
.. pull-quote:: Note
The new modular API for data flow described here is available alongside the previous library from CodeQL 2.13.0 onwards. For information about how the library has changed and how to migrate any existing queries to the modular API, see `New dataflow API for CodeQL query writing <https://gh.io/codeql-new-dataflow-api>`__.

View File

@@ -5,6 +5,8 @@ Creating path queries
You can create path queries to visualize the flow of information through a codebase.
.. include:: ../reusables/new-data-flow-api.rst
Overview
========

View File

@@ -3,6 +3,8 @@
Debugging data-flow queries using partial flow
==============================================
.. include:: ../reusables/new-data-flow-api.rst
If a data-flow query doesn't produce the results you expect to see, you can use partial flow to debug the problem.
In CodeQL, you can use :ref:`data flow analysis <about-data-flow-analysis>` to compute the possible values that a variable can hold at various points in a program.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added more dataflow steps for `java.io.InputStream`s that wrap other `java.io.InputStream`s.

View File

@@ -4849,15 +4849,6 @@ extensions:
- ["org.apache.struts2", "StrutsException", true, "StrutsException", "(Throwable,Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["org.apache.struts2", "StrutsException", true, "StrutsException", "(Throwable,Object)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"]
- ["org.apache.struts2", "StrutsException", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "Order", "(String,String,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "Order", "(String,String,int)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "getClientName", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "getId", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "setClientName", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "setId", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["org.demo.rest.example", "Order", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["org.demo.rest.example", "OrdersController", true, "create", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["org.demo.rest.example", "OrdersController", true, "setId", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
@@ -6886,19 +6877,5 @@ extensions:
- ["org.apache.struts2", "ServletActionContext", "setResponse", "(HttpServletResponse)", "summary", "df-generated"]
- ["org.apache.struts2", "ServletActionContext", "setServletContext", "(ServletContext)", "summary", "df-generated"]
- ["org.apache.struts2", "ServletCache", "clear", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "IndexController", "index", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "Order", "getAmount", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "Order", "setAmount", "(int)", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "deleteConfirm", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "destroy", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "edit", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "editNew", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "index", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "show", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersController", "update", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersService", "get", "(String)", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersService", "getAll", "()", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersService", "remove", "(String)", "summary", "df-generated"]
- ["org.demo.rest.example", "OrdersService", "save", "(Order)", "summary", "df-generated"]
- ["org.w3c.dom", "Document", "getElementsByTagName", "(String)", "summary", "df-generated"]
- ["org.w3c.dom", "Document", "getElementsByTagNameNS", "(String,String)", "summary", "df-generated"]

View File

@@ -177,6 +177,11 @@ class TypeObjectInputStream extends RefType {
TypeObjectInputStream() { this.hasQualifiedName("java.io", "ObjectInputStream") }
}
/** The class `java.io.InputStream`. */
class TypeInputStream extends RefType {
TypeInputStream() { this.hasQualifiedName("java.io", "InputStream") }
}
/** The class `java.nio.file.Paths`. */
class TypePaths extends Class {
TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") }

View File

@@ -20,11 +20,11 @@ private module Frameworks {
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.IoJsonWebToken
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.InputStream
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.ratpack.RatpackExec
private import semmle.code.java.frameworks.stapler.Stapler
private import semmle.code.java.JDK
}
/**

View File

@@ -757,7 +757,7 @@ private predicate baseBound(Expr e, int b, boolean upper) {
or
exists(Method read |
e.(MethodAccess).getMethod().overrides*(read) and
read.getDeclaringType().hasQualifiedName("java.io", "InputStream") and
read.getDeclaringType() instanceof TypeInputStream and
read.hasName("read") and
read.getNumberOfParameters() = 0
|

View File

@@ -239,7 +239,7 @@ private class BulkData extends RefType {
this.(Array).getElementType().(PrimitiveType).hasName(["byte", "char"])
or
exists(RefType t | this.getASourceSupertype*() = t |
t.hasQualifiedName("java.io", "InputStream") or
t instanceof TypeInputStream or
t.hasQualifiedName("java.nio", "ByteBuffer") or
t.hasQualifiedName("java.lang", "Readable") or
t.hasQualifiedName("java.io", "DataInput") or
@@ -259,7 +259,7 @@ private class BulkData extends RefType {
private predicate inputStreamWrapper(Constructor c, int argi) {
not c.fromSource() and
c.getParameterType(argi) instanceof BulkData and
c.getDeclaringType().getASourceSupertype+().hasQualifiedName("java.io", "InputStream")
c.getDeclaringType().getASourceSupertype+() instanceof TypeInputStream
}
/** An object construction that preserves the data flow status of any of its arguments. */

View File

@@ -102,7 +102,7 @@ private module Dispatch {
or
t instanceof Interface and not t.fromSource()
or
t.hasQualifiedName("java.io", "InputStream")
t instanceof TypeInputStream
or
t.hasQualifiedName("java.io", "Serializable")
or

View File

@@ -0,0 +1,90 @@
/** Provides definitions related to `java.io.InputStream`. */
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dataflow.TaintTracking
/**
* A jump taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
* to a class instance expression of the type extending `InputStream`.
*
* This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
* normally only happen in nested classes.
*/
private class InputStreamWrapperCapturedJumpStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(InputStreamRead m, NestedClass wrapper |
m.getDeclaringType() = wrapper and
wrapper.getASourceSupertype+() instanceof TypeInputStream
|
n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
n2.asExpr()
.(ClassInstanceExpr)
.getConstructedType()
.getASourceSupertype*()
.getSourceDeclaration() = wrapper
)
}
}
/**
* A local taint step from the definition of a captured variable, the capturer of which
* updates the `bytes[]` parameter in an override of the `InputStream.read` method,
* to a class instance expression of the type extending `InputStream`.
*
* This models how a subtype of `InputStream` could be tainted by capturing tainted variables in
* the definition of its methods.
*/
private class InputStreamWrapperCapturedLocalStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(InputStreamRead m, NestedClass wrapper, SsaVariable captured, SsaImplicitInit capturer |
wrapper.getASourceSupertype+() instanceof TypeInputStream and
m.getDeclaringType() = wrapper and
capturer.captures(captured) and
TaintTracking::localTaint(DataFlow::exprNode(capturer.getAFirstUse()),
any(DataFlow::PostUpdateNode pun |
pun.getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess()
)) and
n2.asExpr()
.(ClassInstanceExpr)
.getConstructedType()
.getASourceSupertype*()
.getSourceDeclaration() = wrapper
|
n1.asExpr() = captured.(SsaExplicitUpdate).getDefiningExpr().(VariableAssign).getSource()
or
captured.(SsaImplicitInit).isParameterDefinition(n1.asParameter())
)
}
}
/**
* A taint step from an `InputStream` argument of the constructor of an `InputStream` subtype
* to the call of the constructor, only if the argument is assigned to a class field.
*
* This models how it's assumed that an `InputStream` wrapper is tainted by the wrapped stream,
* and is a workaround to low `fieldFlowBranchLimit`s in dataflow configurations.
*/
private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(ClassInstanceExpr cc, Argument a, AssignExpr ae, int pos |
cc.getConstructedType().getASourceSupertype+() instanceof TypeInputStream and
cc.getArgument(pragma[only_bind_into](pos)) = a and
cc.getCallee().getParameter(pragma[only_bind_into](pos)).getAnAccess() = ae.getRhs() and
ae.getDest().(FieldWrite).getField().getType().(RefType).getASourceSupertype*() instanceof
TypeInputStream
|
n1.asExpr() = a and
n2.asExpr() = cc
)
}
}
private class InputStreamRead extends Method {
InputStreamRead() {
this.hasName("read") and
this.getDeclaringType().getASourceSupertype*() instanceof TypeInputStream
}
}

View File

@@ -317,7 +317,7 @@ class SystemSetInputStreamMethod extends Method {
SystemSetInputStreamMethod() {
this.hasName("setIn") and
this.getNumberOfParameters() = 1 and
this.getParameter(0).getType().(RefType).hasQualifiedName("java.io", "InputStream") and
this.getParameter(0).getType() instanceof TypeInputStream and
this.getDeclaringType()
.getAnAncestor()
.getSourceDeclaration()

View File

@@ -237,7 +237,7 @@ class SpringRequestMappingParameter extends Parameter {
private predicate isExplicitlyTaintedInput() {
// InputStream or Reader parameters allow access to the body of a request
this.getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or
this.getType().(RefType).getAnAncestor() instanceof TypeInputStream or
this.getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or
// The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request
this.getAnAnnotation() instanceof SpringServletInputAnnotation or

View File

@@ -0,0 +1,139 @@
import java.io.InputStream;
import java.io.IOException;
public class A {
private static InputStream source() {
return null;
}
private static void sink(Object s) {}
static class MyStream extends InputStream {
private InputStream wrapped;
MyStream(InputStream wrapped) {
this.wrapped = wrapped;
}
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
return wrapped.read(b);
}
}
public static void testSeveralWrappers() {
InputStream src = source();
InputStream wrapper1 = new MyStream(src);
sink(wrapper1); // $ hasTaintFlow
InputStream wrapper2 = new MyStream(wrapper1);
sink(wrapper2); // $ hasTaintFlow
InputStream wrapper3 = new MyStream(wrapper2);
sink(wrapper3); // $ hasTaintFlow
InputStream wrapper4 = new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
return wrapper3.read(b);
}
};
sink(wrapper4); // $ hasTaintFlow
}
public static void testAnonymous() throws Exception {
InputStream wrapper = new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
InputStream in = source();
return in.read(b);
}
};
sink(wrapper); // $ hasTaintFlow
}
public static void testAnonymousVarCapture() throws Exception {
InputStream in = source();
InputStream wrapper = new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
return in.read(b);
}
};
sink(wrapper); // $ hasTaintFlow
}
public static InputStream wrapStream(InputStream in) {
return new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
return in.read(b);
}
};
}
public static void testWrapCall() {
sink(wrapStream(null)); // $ SPURIOUS: hasTaintFlow
sink(wrapStream(source())); // $ hasTaintFlow
}
public static void testLocal() {
class LocalInputStream extends InputStream {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
InputStream in = source();
return in.read(b);
}
}
sink(new LocalInputStream()); // $ hasTaintFlow
}
public static void testLocalVarCapture() {
InputStream in = source();
class LocalInputStream extends InputStream {
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] b) throws IOException {
return in.read(b);
}
}
sink(new LocalInputStream()); // $ hasTaintFlow
}
}

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -0,0 +1,2 @@
import TestUtilities.InlineFlowTest
import DefaultFlowTest

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added taint flow for `NSUserActivity.referrerURL`.

View File

@@ -83,7 +83,7 @@ private class UserActivityUrlInheritTaint extends TaintInheritingContent,
{
UserActivityUrlInheritTaint() {
this.getField().getEnclosingDecl().asNominalTypeDecl().getName() = "NSUserActivity" and
this.getField().getName() = "webpageURL"
this.getField().getName() = ["webpageURL", "referrerURL"]
}
}

View File

@@ -0,0 +1,85 @@
/**
* Provides classes and predicates for reasoning about system
* commands built from user-controlled sources (that is, command injection
* vulnerabilities).
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.ExternalFlow
/**
* A dataflow sink for command injection vulnerabilities.
*/
abstract class CommandInjectionSink extends DataFlow::Node { }
/**
* A barrier for command injection vulnerabilities.
*/
abstract class CommandInjectionBarrier extends DataFlow::Node { }
/**
* A unit class for adding additional flow steps.
*/
class CommandInjectionAdditionalFlowStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a flow
* step for paths related to command injection vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
private class ProcessSink2 extends CommandInjectionSink instanceof DataFlow::Node {
ProcessSink2() {
exists(AssignExpr assign, ProcessHost s |
assign.getDest() = s and
this.asExpr() = assign.getSource()
)
or
exists(AssignExpr assign, ProcessHost s, ArrayExpr a |
assign.getDest() = s and
a = assign.getSource() and
this.asExpr() = a.getAnElement()
)
}
}
private class ProcessHost extends MemberRefExpr {
ProcessHost() { this.getBase() instanceof ProcessRef }
}
/** An expression of type `Process`. */
private class ProcessRef extends Expr {
ProcessRef() {
this.getType() instanceof ProcessType or
this.getType() = any(OptionalType t | t.getBaseType() instanceof ProcessType)
}
}
/** The type `Process`. */
private class ProcessType extends NominalType {
ProcessType() { this.getFullName() = "Process" }
}
/**
* A `DataFlow::Node` that is written into a `Process` object.
*/
private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node {
ProcessSink() {
// any write into a class derived from `Process` is a sink. For
// example in `Process.launchPath = sensitive` the post-update node corresponding
// with `Process.launchPath` is a sink.
exists(NominalType t, Expr e |
t.getABaseType*().getUnderlyingType().getName() = "Process" and
e.getFullyConverted() = this.asExpr() and
e.getFullyConverted().getType() = t
)
}
}
/**
* A sink defined in a CSV model.
*/
private class DefaultCommandInjectionSink extends CommandInjectionSink {
DefaultCommandInjectionSink() { sinkNode(this, "command-injection") }
}

View File

@@ -0,0 +1,31 @@
/**
* Provides a taint-tracking configuration for reasoning about system
* commands built from user-controlled sources (that is, Command injection
* vulnerabilities).
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
import codeql.swift.security.CommandInjectionExtensions
/**
* A taint configuration for tainted data that reaches a Command Injection sink.
*/
module CommandInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
predicate isSink(DataFlow::Node node) { node instanceof CommandInjectionSink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof CommandInjectionBarrier }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(CommandInjectionAdditionalFlowStep s).step(nodeFrom, nodeTo)
}
}
/**
* Detect taint flow of tainted data that reaches a Command Injection sink.
*/
module CommandInjectionFlow = TaintTracking::Global<CommandInjectionConfig>;

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added new query "Command injection" (`swift/command-line-injection`). The query finds places where user input is used to execute system commands without proper escaping.

View File

@@ -0,0 +1,45 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Constructing a system command with unsanitized user input is dangerous,
since a malicious user may be able to craft input that executes arbitrary code.
</p>
</overview>
<recommendation>
<p>
If possible, use hard-coded string literals to specify the command to run. Instead of interpreting
user input directly as command names, examine the input and then choose among hard-coded string
literals.
</p>
<p>
If this is not possible, then add sanitization code to verify that the user input is safe before
using it.
</p>
</recommendation>
<example>
<p>
The following examples execute code from user input without
sanitizing it first:
</p>
<sample src="CommandInjectionBad.swift" />
<p>
If user input is used to construct a command it should be checked
first. This ensures that the user cannot insert characters that have special
meanings.
</p>
<sample src="CommandInjectionGood.swift" />
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Command_Injection">Command Injection</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,22 @@
/**
* @name System command built from user-controlled sources
* @description Building a system command from user-controlled sources is vulnerable to insertion of malicious code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id swift/command-line-injection
* @tags security
* external/cwe/cwe-078
* external/cwe/cwe-088
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.security.CommandInjectionQuery
import CommandInjectionFlow::PathGraph
from CommandInjectionFlow::PathNode sourceNode, CommandInjectionFlow::PathNode sinkNode
where CommandInjectionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This command depends on a $@.",
sourceNode.getNode(), "user-provided value"

View File

@@ -0,0 +1,5 @@
var task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", userControlledString] // BAD
task.launch()

View File

@@ -0,0 +1,13 @@
func validateCommand(_ command: String) -> String? {
let allowedCommands = ["ls -l", "pwd", "echo"]
if allowedCommands.contains(command) {
return command
}
return nil
}
var task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", validateCommand(userControlledString)] // GOOD
task.launch()

View File

@@ -0,0 +1,3 @@
deadEnd
| customurlschemes.swift:94:59:94:76 | options |
| customurlschemes.swift:133:59:133:76 | options |

View File

@@ -1,6 +1,21 @@
import swift
import TestUtilities.InlineExpectationsTest
import FlowConfig
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.DataFlow
module TestConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src instanceof FlowSource }
predicate isSink(DataFlow::Node sink) {
exists(CallExpr sinkCall |
sinkCall.getStaticTarget().getName().matches("sink%") and
sinkCall.getAnArgument().getExpr() = sink.asExpr()
)
}
}
module TestFlow = TaintTracking::Global<TestConfiguration>;
string describe(FlowSource source) {
source instanceof RemoteFlowSource and result = "remote"
@@ -9,7 +24,7 @@ string describe(FlowSource source) {
}
module FlowSourcesTest implements TestSig {
string getARelevantTag() { result = "source" }
string getARelevantTag() { result = ["source", "tainted"] }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(FlowSource source |
@@ -19,6 +34,16 @@ module FlowSourcesTest implements TestSig {
tag = "source" and
value = describe(source)
)
or
exists(DataFlow::Node sink |
// this is not really what the "flowsources" test is about, but sometimes it's helpful to
// have sinks and confirm that taint reaches obvious points in the flow source test code.
TestFlow::flowTo(sink) and
location = sink.getLocation() and
element = sink.toString() and
tag = "tainted" and
value = ""
)
}
}

View File

@@ -26,12 +26,24 @@ protocol UIApplicationDelegate {
}
class UIScene {
class ConnectionOptions {}
class ConnectionOptions {
var userActivities: Set<NSUserActivity> { get { return Set() } }
var urlContexts: Set<UIOpenURLContext> { get { return Set() } }
}
}
class UISceneSession {}
class NSUserActivity {}
class NSUserActivity: Hashable {
static func == (lhs: NSUserActivity, rhs: NSUserActivity) -> Bool {
return true;
}
func hash(into hasher: inout Hasher) {}
var webpageURL: URL? { get { return nil } set { } }
var referrerURL: URL? { get { return nil } set { } }
}
class UIOpenURLContext: Hashable {
static func == (lhs: UIOpenURLContext, rhs: UIOpenURLContext) -> Bool {
@@ -39,6 +51,8 @@ class UIOpenURLContext: Hashable {
}
func hash(into hasher: inout Hasher) {}
var url: URL { get { return URL() } }
}
protocol UISceneDelegate {
@@ -48,6 +62,8 @@ protocol UISceneDelegate {
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>)
}
func sink(arg: Any) {}
// --- tests ---
class AppDelegate: UIApplicationDelegate {
@@ -64,28 +80,88 @@ class AppDelegate: UIApplicationDelegate {
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
launchOptions?[.url] // $ source=remote
_ = launchOptions?[.url] // $ source=remote
return true
}
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
launchOptions?[.url] // $ source=remote
_ = launchOptions?[.url] // $ source=remote
return true
}
}
class SceneDelegate : UISceneDelegate {
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // $ source=remote
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
for userActivity in options.userActivities {
let x = userActivity.webpageURL
sink(arg: x) // $ MISSING: tainted
let y = userActivity.referrerURL
sink(arg: y) // $ MISSING: tainted
}
for urlContext in options.urlContexts {
let z = urlContext.url
sink(arg: z) // $ MISSING: tainted
}
}
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
let x = `continue`.webpageURL
sink(arg: x) // $ tainted
let y = `continue`.referrerURL
sink(arg: y) // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
sink(arg: x) // $ tainted
let y = didUpdate.referrerURL
sink(arg: y) // $ tainted
}
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) { // $ source=remote
for openURLContext in openURLContexts {
let x = openURLContext.url
sink(arg: x) // $ MISSING: tainted
}
}
}
class Extended {}
extension Extended : UISceneDelegate {
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // $ source=remote
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
for userActivity in options.userActivities {
let x = userActivity.webpageURL
sink(arg: x) // $ MISSING: tainted
let y = userActivity.referrerURL
sink(arg: y) // $ MISSING: tainted
}
for urlContext in options.urlContexts {
let z = urlContext.url
sink(arg: z) // $ MISSING: tainted
}
}
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
let x = `continue`.webpageURL
sink(arg: x) // $ tainted
let y = `continue`.referrerURL
sink(arg: y) // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
sink(arg: x) // $ tainted
let y = didUpdate.referrerURL
sink(arg: y) // $ tainted
}
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) { // $ source=remote
for openURLContext in openURLContexts {
let x = openURLContext.url
sink(arg: x) // $ MISSING: tainted
}
}
}