From 511f79151142049cbdfb45012f14a092480296a3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:52:59 +0100 Subject: [PATCH 1/4] Rust: Add more flow tests --- .../dataflow/local/DataFlowStep.expected | 204 ++++++++++++++---- .../dataflow/local/DataFlowStep.ql | 9 +- .../test/library-tests/dataflow/local/main.rs | 152 ++++++++++--- 3 files changed, 299 insertions(+), 66 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 02cc2fdf5919..f16bdf9a844d 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,3 +1,4 @@ +localStep | main.rs:3:11:3:11 | [SSA] i | main.rs:4:12:4:12 | i | | main.rs:3:11:3:11 | i | main.rs:3:11:3:11 | [SSA] i | | main.rs:3:11:3:16 | ...: i64 | main.rs:3:11:3:11 | i | @@ -75,42 +76,171 @@ | main.rs:97:38:97:38 | p | main.rs:97:9:97:34 | Point {...} | | main.rs:104:9:104:10 | [SSA] s1 | main.rs:106:11:106:12 | s1 | | main.rs:104:9:104:10 | s1 | main.rs:104:9:104:10 | [SSA] s1 | -| main.rs:104:14:104:28 | Some(...) | main.rs:104:9:104:10 | s1 | +| main.rs:104:14:104:37 | ...::Some(...) | main.rs:104:9:104:10 | s1 | | main.rs:105:9:105:10 | [SSA] s2 | main.rs:110:11:110:12 | s2 | | main.rs:105:9:105:10 | s2 | main.rs:105:9:105:10 | [SSA] s2 | -| main.rs:105:14:105:20 | Some(...) | main.rs:105:9:105:10 | s2 | -| main.rs:107:14:107:14 | [SSA] n | main.rs:107:25:107:25 | n | -| main.rs:107:14:107:14 | n | main.rs:107:14:107:14 | [SSA] n | -| main.rs:107:20:107:26 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | -| main.rs:108:17:108:23 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | -| main.rs:110:5:113:5 | match s2 { ... } | main.rs:103:27:114:1 | { ... } | -| main.rs:111:14:111:14 | [SSA] n | main.rs:111:25:111:25 | n | -| main.rs:111:14:111:14 | n | main.rs:111:14:111:14 | [SSA] n | -| main.rs:111:20:111:26 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | -| main.rs:112:17:112:23 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | -| main.rs:117:9:117:9 | [SSA] a | main.rs:118:5:118:5 | a | -| main.rs:117:9:117:9 | a | main.rs:117:9:117:9 | [SSA] a | -| main.rs:117:13:117:17 | { ... } | main.rs:117:9:117:9 | a | -| main.rs:117:15:117:15 | 0 | main.rs:117:13:117:17 | { ... } | -| main.rs:118:5:118:5 | a | main.rs:116:31:119:1 | { ... } | -| main.rs:121:22:121:22 | [SSA] b | main.rs:123:12:123:12 | b | -| main.rs:121:22:121:22 | b | main.rs:121:22:121:22 | [SSA] b | -| main.rs:121:22:121:28 | ...: bool | main.rs:121:22:121:22 | b | -| main.rs:122:9:122:9 | [SSA] a | main.rs:128:5:128:5 | a | -| main.rs:122:9:122:9 | a | main.rs:122:9:122:9 | [SSA] a | -| main.rs:122:13:127:5 | 'block: { ... } | main.rs:122:9:122:9 | a | -| main.rs:124:13:124:26 | break ''block 1 | main.rs:122:13:127:5 | 'block: { ... } | -| main.rs:124:26:124:26 | 1 | main.rs:124:13:124:26 | break ''block 1 | -| main.rs:126:9:126:9 | 2 | main.rs:122:13:127:5 | 'block: { ... } | -| main.rs:128:5:128:5 | a | main.rs:121:38:129:1 | { ... } | -| main.rs:131:22:131:22 | [SSA] b | main.rs:133:12:133:12 | b | -| main.rs:131:22:131:22 | b | main.rs:131:22:131:22 | [SSA] b | -| main.rs:131:22:131:28 | ...: bool | main.rs:131:22:131:22 | b | -| main.rs:132:9:132:9 | [SSA] a | main.rs:138:5:138:5 | a | -| main.rs:132:9:132:9 | a | main.rs:132:9:132:9 | [SSA] a | -| main.rs:132:13:137:5 | 'block: { ... } | main.rs:132:9:132:9 | a | -| main.rs:134:13:134:26 | break ''block 1 | main.rs:132:13:137:5 | 'block: { ... } | -| main.rs:134:26:134:26 | 1 | main.rs:134:13:134:26 | break ''block 1 | -| main.rs:136:9:136:22 | break ''block 2 | main.rs:132:13:137:5 | 'block: { ... } | -| main.rs:136:22:136:22 | 2 | main.rs:136:9:136:22 | break ''block 2 | -| main.rs:138:5:138:5 | a | main.rs:131:38:139:1 | { ... } | +| main.rs:105:14:105:28 | ...::Some(...) | main.rs:105:9:105:10 | s2 | +| main.rs:107:22:107:22 | [SSA] n | main.rs:107:33:107:33 | n | +| main.rs:107:22:107:22 | n | main.rs:107:22:107:22 | [SSA] n | +| main.rs:107:28:107:34 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | +| main.rs:108:25:108:31 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | +| main.rs:110:5:113:5 | match s2 { ... } | main.rs:103:37:114:1 | { ... } | +| main.rs:111:22:111:22 | [SSA] n | main.rs:111:33:111:33 | n | +| main.rs:111:22:111:22 | n | main.rs:111:22:111:22 | [SSA] n | +| main.rs:111:28:111:34 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | +| main.rs:112:25:112:31 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | +| main.rs:117:9:117:10 | [SSA] s1 | main.rs:119:11:119:12 | s1 | +| main.rs:117:9:117:10 | s1 | main.rs:117:9:117:10 | [SSA] s1 | +| main.rs:117:14:117:29 | Some(...) | main.rs:117:9:117:10 | s1 | +| main.rs:118:9:118:10 | [SSA] s2 | main.rs:123:11:123:12 | s2 | +| main.rs:118:9:118:10 | s2 | main.rs:118:9:118:10 | [SSA] s2 | +| main.rs:118:14:118:20 | Some(...) | main.rs:118:9:118:10 | s2 | +| main.rs:120:14:120:14 | [SSA] n | main.rs:120:25:120:25 | n | +| main.rs:120:14:120:14 | n | main.rs:120:14:120:14 | [SSA] n | +| main.rs:120:20:120:26 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | +| main.rs:121:17:121:23 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | +| main.rs:123:5:126:5 | match s2 { ... } | main.rs:116:39:127:1 | { ... } | +| main.rs:124:14:124:14 | [SSA] n | main.rs:124:25:124:25 | n | +| main.rs:124:14:124:14 | n | main.rs:124:14:124:14 | [SSA] n | +| main.rs:124:20:124:26 | sink(...) | main.rs:123:5:126:5 | match s2 { ... } | +| main.rs:125:17:125:23 | sink(...) | main.rs:123:5:126:5 | match s2 { ... } | +| main.rs:135:9:135:10 | [SSA] s1 | main.rs:137:11:137:12 | s1 | +| main.rs:135:9:135:10 | s1 | main.rs:135:9:135:10 | [SSA] s1 | +| main.rs:135:14:135:39 | ...::A(...) | main.rs:135:9:135:10 | s1 | +| main.rs:136:9:136:10 | [SSA] s2 | main.rs:144:11:144:12 | s2 | +| main.rs:136:9:136:10 | s2 | main.rs:136:9:136:10 | [SSA] s2 | +| main.rs:136:14:136:30 | ...::B(...) | main.rs:136:9:136:10 | s2 | +| main.rs:137:11:137:12 | s1 | main.rs:141:11:141:12 | s1 | +| main.rs:138:24:138:24 | [SSA] n | main.rs:138:35:138:35 | n | +| main.rs:138:24:138:24 | n | main.rs:138:24:138:24 | [SSA] n | +| main.rs:138:30:138:36 | sink(...) | main.rs:137:5:140:5 | match s1 { ... } | +| main.rs:139:24:139:24 | [SSA] n | main.rs:139:35:139:35 | n | +| main.rs:139:24:139:24 | n | main.rs:139:24:139:24 | [SSA] n | +| main.rs:139:30:139:36 | sink(...) | main.rs:137:5:140:5 | match s1 { ... } | +| main.rs:142:10:142:46 | [SSA] [match(true)] phi | main.rs:142:57:142:57 | n | +| main.rs:142:25:142:25 | [SSA] [input] [match(true)] phi | main.rs:142:10:142:46 | [SSA] [match(true)] phi | +| main.rs:142:25:142:25 | [SSA] n | main.rs:142:25:142:25 | [SSA] [input] [match(true)] phi | +| main.rs:142:25:142:25 | n | main.rs:142:25:142:25 | [SSA] n | +| main.rs:142:45:142:45 | [SSA] [input] [match(true)] phi | main.rs:142:10:142:46 | [SSA] [match(true)] phi | +| main.rs:142:45:142:45 | [SSA] n | main.rs:142:45:142:45 | [SSA] [input] [match(true)] phi | +| main.rs:142:45:142:45 | n | main.rs:142:45:142:45 | [SSA] n | +| main.rs:142:52:142:58 | sink(...) | main.rs:141:5:143:5 | match s1 { ... } | +| main.rs:144:5:147:5 | match s2 { ... } | main.rs:134:48:148:1 | { ... } | +| main.rs:145:24:145:24 | [SSA] n | main.rs:145:35:145:35 | n | +| main.rs:145:24:145:24 | n | main.rs:145:24:145:24 | [SSA] n | +| main.rs:145:30:145:36 | sink(...) | main.rs:144:5:147:5 | match s2 { ... } | +| main.rs:146:24:146:24 | [SSA] n | main.rs:146:35:146:35 | n | +| main.rs:146:24:146:24 | n | main.rs:146:24:146:24 | [SSA] n | +| main.rs:146:30:146:36 | sink(...) | main.rs:144:5:147:5 | match s2 { ... } | +| main.rs:153:9:153:10 | [SSA] s1 | main.rs:155:11:155:12 | s1 | +| main.rs:153:9:153:10 | s1 | main.rs:153:9:153:10 | [SSA] s1 | +| main.rs:153:14:153:26 | A(...) | main.rs:153:9:153:10 | s1 | +| main.rs:154:9:154:10 | [SSA] s2 | main.rs:162:11:162:12 | s2 | +| main.rs:154:9:154:10 | s2 | main.rs:154:9:154:10 | [SSA] s2 | +| main.rs:154:14:154:17 | B(...) | main.rs:154:9:154:10 | s2 | +| main.rs:155:11:155:12 | s1 | main.rs:159:11:159:12 | s1 | +| main.rs:156:11:156:11 | [SSA] n | main.rs:156:22:156:22 | n | +| main.rs:156:11:156:11 | n | main.rs:156:11:156:11 | [SSA] n | +| main.rs:156:17:156:23 | sink(...) | main.rs:155:5:158:5 | match s1 { ... } | +| main.rs:157:11:157:11 | [SSA] n | main.rs:157:22:157:22 | n | +| main.rs:157:11:157:11 | n | main.rs:157:11:157:11 | [SSA] n | +| main.rs:157:17:157:23 | sink(...) | main.rs:155:5:158:5 | match s1 { ... } | +| main.rs:160:10:160:20 | [SSA] [match(true)] phi | main.rs:160:31:160:31 | n | +| main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | main.rs:160:10:160:20 | [SSA] [match(true)] phi | +| main.rs:160:12:160:12 | [SSA] n | main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | +| main.rs:160:12:160:12 | n | main.rs:160:12:160:12 | [SSA] n | +| main.rs:160:19:160:19 | [SSA] [input] [match(true)] phi | main.rs:160:10:160:20 | [SSA] [match(true)] phi | +| main.rs:160:19:160:19 | [SSA] n | main.rs:160:19:160:19 | [SSA] [input] [match(true)] phi | +| main.rs:160:19:160:19 | n | main.rs:160:19:160:19 | [SSA] n | +| main.rs:160:26:160:32 | sink(...) | main.rs:159:5:161:5 | match s1 { ... } | +| main.rs:162:5:165:5 | match s2 { ... } | main.rs:152:50:166:1 | { ... } | +| main.rs:163:11:163:11 | [SSA] n | main.rs:163:22:163:22 | n | +| main.rs:163:11:163:11 | n | main.rs:163:11:163:11 | [SSA] n | +| main.rs:163:17:163:23 | sink(...) | main.rs:162:5:165:5 | match s2 { ... } | +| main.rs:164:11:164:11 | [SSA] n | main.rs:164:22:164:22 | n | +| main.rs:164:11:164:11 | n | main.rs:164:11:164:11 | [SSA] n | +| main.rs:164:17:164:23 | sink(...) | main.rs:162:5:165:5 | match s2 { ... } | +| main.rs:174:9:174:10 | [SSA] s1 | main.rs:178:11:178:12 | s1 | +| main.rs:174:9:174:10 | s1 | main.rs:174:9:174:10 | [SSA] s1 | +| main.rs:174:14:176:5 | ...::C {...} | main.rs:174:9:174:10 | s1 | +| main.rs:177:9:177:10 | [SSA] s2 | main.rs:185:11:185:12 | s2 | +| main.rs:177:9:177:10 | s2 | main.rs:177:9:177:10 | [SSA] s2 | +| main.rs:177:14:177:43 | ...::D {...} | main.rs:177:9:177:10 | s2 | +| main.rs:178:11:178:12 | s1 | main.rs:182:11:182:12 | s1 | +| main.rs:179:36:179:36 | [SSA] n | main.rs:179:48:179:48 | n | +| main.rs:179:36:179:36 | n | main.rs:179:36:179:36 | [SSA] n | +| main.rs:179:43:179:49 | sink(...) | main.rs:178:5:181:5 | match s1 { ... } | +| main.rs:180:36:180:36 | [SSA] n | main.rs:180:48:180:48 | n | +| main.rs:180:36:180:36 | n | main.rs:180:36:180:36 | [SSA] n | +| main.rs:180:43:180:49 | sink(...) | main.rs:178:5:181:5 | match s1 { ... } | +| main.rs:183:10:183:72 | [SSA] [match(true)] phi | main.rs:183:83:183:83 | n | +| main.rs:183:37:183:37 | [SSA] [input] [match(true)] phi | main.rs:183:10:183:72 | [SSA] [match(true)] phi | +| main.rs:183:37:183:37 | [SSA] n | main.rs:183:37:183:37 | [SSA] [input] [match(true)] phi | +| main.rs:183:37:183:37 | n | main.rs:183:37:183:37 | [SSA] n | +| main.rs:183:70:183:70 | [SSA] [input] [match(true)] phi | main.rs:183:10:183:72 | [SSA] [match(true)] phi | +| main.rs:183:70:183:70 | [SSA] n | main.rs:183:70:183:70 | [SSA] [input] [match(true)] phi | +| main.rs:183:70:183:70 | n | main.rs:183:70:183:70 | [SSA] n | +| main.rs:183:78:183:84 | sink(...) | main.rs:182:5:184:5 | match s1 { ... } | +| main.rs:185:5:188:5 | match s2 { ... } | main.rs:173:49:189:1 | { ... } | +| main.rs:186:36:186:36 | [SSA] n | main.rs:186:48:186:48 | n | +| main.rs:186:36:186:36 | n | main.rs:186:36:186:36 | [SSA] n | +| main.rs:186:43:186:49 | sink(...) | main.rs:185:5:188:5 | match s2 { ... } | +| main.rs:187:36:187:36 | [SSA] n | main.rs:187:48:187:48 | n | +| main.rs:187:36:187:36 | n | main.rs:187:36:187:36 | [SSA] n | +| main.rs:187:43:187:49 | sink(...) | main.rs:185:5:188:5 | match s2 { ... } | +| main.rs:194:9:194:10 | [SSA] s1 | main.rs:198:11:198:12 | s1 | +| main.rs:194:9:194:10 | s1 | main.rs:194:9:194:10 | [SSA] s1 | +| main.rs:194:14:196:5 | C {...} | main.rs:194:9:194:10 | s1 | +| main.rs:197:9:197:10 | [SSA] s2 | main.rs:205:11:205:12 | s2 | +| main.rs:197:9:197:10 | s2 | main.rs:197:9:197:10 | [SSA] s2 | +| main.rs:197:14:197:29 | D {...} | main.rs:197:9:197:10 | s2 | +| main.rs:198:11:198:12 | s1 | main.rs:202:11:202:12 | s1 | +| main.rs:199:22:199:22 | [SSA] n | main.rs:199:34:199:34 | n | +| main.rs:199:22:199:22 | n | main.rs:199:22:199:22 | [SSA] n | +| main.rs:199:29:199:35 | sink(...) | main.rs:198:5:201:5 | match s1 { ... } | +| main.rs:200:22:200:22 | [SSA] n | main.rs:200:34:200:34 | n | +| main.rs:200:22:200:22 | n | main.rs:200:22:200:22 | [SSA] n | +| main.rs:200:29:200:35 | sink(...) | main.rs:198:5:201:5 | match s1 { ... } | +| main.rs:203:10:203:44 | [SSA] [match(true)] phi | main.rs:203:55:203:55 | n | +| main.rs:203:23:203:23 | [SSA] [input] [match(true)] phi | main.rs:203:10:203:44 | [SSA] [match(true)] phi | +| main.rs:203:23:203:23 | [SSA] n | main.rs:203:23:203:23 | [SSA] [input] [match(true)] phi | +| main.rs:203:23:203:23 | n | main.rs:203:23:203:23 | [SSA] n | +| main.rs:203:42:203:42 | [SSA] [input] [match(true)] phi | main.rs:203:10:203:44 | [SSA] [match(true)] phi | +| main.rs:203:42:203:42 | [SSA] n | main.rs:203:42:203:42 | [SSA] [input] [match(true)] phi | +| main.rs:203:42:203:42 | n | main.rs:203:42:203:42 | [SSA] n | +| main.rs:203:50:203:56 | sink(...) | main.rs:202:5:204:5 | match s1 { ... } | +| main.rs:205:5:208:5 | match s2 { ... } | main.rs:193:51:209:1 | { ... } | +| main.rs:206:22:206:22 | [SSA] n | main.rs:206:34:206:34 | n | +| main.rs:206:22:206:22 | n | main.rs:206:22:206:22 | [SSA] n | +| main.rs:206:29:206:35 | sink(...) | main.rs:205:5:208:5 | match s2 { ... } | +| main.rs:207:22:207:22 | [SSA] n | main.rs:207:34:207:34 | n | +| main.rs:207:22:207:22 | n | main.rs:207:22:207:22 | [SSA] n | +| main.rs:207:29:207:35 | sink(...) | main.rs:205:5:208:5 | match s2 { ... } | +| main.rs:212:9:212:9 | [SSA] a | main.rs:213:5:213:5 | a | +| main.rs:212:9:212:9 | a | main.rs:212:9:212:9 | [SSA] a | +| main.rs:212:13:212:17 | { ... } | main.rs:212:9:212:9 | a | +| main.rs:212:15:212:15 | 0 | main.rs:212:13:212:17 | { ... } | +| main.rs:213:5:213:5 | a | main.rs:211:31:214:1 | { ... } | +| main.rs:216:22:216:22 | [SSA] b | main.rs:218:12:218:12 | b | +| main.rs:216:22:216:22 | b | main.rs:216:22:216:22 | [SSA] b | +| main.rs:216:22:216:28 | ...: bool | main.rs:216:22:216:22 | b | +| main.rs:217:9:217:9 | [SSA] a | main.rs:223:5:223:5 | a | +| main.rs:217:9:217:9 | a | main.rs:217:9:217:9 | [SSA] a | +| main.rs:217:13:222:5 | 'block: { ... } | main.rs:217:9:217:9 | a | +| main.rs:219:13:219:26 | break ''block 1 | main.rs:217:13:222:5 | 'block: { ... } | +| main.rs:219:26:219:26 | 1 | main.rs:219:13:219:26 | break ''block 1 | +| main.rs:221:9:221:9 | 2 | main.rs:217:13:222:5 | 'block: { ... } | +| main.rs:223:5:223:5 | a | main.rs:216:38:224:1 | { ... } | +| main.rs:226:22:226:22 | [SSA] b | main.rs:228:12:228:12 | b | +| main.rs:226:22:226:22 | b | main.rs:226:22:226:22 | [SSA] b | +| main.rs:226:22:226:28 | ...: bool | main.rs:226:22:226:22 | b | +| main.rs:227:9:227:9 | [SSA] a | main.rs:233:5:233:5 | a | +| main.rs:227:9:227:9 | a | main.rs:227:9:227:9 | [SSA] a | +| main.rs:227:13:232:5 | 'block: { ... } | main.rs:227:9:227:9 | a | +| main.rs:229:13:229:26 | break ''block 1 | main.rs:227:13:232:5 | 'block: { ... } | +| main.rs:229:26:229:26 | 1 | main.rs:229:13:229:26 | break ''block 1 | +| main.rs:231:9:231:22 | break ''block 2 | main.rs:227:13:232:5 | 'block: { ... } | +| main.rs:231:22:231:22 | 2 | main.rs:231:9:231:22 | break ''block 2 | +| main.rs:233:5:233:5 | a | main.rs:226:38:234:1 | { ... } | +storeStep +readStep diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql index 77147a50573a..8bbde28564ac 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql @@ -1,5 +1,8 @@ import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.internal.DataFlowImpl -from DataFlow::Node pred, DataFlow::Node succ -where DataFlow::localFlowStep(pred, succ) -select pred, succ +query predicate localStep = DataFlow::localFlowStep/2; + +query predicate storeStep = RustDataFlow::storeStep/3; + +query predicate readStep = RustDataFlow::readStep/3; diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index 50aa4fdb965e..b9dcc78c3a80 100644 --- a/rust/ql/test/library-tests/dataflow/local/main.rs +++ b/rust/ql/test/library-tests/dataflow/local/main.rs @@ -16,24 +16,24 @@ fn direct() { } fn variable_usage() { - let s = source(1); - sink(s); // $ hasValueFlow=1 + let s = source(2); + sink(s); // $ hasValueFlow=2 } fn if_expression(cond: bool) { - let a = source(1); + let a = source(3); let b = 2; let c = if cond { a } else { b }; - sink(c); // $ hasValueFlow=1 + sink(c); // $ hasValueFlow=3 } fn match_expression(m: Option) { - let a = source(1); + let a = source(4); let b = match m { Some(_) => a, None => 0, }; - sink(b); // $ hasValueFlow=1 + sink(b); // $ hasValueFlow=4 } fn loop_with_break() { @@ -42,29 +42,29 @@ fn loop_with_break() { }; sink(a); let b = loop { - break source(1); + break source(5); }; - sink(b); // $ hasValueFlow=1 + sink(b); // $ hasValueFlow=5 } fn assignment() { let mut i = 1; sink(i); - i = source(2); - sink(i); // $ hasValueFlow=2 + i = source(6); + sink(i); // $ hasValueFlow=6 } // ----------------------------------------------------------------------------- // Data flow through data structures by writing and reading fn box_deref() { - let i = Box::new(source(1)); - sink(*i); // $ MISSING: hasValueFlow=1 + let i = Box::new(source(7)); + sink(*i); // $ MISSING: hasValueFlow=7 } fn tuple() { - let a = (source(1), 2); - sink(a.0); // $ MISSING: hasValueFlow=1 + let a = (source(8), 2); + sink(a.0); // $ MISSING: hasValueFlow=8 sink(a.1); } @@ -76,13 +76,13 @@ struct Point { fn struct_field() { let p = Point { - x: source(1), + x: source(9), y: 2, - z: source(3), + z: source(10), }; - sink(p.x); // MISSING: hasValueFlow=1 + sink(p.x); // $ MISSING: hasValueFlow=9 sink(p.y); - sink(p.z); // MISSING: hasValueFlow=3 + sink(p.z); // $ MISSING: hasValueFlow=10 } // ----------------------------------------------------------------------------- @@ -90,21 +90,34 @@ fn struct_field() { fn struct_pattern_match() { let p = Point { - x: source(1), + x: source(11), y: 2, - z: source(3), + z: source(12), }; let Point { x: a, y: b, z: c } = p; - sink(a); // MISSING: hasValueFlow=1 + sink(a); // $ MISSING: hasValueFlow=11 sink(b); - sink(c); // MISSING: hasValueFlow=3 + sink(c); // $ MISSING: hasValueFlow=12 } -fn option_pattern_match() { - let s1 = Some(source(1)); +fn option_pattern_match_qualified() { + let s1 = Option::Some(source(13)); + let s2 = Option::Some(2); + match s1 { + Option::Some(n) => sink(n), // $ MISSING: hasValueFlow=13 + Option::None => sink(0), + } + match s2 { + Option::Some(n) => sink(n), + Option::None => sink(0), + } +} + +fn option_pattern_match_unqualified() { + let s1 = Some(source(14)); let s2 = Some(2); match s1 { - Some(n) => sink(n), // MISSING: hasValueFlow=3 + Some(n) => sink(n), // $ MISSING: hasValueFlow=14 None => sink(0), } match s2 { @@ -113,6 +126,88 @@ fn option_pattern_match() { } } +enum MyTupleEnum { + A(i64), + B(i64), +} + +fn custom_tuple_enum_pattern_match_qualified() { + let s1 = MyTupleEnum::A(source(15)); + let s2 = MyTupleEnum::B(2); + match s1 { + MyTupleEnum::A(n) => sink(n), // $ MISSING: hasValueFlow=15 + MyTupleEnum::B(n) => sink(n), + } + match s1 { + (MyTupleEnum::A(n) | MyTupleEnum::B(n)) => sink(n), // $ MISSING: hasValueFlow=15 + } + match s2 { + MyTupleEnum::A(n) => sink(n), + MyTupleEnum::B(n) => sink(n), + } +} + +use crate::MyTupleEnum::*; + +fn custom_tuple_enum_pattern_match_unqualified() { + let s1 = A(source(16)); + let s2 = B(2); + match s1 { + A(n) => sink(n), // $ MISSING: hasValueFlow=16 + B(n) => sink(n), + } + match s1 { + (A(n) | B(n)) => sink(n), // $ MISSING: hasValueFlow=16 + } + match s2 { + A(n) => sink(n), + B(n) => sink(n), + } +} + +enum MyRecordEnum { + C { field_c: i64 }, + D { field_d: i64 }, +} + +fn custom_record_enum_pattern_match_qualified() { + let s1 = MyRecordEnum::C { + field_c: source(17), + }; + let s2 = MyRecordEnum::D { field_d: 2 }; + match s1 { + MyRecordEnum::C { field_c: n } => sink(n), // $ MISSING: hasValueFlow=17 + MyRecordEnum::D { field_d: n } => sink(n), + } + match s1 { + (MyRecordEnum::C { field_c: n } | MyRecordEnum::D { field_d: n }) => sink(n), // $ MISSING: hasValueFlow=17 + } + match s2 { + MyRecordEnum::C { field_c: n } => sink(n), + MyRecordEnum::D { field_d: n } => sink(n), + } +} + +use crate::MyRecordEnum::*; + +fn custom_record_enum_pattern_match_unqualified() { + let s1 = C { + field_c: source(18), + }; + let s2 = D { field_d: 2 }; + match s1 { + C { field_c: n } => sink(n), // $ MISSING: hasValueFlow=18 + D { field_d: n } => sink(n), + } + match s1 { + (C { field_c: n } | D { field_d: n }) => sink(n), // $ MISSING: hasValueFlow=18 + } + match s2 { + C { field_c: n } => sink(n), + D { field_d: n } => sink(n), + } +} + fn block_expression1() -> i64 { let a = { 0 }; a @@ -149,7 +244,12 @@ fn main() { tuple(); struct_field(); struct_pattern_match(); - option_pattern_match(); + option_pattern_match_qualified(); + option_pattern_match_unqualified(); + custom_tuple_enum_pattern_match_qualified(); + custom_tuple_enum_pattern_match_unqualified(); + custom_record_enum_pattern_match_qualified(); + custom_record_enum_pattern_match_unqualified(); block_expression1(); block_expression2(true); block_expression3(true); From 2fb670a27c65f88897bfeb1ebacaf5df8bbf6826 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:54:20 +0100 Subject: [PATCH 2/4] Rust: Do not print `unit` type in data flow --- .../rust/dataflow/internal/DataFlowImpl.qll | 4 +- .../dataflow/barrier/inline-flow.expected | 36 +++--- .../dataflow/global/inline-flow.expected | 122 +++++++++--------- .../dataflow/local/inline-flow.expected | 30 ++--- 4 files changed, 97 insertions(+), 95 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 91f8065ab5a4..7c78db0588b6 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -450,7 +450,9 @@ module RustDataFlow implements InputSig { // NOTE: For now we use the type `Unit` and do not benefit from type // information in the data flow analysis. - final class DataFlowType = Unit; + final class DataFlowType extends Unit { + string toString() { result = "" } + } predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() } diff --git a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected index 660aee690861..7df553b65a06 100644 --- a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected @@ -1,29 +1,29 @@ models edges -| main.rs:9:13:9:19 | ...: ... : unit | main.rs:9:30:14:1 | { ... } : unit | provenance | | -| main.rs:21:13:21:21 | source(...) : unit | main.rs:22:10:22:10 | s | provenance | | -| main.rs:26:13:26:21 | source(...) : unit | main.rs:27:22:27:22 | s : unit | provenance | | -| main.rs:27:13:27:23 | sanitize(...) : unit | main.rs:28:10:28:10 | s | provenance | | -| main.rs:27:22:27:22 | s : unit | main.rs:9:13:9:19 | ...: ... : unit | provenance | | -| main.rs:27:22:27:22 | s : unit | main.rs:27:13:27:23 | sanitize(...) : unit | provenance | | -| main.rs:32:13:32:21 | source(...) : unit | main.rs:33:10:33:10 | s | provenance | | +| main.rs:9:13:9:19 | ...: ... | main.rs:9:30:14:1 | { ... } | provenance | | +| main.rs:21:13:21:21 | source(...) | main.rs:22:10:22:10 | s | provenance | | +| main.rs:26:13:26:21 | source(...) | main.rs:27:22:27:22 | s | provenance | | +| main.rs:27:13:27:23 | sanitize(...) | main.rs:28:10:28:10 | s | provenance | | +| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | ...: ... | provenance | | +| main.rs:27:22:27:22 | s | main.rs:27:13:27:23 | sanitize(...) | provenance | | +| main.rs:32:13:32:21 | source(...) | main.rs:33:10:33:10 | s | provenance | | nodes -| main.rs:9:13:9:19 | ...: ... : unit | semmle.label | ...: ... : unit | -| main.rs:9:30:14:1 | { ... } : unit | semmle.label | { ... } : unit | +| main.rs:9:13:9:19 | ...: ... | semmle.label | ...: ... | +| main.rs:9:30:14:1 | { ... } | semmle.label | { ... } | | main.rs:17:10:17:18 | source(...) | semmle.label | source(...) | -| main.rs:21:13:21:21 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:21:13:21:21 | source(...) | semmle.label | source(...) | | main.rs:22:10:22:10 | s | semmle.label | s | -| main.rs:26:13:26:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:27:13:27:23 | sanitize(...) : unit | semmle.label | sanitize(...) : unit | -| main.rs:27:22:27:22 | s : unit | semmle.label | s : unit | +| main.rs:26:13:26:21 | source(...) | semmle.label | source(...) | +| main.rs:27:13:27:23 | sanitize(...) | semmle.label | sanitize(...) | +| main.rs:27:22:27:22 | s | semmle.label | s | | main.rs:28:10:28:10 | s | semmle.label | s | -| main.rs:32:13:32:21 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:32:13:32:21 | source(...) | semmle.label | source(...) | | main.rs:33:10:33:10 | s | semmle.label | s | subpaths -| main.rs:27:22:27:22 | s : unit | main.rs:9:13:9:19 | ...: ... : unit | main.rs:9:30:14:1 | { ... } : unit | main.rs:27:13:27:23 | sanitize(...) : unit | +| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | ...: ... | main.rs:9:30:14:1 | { ... } | main.rs:27:13:27:23 | sanitize(...) | testFailures #select | main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | $@ | main.rs:17:10:17:18 | source(...) | source(...) | -| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | source(...) : unit | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | source(...) : unit | source(...) : unit | -| main.rs:28:10:28:10 | s | main.rs:26:13:26:21 | source(...) : unit | main.rs:28:10:28:10 | s | $@ | main.rs:26:13:26:21 | source(...) : unit | source(...) : unit | -| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | source(...) : unit | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | source(...) : unit | source(...) : unit | +| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | source(...) | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | source(...) | source(...) | +| main.rs:28:10:28:10 | s | main.rs:26:13:26:21 | source(...) | main.rs:28:10:28:10 | s | $@ | main.rs:26:13:26:21 | source(...) | source(...) | +| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | source(...) | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected index 147fa059c31f..89fa0442293a 100644 --- a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected @@ -1,74 +1,74 @@ models edges -| main.rs:12:28:14:1 | { ... } : unit | main.rs:17:13:17:23 | get_data(...) : unit | provenance | | -| main.rs:13:5:13:13 | source(...) : unit | main.rs:12:28:14:1 | { ... } : unit | provenance | | -| main.rs:17:13:17:23 | get_data(...) : unit | main.rs:18:10:18:10 | a | provenance | | -| main.rs:21:12:21:17 | ...: i64 : unit | main.rs:22:10:22:10 | n | provenance | | -| main.rs:26:13:26:21 | source(...) : unit | main.rs:27:13:27:13 | a : unit | provenance | | -| main.rs:27:13:27:13 | a : unit | main.rs:21:12:21:17 | ...: i64 : unit | provenance | | -| main.rs:30:17:30:22 | ...: i64 : unit | main.rs:30:32:32:1 | { ... } : unit | provenance | | -| main.rs:35:13:35:21 | source(...) : unit | main.rs:36:26:36:26 | a : unit | provenance | | -| main.rs:36:13:36:27 | pass_through(...) : unit | main.rs:37:10:37:10 | b | provenance | | -| main.rs:36:26:36:26 | a : unit | main.rs:30:17:30:22 | ...: i64 : unit | provenance | | -| main.rs:36:26:36:26 | a : unit | main.rs:36:13:36:27 | pass_through(...) : unit | provenance | | -| main.rs:41:13:44:6 | pass_through(...) : unit | main.rs:45:10:45:10 | a | provenance | | -| main.rs:41:26:44:5 | { ... } : unit | main.rs:30:17:30:22 | ...: i64 : unit | provenance | | -| main.rs:41:26:44:5 | { ... } : unit | main.rs:41:13:44:6 | pass_through(...) : unit | provenance | | -| main.rs:43:9:43:18 | source(...) : unit | main.rs:41:26:44:5 | { ... } : unit | provenance | | -| main.rs:56:23:56:28 | ...: i64 : unit | main.rs:57:14:57:14 | n | provenance | | -| main.rs:59:31:65:5 | { ... } : unit | main.rs:77:13:77:25 | ... .get_data(...) : unit | provenance | | -| main.rs:63:13:63:21 | source(...) : unit | main.rs:59:31:65:5 | { ... } : unit | provenance | | -| main.rs:66:28:66:33 | ...: i64 : unit | main.rs:66:43:72:5 | { ... } : unit | provenance | | -| main.rs:77:13:77:25 | ... .get_data(...) : unit | main.rs:78:10:78:10 | a | provenance | | -| main.rs:83:13:83:21 | source(...) : unit | main.rs:84:16:84:16 | a : unit | provenance | | -| main.rs:84:16:84:16 | a : unit | main.rs:56:23:56:28 | ...: i64 : unit | provenance | | -| main.rs:89:13:89:21 | source(...) : unit | main.rs:90:29:90:29 | a : unit | provenance | | -| main.rs:90:13:90:30 | ... .data_through(...) : unit | main.rs:91:10:91:10 | b | provenance | | -| main.rs:90:29:90:29 | a : unit | main.rs:66:28:66:33 | ...: i64 : unit | provenance | | -| main.rs:90:29:90:29 | a : unit | main.rs:90:13:90:30 | ... .data_through(...) : unit | provenance | | +| main.rs:12:28:14:1 | { ... } | main.rs:17:13:17:23 | get_data(...) | provenance | | +| main.rs:13:5:13:13 | source(...) | main.rs:12:28:14:1 | { ... } | provenance | | +| main.rs:17:13:17:23 | get_data(...) | main.rs:18:10:18:10 | a | provenance | | +| main.rs:21:12:21:17 | ...: i64 | main.rs:22:10:22:10 | n | provenance | | +| main.rs:26:13:26:21 | source(...) | main.rs:27:13:27:13 | a | provenance | | +| main.rs:27:13:27:13 | a | main.rs:21:12:21:17 | ...: i64 | provenance | | +| main.rs:30:17:30:22 | ...: i64 | main.rs:30:32:32:1 | { ... } | provenance | | +| main.rs:35:13:35:21 | source(...) | main.rs:36:26:36:26 | a | provenance | | +| main.rs:36:13:36:27 | pass_through(...) | main.rs:37:10:37:10 | b | provenance | | +| main.rs:36:26:36:26 | a | main.rs:30:17:30:22 | ...: i64 | provenance | | +| main.rs:36:26:36:26 | a | main.rs:36:13:36:27 | pass_through(...) | provenance | | +| main.rs:41:13:44:6 | pass_through(...) | main.rs:45:10:45:10 | a | provenance | | +| main.rs:41:26:44:5 | { ... } | main.rs:30:17:30:22 | ...: i64 | provenance | | +| main.rs:41:26:44:5 | { ... } | main.rs:41:13:44:6 | pass_through(...) | provenance | | +| main.rs:43:9:43:18 | source(...) | main.rs:41:26:44:5 | { ... } | provenance | | +| main.rs:56:23:56:28 | ...: i64 | main.rs:57:14:57:14 | n | provenance | | +| main.rs:59:31:65:5 | { ... } | main.rs:77:13:77:25 | ... .get_data(...) | provenance | | +| main.rs:63:13:63:21 | source(...) | main.rs:59:31:65:5 | { ... } | provenance | | +| main.rs:66:28:66:33 | ...: i64 | main.rs:66:43:72:5 | { ... } | provenance | | +| main.rs:77:13:77:25 | ... .get_data(...) | main.rs:78:10:78:10 | a | provenance | | +| main.rs:83:13:83:21 | source(...) | main.rs:84:16:84:16 | a | provenance | | +| main.rs:84:16:84:16 | a | main.rs:56:23:56:28 | ...: i64 | provenance | | +| main.rs:89:13:89:21 | source(...) | main.rs:90:29:90:29 | a | provenance | | +| main.rs:90:13:90:30 | ... .data_through(...) | main.rs:91:10:91:10 | b | provenance | | +| main.rs:90:29:90:29 | a | main.rs:66:28:66:33 | ...: i64 | provenance | | +| main.rs:90:29:90:29 | a | main.rs:90:13:90:30 | ... .data_through(...) | provenance | | nodes -| main.rs:12:28:14:1 | { ... } : unit | semmle.label | { ... } : unit | -| main.rs:13:5:13:13 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:17:13:17:23 | get_data(...) : unit | semmle.label | get_data(...) : unit | +| main.rs:12:28:14:1 | { ... } | semmle.label | { ... } | +| main.rs:13:5:13:13 | source(...) | semmle.label | source(...) | +| main.rs:17:13:17:23 | get_data(...) | semmle.label | get_data(...) | | main.rs:18:10:18:10 | a | semmle.label | a | -| main.rs:21:12:21:17 | ...: i64 : unit | semmle.label | ...: i64 : unit | +| main.rs:21:12:21:17 | ...: i64 | semmle.label | ...: i64 | | main.rs:22:10:22:10 | n | semmle.label | n | -| main.rs:26:13:26:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:27:13:27:13 | a : unit | semmle.label | a : unit | -| main.rs:30:17:30:22 | ...: i64 : unit | semmle.label | ...: i64 : unit | -| main.rs:30:32:32:1 | { ... } : unit | semmle.label | { ... } : unit | -| main.rs:35:13:35:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:36:13:36:27 | pass_through(...) : unit | semmle.label | pass_through(...) : unit | -| main.rs:36:26:36:26 | a : unit | semmle.label | a : unit | +| main.rs:26:13:26:21 | source(...) | semmle.label | source(...) | +| main.rs:27:13:27:13 | a | semmle.label | a | +| main.rs:30:17:30:22 | ...: i64 | semmle.label | ...: i64 | +| main.rs:30:32:32:1 | { ... } | semmle.label | { ... } | +| main.rs:35:13:35:21 | source(...) | semmle.label | source(...) | +| main.rs:36:13:36:27 | pass_through(...) | semmle.label | pass_through(...) | +| main.rs:36:26:36:26 | a | semmle.label | a | | main.rs:37:10:37:10 | b | semmle.label | b | -| main.rs:41:13:44:6 | pass_through(...) : unit | semmle.label | pass_through(...) : unit | -| main.rs:41:26:44:5 | { ... } : unit | semmle.label | { ... } : unit | -| main.rs:43:9:43:18 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:41:13:44:6 | pass_through(...) | semmle.label | pass_through(...) | +| main.rs:41:26:44:5 | { ... } | semmle.label | { ... } | +| main.rs:43:9:43:18 | source(...) | semmle.label | source(...) | | main.rs:45:10:45:10 | a | semmle.label | a | -| main.rs:56:23:56:28 | ...: i64 : unit | semmle.label | ...: i64 : unit | +| main.rs:56:23:56:28 | ...: i64 | semmle.label | ...: i64 | | main.rs:57:14:57:14 | n | semmle.label | n | -| main.rs:59:31:65:5 | { ... } : unit | semmle.label | { ... } : unit | -| main.rs:63:13:63:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:66:28:66:33 | ...: i64 : unit | semmle.label | ...: i64 : unit | -| main.rs:66:43:72:5 | { ... } : unit | semmle.label | { ... } : unit | -| main.rs:77:13:77:25 | ... .get_data(...) : unit | semmle.label | ... .get_data(...) : unit | +| main.rs:59:31:65:5 | { ... } | semmle.label | { ... } | +| main.rs:63:13:63:21 | source(...) | semmle.label | source(...) | +| main.rs:66:28:66:33 | ...: i64 | semmle.label | ...: i64 | +| main.rs:66:43:72:5 | { ... } | semmle.label | { ... } | +| main.rs:77:13:77:25 | ... .get_data(...) | semmle.label | ... .get_data(...) | | main.rs:78:10:78:10 | a | semmle.label | a | -| main.rs:83:13:83:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:84:16:84:16 | a : unit | semmle.label | a : unit | -| main.rs:89:13:89:21 | source(...) : unit | semmle.label | source(...) : unit | -| main.rs:90:13:90:30 | ... .data_through(...) : unit | semmle.label | ... .data_through(...) : unit | -| main.rs:90:29:90:29 | a : unit | semmle.label | a : unit | +| main.rs:83:13:83:21 | source(...) | semmle.label | source(...) | +| main.rs:84:16:84:16 | a | semmle.label | a | +| main.rs:89:13:89:21 | source(...) | semmle.label | source(...) | +| main.rs:90:13:90:30 | ... .data_through(...) | semmle.label | ... .data_through(...) | +| main.rs:90:29:90:29 | a | semmle.label | a | | main.rs:91:10:91:10 | b | semmle.label | b | subpaths -| main.rs:36:26:36:26 | a : unit | main.rs:30:17:30:22 | ...: i64 : unit | main.rs:30:32:32:1 | { ... } : unit | main.rs:36:13:36:27 | pass_through(...) : unit | -| main.rs:41:26:44:5 | { ... } : unit | main.rs:30:17:30:22 | ...: i64 : unit | main.rs:30:32:32:1 | { ... } : unit | main.rs:41:13:44:6 | pass_through(...) : unit | -| main.rs:90:29:90:29 | a : unit | main.rs:66:28:66:33 | ...: i64 : unit | main.rs:66:43:72:5 | { ... } : unit | main.rs:90:13:90:30 | ... .data_through(...) : unit | +| main.rs:36:26:36:26 | a | main.rs:30:17:30:22 | ...: i64 | main.rs:30:32:32:1 | { ... } | main.rs:36:13:36:27 | pass_through(...) | +| main.rs:41:26:44:5 | { ... } | main.rs:30:17:30:22 | ...: i64 | main.rs:30:32:32:1 | { ... } | main.rs:41:13:44:6 | pass_through(...) | +| main.rs:90:29:90:29 | a | main.rs:66:28:66:33 | ...: i64 | main.rs:66:43:72:5 | { ... } | main.rs:90:13:90:30 | ... .data_through(...) | testFailures #select -| main.rs:18:10:18:10 | a | main.rs:13:5:13:13 | source(...) : unit | main.rs:18:10:18:10 | a | $@ | main.rs:13:5:13:13 | source(...) : unit | source(...) : unit | -| main.rs:22:10:22:10 | n | main.rs:26:13:26:21 | source(...) : unit | main.rs:22:10:22:10 | n | $@ | main.rs:26:13:26:21 | source(...) : unit | source(...) : unit | -| main.rs:37:10:37:10 | b | main.rs:35:13:35:21 | source(...) : unit | main.rs:37:10:37:10 | b | $@ | main.rs:35:13:35:21 | source(...) : unit | source(...) : unit | -| main.rs:45:10:45:10 | a | main.rs:43:9:43:18 | source(...) : unit | main.rs:45:10:45:10 | a | $@ | main.rs:43:9:43:18 | source(...) : unit | source(...) : unit | -| main.rs:57:14:57:14 | n | main.rs:83:13:83:21 | source(...) : unit | main.rs:57:14:57:14 | n | $@ | main.rs:83:13:83:21 | source(...) : unit | source(...) : unit | -| main.rs:78:10:78:10 | a | main.rs:63:13:63:21 | source(...) : unit | main.rs:78:10:78:10 | a | $@ | main.rs:63:13:63:21 | source(...) : unit | source(...) : unit | -| main.rs:91:10:91:10 | b | main.rs:89:13:89:21 | source(...) : unit | main.rs:91:10:91:10 | b | $@ | main.rs:89:13:89:21 | source(...) : unit | source(...) : unit | +| main.rs:18:10:18:10 | a | main.rs:13:5:13:13 | source(...) | main.rs:18:10:18:10 | a | $@ | main.rs:13:5:13:13 | source(...) | source(...) | +| main.rs:22:10:22:10 | n | main.rs:26:13:26:21 | source(...) | main.rs:22:10:22:10 | n | $@ | main.rs:26:13:26:21 | source(...) | source(...) | +| main.rs:37:10:37:10 | b | main.rs:35:13:35:21 | source(...) | main.rs:37:10:37:10 | b | $@ | main.rs:35:13:35:21 | source(...) | source(...) | +| main.rs:45:10:45:10 | a | main.rs:43:9:43:18 | source(...) | main.rs:45:10:45:10 | a | $@ | main.rs:43:9:43:18 | source(...) | source(...) | +| main.rs:57:14:57:14 | n | main.rs:83:13:83:21 | source(...) | main.rs:57:14:57:14 | n | $@ | main.rs:83:13:83:21 | source(...) | source(...) | +| main.rs:78:10:78:10 | a | main.rs:63:13:63:21 | source(...) | main.rs:78:10:78:10 | a | $@ | main.rs:63:13:63:21 | source(...) | source(...) | +| main.rs:91:10:91:10 | b | main.rs:89:13:89:21 | source(...) | main.rs:91:10:91:10 | b | $@ | main.rs:89:13:89:21 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected index 0932efcf4846..f8585809e942 100644 --- a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected @@ -1,28 +1,28 @@ models edges -| main.rs:19:13:19:21 | source(...) : unit | main.rs:20:10:20:10 | s | provenance | | -| main.rs:24:13:24:21 | source(...) : unit | main.rs:27:10:27:10 | c | provenance | | -| main.rs:31:13:31:21 | source(...) : unit | main.rs:36:10:36:10 | b | provenance | | -| main.rs:45:15:45:23 | source(...) : unit | main.rs:47:10:47:10 | b | provenance | | -| main.rs:53:9:53:17 | source(...) : unit | main.rs:54:10:54:10 | i | provenance | | +| main.rs:19:13:19:21 | source(...) | main.rs:20:10:20:10 | s | provenance | | +| main.rs:24:13:24:21 | source(...) | main.rs:27:10:27:10 | c | provenance | | +| main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | provenance | | +| main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | provenance | | +| main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | provenance | | nodes | main.rs:15:10:15:18 | source(...) | semmle.label | source(...) | -| main.rs:19:13:19:21 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:19:13:19:21 | source(...) | semmle.label | source(...) | | main.rs:20:10:20:10 | s | semmle.label | s | -| main.rs:24:13:24:21 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:24:13:24:21 | source(...) | semmle.label | source(...) | | main.rs:27:10:27:10 | c | semmle.label | c | -| main.rs:31:13:31:21 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:31:13:31:21 | source(...) | semmle.label | source(...) | | main.rs:36:10:36:10 | b | semmle.label | b | -| main.rs:45:15:45:23 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:45:15:45:23 | source(...) | semmle.label | source(...) | | main.rs:47:10:47:10 | b | semmle.label | b | -| main.rs:53:9:53:17 | source(...) : unit | semmle.label | source(...) : unit | +| main.rs:53:9:53:17 | source(...) | semmle.label | source(...) | | main.rs:54:10:54:10 | i | semmle.label | i | subpaths testFailures #select | main.rs:15:10:15:18 | source(...) | main.rs:15:10:15:18 | source(...) | main.rs:15:10:15:18 | source(...) | $@ | main.rs:15:10:15:18 | source(...) | source(...) | -| main.rs:20:10:20:10 | s | main.rs:19:13:19:21 | source(...) : unit | main.rs:20:10:20:10 | s | $@ | main.rs:19:13:19:21 | source(...) : unit | source(...) : unit | -| main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | source(...) : unit | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | source(...) : unit | source(...) : unit | -| main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | source(...) : unit | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | source(...) : unit | source(...) : unit | -| main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | source(...) : unit | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | source(...) : unit | source(...) : unit | -| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | source(...) : unit | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | source(...) : unit | source(...) : unit | +| main.rs:20:10:20:10 | s | main.rs:19:13:19:21 | source(...) | main.rs:20:10:20:10 | s | $@ | main.rs:19:13:19:21 | source(...) | source(...) | +| main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | source(...) | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | source(...) | source(...) | +| main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | source(...) | source(...) | +| main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | source(...) | source(...) | +| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | source(...) | source(...) | From 5e7cd461178d756b739700e397784b73b99a6286 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:54:39 +0100 Subject: [PATCH 3/4] Rust: Flow through variants --- .../lib/codeql/rust/controlflow/CfgNodes.qll | 36 +- .../rust/controlflow/internal/CfgNodes.qll | 6 + rust/ql/lib/codeql/rust/dataflow/DataFlow.qll | 6 + .../rust/dataflow/internal/DataFlowImpl.qll | 348 ++++++++++++++---- .../dataflow/local/DataFlowStep.expected | 60 +++ .../dataflow/local/inline-flow.expected | 44 +++ .../test/library-tests/dataflow/local/main.rs | 10 +- 7 files changed, 427 insertions(+), 83 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll index 3ee3a3eeb611..07bc8946bc18 100644 --- a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll +++ b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll @@ -187,9 +187,37 @@ final class RecordExprCfgNode extends Nodes::RecordExprCfgNode { RecordExprCfgNode() { node = this.getRecordExpr() } - /** Gets the `i`th record expression. */ - ExprCfgNode getExpr(int i) { - any(ChildMapping mapping) - .hasCfgChild(node, node.getRecordExprFieldList().getField(i).getExpr(), this, result) + /** Gets the record expression for the field `field`. */ + pragma[nomagic] + ExprCfgNode getFieldExpr(string field) { + exists(RecordExprField ref | + ref = node.getRecordExprFieldList().getAField() and + any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result) and + field = ref.getNameRef().getText() + ) + } +} + +/** + * A record pattern. For example: + * ```rust + * match x { + * Foo { a: 1, b: 2 } => "ok", + * Foo { .. } => "fail", + * } + * ``` + */ +final class RecordPatCfgNode extends Nodes::RecordPatCfgNode { + private RecordPatChildMapping node; + + RecordPatCfgNode() { node = this.getRecordPat() } + + /** Gets the record pattern for the field `field`. */ + PatCfgNode getFieldPat(string field) { + exists(RecordPatField rpf | + rpf = node.getRecordPatFieldList().getAField() and + any(ChildMapping mapping).hasCfgChild(node, rpf.getPat(), this, result) and + field = rpf.getNameRef().getText() + ) } } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll index fc0df95f24a2..0f3dee7a9f49 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll @@ -68,6 +68,12 @@ class RecordExprChildMapping extends ParentAstNode, RecordExpr { } } +class RecordPatChildMapping extends ParentAstNode, RecordPat { + override predicate relevantChild(AstNode child) { + child = this.getRecordPatFieldList().getAField().getPat() + } +} + class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::FormatArgsExprTree { override predicate relevantChild(AstNode child) { child = this.getChildNode(_) } } diff --git a/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll b/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll index 3a09df2c45d1..c0d47f8f6a77 100644 --- a/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll +++ b/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll @@ -19,6 +19,12 @@ module DataFlow { final class PostUpdateNode = Node::PostUpdateNode; + final class Content = DataFlowImpl::Content; + + final class VariantContent = DataFlowImpl::VariantContent; + + final class ContentSet = DataFlowImpl::ContentSet; + /** * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * (intra-procedural) step. diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 7c78db0588b6..808b410c8d00 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -115,6 +115,11 @@ module Node { */ ExprCfgNode asExpr() { none() } + /** + * Gets the pattern that corresponds to this node, if any. + */ + PatCfgNode asPat() { none() } + /** Gets the enclosing callable. */ DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) } @@ -177,8 +182,7 @@ module Node { PatNode() { this = TPatNode(n) } - /** Gets the `PatCfgNode` in the CFG that this node corresponds to. */ - PatCfgNode getPat() { result = n } + override PatCfgNode asPat() { result = n } } /** @@ -322,8 +326,7 @@ module LocalFlow { nodeFrom.(Node::AstCfgFlowNode).getCfgNode() = nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode() or - nodeFrom.(Node::ParameterNode).getParameter().(ParamCfgNode).getPat() = - nodeTo.(Node::PatNode).getPat() + nodeFrom.(Node::ParameterNode).getParameter().(ParamCfgNode).getPat() = nodeTo.asPat() or SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _) or @@ -331,18 +334,165 @@ module LocalFlow { a.getRhs() = nodeFrom.getCfgNode() and a.getLhs() = nodeTo.getCfgNode() ) + or + exists(MatchExprCfgNode match | + nodeFrom.asExpr() = match.getScrutinee() and + nodeTo.asPat() = match.getArmPat(_) + ) + or + nodeFrom.asPat().(OrPatCfgNode).getAPat() = nodeTo.asPat() + } +} + +private import codeql.util.Option + +private class CrateOrigin extends string { + CrateOrigin() { + this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()] + } +} + +private class CrateOriginOption = Option::Option; + +pragma[nomagic] +private predicate hasExtendedCanonicalPath(Item i, CrateOriginOption crate, string path) { + path = i.getExtendedCanonicalPath() and + ( + crate.asSome() = i.getCrateOrigin() + or + crate.isNone() and + not i.hasCrateOrigin() + ) +} + +pragma[nomagic] +private predicate variantHasExtendedCanonicalPath( + Enum e, Variant v, CrateOriginOption crate, string path, string name +) { + hasExtendedCanonicalPath(e, crate, path) and + v = e.getVariantList().getAVariant() and + name = v.getName().getText() +} + +pragma[nomagic] +private predicate resolveExtendedCanonicalPath(Resolvable r, CrateOriginOption crate, string path) { + path = r.getResolvedPath() and + ( + crate.asSome() = r.getResolvedCrateOrigin() + or + crate.isNone() and + not r.hasResolvedCrateOrigin() + ) +} + +/** + * A reference contained in an object. For example a field in a struct. + */ +abstract class Content extends TContent { + /** Gets a textual representation of this content. */ + abstract string toString(); +} + +/** A canonical path pointing to an enum variant. */ +private class VariantCanonicalPath extends MkVariantCanonicalPath { + CrateOriginOption crate; + string path; + string name; + + VariantCanonicalPath() { this = MkVariantCanonicalPath(crate, path, name) } + + /** Gets the underlying variant. */ + Variant getVariant() { variantHasExtendedCanonicalPath(_, result, crate, path, name) } + + string toString() { result = name } + + Location getLocation() { result = this.getVariant().getLocation() } +} + +/** + * A variant of an `enum`. In addition to the variant itself, this also includes the + * position (for tuple variants) or the field name (for record variants). + */ +abstract class VariantContent extends Content { } + +/** A tuple variant. */ +private class TupleVariantContent extends VariantContent, TTupleVariantContent { + private VariantCanonicalPath v; + private int pos_; + + TupleVariantContent() { this = TTupleVariantContent(v, pos_) } + + VariantCanonicalPath getVariantCanonicalPath(int pos) { result = v and pos = pos_ } + + final override string toString() { + // only print indices when the arity is > 1 + if exists(TTupleVariantContent(v, 1)) + then result = v.toString() + "(" + pos_ + ")" + else result = v.toString() } } -private class DataFlowCallableAlias = DataFlowCallable; +/** A record variant. */ +private class RecordVariantContent extends VariantContent, TRecordVariantContent { + private VariantCanonicalPath v; + private string field_; + + RecordVariantContent() { this = TRecordVariantContent(v, field_) } -private class ReturnKindAlias = ReturnKind; + VariantCanonicalPath getVariantCanonicalPath(string field) { result = v and field = field_ } -private class DataFlowCallAlias = DataFlowCall; + final override string toString() { + // only print field when the arity is > 1 + if strictcount(string f | exists(TRecordVariantContent(v, f))) > 1 + then result = v.toString() + "{" + field_ + "}" + else result = v.toString() + } +} -private class ParameterPositionAlias = ParameterPosition; +/** A value that represents a set of `Content`s. */ +abstract class ContentSet extends TContentSet { + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets a content that may be stored into when storing into this set. */ + abstract Content getAStoreContent(); + + /** Gets a content that may be read from when reading from this set. */ + abstract Content getAReadContent(); +} + +private class SingletonContentSet extends ContentSet, TSingletonContentSet { + private Content c; + + SingletonContentSet() { this = TSingletonContentSet(c) } + + Content getContent() { result = c } + + override string toString() { result = c.toString() } + + override Content getAStoreContent() { result = c } + + override Content getAReadContent() { result = c } +} + +// Defines a set of aliases needed for the `RustDataFlow` module +private module Aliases { + class DataFlowCallableAlias = DataFlowCallable; + + class ReturnKindAlias = ReturnKind; + + class DataFlowCallAlias = DataFlowCall; + + class ParameterPositionAlias = ParameterPosition; + + class ContentAlias = Content; + + class ContentSetAlias = ContentSet; +} module RustDataFlow implements InputSig { + private import Aliases + /** * An element, viewed as a node in a data flow graph. Either an expression * (`ExprNode`) or a parameter (`ParameterNode`). @@ -388,55 +538,22 @@ module RustDataFlow implements InputSig { final class ReturnKind = ReturnKindAlias; - private import codeql.util.Option - - private class CrateOrigin extends string { - CrateOrigin() { - this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()] - } - } - - private class CrateOriginOption = Option::Option; - pragma[nomagic] - private predicate hasExtendedCanonicalPath( - DataFlowCallable c, CrateOriginOption crate, string path + private predicate callResolveExtendedCanonicalPath( + CallExprBase call, CrateOriginOption crate, string path ) { - exists(Item i | - i = c.asCfgScope() and - path = i.getExtendedCanonicalPath() - | - crate.asSome() = i.getCrateOrigin() + exists(Resolvable r | resolveExtendedCanonicalPath(r, crate, path) | + r = call.(MethodCallExpr) or - crate.isNone() and - not i.hasCrateOrigin() - ) - } - - pragma[nomagic] - private predicate resolvesExtendedCanonicalPath( - DataFlowCall c, CrateOriginOption crate, string path - ) { - exists(Resolvable r | - path = r.getResolvedPath() and - ( - r = c.asMethodCallExprCfgNode().getExpr() - or - r = c.asCallExprCfgNode().getExpr().(PathExprCfgNode).getPath() - ) - | - crate.asSome() = r.getResolvedCrateOrigin() - or - crate.isNone() and - not r.hasResolvedCrateOrigin() + r = call.(CallExpr).getExpr().(PathExpr).getPath() ) } /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall call) { exists(string path, CrateOriginOption crate | - hasExtendedCanonicalPath(result, crate, path) and - resolvesExtendedCanonicalPath(call, crate, path) + hasExtendedCanonicalPath(result.asCfgScope(), crate, path) and + callResolveExtendedCanonicalPath(call.asCallBaseExprCfgNode().getExpr(), crate, path) ) } @@ -458,24 +575,15 @@ module RustDataFlow implements InputSig { predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } - final class Content = Void; + class Content = ContentAlias; - predicate forceHighPrecision(Content c) { none() } + class ContentSet = ContentSetAlias; - class ContentSet extends TContentSet { - /** Gets a textual representation of this element. */ - string toString() { result = "ContentSet" } - - /** Gets a content that may be stored into when storing into this set. */ - Content getAStoreContent() { none() } - - /** Gets a content that may be read from when reading from this set. */ - Content getAReadContent() { none() } - } + predicate forceHighPrecision(Content c) { none() } - final class ContentApprox = Void; + final class ContentApprox = Content; // todo - ContentApprox getContentApprox(Content c) { any() } + ContentApprox getContentApprox(Content c) { result = c } class ParameterPosition = ParameterPositionAlias; @@ -503,19 +611,94 @@ module RustDataFlow implements InputSig { */ predicate jumpStep(Node node1, Node node2) { none() } + /** Holds if path `p` resolves to variant `v`. */ + private predicate pathResolveToVariantCanonicalPath(Path p, VariantCanonicalPath v) { + exists(CrateOriginOption crate, string path | + resolveExtendedCanonicalPath(p.getQualifier(), crate, path) and + v = MkVariantCanonicalPath(crate, path, p.getPart().getNameRef().getText()) + ) + or + // TODO: Remove once library types are extracted + not p.hasQualifier() and + v = MkVariantCanonicalPath(_, "crate::std::option::Option", p.getPart().getNameRef().getText()) + } + + /** Holds if `p` destructs an enum variant `v`. */ + pragma[nomagic] + private predicate tupleVariantDestruction(TupleStructPat p, VariantCanonicalPath v) { + pathResolveToVariantCanonicalPath(p.getPath(), v) + } + + /** Holds if `p` destructs an enum variant `v`. */ + pragma[nomagic] + private predicate recordVariantDestruction(RecordPat p, VariantCanonicalPath v) { + pathResolveToVariantCanonicalPath(p.getPath(), v) + } + /** * Holds if data can flow from `node1` to `node2` via a read of `c`. Thus, * `node1` references an object with a content `c.getAReadContent()` whose * value ends up in `node2`. */ - predicate readStep(Node node1, ContentSet c, Node node2) { none() } + predicate readStep(Node node1, ContentSet cs, Node node2) { + exists(Content c | c = cs.(SingletonContentSet).getContent() | + node1.asPat() = + any(TupleStructPatCfgNode pat, int pos | + tupleVariantDestruction(pat.getPat(), c.(TupleVariantContent).getVariantCanonicalPath(pos)) and + node2.asPat() = pat.getField(pos) + | + pat + ) + or + node1.asPat() = + any(RecordPatCfgNode pat, string field | + recordVariantDestruction(pat.getPat(), + c.(RecordVariantContent).getVariantCanonicalPath(field)) and + node2.asPat() = pat.getFieldPat(field) + | + pat + ) + ) + } + + /** Holds if `ce` constructs an enum value of type `v`. */ + pragma[nomagic] + private predicate tupleVariantConstruction(CallExpr ce, VariantCanonicalPath v) { + pathResolveToVariantCanonicalPath(ce.getExpr().(PathExpr).getPath(), v) + } + + /** Holds if `re` constructs an enum value of type `v`. */ + pragma[nomagic] + private predicate recordVariantConstruction(RecordExpr re, VariantCanonicalPath v) { + pathResolveToVariantCanonicalPath(re.getPath(), v) + } /** * Holds if data can flow from `node1` to `node2` via a store into `c`. Thus, * `node2` references an object with a content `c.getAStoreContent()` that * contains the value of `node1`. */ - predicate storeStep(Node node1, ContentSet c, Node node2) { none() } + predicate storeStep(Node node1, ContentSet cs, Node node2) { + exists(Content c | c = cs.(SingletonContentSet).getContent() | + node2.asExpr() = + any(CallExprCfgNode call, int pos | + tupleVariantConstruction(call.getCallExpr(), + c.(TupleVariantContent).getVariantCanonicalPath(pos)) and + node1.asExpr() = call.getArgument(pos) + | + call + ) + or + node2.asExpr() = + any(RecordExprCfgNode re, string field | + recordVariantConstruction(re.getRecordExpr(), + c.(RecordVariantContent).getVariantCanonicalPath(field)) and + node1.asExpr() = re.getFieldExpr(field) + | + re + ) + ) + } /** * Holds if values stored inside content `c` are cleared at node `n`. For example, @@ -582,8 +765,6 @@ module RustDataFlow implements InputSig { class DataFlowSecondLevelScope = Void; } -final class ContentSet = RustDataFlow::ContentSet; - import MakeImpl /** A collection of cached types and predicates to be evaluated in the same stage. */ @@ -600,14 +781,6 @@ private module Cached { cached newtype TDataFlowCall = TCall(CallExprBaseCfgNode c) - cached - newtype TOptionalContentSet = - TAnyElementContent() or - TAnyContent() - - cached - class TContentSet = TAnyElementContent or TAnyContent; - cached newtype TDataFlowCallable = TCfgScope(CfgScope scope) @@ -623,6 +796,33 @@ private module Cached { i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] } or TSelfParameterPosition() + + cached + newtype TVariantCanonicalPath = + MkVariantCanonicalPath(CrateOriginOption crate, string path, string name) { + variantHasExtendedCanonicalPath(_, _, crate, path, name) + or + // TODO: Remove once library types are extracted + crate.isNone() and + path = "crate::std::option::Option" and + name = "Some" + } + + cached + newtype TContent = + TTupleVariantContent(VariantCanonicalPath v, int pos) { + pos in [0 .. v.getVariant().getFieldList().(TupleFieldList).getNumberOfFields() - 1] + or + // TODO: Remove once library types are extracted + v = MkVariantCanonicalPath(_, "crate::std::option::Option", "Some") and + pos = 0 + } or + TRecordVariantContent(VariantCanonicalPath v, string field) { + field = v.getVariant().getFieldList().(RecordFieldList).getAField().getName().getText() + } + + cached + newtype TContentSet = TSingletonContentSet(Content c) } import Cached diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index f16bdf9a844d..a49da7516790 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -34,6 +34,8 @@ localStep | main.rs:32:9:32:9 | [SSA] b | main.rs:36:10:36:10 | b | | main.rs:32:9:32:9 | b | main.rs:32:9:32:9 | [SSA] b | | main.rs:32:13:35:5 | match m { ... } | main.rs:32:9:32:9 | b | +| main.rs:32:19:32:19 | m | main.rs:33:9:33:15 | TupleStructPat | +| main.rs:32:19:32:19 | m | main.rs:34:9:34:12 | None | | main.rs:33:20:33:20 | a | main.rs:32:13:35:5 | match m { ... } | | main.rs:34:17:34:17 | 0 | main.rs:32:13:35:5 | match m { ... } | | main.rs:40:9:40:9 | [SSA] a | main.rs:43:10:43:10 | a | @@ -80,11 +82,15 @@ localStep | main.rs:105:9:105:10 | [SSA] s2 | main.rs:110:11:110:12 | s2 | | main.rs:105:9:105:10 | s2 | main.rs:105:9:105:10 | [SSA] s2 | | main.rs:105:14:105:28 | ...::Some(...) | main.rs:105:9:105:10 | s2 | +| main.rs:106:11:106:12 | s1 | main.rs:107:9:107:23 | TupleStructPat | +| main.rs:106:11:106:12 | s1 | main.rs:108:9:108:20 | ...::None | | main.rs:107:22:107:22 | [SSA] n | main.rs:107:33:107:33 | n | | main.rs:107:22:107:22 | n | main.rs:107:22:107:22 | [SSA] n | | main.rs:107:28:107:34 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | | main.rs:108:25:108:31 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | | main.rs:110:5:113:5 | match s2 { ... } | main.rs:103:37:114:1 | { ... } | +| main.rs:110:11:110:12 | s2 | main.rs:111:9:111:23 | TupleStructPat | +| main.rs:110:11:110:12 | s2 | main.rs:112:9:112:20 | ...::None | | main.rs:111:22:111:22 | [SSA] n | main.rs:111:33:111:33 | n | | main.rs:111:22:111:22 | n | main.rs:111:22:111:22 | [SSA] n | | main.rs:111:28:111:34 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | @@ -95,11 +101,15 @@ localStep | main.rs:118:9:118:10 | [SSA] s2 | main.rs:123:11:123:12 | s2 | | main.rs:118:9:118:10 | s2 | main.rs:118:9:118:10 | [SSA] s2 | | main.rs:118:14:118:20 | Some(...) | main.rs:118:9:118:10 | s2 | +| main.rs:119:11:119:12 | s1 | main.rs:120:9:120:15 | TupleStructPat | +| main.rs:119:11:119:12 | s1 | main.rs:121:9:121:12 | None | | main.rs:120:14:120:14 | [SSA] n | main.rs:120:25:120:25 | n | | main.rs:120:14:120:14 | n | main.rs:120:14:120:14 | [SSA] n | | main.rs:120:20:120:26 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | | main.rs:121:17:121:23 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | | main.rs:123:5:126:5 | match s2 { ... } | main.rs:116:39:127:1 | { ... } | +| main.rs:123:11:123:12 | s2 | main.rs:124:9:124:15 | TupleStructPat | +| main.rs:123:11:123:12 | s2 | main.rs:125:9:125:12 | None | | main.rs:124:14:124:14 | [SSA] n | main.rs:124:25:124:25 | n | | main.rs:124:14:124:14 | n | main.rs:124:14:124:14 | [SSA] n | | main.rs:124:20:124:26 | sink(...) | main.rs:123:5:126:5 | match s2 { ... } | @@ -110,6 +120,8 @@ localStep | main.rs:136:9:136:10 | [SSA] s2 | main.rs:144:11:144:12 | s2 | | main.rs:136:9:136:10 | s2 | main.rs:136:9:136:10 | [SSA] s2 | | main.rs:136:14:136:30 | ...::B(...) | main.rs:136:9:136:10 | s2 | +| main.rs:137:11:137:12 | s1 | main.rs:138:9:138:25 | TupleStructPat | +| main.rs:137:11:137:12 | s1 | main.rs:139:9:139:25 | TupleStructPat | | main.rs:137:11:137:12 | s1 | main.rs:141:11:141:12 | s1 | | main.rs:138:24:138:24 | [SSA] n | main.rs:138:35:138:35 | n | | main.rs:138:24:138:24 | n | main.rs:138:24:138:24 | [SSA] n | @@ -117,6 +129,9 @@ localStep | main.rs:139:24:139:24 | [SSA] n | main.rs:139:35:139:35 | n | | main.rs:139:24:139:24 | n | main.rs:139:24:139:24 | [SSA] n | | main.rs:139:30:139:36 | sink(...) | main.rs:137:5:140:5 | match s1 { ... } | +| main.rs:141:11:141:12 | s1 | main.rs:142:10:142:46 | ... \| ... | +| main.rs:142:10:142:46 | ... \| ... | main.rs:142:10:142:26 | TupleStructPat | +| main.rs:142:10:142:46 | ... \| ... | main.rs:142:30:142:46 | TupleStructPat | | main.rs:142:10:142:46 | [SSA] [match(true)] phi | main.rs:142:57:142:57 | n | | main.rs:142:25:142:25 | [SSA] [input] [match(true)] phi | main.rs:142:10:142:46 | [SSA] [match(true)] phi | | main.rs:142:25:142:25 | [SSA] n | main.rs:142:25:142:25 | [SSA] [input] [match(true)] phi | @@ -126,6 +141,8 @@ localStep | main.rs:142:45:142:45 | n | main.rs:142:45:142:45 | [SSA] n | | main.rs:142:52:142:58 | sink(...) | main.rs:141:5:143:5 | match s1 { ... } | | main.rs:144:5:147:5 | match s2 { ... } | main.rs:134:48:148:1 | { ... } | +| main.rs:144:11:144:12 | s2 | main.rs:145:9:145:25 | TupleStructPat | +| main.rs:144:11:144:12 | s2 | main.rs:146:9:146:25 | TupleStructPat | | main.rs:145:24:145:24 | [SSA] n | main.rs:145:35:145:35 | n | | main.rs:145:24:145:24 | n | main.rs:145:24:145:24 | [SSA] n | | main.rs:145:30:145:36 | sink(...) | main.rs:144:5:147:5 | match s2 { ... } | @@ -138,6 +155,8 @@ localStep | main.rs:154:9:154:10 | [SSA] s2 | main.rs:162:11:162:12 | s2 | | main.rs:154:9:154:10 | s2 | main.rs:154:9:154:10 | [SSA] s2 | | main.rs:154:14:154:17 | B(...) | main.rs:154:9:154:10 | s2 | +| main.rs:155:11:155:12 | s1 | main.rs:156:9:156:12 | TupleStructPat | +| main.rs:155:11:155:12 | s1 | main.rs:157:9:157:12 | TupleStructPat | | main.rs:155:11:155:12 | s1 | main.rs:159:11:159:12 | s1 | | main.rs:156:11:156:11 | [SSA] n | main.rs:156:22:156:22 | n | | main.rs:156:11:156:11 | n | main.rs:156:11:156:11 | [SSA] n | @@ -145,6 +164,9 @@ localStep | main.rs:157:11:157:11 | [SSA] n | main.rs:157:22:157:22 | n | | main.rs:157:11:157:11 | n | main.rs:157:11:157:11 | [SSA] n | | main.rs:157:17:157:23 | sink(...) | main.rs:155:5:158:5 | match s1 { ... } | +| main.rs:159:11:159:12 | s1 | main.rs:160:10:160:20 | ... \| ... | +| main.rs:160:10:160:20 | ... \| ... | main.rs:160:10:160:13 | TupleStructPat | +| main.rs:160:10:160:20 | ... \| ... | main.rs:160:17:160:20 | TupleStructPat | | main.rs:160:10:160:20 | [SSA] [match(true)] phi | main.rs:160:31:160:31 | n | | main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | main.rs:160:10:160:20 | [SSA] [match(true)] phi | | main.rs:160:12:160:12 | [SSA] n | main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | @@ -154,6 +176,8 @@ localStep | main.rs:160:19:160:19 | n | main.rs:160:19:160:19 | [SSA] n | | main.rs:160:26:160:32 | sink(...) | main.rs:159:5:161:5 | match s1 { ... } | | main.rs:162:5:165:5 | match s2 { ... } | main.rs:152:50:166:1 | { ... } | +| main.rs:162:11:162:12 | s2 | main.rs:163:9:163:12 | TupleStructPat | +| main.rs:162:11:162:12 | s2 | main.rs:164:9:164:12 | TupleStructPat | | main.rs:163:11:163:11 | [SSA] n | main.rs:163:22:163:22 | n | | main.rs:163:11:163:11 | n | main.rs:163:11:163:11 | [SSA] n | | main.rs:163:17:163:23 | sink(...) | main.rs:162:5:165:5 | match s2 { ... } | @@ -166,6 +190,8 @@ localStep | main.rs:177:9:177:10 | [SSA] s2 | main.rs:185:11:185:12 | s2 | | main.rs:177:9:177:10 | s2 | main.rs:177:9:177:10 | [SSA] s2 | | main.rs:177:14:177:43 | ...::D {...} | main.rs:177:9:177:10 | s2 | +| main.rs:178:11:178:12 | s1 | main.rs:179:9:179:38 | ...::C {...} | +| main.rs:178:11:178:12 | s1 | main.rs:180:9:180:38 | ...::D {...} | | main.rs:178:11:178:12 | s1 | main.rs:182:11:182:12 | s1 | | main.rs:179:36:179:36 | [SSA] n | main.rs:179:48:179:48 | n | | main.rs:179:36:179:36 | n | main.rs:179:36:179:36 | [SSA] n | @@ -173,6 +199,9 @@ localStep | main.rs:180:36:180:36 | [SSA] n | main.rs:180:48:180:48 | n | | main.rs:180:36:180:36 | n | main.rs:180:36:180:36 | [SSA] n | | main.rs:180:43:180:49 | sink(...) | main.rs:178:5:181:5 | match s1 { ... } | +| main.rs:182:11:182:12 | s1 | main.rs:183:10:183:72 | ... \| ... | +| main.rs:183:10:183:72 | ... \| ... | main.rs:183:10:183:39 | ...::C {...} | +| main.rs:183:10:183:72 | ... \| ... | main.rs:183:43:183:72 | ...::D {...} | | main.rs:183:10:183:72 | [SSA] [match(true)] phi | main.rs:183:83:183:83 | n | | main.rs:183:37:183:37 | [SSA] [input] [match(true)] phi | main.rs:183:10:183:72 | [SSA] [match(true)] phi | | main.rs:183:37:183:37 | [SSA] n | main.rs:183:37:183:37 | [SSA] [input] [match(true)] phi | @@ -182,6 +211,8 @@ localStep | main.rs:183:70:183:70 | n | main.rs:183:70:183:70 | [SSA] n | | main.rs:183:78:183:84 | sink(...) | main.rs:182:5:184:5 | match s1 { ... } | | main.rs:185:5:188:5 | match s2 { ... } | main.rs:173:49:189:1 | { ... } | +| main.rs:185:11:185:12 | s2 | main.rs:186:9:186:38 | ...::C {...} | +| main.rs:185:11:185:12 | s2 | main.rs:187:9:187:38 | ...::D {...} | | main.rs:186:36:186:36 | [SSA] n | main.rs:186:48:186:48 | n | | main.rs:186:36:186:36 | n | main.rs:186:36:186:36 | [SSA] n | | main.rs:186:43:186:49 | sink(...) | main.rs:185:5:188:5 | match s2 { ... } | @@ -194,6 +225,8 @@ localStep | main.rs:197:9:197:10 | [SSA] s2 | main.rs:205:11:205:12 | s2 | | main.rs:197:9:197:10 | s2 | main.rs:197:9:197:10 | [SSA] s2 | | main.rs:197:14:197:29 | D {...} | main.rs:197:9:197:10 | s2 | +| main.rs:198:11:198:12 | s1 | main.rs:199:9:199:24 | C {...} | +| main.rs:198:11:198:12 | s1 | main.rs:200:9:200:24 | D {...} | | main.rs:198:11:198:12 | s1 | main.rs:202:11:202:12 | s1 | | main.rs:199:22:199:22 | [SSA] n | main.rs:199:34:199:34 | n | | main.rs:199:22:199:22 | n | main.rs:199:22:199:22 | [SSA] n | @@ -201,6 +234,9 @@ localStep | main.rs:200:22:200:22 | [SSA] n | main.rs:200:34:200:34 | n | | main.rs:200:22:200:22 | n | main.rs:200:22:200:22 | [SSA] n | | main.rs:200:29:200:35 | sink(...) | main.rs:198:5:201:5 | match s1 { ... } | +| main.rs:202:11:202:12 | s1 | main.rs:203:10:203:44 | ... \| ... | +| main.rs:203:10:203:44 | ... \| ... | main.rs:203:10:203:25 | C {...} | +| main.rs:203:10:203:44 | ... \| ... | main.rs:203:29:203:44 | D {...} | | main.rs:203:10:203:44 | [SSA] [match(true)] phi | main.rs:203:55:203:55 | n | | main.rs:203:23:203:23 | [SSA] [input] [match(true)] phi | main.rs:203:10:203:44 | [SSA] [match(true)] phi | | main.rs:203:23:203:23 | [SSA] n | main.rs:203:23:203:23 | [SSA] [input] [match(true)] phi | @@ -210,6 +246,8 @@ localStep | main.rs:203:42:203:42 | n | main.rs:203:42:203:42 | [SSA] n | | main.rs:203:50:203:56 | sink(...) | main.rs:202:5:204:5 | match s1 { ... } | | main.rs:205:5:208:5 | match s2 { ... } | main.rs:193:51:209:1 | { ... } | +| main.rs:205:11:205:12 | s2 | main.rs:206:9:206:24 | C {...} | +| main.rs:205:11:205:12 | s2 | main.rs:207:9:207:24 | D {...} | | main.rs:206:22:206:22 | [SSA] n | main.rs:206:34:206:34 | n | | main.rs:206:22:206:22 | n | main.rs:206:22:206:22 | [SSA] n | | main.rs:206:29:206:35 | sink(...) | main.rs:205:5:208:5 | match s2 { ... } | @@ -243,4 +281,26 @@ localStep | main.rs:231:22:231:22 | 2 | main.rs:231:9:231:22 | break ''block 2 | | main.rs:233:5:233:5 | a | main.rs:226:38:234:1 | { ... } | storeStep +| main.rs:117:19:117:28 | source(...) | Some | main.rs:117:14:117:29 | Some(...) | +| main.rs:118:19:118:19 | 2 | Some | main.rs:118:14:118:20 | Some(...) | +| main.rs:135:29:135:38 | source(...) | A | main.rs:135:14:135:39 | ...::A(...) | +| main.rs:136:29:136:29 | 2 | B | main.rs:136:14:136:30 | ...::B(...) | +| main.rs:175:18:175:27 | source(...) | C | main.rs:174:14:176:5 | ...::C {...} | +| main.rs:177:41:177:41 | 2 | D | main.rs:177:14:177:43 | ...::D {...} | +| main.rs:240:27:240:27 | 0 | Some | main.rs:240:22:240:28 | Some(...) | readStep +| main.rs:33:9:33:15 | TupleStructPat | Some | main.rs:33:14:33:14 | _ | +| main.rs:120:9:120:15 | TupleStructPat | Some | main.rs:120:14:120:14 | n | +| main.rs:124:9:124:15 | TupleStructPat | Some | main.rs:124:14:124:14 | n | +| main.rs:138:9:138:25 | TupleStructPat | A | main.rs:138:24:138:24 | n | +| main.rs:139:9:139:25 | TupleStructPat | B | main.rs:139:24:139:24 | n | +| main.rs:142:10:142:26 | TupleStructPat | A | main.rs:142:25:142:25 | n | +| main.rs:142:30:142:46 | TupleStructPat | B | main.rs:142:45:142:45 | n | +| main.rs:145:9:145:25 | TupleStructPat | A | main.rs:145:24:145:24 | n | +| main.rs:146:9:146:25 | TupleStructPat | B | main.rs:146:24:146:24 | n | +| main.rs:179:9:179:38 | ...::C {...} | C | main.rs:179:36:179:36 | n | +| main.rs:180:9:180:38 | ...::D {...} | D | main.rs:180:36:180:36 | n | +| main.rs:183:10:183:39 | ...::C {...} | C | main.rs:183:37:183:37 | n | +| main.rs:183:43:183:72 | ...::D {...} | D | main.rs:183:70:183:70 | n | +| main.rs:186:9:186:38 | ...::C {...} | C | main.rs:186:36:186:36 | n | +| main.rs:187:9:187:38 | ...::D {...} | D | main.rs:187:36:187:36 | n | diff --git a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected index f8585809e942..bfafa38c3ff3 100644 --- a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected @@ -5,6 +5,24 @@ edges | main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | provenance | | | main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | provenance | | | main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | provenance | | +| main.rs:117:14:117:29 | Some(...) [Some] | main.rs:120:9:120:15 | TupleStructPat [Some] | provenance | | +| main.rs:117:19:117:28 | source(...) | main.rs:117:14:117:29 | Some(...) [Some] | provenance | | +| main.rs:120:9:120:15 | TupleStructPat [Some] | main.rs:120:14:120:14 | n | provenance | | +| main.rs:120:14:120:14 | n | main.rs:120:25:120:25 | n | provenance | | +| main.rs:135:14:135:39 | ...::A(...) [A] | main.rs:138:9:138:25 | TupleStructPat [A] | provenance | | +| main.rs:135:14:135:39 | ...::A(...) [A] | main.rs:142:10:142:26 | TupleStructPat [A] | provenance | | +| main.rs:135:29:135:38 | source(...) | main.rs:135:14:135:39 | ...::A(...) [A] | provenance | | +| main.rs:138:9:138:25 | TupleStructPat [A] | main.rs:138:24:138:24 | n | provenance | | +| main.rs:138:24:138:24 | n | main.rs:138:35:138:35 | n | provenance | | +| main.rs:142:10:142:26 | TupleStructPat [A] | main.rs:142:25:142:25 | n | provenance | | +| main.rs:142:25:142:25 | n | main.rs:142:57:142:57 | n | provenance | | +| main.rs:174:14:176:5 | ...::C {...} [C] | main.rs:179:9:179:38 | ...::C {...} [C] | provenance | | +| main.rs:174:14:176:5 | ...::C {...} [C] | main.rs:183:10:183:39 | ...::C {...} [C] | provenance | | +| main.rs:175:18:175:27 | source(...) | main.rs:174:14:176:5 | ...::C {...} [C] | provenance | | +| main.rs:179:9:179:38 | ...::C {...} [C] | main.rs:179:36:179:36 | n | provenance | | +| main.rs:179:36:179:36 | n | main.rs:179:48:179:48 | n | provenance | | +| main.rs:183:10:183:39 | ...::C {...} [C] | main.rs:183:37:183:37 | n | provenance | | +| main.rs:183:37:183:37 | n | main.rs:183:83:183:83 | n | provenance | | nodes | main.rs:15:10:15:18 | source(...) | semmle.label | source(...) | | main.rs:19:13:19:21 | source(...) | semmle.label | source(...) | @@ -17,6 +35,27 @@ nodes | main.rs:47:10:47:10 | b | semmle.label | b | | main.rs:53:9:53:17 | source(...) | semmle.label | source(...) | | main.rs:54:10:54:10 | i | semmle.label | i | +| main.rs:117:14:117:29 | Some(...) [Some] | semmle.label | Some(...) [Some] | +| main.rs:117:19:117:28 | source(...) | semmle.label | source(...) | +| main.rs:120:9:120:15 | TupleStructPat [Some] | semmle.label | TupleStructPat [Some] | +| main.rs:120:14:120:14 | n | semmle.label | n | +| main.rs:120:25:120:25 | n | semmle.label | n | +| main.rs:135:14:135:39 | ...::A(...) [A] | semmle.label | ...::A(...) [A] | +| main.rs:135:29:135:38 | source(...) | semmle.label | source(...) | +| main.rs:138:9:138:25 | TupleStructPat [A] | semmle.label | TupleStructPat [A] | +| main.rs:138:24:138:24 | n | semmle.label | n | +| main.rs:138:35:138:35 | n | semmle.label | n | +| main.rs:142:10:142:26 | TupleStructPat [A] | semmle.label | TupleStructPat [A] | +| main.rs:142:25:142:25 | n | semmle.label | n | +| main.rs:142:57:142:57 | n | semmle.label | n | +| main.rs:174:14:176:5 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | +| main.rs:175:18:175:27 | source(...) | semmle.label | source(...) | +| main.rs:179:9:179:38 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | +| main.rs:179:36:179:36 | n | semmle.label | n | +| main.rs:179:48:179:48 | n | semmle.label | n | +| main.rs:183:10:183:39 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | +| main.rs:183:37:183:37 | n | semmle.label | n | +| main.rs:183:83:183:83 | n | semmle.label | n | subpaths testFailures #select @@ -26,3 +65,8 @@ testFailures | main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | source(...) | source(...) | | main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | source(...) | source(...) | | main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | source(...) | source(...) | +| main.rs:120:25:120:25 | n | main.rs:117:19:117:28 | source(...) | main.rs:120:25:120:25 | n | $@ | main.rs:117:19:117:28 | source(...) | source(...) | +| main.rs:138:35:138:35 | n | main.rs:135:29:135:38 | source(...) | main.rs:138:35:138:35 | n | $@ | main.rs:135:29:135:38 | source(...) | source(...) | +| main.rs:142:57:142:57 | n | main.rs:135:29:135:38 | source(...) | main.rs:142:57:142:57 | n | $@ | main.rs:135:29:135:38 | source(...) | source(...) | +| main.rs:179:48:179:48 | n | main.rs:175:18:175:27 | source(...) | main.rs:179:48:179:48 | n | $@ | main.rs:175:18:175:27 | source(...) | source(...) | +| main.rs:183:83:183:83 | n | main.rs:175:18:175:27 | source(...) | main.rs:183:83:183:83 | n | $@ | main.rs:175:18:175:27 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index b9dcc78c3a80..9a9e6b467e0e 100644 --- a/rust/ql/test/library-tests/dataflow/local/main.rs +++ b/rust/ql/test/library-tests/dataflow/local/main.rs @@ -117,7 +117,7 @@ fn option_pattern_match_unqualified() { let s1 = Some(source(14)); let s2 = Some(2); match s1 { - Some(n) => sink(n), // $ MISSING: hasValueFlow=14 + Some(n) => sink(n), // $ hasValueFlow=14 None => sink(0), } match s2 { @@ -135,11 +135,11 @@ fn custom_tuple_enum_pattern_match_qualified() { let s1 = MyTupleEnum::A(source(15)); let s2 = MyTupleEnum::B(2); match s1 { - MyTupleEnum::A(n) => sink(n), // $ MISSING: hasValueFlow=15 + MyTupleEnum::A(n) => sink(n), // $ hasValueFlow=15 MyTupleEnum::B(n) => sink(n), } match s1 { - (MyTupleEnum::A(n) | MyTupleEnum::B(n)) => sink(n), // $ MISSING: hasValueFlow=15 + (MyTupleEnum::A(n) | MyTupleEnum::B(n)) => sink(n), // $ hasValueFlow=15 } match s2 { MyTupleEnum::A(n) => sink(n), @@ -176,11 +176,11 @@ fn custom_record_enum_pattern_match_qualified() { }; let s2 = MyRecordEnum::D { field_d: 2 }; match s1 { - MyRecordEnum::C { field_c: n } => sink(n), // $ MISSING: hasValueFlow=17 + MyRecordEnum::C { field_c: n } => sink(n), // $ hasValueFlow=17 MyRecordEnum::D { field_d: n } => sink(n), } match s1 { - (MyRecordEnum::C { field_c: n } | MyRecordEnum::D { field_d: n }) => sink(n), // $ MISSING: hasValueFlow=17 + (MyRecordEnum::C { field_c: n } | MyRecordEnum::D { field_d: n }) => sink(n), // $ hasValueFlow=17 } match s2 { MyRecordEnum::C { field_c: n } => sink(n), From 8c111382adf1e52d11eea78967b182378f9aca7c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 26 Nov 2024 13:00:59 +0100 Subject: [PATCH 4/4] Address review comments --- .../rust/dataflow/internal/DataFlowImpl.qll | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 808b410c8d00..79b18b9cd0db 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -386,7 +386,7 @@ private predicate resolveExtendedCanonicalPath(Resolvable r, CrateOriginOption c } /** - * A reference contained in an object. For example a field in a struct. + * A path to a value contained in an object. For example a field name of a struct. */ abstract class Content extends TContent { /** Gets a textual representation of this content. */ @@ -416,34 +416,34 @@ private class VariantCanonicalPath extends MkVariantCanonicalPath { abstract class VariantContent extends Content { } /** A tuple variant. */ -private class TupleVariantContent extends VariantContent, TTupleVariantContent { +private class VariantPositionContent extends VariantContent, TVariantPositionContent { private VariantCanonicalPath v; private int pos_; - TupleVariantContent() { this = TTupleVariantContent(v, pos_) } + VariantPositionContent() { this = TVariantPositionContent(v, pos_) } VariantCanonicalPath getVariantCanonicalPath(int pos) { result = v and pos = pos_ } final override string toString() { // only print indices when the arity is > 1 - if exists(TTupleVariantContent(v, 1)) + if exists(TVariantPositionContent(v, 1)) then result = v.toString() + "(" + pos_ + ")" else result = v.toString() } } /** A record variant. */ -private class RecordVariantContent extends VariantContent, TRecordVariantContent { +private class VariantFieldContent extends VariantContent, TVariantFieldContent { private VariantCanonicalPath v; private string field_; - RecordVariantContent() { this = TRecordVariantContent(v, field_) } + VariantFieldContent() { this = TVariantFieldContent(v, field_) } VariantCanonicalPath getVariantCanonicalPath(string field) { result = v and field = field_ } final override string toString() { // only print field when the arity is > 1 - if strictcount(string f | exists(TRecordVariantContent(v, f))) > 1 + if strictcount(string f | exists(TVariantFieldContent(v, f))) > 1 then result = v.toString() + "{" + field_ + "}" else result = v.toString() } @@ -461,7 +461,7 @@ abstract class ContentSet extends TContentSet { abstract Content getAReadContent(); } -private class SingletonContentSet extends ContentSet, TSingletonContentSet { +final private class SingletonContentSet extends ContentSet, TSingletonContentSet { private Content c; SingletonContentSet() { this = TSingletonContentSet(c) } @@ -539,21 +539,18 @@ module RustDataFlow implements InputSig { final class ReturnKind = ReturnKindAlias; pragma[nomagic] - private predicate callResolveExtendedCanonicalPath( - CallExprBase call, CrateOriginOption crate, string path - ) { - exists(Resolvable r | resolveExtendedCanonicalPath(r, crate, path) | - r = call.(MethodCallExpr) - or - r = call.(CallExpr).getExpr().(PathExpr).getPath() - ) + private Resolvable getCallResolvable(CallExprBase call) { + result = call.(MethodCallExpr) + or + result = call.(CallExpr).getExpr().(PathExpr).getPath() } /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall call) { - exists(string path, CrateOriginOption crate | + exists(Resolvable r, string path, CrateOriginOption crate | hasExtendedCanonicalPath(result.asCfgScope(), crate, path) and - callResolveExtendedCanonicalPath(call.asCallBaseExprCfgNode().getExpr(), crate, path) + r = getCallResolvable(call.asCallBaseExprCfgNode().getExpr()) and + resolveExtendedCanonicalPath(r, crate, path) ) } @@ -581,7 +578,7 @@ module RustDataFlow implements InputSig { predicate forceHighPrecision(Content c) { none() } - final class ContentApprox = Content; // todo + final class ContentApprox = Content; // TODO: Implement if needed ContentApprox getContentApprox(Content c) { result = c } @@ -621,6 +618,10 @@ module RustDataFlow implements InputSig { // TODO: Remove once library types are extracted not p.hasQualifier() and v = MkVariantCanonicalPath(_, "crate::std::option::Option", p.getPart().getNameRef().getText()) + or + // TODO: Remove once library types are extracted + not p.hasQualifier() and + v = MkVariantCanonicalPath(_, "crate::std::result::Result", p.getPart().getNameRef().getText()) } /** Holds if `p` destructs an enum variant `v`. */ @@ -642,22 +643,19 @@ module RustDataFlow implements InputSig { */ predicate readStep(Node node1, ContentSet cs, Node node2) { exists(Content c | c = cs.(SingletonContentSet).getContent() | - node1.asPat() = - any(TupleStructPatCfgNode pat, int pos | - tupleVariantDestruction(pat.getPat(), c.(TupleVariantContent).getVariantCanonicalPath(pos)) and - node2.asPat() = pat.getField(pos) - | - pat - ) + exists(TupleStructPatCfgNode pat, int pos | + pat = node1.asPat() and + tupleVariantDestruction(pat.getPat(), + c.(VariantPositionContent).getVariantCanonicalPath(pos)) and + node2.asPat() = pat.getField(pos) + ) or - node1.asPat() = - any(RecordPatCfgNode pat, string field | - recordVariantDestruction(pat.getPat(), - c.(RecordVariantContent).getVariantCanonicalPath(field)) and - node2.asPat() = pat.getFieldPat(field) - | - pat - ) + exists(RecordPatCfgNode pat, string field | + pat = node1.asPat() and + recordVariantDestruction(pat.getPat(), + c.(VariantFieldContent).getVariantCanonicalPath(field)) and + node2.asPat() = pat.getFieldPat(field) + ) ) } @@ -683,7 +681,7 @@ module RustDataFlow implements InputSig { node2.asExpr() = any(CallExprCfgNode call, int pos | tupleVariantConstruction(call.getCallExpr(), - c.(TupleVariantContent).getVariantCanonicalPath(pos)) and + c.(VariantPositionContent).getVariantCanonicalPath(pos)) and node1.asExpr() = call.getArgument(pos) | call @@ -692,7 +690,7 @@ module RustDataFlow implements InputSig { node2.asExpr() = any(RecordExprCfgNode re, string field | recordVariantConstruction(re.getRecordExpr(), - c.(RecordVariantContent).getVariantCanonicalPath(field)) and + c.(VariantFieldContent).getVariantCanonicalPath(field)) and node1.asExpr() = re.getFieldExpr(field) | re @@ -806,18 +804,27 @@ private module Cached { crate.isNone() and path = "crate::std::option::Option" and name = "Some" + or + // TODO: Remove once library types are extracted + crate.isNone() and + path = "crate::std::result::Result" and + name = ["Ok", "Err"] } cached newtype TContent = - TTupleVariantContent(VariantCanonicalPath v, int pos) { + TVariantPositionContent(VariantCanonicalPath v, int pos) { pos in [0 .. v.getVariant().getFieldList().(TupleFieldList).getNumberOfFields() - 1] or // TODO: Remove once library types are extracted v = MkVariantCanonicalPath(_, "crate::std::option::Option", "Some") and pos = 0 + or + // TODO: Remove once library types are extracted + v = MkVariantCanonicalPath(_, "crate::std::result::Result", ["Ok", "Err"]) and + pos = 0 } or - TRecordVariantContent(VariantCanonicalPath v, string field) { + TVariantFieldContent(VariantCanonicalPath v, string field) { field = v.getVariant().getFieldList().(RecordFieldList).getAField().getName().getText() }