From 18583550ae1eb56c6b40b0a37900de499282bc69 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 6 Jun 2025 12:40:03 +0200 Subject: [PATCH 01/11] Rust: Add data flow tests for operator overloading --- .../dataflow/global/inline-flow.expected | 478 +++++++++--------- .../library-tests/dataflow/global/main.rs | 45 +- .../dataflow/global/viableCallable.expected | 152 +++--- 3 files changed, 362 insertions(+), 313 deletions(-) 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 c64956c59a03..53bbf61e3b68 100644 --- a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected @@ -19,106 +19,106 @@ edges | main.rs:38:23:38:31 | source(...) | main.rs:38:6:38:11 | [post] &mut a [&ref, MyStruct] | provenance | | | main.rs:39:10:39:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | provenance | | | main.rs:39:10:39:10 | a [MyStruct] | main.rs:39:10:39:21 | a.get_data() | provenance | | -| main.rs:44:12:44:17 | [post] &mut a [&ref, MyStruct] | main.rs:44:17:44:17 | [post] a [MyStruct] | provenance | | -| main.rs:44:17:44:17 | [post] a [MyStruct] | main.rs:45:10:45:10 | a [MyStruct] | provenance | | -| main.rs:44:30:44:38 | source(...) | main.rs:26:28:26:33 | ...: i64 | provenance | | -| main.rs:44:30:44:38 | source(...) | main.rs:44:12:44:17 | [post] &mut a [&ref, MyStruct] | provenance | | -| main.rs:45:10:45:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | provenance | | -| main.rs:45:10:45:10 | a [MyStruct] | main.rs:45:10:45:21 | a.get_data() | provenance | | -| main.rs:48:12:48:17 | ...: i64 | main.rs:49:10:49:10 | n | provenance | | -| main.rs:53:9:53:9 | a | main.rs:54:13:54:13 | a | provenance | | -| main.rs:53:13:53:21 | source(...) | main.rs:53:9:53:9 | a | provenance | | -| main.rs:54:13:54:13 | a | main.rs:48:12:48:17 | ...: i64 | provenance | | -| main.rs:57:17:57:22 | ...: i64 | main.rs:57:32:59:1 | { ... } | provenance | | -| main.rs:62:9:62:9 | a | main.rs:63:26:63:26 | a | provenance | | -| main.rs:62:13:62:21 | source(...) | main.rs:62:9:62:9 | a | provenance | | -| main.rs:63:9:63:9 | b | main.rs:64:10:64:10 | b | provenance | | -| main.rs:63:13:63:27 | pass_through(...) | main.rs:63:9:63:9 | b | provenance | | -| main.rs:63:26:63:26 | a | main.rs:57:17:57:22 | ...: i64 | provenance | | -| main.rs:63:26:63:26 | a | main.rs:63:13:63:27 | pass_through(...) | provenance | | -| main.rs:68:9:68:9 | a | main.rs:72:10:72:10 | a | provenance | | -| main.rs:68:13:71:6 | pass_through(...) | main.rs:68:9:68:9 | a | provenance | | -| main.rs:68:26:71:5 | { ... } | main.rs:57:17:57:22 | ...: i64 | provenance | | -| main.rs:68:26:71:5 | { ... } | main.rs:68:13:71:6 | pass_through(...) | provenance | | -| main.rs:70:9:70:18 | source(...) | main.rs:68:26:71:5 | { ... } | provenance | | -| main.rs:76:9:76:9 | a | main.rs:82:26:82:26 | a | provenance | | -| main.rs:76:13:76:22 | source(...) | main.rs:76:9:76:9 | a | provenance | | -| main.rs:78:21:78:26 | ...: i64 | main.rs:78:36:80:5 | { ... } | provenance | | -| main.rs:82:9:82:9 | b | main.rs:83:10:83:10 | b | provenance | | -| main.rs:82:13:82:27 | pass_through(...) | main.rs:82:9:82:9 | b | provenance | | -| main.rs:82:26:82:26 | a | main.rs:78:21:78:26 | ...: i64 | provenance | | -| main.rs:82:26:82:26 | a | main.rs:82:13:82:27 | pass_through(...) | provenance | | -| main.rs:94:22:94:27 | ...: i64 | main.rs:95:14:95:14 | n | provenance | | -| main.rs:98:30:104:5 | { ... } | main.rs:117:13:117:25 | mn.get_data() | provenance | | -| main.rs:102:13:102:21 | source(...) | main.rs:98:30:104:5 | { ... } | provenance | | -| main.rs:106:27:106:32 | ...: i64 | main.rs:106:42:112:5 | { ... } | provenance | | -| main.rs:117:9:117:9 | a | main.rs:118:10:118:10 | a | provenance | | -| main.rs:117:13:117:25 | mn.get_data() | main.rs:117:9:117:9 | a | provenance | | -| main.rs:123:9:123:9 | a | main.rs:124:16:124:16 | a | provenance | | -| main.rs:123:13:123:21 | source(...) | main.rs:123:9:123:9 | a | provenance | | -| main.rs:124:16:124:16 | a | main.rs:94:22:94:27 | ...: i64 | provenance | | -| main.rs:129:9:129:9 | a | main.rs:130:29:130:29 | a | provenance | | -| main.rs:129:13:129:21 | source(...) | main.rs:129:9:129:9 | a | provenance | | -| main.rs:130:9:130:9 | b | main.rs:131:10:131:10 | b | provenance | | -| main.rs:130:13:130:30 | mn.data_through(...) | main.rs:130:9:130:9 | b | provenance | | -| main.rs:130:29:130:29 | a | main.rs:106:27:106:32 | ...: i64 | provenance | | -| main.rs:130:29:130:29 | a | main.rs:130:13:130:30 | mn.data_through(...) | provenance | | -| main.rs:136:9:136:9 | a | main.rs:137:25:137:25 | a | provenance | | -| main.rs:136:13:136:21 | source(...) | main.rs:136:9:136:9 | a | provenance | | -| main.rs:137:25:137:25 | a | main.rs:94:22:94:27 | ...: i64 | provenance | | -| main.rs:142:9:142:9 | a | main.rs:143:38:143:38 | a | provenance | | -| main.rs:142:13:142:22 | source(...) | main.rs:142:9:142:9 | a | provenance | | -| main.rs:143:9:143:9 | b | main.rs:144:10:144:10 | b | provenance | | -| main.rs:143:13:143:39 | ...::data_through(...) | main.rs:143:9:143:9 | b | provenance | | -| main.rs:143:38:143:38 | a | main.rs:106:27:106:32 | ...: i64 | provenance | | -| main.rs:143:38:143:38 | a | main.rs:143:13:143:39 | ...::data_through(...) | provenance | | -| main.rs:155:12:155:17 | ...: i64 | main.rs:156:24:156:24 | n | provenance | | -| main.rs:156:9:156:26 | MyInt {...} [MyInt] | main.rs:155:28:157:5 | { ... } [MyInt] | provenance | | -| main.rs:156:24:156:24 | n | main.rs:156:9:156:26 | MyInt {...} [MyInt] | provenance | | -| main.rs:161:9:161:9 | n [MyInt] | main.rs:162:9:162:26 | MyInt {...} [MyInt] | provenance | | -| main.rs:161:13:161:34 | ...::new(...) [MyInt] | main.rs:161:9:161:9 | n [MyInt] | provenance | | -| main.rs:161:24:161:33 | source(...) | main.rs:155:12:155:17 | ...: i64 | provenance | | -| main.rs:161:24:161:33 | source(...) | main.rs:161:13:161:34 | ...::new(...) [MyInt] | provenance | | -| main.rs:162:9:162:26 | MyInt {...} [MyInt] | main.rs:162:24:162:24 | m | provenance | | -| main.rs:162:24:162:24 | m | main.rs:163:10:163:10 | m | provenance | | -| main.rs:169:12:169:15 | SelfParam [MyInt] | main.rs:171:24:171:27 | self [MyInt] | provenance | | -| main.rs:171:9:171:35 | MyInt {...} [MyInt] | main.rs:169:42:172:5 | { ... } [MyInt] | provenance | | -| main.rs:171:24:171:27 | self [MyInt] | main.rs:171:24:171:33 | self.value | provenance | | -| main.rs:171:24:171:33 | self.value | main.rs:171:9:171:35 | MyInt {...} [MyInt] | provenance | | -| main.rs:186:9:186:9 | a [MyInt] | main.rs:169:12:169:15 | SelfParam [MyInt] | provenance | | -| main.rs:186:9:186:9 | a [MyInt] | main.rs:188:13:188:20 | a.add(...) [MyInt] | provenance | | -| main.rs:186:13:186:38 | MyInt {...} [MyInt] | main.rs:186:9:186:9 | a [MyInt] | provenance | | -| main.rs:186:28:186:36 | source(...) | main.rs:186:13:186:38 | MyInt {...} [MyInt] | provenance | | -| main.rs:188:9:188:9 | d [MyInt] | main.rs:189:10:189:10 | d [MyInt] | provenance | | -| main.rs:188:13:188:20 | a.add(...) [MyInt] | main.rs:188:9:188:9 | d [MyInt] | provenance | | -| main.rs:189:10:189:10 | d [MyInt] | main.rs:189:10:189:16 | d.value | provenance | | -| main.rs:201:18:201:21 | SelfParam [MyInt] | main.rs:201:48:203:5 | { ... } [MyInt] | provenance | | -| main.rs:205:26:205:37 | ...: MyInt [MyInt] | main.rs:205:49:207:5 | { ... } [MyInt] | provenance | | -| main.rs:211:9:211:9 | a [MyInt] | main.rs:213:49:213:49 | a [MyInt] | provenance | | -| main.rs:211:13:211:38 | MyInt {...} [MyInt] | main.rs:211:9:211:9 | a [MyInt] | provenance | | -| main.rs:211:28:211:36 | source(...) | main.rs:211:13:211:38 | MyInt {...} [MyInt] | provenance | | -| main.rs:213:9:213:26 | MyInt {...} [MyInt] | main.rs:213:24:213:24 | c | provenance | | -| main.rs:213:24:213:24 | c | main.rs:214:10:214:10 | c | provenance | | -| main.rs:213:30:213:53 | ...::take_self(...) [MyInt] | main.rs:213:9:213:26 | MyInt {...} [MyInt] | provenance | | -| main.rs:213:49:213:49 | a [MyInt] | main.rs:201:18:201:21 | SelfParam [MyInt] | provenance | | -| main.rs:213:49:213:49 | a [MyInt] | main.rs:213:30:213:53 | ...::take_self(...) [MyInt] | provenance | | -| main.rs:217:9:217:9 | b [MyInt] | main.rs:218:54:218:54 | b [MyInt] | provenance | | -| main.rs:217:13:217:39 | MyInt {...} [MyInt] | main.rs:217:9:217:9 | b [MyInt] | provenance | | -| main.rs:217:28:217:37 | source(...) | main.rs:217:13:217:39 | MyInt {...} [MyInt] | provenance | | -| main.rs:218:9:218:26 | MyInt {...} [MyInt] | main.rs:218:24:218:24 | c | provenance | | -| main.rs:218:24:218:24 | c | main.rs:219:10:219:10 | c | provenance | | -| main.rs:218:30:218:55 | ...::take_second(...) [MyInt] | main.rs:218:9:218:26 | MyInt {...} [MyInt] | provenance | | -| main.rs:218:54:218:54 | b [MyInt] | main.rs:205:26:205:37 | ...: MyInt [MyInt] | provenance | | -| main.rs:218:54:218:54 | b [MyInt] | main.rs:218:30:218:55 | ...::take_second(...) [MyInt] | provenance | | -| main.rs:227:32:231:1 | { ... } | main.rs:246:41:246:54 | async_source(...) | provenance | | -| main.rs:228:9:228:9 | a | main.rs:227:32:231:1 | { ... } | provenance | | -| main.rs:228:9:228:9 | a | main.rs:229:10:229:10 | a | provenance | | -| main.rs:228:13:228:21 | source(...) | main.rs:228:9:228:9 | a | provenance | | -| main.rs:238:13:238:13 | c | main.rs:239:14:239:14 | c | provenance | | -| main.rs:238:17:238:25 | source(...) | main.rs:238:13:238:13 | c | provenance | | -| main.rs:246:9:246:9 | a | main.rs:247:10:247:10 | a | provenance | | -| main.rs:246:13:246:55 | ...::block_on(...) | main.rs:246:9:246:9 | a | provenance | | -| main.rs:246:41:246:54 | async_source(...) | main.rs:246:13:246:55 | ...::block_on(...) | provenance | MaD:1 | +| main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | main.rs:46:14:46:14 | [post] a [MyStruct] | provenance | | +| main.rs:46:14:46:14 | [post] a [MyStruct] | main.rs:49:10:49:10 | a [MyStruct] | provenance | | +| main.rs:48:15:48:23 | source(...) | main.rs:26:28:26:33 | ...: i64 | provenance | | +| main.rs:48:15:48:23 | source(...) | main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | provenance | | +| main.rs:49:10:49:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | provenance | | +| main.rs:49:10:49:10 | a [MyStruct] | main.rs:49:10:49:21 | a.get_data() | provenance | | +| main.rs:52:12:52:17 | ...: i64 | main.rs:53:10:53:10 | n | provenance | | +| main.rs:57:9:57:9 | a | main.rs:58:13:58:13 | a | provenance | | +| main.rs:57:13:57:21 | source(...) | main.rs:57:9:57:9 | a | provenance | | +| main.rs:58:13:58:13 | a | main.rs:52:12:52:17 | ...: i64 | provenance | | +| main.rs:61:17:61:22 | ...: i64 | main.rs:61:32:63:1 | { ... } | provenance | | +| main.rs:66:9:66:9 | a | main.rs:67:26:67:26 | a | provenance | | +| main.rs:66:13:66:21 | source(...) | main.rs:66:9:66:9 | a | provenance | | +| main.rs:67:9:67:9 | b | main.rs:68:10:68:10 | b | provenance | | +| main.rs:67:13:67:27 | pass_through(...) | main.rs:67:9:67:9 | b | provenance | | +| main.rs:67:26:67:26 | a | main.rs:61:17:61:22 | ...: i64 | provenance | | +| main.rs:67:26:67:26 | a | main.rs:67:13:67:27 | pass_through(...) | provenance | | +| main.rs:72:9:72:9 | a | main.rs:76:10:76:10 | a | provenance | | +| main.rs:72:13:75:6 | pass_through(...) | main.rs:72:9:72:9 | a | provenance | | +| main.rs:72:26:75:5 | { ... } | main.rs:61:17:61:22 | ...: i64 | provenance | | +| main.rs:72:26:75:5 | { ... } | main.rs:72:13:75:6 | pass_through(...) | provenance | | +| main.rs:74:9:74:18 | source(...) | main.rs:72:26:75:5 | { ... } | provenance | | +| main.rs:80:9:80:9 | a | main.rs:86:26:86:26 | a | provenance | | +| main.rs:80:13:80:22 | source(...) | main.rs:80:9:80:9 | a | provenance | | +| main.rs:82:21:82:26 | ...: i64 | main.rs:82:36:84:5 | { ... } | provenance | | +| main.rs:86:9:86:9 | b | main.rs:87:10:87:10 | b | provenance | | +| main.rs:86:13:86:27 | pass_through(...) | main.rs:86:9:86:9 | b | provenance | | +| main.rs:86:26:86:26 | a | main.rs:82:21:82:26 | ...: i64 | provenance | | +| main.rs:86:26:86:26 | a | main.rs:86:13:86:27 | pass_through(...) | provenance | | +| main.rs:98:22:98:27 | ...: i64 | main.rs:99:14:99:14 | n | provenance | | +| main.rs:102:30:108:5 | { ... } | main.rs:121:13:121:25 | mn.get_data() | provenance | | +| main.rs:106:13:106:21 | source(...) | main.rs:102:30:108:5 | { ... } | provenance | | +| main.rs:110:27:110:32 | ...: i64 | main.rs:110:42:116:5 | { ... } | provenance | | +| main.rs:121:9:121:9 | a | main.rs:122:10:122:10 | a | provenance | | +| main.rs:121:13:121:25 | mn.get_data() | main.rs:121:9:121:9 | a | provenance | | +| main.rs:127:9:127:9 | a | main.rs:128:16:128:16 | a | provenance | | +| main.rs:127:13:127:21 | source(...) | main.rs:127:9:127:9 | a | provenance | | +| main.rs:128:16:128:16 | a | main.rs:98:22:98:27 | ...: i64 | provenance | | +| main.rs:133:9:133:9 | a | main.rs:134:29:134:29 | a | provenance | | +| main.rs:133:13:133:21 | source(...) | main.rs:133:9:133:9 | a | provenance | | +| main.rs:134:9:134:9 | b | main.rs:135:10:135:10 | b | provenance | | +| main.rs:134:13:134:30 | mn.data_through(...) | main.rs:134:9:134:9 | b | provenance | | +| main.rs:134:29:134:29 | a | main.rs:110:27:110:32 | ...: i64 | provenance | | +| main.rs:134:29:134:29 | a | main.rs:134:13:134:30 | mn.data_through(...) | provenance | | +| main.rs:140:9:140:9 | a | main.rs:141:25:141:25 | a | provenance | | +| main.rs:140:13:140:21 | source(...) | main.rs:140:9:140:9 | a | provenance | | +| main.rs:141:25:141:25 | a | main.rs:98:22:98:27 | ...: i64 | provenance | | +| main.rs:146:9:146:9 | a | main.rs:147:38:147:38 | a | provenance | | +| main.rs:146:13:146:22 | source(...) | main.rs:146:9:146:9 | a | provenance | | +| main.rs:147:9:147:9 | b | main.rs:148:10:148:10 | b | provenance | | +| main.rs:147:13:147:39 | ...::data_through(...) | main.rs:147:9:147:9 | b | provenance | | +| main.rs:147:38:147:38 | a | main.rs:110:27:110:32 | ...: i64 | provenance | | +| main.rs:147:38:147:38 | a | main.rs:147:13:147:39 | ...::data_through(...) | provenance | | +| main.rs:159:12:159:17 | ...: i64 | main.rs:160:24:160:24 | n | provenance | | +| main.rs:160:9:160:26 | MyInt {...} [MyInt] | main.rs:159:28:161:5 | { ... } [MyInt] | provenance | | +| main.rs:160:24:160:24 | n | main.rs:160:9:160:26 | MyInt {...} [MyInt] | provenance | | +| main.rs:165:9:165:9 | n [MyInt] | main.rs:166:9:166:26 | MyInt {...} [MyInt] | provenance | | +| main.rs:165:13:165:34 | ...::new(...) [MyInt] | main.rs:165:9:165:9 | n [MyInt] | provenance | | +| main.rs:165:24:165:33 | source(...) | main.rs:159:12:159:17 | ...: i64 | provenance | | +| main.rs:165:24:165:33 | source(...) | main.rs:165:13:165:34 | ...::new(...) [MyInt] | provenance | | +| main.rs:166:9:166:26 | MyInt {...} [MyInt] | main.rs:166:24:166:24 | m | provenance | | +| main.rs:166:24:166:24 | m | main.rs:167:10:167:10 | m | provenance | | +| main.rs:173:12:173:15 | SelfParam [MyInt] | main.rs:175:24:175:27 | self [MyInt] | provenance | | +| main.rs:175:9:175:35 | MyInt {...} [MyInt] | main.rs:173:42:176:5 | { ... } [MyInt] | provenance | | +| main.rs:175:24:175:27 | self [MyInt] | main.rs:175:24:175:33 | self.value | provenance | | +| main.rs:175:24:175:33 | self.value | main.rs:175:9:175:35 | MyInt {...} [MyInt] | provenance | | +| main.rs:205:9:205:9 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | provenance | | +| main.rs:205:9:205:9 | a [MyInt] | main.rs:207:13:207:20 | a.add(...) [MyInt] | provenance | | +| main.rs:205:13:205:38 | MyInt {...} [MyInt] | main.rs:205:9:205:9 | a [MyInt] | provenance | | +| main.rs:205:28:205:36 | source(...) | main.rs:205:13:205:38 | MyInt {...} [MyInt] | provenance | | +| main.rs:207:9:207:9 | d [MyInt] | main.rs:208:10:208:10 | d [MyInt] | provenance | | +| main.rs:207:13:207:20 | a.add(...) [MyInt] | main.rs:207:9:207:9 | d [MyInt] | provenance | | +| main.rs:208:10:208:10 | d [MyInt] | main.rs:208:10:208:16 | d.value | provenance | | +| main.rs:242:18:242:21 | SelfParam [MyInt] | main.rs:242:48:244:5 | { ... } [MyInt] | provenance | | +| main.rs:246:26:246:37 | ...: MyInt [MyInt] | main.rs:246:49:248:5 | { ... } [MyInt] | provenance | | +| main.rs:252:9:252:9 | a [MyInt] | main.rs:254:49:254:49 | a [MyInt] | provenance | | +| main.rs:252:13:252:38 | MyInt {...} [MyInt] | main.rs:252:9:252:9 | a [MyInt] | provenance | | +| main.rs:252:28:252:36 | source(...) | main.rs:252:13:252:38 | MyInt {...} [MyInt] | provenance | | +| main.rs:254:9:254:26 | MyInt {...} [MyInt] | main.rs:254:24:254:24 | c | provenance | | +| main.rs:254:24:254:24 | c | main.rs:255:10:255:10 | c | provenance | | +| main.rs:254:30:254:53 | ...::take_self(...) [MyInt] | main.rs:254:9:254:26 | MyInt {...} [MyInt] | provenance | | +| main.rs:254:49:254:49 | a [MyInt] | main.rs:242:18:242:21 | SelfParam [MyInt] | provenance | | +| main.rs:254:49:254:49 | a [MyInt] | main.rs:254:30:254:53 | ...::take_self(...) [MyInt] | provenance | | +| main.rs:258:9:258:9 | b [MyInt] | main.rs:259:54:259:54 | b [MyInt] | provenance | | +| main.rs:258:13:258:39 | MyInt {...} [MyInt] | main.rs:258:9:258:9 | b [MyInt] | provenance | | +| main.rs:258:28:258:37 | source(...) | main.rs:258:13:258:39 | MyInt {...} [MyInt] | provenance | | +| main.rs:259:9:259:26 | MyInt {...} [MyInt] | main.rs:259:24:259:24 | c | provenance | | +| main.rs:259:24:259:24 | c | main.rs:260:10:260:10 | c | provenance | | +| main.rs:259:30:259:55 | ...::take_second(...) [MyInt] | main.rs:259:9:259:26 | MyInt {...} [MyInt] | provenance | | +| main.rs:259:54:259:54 | b [MyInt] | main.rs:246:26:246:37 | ...: MyInt [MyInt] | provenance | | +| main.rs:259:54:259:54 | b [MyInt] | main.rs:259:30:259:55 | ...::take_second(...) [MyInt] | provenance | | +| main.rs:268:32:272:1 | { ... } | main.rs:287:41:287:54 | async_source(...) | provenance | | +| main.rs:269:9:269:9 | a | main.rs:268:32:272:1 | { ... } | provenance | | +| main.rs:269:9:269:9 | a | main.rs:270:10:270:10 | a | provenance | | +| main.rs:269:13:269:21 | source(...) | main.rs:269:9:269:9 | a | provenance | | +| main.rs:279:13:279:13 | c | main.rs:280:14:280:14 | c | provenance | | +| main.rs:279:17:279:25 | source(...) | main.rs:279:13:279:13 | c | provenance | | +| main.rs:287:9:287:9 | a | main.rs:288:10:288:10 | a | provenance | | +| main.rs:287:13:287:55 | ...::block_on(...) | main.rs:287:9:287:9 | a | provenance | | +| main.rs:287:41:287:54 | async_source(...) | main.rs:287:13:287:55 | ...::block_on(...) | provenance | MaD:1 | nodes | main.rs:12:28:14:1 | { ... } | semmle.label | { ... } | | main.rs:13:5:13:13 | source(...) | semmle.label | source(...) | @@ -140,149 +140,149 @@ nodes | main.rs:38:23:38:31 | source(...) | semmle.label | source(...) | | main.rs:39:10:39:10 | a [MyStruct] | semmle.label | a [MyStruct] | | main.rs:39:10:39:21 | a.get_data() | semmle.label | a.get_data() | -| main.rs:44:12:44:17 | [post] &mut a [&ref, MyStruct] | semmle.label | [post] &mut a [&ref, MyStruct] | -| main.rs:44:17:44:17 | [post] a [MyStruct] | semmle.label | [post] a [MyStruct] | -| main.rs:44:30:44:38 | source(...) | semmle.label | source(...) | -| main.rs:45:10:45:10 | a [MyStruct] | semmle.label | a [MyStruct] | -| main.rs:45:10:45:21 | a.get_data() | semmle.label | a.get_data() | -| main.rs:48:12:48:17 | ...: i64 | semmle.label | ...: i64 | -| main.rs:49:10:49:10 | n | semmle.label | n | -| main.rs:53:9:53:9 | a | semmle.label | a | -| main.rs:53:13:53:21 | source(...) | semmle.label | source(...) | -| main.rs:54:13:54:13 | a | semmle.label | a | -| main.rs:57:17:57:22 | ...: i64 | semmle.label | ...: i64 | -| main.rs:57:32:59:1 | { ... } | semmle.label | { ... } | -| main.rs:62:9:62:9 | a | semmle.label | a | -| main.rs:62:13:62:21 | source(...) | semmle.label | source(...) | -| main.rs:63:9:63:9 | b | semmle.label | b | -| main.rs:63:13:63:27 | pass_through(...) | semmle.label | pass_through(...) | -| main.rs:63:26:63:26 | a | semmle.label | a | -| main.rs:64:10:64:10 | b | semmle.label | b | -| main.rs:68:9:68:9 | a | semmle.label | a | -| main.rs:68:13:71:6 | pass_through(...) | semmle.label | pass_through(...) | -| main.rs:68:26:71:5 | { ... } | semmle.label | { ... } | -| main.rs:70:9:70:18 | source(...) | semmle.label | source(...) | -| main.rs:72:10:72:10 | a | semmle.label | a | -| main.rs:76:9:76:9 | a | semmle.label | a | -| main.rs:76:13:76:22 | source(...) | semmle.label | source(...) | -| main.rs:78:21:78:26 | ...: i64 | semmle.label | ...: i64 | -| main.rs:78:36:80:5 | { ... } | semmle.label | { ... } | -| main.rs:82:9:82:9 | b | semmle.label | b | -| main.rs:82:13:82:27 | pass_through(...) | semmle.label | pass_through(...) | -| main.rs:82:26:82:26 | a | semmle.label | a | -| main.rs:83:10:83:10 | b | semmle.label | b | -| main.rs:94:22:94:27 | ...: i64 | semmle.label | ...: i64 | -| main.rs:95:14:95:14 | n | semmle.label | n | -| main.rs:98:30:104:5 | { ... } | semmle.label | { ... } | -| main.rs:102:13:102:21 | source(...) | semmle.label | source(...) | -| main.rs:106:27:106:32 | ...: i64 | semmle.label | ...: i64 | -| main.rs:106:42:112:5 | { ... } | semmle.label | { ... } | -| main.rs:117:9:117:9 | a | semmle.label | a | -| main.rs:117:13:117:25 | mn.get_data() | semmle.label | mn.get_data() | -| main.rs:118:10:118:10 | a | semmle.label | a | -| main.rs:123:9:123:9 | a | semmle.label | a | -| main.rs:123:13:123:21 | source(...) | semmle.label | source(...) | -| main.rs:124:16:124:16 | a | semmle.label | a | -| main.rs:129:9:129:9 | a | semmle.label | a | -| main.rs:129:13:129:21 | source(...) | semmle.label | source(...) | -| main.rs:130:9:130:9 | b | semmle.label | b | -| main.rs:130:13:130:30 | mn.data_through(...) | semmle.label | mn.data_through(...) | -| main.rs:130:29:130:29 | a | semmle.label | a | -| main.rs:131:10:131:10 | b | semmle.label | b | -| main.rs:136:9:136:9 | a | semmle.label | a | -| main.rs:136:13:136:21 | source(...) | semmle.label | source(...) | -| main.rs:137:25:137:25 | a | semmle.label | a | -| main.rs:142:9:142:9 | a | semmle.label | a | -| main.rs:142:13:142:22 | source(...) | semmle.label | source(...) | -| main.rs:143:9:143:9 | b | semmle.label | b | -| main.rs:143:13:143:39 | ...::data_through(...) | semmle.label | ...::data_through(...) | -| main.rs:143:38:143:38 | a | semmle.label | a | -| main.rs:144:10:144:10 | b | semmle.label | b | -| main.rs:155:12:155:17 | ...: i64 | semmle.label | ...: i64 | -| main.rs:155:28:157:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | -| main.rs:156:9:156:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:156:24:156:24 | n | semmle.label | n | -| main.rs:161:9:161:9 | n [MyInt] | semmle.label | n [MyInt] | -| main.rs:161:13:161:34 | ...::new(...) [MyInt] | semmle.label | ...::new(...) [MyInt] | -| main.rs:161:24:161:33 | source(...) | semmle.label | source(...) | -| main.rs:162:9:162:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:162:24:162:24 | m | semmle.label | m | -| main.rs:163:10:163:10 | m | semmle.label | m | -| main.rs:169:12:169:15 | SelfParam [MyInt] | semmle.label | SelfParam [MyInt] | -| main.rs:169:42:172:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | -| main.rs:171:9:171:35 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:171:24:171:27 | self [MyInt] | semmle.label | self [MyInt] | -| main.rs:171:24:171:33 | self.value | semmle.label | self.value | -| main.rs:186:9:186:9 | a [MyInt] | semmle.label | a [MyInt] | -| main.rs:186:13:186:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:186:28:186:36 | source(...) | semmle.label | source(...) | -| main.rs:188:9:188:9 | d [MyInt] | semmle.label | d [MyInt] | -| main.rs:188:13:188:20 | a.add(...) [MyInt] | semmle.label | a.add(...) [MyInt] | -| main.rs:189:10:189:10 | d [MyInt] | semmle.label | d [MyInt] | -| main.rs:189:10:189:16 | d.value | semmle.label | d.value | -| main.rs:201:18:201:21 | SelfParam [MyInt] | semmle.label | SelfParam [MyInt] | -| main.rs:201:48:203:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | -| main.rs:205:26:205:37 | ...: MyInt [MyInt] | semmle.label | ...: MyInt [MyInt] | -| main.rs:205:49:207:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | -| main.rs:211:9:211:9 | a [MyInt] | semmle.label | a [MyInt] | -| main.rs:211:13:211:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:211:28:211:36 | source(...) | semmle.label | source(...) | -| main.rs:213:9:213:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:213:24:213:24 | c | semmle.label | c | -| main.rs:213:30:213:53 | ...::take_self(...) [MyInt] | semmle.label | ...::take_self(...) [MyInt] | -| main.rs:213:49:213:49 | a [MyInt] | semmle.label | a [MyInt] | -| main.rs:214:10:214:10 | c | semmle.label | c | -| main.rs:217:9:217:9 | b [MyInt] | semmle.label | b [MyInt] | -| main.rs:217:13:217:39 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:217:28:217:37 | source(...) | semmle.label | source(...) | -| main.rs:218:9:218:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | -| main.rs:218:24:218:24 | c | semmle.label | c | -| main.rs:218:30:218:55 | ...::take_second(...) [MyInt] | semmle.label | ...::take_second(...) [MyInt] | -| main.rs:218:54:218:54 | b [MyInt] | semmle.label | b [MyInt] | -| main.rs:219:10:219:10 | c | semmle.label | c | -| main.rs:227:32:231:1 | { ... } | semmle.label | { ... } | -| main.rs:228:9:228:9 | a | semmle.label | a | -| main.rs:228:13:228:21 | source(...) | semmle.label | source(...) | -| main.rs:229:10:229:10 | a | semmle.label | a | -| main.rs:238:13:238:13 | c | semmle.label | c | -| main.rs:238:17:238:25 | source(...) | semmle.label | source(...) | -| main.rs:239:14:239:14 | c | semmle.label | c | -| main.rs:246:9:246:9 | a | semmle.label | a | -| main.rs:246:13:246:55 | ...::block_on(...) | semmle.label | ...::block_on(...) | -| main.rs:246:41:246:54 | async_source(...) | semmle.label | async_source(...) | -| main.rs:247:10:247:10 | a | semmle.label | a | +| main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | semmle.label | [post] &mut a [&ref, MyStruct] | +| main.rs:46:14:46:14 | [post] a [MyStruct] | semmle.label | [post] a [MyStruct] | +| main.rs:48:15:48:23 | source(...) | semmle.label | source(...) | +| main.rs:49:10:49:10 | a [MyStruct] | semmle.label | a [MyStruct] | +| main.rs:49:10:49:21 | a.get_data() | semmle.label | a.get_data() | +| main.rs:52:12:52:17 | ...: i64 | semmle.label | ...: i64 | +| main.rs:53:10:53:10 | n | semmle.label | n | +| main.rs:57:9:57:9 | a | semmle.label | a | +| main.rs:57:13:57:21 | source(...) | semmle.label | source(...) | +| main.rs:58:13:58:13 | a | semmle.label | a | +| main.rs:61:17:61:22 | ...: i64 | semmle.label | ...: i64 | +| main.rs:61:32:63:1 | { ... } | semmle.label | { ... } | +| main.rs:66:9:66:9 | a | semmle.label | a | +| main.rs:66:13:66:21 | source(...) | semmle.label | source(...) | +| main.rs:67:9:67:9 | b | semmle.label | b | +| main.rs:67:13:67:27 | pass_through(...) | semmle.label | pass_through(...) | +| main.rs:67:26:67:26 | a | semmle.label | a | +| main.rs:68:10:68:10 | b | semmle.label | b | +| main.rs:72:9:72:9 | a | semmle.label | a | +| main.rs:72:13:75:6 | pass_through(...) | semmle.label | pass_through(...) | +| main.rs:72:26:75:5 | { ... } | semmle.label | { ... } | +| main.rs:74:9:74:18 | source(...) | semmle.label | source(...) | +| main.rs:76:10:76:10 | a | semmle.label | a | +| main.rs:80:9:80:9 | a | semmle.label | a | +| main.rs:80:13:80:22 | source(...) | semmle.label | source(...) | +| main.rs:82:21:82:26 | ...: i64 | semmle.label | ...: i64 | +| main.rs:82:36:84:5 | { ... } | semmle.label | { ... } | +| main.rs:86:9:86:9 | b | semmle.label | b | +| main.rs:86:13:86:27 | pass_through(...) | semmle.label | pass_through(...) | +| main.rs:86:26:86:26 | a | semmle.label | a | +| main.rs:87:10:87:10 | b | semmle.label | b | +| main.rs:98:22:98:27 | ...: i64 | semmle.label | ...: i64 | +| main.rs:99:14:99:14 | n | semmle.label | n | +| main.rs:102:30:108:5 | { ... } | semmle.label | { ... } | +| main.rs:106:13:106:21 | source(...) | semmle.label | source(...) | +| main.rs:110:27:110:32 | ...: i64 | semmle.label | ...: i64 | +| main.rs:110:42:116:5 | { ... } | semmle.label | { ... } | +| main.rs:121:9:121:9 | a | semmle.label | a | +| main.rs:121:13:121:25 | mn.get_data() | semmle.label | mn.get_data() | +| main.rs:122:10:122:10 | a | semmle.label | a | +| main.rs:127:9:127:9 | a | semmle.label | a | +| main.rs:127:13:127:21 | source(...) | semmle.label | source(...) | +| main.rs:128:16:128:16 | a | semmle.label | a | +| main.rs:133:9:133:9 | a | semmle.label | a | +| main.rs:133:13:133:21 | source(...) | semmle.label | source(...) | +| main.rs:134:9:134:9 | b | semmle.label | b | +| main.rs:134:13:134:30 | mn.data_through(...) | semmle.label | mn.data_through(...) | +| main.rs:134:29:134:29 | a | semmle.label | a | +| main.rs:135:10:135:10 | b | semmle.label | b | +| main.rs:140:9:140:9 | a | semmle.label | a | +| main.rs:140:13:140:21 | source(...) | semmle.label | source(...) | +| main.rs:141:25:141:25 | a | semmle.label | a | +| main.rs:146:9:146:9 | a | semmle.label | a | +| main.rs:146:13:146:22 | source(...) | semmle.label | source(...) | +| main.rs:147:9:147:9 | b | semmle.label | b | +| main.rs:147:13:147:39 | ...::data_through(...) | semmle.label | ...::data_through(...) | +| main.rs:147:38:147:38 | a | semmle.label | a | +| main.rs:148:10:148:10 | b | semmle.label | b | +| main.rs:159:12:159:17 | ...: i64 | semmle.label | ...: i64 | +| main.rs:159:28:161:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | +| main.rs:160:9:160:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:160:24:160:24 | n | semmle.label | n | +| main.rs:165:9:165:9 | n [MyInt] | semmle.label | n [MyInt] | +| main.rs:165:13:165:34 | ...::new(...) [MyInt] | semmle.label | ...::new(...) [MyInt] | +| main.rs:165:24:165:33 | source(...) | semmle.label | source(...) | +| main.rs:166:9:166:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:166:24:166:24 | m | semmle.label | m | +| main.rs:167:10:167:10 | m | semmle.label | m | +| main.rs:173:12:173:15 | SelfParam [MyInt] | semmle.label | SelfParam [MyInt] | +| main.rs:173:42:176:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | +| main.rs:175:9:175:35 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:175:24:175:27 | self [MyInt] | semmle.label | self [MyInt] | +| main.rs:175:24:175:33 | self.value | semmle.label | self.value | +| main.rs:205:9:205:9 | a [MyInt] | semmle.label | a [MyInt] | +| main.rs:205:13:205:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:205:28:205:36 | source(...) | semmle.label | source(...) | +| main.rs:207:9:207:9 | d [MyInt] | semmle.label | d [MyInt] | +| main.rs:207:13:207:20 | a.add(...) [MyInt] | semmle.label | a.add(...) [MyInt] | +| main.rs:208:10:208:10 | d [MyInt] | semmle.label | d [MyInt] | +| main.rs:208:10:208:16 | d.value | semmle.label | d.value | +| main.rs:242:18:242:21 | SelfParam [MyInt] | semmle.label | SelfParam [MyInt] | +| main.rs:242:48:244:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | +| main.rs:246:26:246:37 | ...: MyInt [MyInt] | semmle.label | ...: MyInt [MyInt] | +| main.rs:246:49:248:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] | +| main.rs:252:9:252:9 | a [MyInt] | semmle.label | a [MyInt] | +| main.rs:252:13:252:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:252:28:252:36 | source(...) | semmle.label | source(...) | +| main.rs:254:9:254:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:254:24:254:24 | c | semmle.label | c | +| main.rs:254:30:254:53 | ...::take_self(...) [MyInt] | semmle.label | ...::take_self(...) [MyInt] | +| main.rs:254:49:254:49 | a [MyInt] | semmle.label | a [MyInt] | +| main.rs:255:10:255:10 | c | semmle.label | c | +| main.rs:258:9:258:9 | b [MyInt] | semmle.label | b [MyInt] | +| main.rs:258:13:258:39 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:258:28:258:37 | source(...) | semmle.label | source(...) | +| main.rs:259:9:259:26 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:259:24:259:24 | c | semmle.label | c | +| main.rs:259:30:259:55 | ...::take_second(...) [MyInt] | semmle.label | ...::take_second(...) [MyInt] | +| main.rs:259:54:259:54 | b [MyInt] | semmle.label | b [MyInt] | +| main.rs:260:10:260:10 | c | semmle.label | c | +| main.rs:268:32:272:1 | { ... } | semmle.label | { ... } | +| main.rs:269:9:269:9 | a | semmle.label | a | +| main.rs:269:13:269:21 | source(...) | semmle.label | source(...) | +| main.rs:270:10:270:10 | a | semmle.label | a | +| main.rs:279:13:279:13 | c | semmle.label | c | +| main.rs:279:17:279:25 | source(...) | semmle.label | source(...) | +| main.rs:280:14:280:14 | c | semmle.label | c | +| main.rs:287:9:287:9 | a | semmle.label | a | +| main.rs:287:13:287:55 | ...::block_on(...) | semmle.label | ...::block_on(...) | +| main.rs:287:41:287:54 | async_source(...) | semmle.label | async_source(...) | +| main.rs:288:10:288:10 | a | semmle.label | a | subpaths | main.rs:38:23:38:31 | source(...) | main.rs:26:28:26:33 | ...: i64 | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | main.rs:38:6:38:11 | [post] &mut a [&ref, MyStruct] | | main.rs:39:10:39:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:30:31:32:5 | { ... } | main.rs:39:10:39:21 | a.get_data() | -| main.rs:44:30:44:38 | source(...) | main.rs:26:28:26:33 | ...: i64 | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | main.rs:44:12:44:17 | [post] &mut a [&ref, MyStruct] | -| main.rs:45:10:45:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:30:31:32:5 | { ... } | main.rs:45:10:45:21 | a.get_data() | -| main.rs:63:26:63:26 | a | main.rs:57:17:57:22 | ...: i64 | main.rs:57:32:59:1 | { ... } | main.rs:63:13:63:27 | pass_through(...) | -| main.rs:68:26:71:5 | { ... } | main.rs:57:17:57:22 | ...: i64 | main.rs:57:32:59:1 | { ... } | main.rs:68:13:71:6 | pass_through(...) | -| main.rs:82:26:82:26 | a | main.rs:78:21:78:26 | ...: i64 | main.rs:78:36:80:5 | { ... } | main.rs:82:13:82:27 | pass_through(...) | -| main.rs:130:29:130:29 | a | main.rs:106:27:106:32 | ...: i64 | main.rs:106:42:112:5 | { ... } | main.rs:130:13:130:30 | mn.data_through(...) | -| main.rs:143:38:143:38 | a | main.rs:106:27:106:32 | ...: i64 | main.rs:106:42:112:5 | { ... } | main.rs:143:13:143:39 | ...::data_through(...) | -| main.rs:161:24:161:33 | source(...) | main.rs:155:12:155:17 | ...: i64 | main.rs:155:28:157:5 | { ... } [MyInt] | main.rs:161:13:161:34 | ...::new(...) [MyInt] | -| main.rs:186:9:186:9 | a [MyInt] | main.rs:169:12:169:15 | SelfParam [MyInt] | main.rs:169:42:172:5 | { ... } [MyInt] | main.rs:188:13:188:20 | a.add(...) [MyInt] | -| main.rs:213:49:213:49 | a [MyInt] | main.rs:201:18:201:21 | SelfParam [MyInt] | main.rs:201:48:203:5 | { ... } [MyInt] | main.rs:213:30:213:53 | ...::take_self(...) [MyInt] | -| main.rs:218:54:218:54 | b [MyInt] | main.rs:205:26:205:37 | ...: MyInt [MyInt] | main.rs:205:49:207:5 | { ... } [MyInt] | main.rs:218:30:218:55 | ...::take_second(...) [MyInt] | +| main.rs:48:15:48:23 | source(...) | main.rs:26:28:26:33 | ...: i64 | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | +| main.rs:49:10:49:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:30:31:32:5 | { ... } | main.rs:49:10:49:21 | a.get_data() | +| main.rs:67:26:67:26 | a | main.rs:61:17:61:22 | ...: i64 | main.rs:61:32:63:1 | { ... } | main.rs:67:13:67:27 | pass_through(...) | +| main.rs:72:26:75:5 | { ... } | main.rs:61:17:61:22 | ...: i64 | main.rs:61:32:63:1 | { ... } | main.rs:72:13:75:6 | pass_through(...) | +| main.rs:86:26:86:26 | a | main.rs:82:21:82:26 | ...: i64 | main.rs:82:36:84:5 | { ... } | main.rs:86:13:86:27 | pass_through(...) | +| main.rs:134:29:134:29 | a | main.rs:110:27:110:32 | ...: i64 | main.rs:110:42:116:5 | { ... } | main.rs:134:13:134:30 | mn.data_through(...) | +| main.rs:147:38:147:38 | a | main.rs:110:27:110:32 | ...: i64 | main.rs:110:42:116:5 | { ... } | main.rs:147:13:147:39 | ...::data_through(...) | +| main.rs:165:24:165:33 | source(...) | main.rs:159:12:159:17 | ...: i64 | main.rs:159:28:161:5 | { ... } [MyInt] | main.rs:165:13:165:34 | ...::new(...) [MyInt] | +| main.rs:205:9:205:9 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | main.rs:173:42:176:5 | { ... } [MyInt] | main.rs:207:13:207:20 | a.add(...) [MyInt] | +| main.rs:254:49:254:49 | a [MyInt] | main.rs:242:18:242:21 | SelfParam [MyInt] | main.rs:242:48:244:5 | { ... } [MyInt] | main.rs:254:30:254:53 | ...::take_self(...) [MyInt] | +| main.rs:259:54:259:54 | b [MyInt] | main.rs:246:26:246:37 | ...: MyInt [MyInt] | main.rs:246:49:248:5 | { ... } [MyInt] | main.rs:259:30:259:55 | ...::take_second(...) [MyInt] | testFailures #select | 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:39:10:39:21 | a.get_data() | main.rs:38:23:38:31 | source(...) | main.rs:39:10:39:21 | a.get_data() | $@ | main.rs:38:23:38:31 | source(...) | source(...) | -| main.rs:45:10:45:21 | a.get_data() | main.rs:44:30:44:38 | source(...) | main.rs:45:10:45:21 | a.get_data() | $@ | main.rs:44:30:44:38 | source(...) | source(...) | -| main.rs:49:10:49:10 | n | main.rs:53:13:53:21 | source(...) | main.rs:49:10:49:10 | n | $@ | main.rs:53:13:53:21 | source(...) | source(...) | -| main.rs:64:10:64:10 | b | main.rs:62:13:62:21 | source(...) | main.rs:64:10:64:10 | b | $@ | main.rs:62:13:62:21 | source(...) | source(...) | -| main.rs:72:10:72:10 | a | main.rs:70:9:70:18 | source(...) | main.rs:72:10:72:10 | a | $@ | main.rs:70:9:70:18 | source(...) | source(...) | -| main.rs:83:10:83:10 | b | main.rs:76:13:76:22 | source(...) | main.rs:83:10:83:10 | b | $@ | main.rs:76:13:76:22 | source(...) | source(...) | -| main.rs:95:14:95:14 | n | main.rs:123:13:123:21 | source(...) | main.rs:95:14:95:14 | n | $@ | main.rs:123:13:123:21 | source(...) | source(...) | -| main.rs:95:14:95:14 | n | main.rs:136:13:136:21 | source(...) | main.rs:95:14:95:14 | n | $@ | main.rs:136:13:136:21 | source(...) | source(...) | -| main.rs:118:10:118:10 | a | main.rs:102:13:102:21 | source(...) | main.rs:118:10:118:10 | a | $@ | main.rs:102:13:102:21 | source(...) | source(...) | -| main.rs:131:10:131:10 | b | main.rs:129:13:129:21 | source(...) | main.rs:131:10:131:10 | b | $@ | main.rs:129:13:129:21 | source(...) | source(...) | -| main.rs:144:10:144:10 | b | main.rs:142:13:142:22 | source(...) | main.rs:144:10:144:10 | b | $@ | main.rs:142:13:142:22 | source(...) | source(...) | -| main.rs:163:10:163:10 | m | main.rs:161:24:161:33 | source(...) | main.rs:163:10:163:10 | m | $@ | main.rs:161:24:161:33 | source(...) | source(...) | -| main.rs:189:10:189:16 | d.value | main.rs:186:28:186:36 | source(...) | main.rs:189:10:189:16 | d.value | $@ | main.rs:186:28:186:36 | source(...) | source(...) | -| main.rs:214:10:214:10 | c | main.rs:211:28:211:36 | source(...) | main.rs:214:10:214:10 | c | $@ | main.rs:211:28:211:36 | source(...) | source(...) | -| main.rs:219:10:219:10 | c | main.rs:217:28:217:37 | source(...) | main.rs:219:10:219:10 | c | $@ | main.rs:217:28:217:37 | source(...) | source(...) | -| main.rs:229:10:229:10 | a | main.rs:228:13:228:21 | source(...) | main.rs:229:10:229:10 | a | $@ | main.rs:228:13:228:21 | source(...) | source(...) | -| main.rs:239:14:239:14 | c | main.rs:238:17:238:25 | source(...) | main.rs:239:14:239:14 | c | $@ | main.rs:238:17:238:25 | source(...) | source(...) | -| main.rs:247:10:247:10 | a | main.rs:228:13:228:21 | source(...) | main.rs:247:10:247:10 | a | $@ | main.rs:228:13:228:21 | source(...) | source(...) | +| main.rs:49:10:49:21 | a.get_data() | main.rs:48:15:48:23 | source(...) | main.rs:49:10:49:21 | a.get_data() | $@ | main.rs:48:15:48:23 | source(...) | source(...) | +| main.rs:53:10:53:10 | n | main.rs:57:13:57:21 | source(...) | main.rs:53:10:53:10 | n | $@ | main.rs:57:13:57:21 | source(...) | source(...) | +| main.rs:68:10:68:10 | b | main.rs:66:13:66:21 | source(...) | main.rs:68:10:68:10 | b | $@ | main.rs:66:13:66:21 | source(...) | source(...) | +| main.rs:76:10:76:10 | a | main.rs:74:9:74:18 | source(...) | main.rs:76:10:76:10 | a | $@ | main.rs:74:9:74:18 | source(...) | source(...) | +| main.rs:87:10:87:10 | b | main.rs:80:13:80:22 | source(...) | main.rs:87:10:87:10 | b | $@ | main.rs:80:13:80:22 | source(...) | source(...) | +| main.rs:99:14:99:14 | n | main.rs:127:13:127:21 | source(...) | main.rs:99:14:99:14 | n | $@ | main.rs:127:13:127:21 | source(...) | source(...) | +| main.rs:99:14:99:14 | n | main.rs:140:13:140:21 | source(...) | main.rs:99:14:99:14 | n | $@ | main.rs:140:13:140:21 | source(...) | source(...) | +| main.rs:122:10:122:10 | a | main.rs:106:13:106:21 | source(...) | main.rs:122:10:122:10 | a | $@ | main.rs:106:13:106:21 | source(...) | source(...) | +| main.rs:135:10:135:10 | b | main.rs:133:13:133:21 | source(...) | main.rs:135:10:135:10 | b | $@ | main.rs:133:13:133:21 | source(...) | source(...) | +| main.rs:148:10:148:10 | b | main.rs:146:13:146:22 | source(...) | main.rs:148:10:148:10 | b | $@ | main.rs:146:13:146:22 | source(...) | source(...) | +| main.rs:167:10:167:10 | m | main.rs:165:24:165:33 | source(...) | main.rs:167:10:167:10 | m | $@ | main.rs:165:24:165:33 | source(...) | source(...) | +| main.rs:208:10:208:16 | d.value | main.rs:205:28:205:36 | source(...) | main.rs:208:10:208:16 | d.value | $@ | main.rs:205:28:205:36 | source(...) | source(...) | +| main.rs:255:10:255:10 | c | main.rs:252:28:252:36 | source(...) | main.rs:255:10:255:10 | c | $@ | main.rs:252:28:252:36 | source(...) | source(...) | +| main.rs:260:10:260:10 | c | main.rs:258:28:258:37 | source(...) | main.rs:260:10:260:10 | c | $@ | main.rs:258:28:258:37 | source(...) | source(...) | +| main.rs:270:10:270:10 | a | main.rs:269:13:269:21 | source(...) | main.rs:270:10:270:10 | a | $@ | main.rs:269:13:269:21 | source(...) | source(...) | +| main.rs:280:14:280:14 | c | main.rs:279:17:279:25 | source(...) | main.rs:280:14:280:14 | c | $@ | main.rs:279:17:279:25 | source(...) | source(...) | +| main.rs:288:10:288:10 | a | main.rs:269:13:269:21 | source(...) | main.rs:288:10:288:10 | a | $@ | main.rs:269:13:269:21 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/global/main.rs b/rust/ql/test/library-tests/dataflow/global/main.rs index 507772692d67..a495ca392fcb 100644 --- a/rust/ql/test/library-tests/dataflow/global/main.rs +++ b/rust/ql/test/library-tests/dataflow/global/main.rs @@ -41,7 +41,11 @@ fn data_out_of_call_side_effect1() { fn data_out_of_call_side_effect2() { let mut a = MyStruct { data: 0 }; - ({ 42; &mut a}).set_data(source(9)); + ({ + 42; + &mut a + }) + .set_data(source(9)); sink(a.get_data()); // $ hasValueFlow=9 } @@ -144,7 +148,7 @@ fn data_through_method_called_as_function() { sink(b); // $ hasValueFlow=12 } -use std::ops::Add; +use std::ops::{Add, Deref, MulAssign}; struct MyInt { value: i64, @@ -172,7 +176,22 @@ impl Add for MyInt { } } +impl MulAssign for MyInt { + fn mul_assign(&mut self, rhs: MyInt) { + (*self).value = rhs.value; // todo: implicit deref not yet supported + } +} + +impl Deref for MyInt { + type Target = i64; + + fn deref(&self) -> &Self::Target { + &(*self).value + } +} + fn test_operator_overloading() { + // Tests for simple binary operator. let a = MyInt { value: source(5) }; let b = MyInt { value: 2 }; let c = a + b; @@ -187,6 +206,28 @@ fn test_operator_overloading() { let b = MyInt { value: 2 }; let d = a.add(b); sink(d.value); // $ hasValueFlow=7 + + // Tests for assignment operator. + let mut a = MyInt { value: 0 }; + let b = MyInt { value: source(34) }; + // The line below is what `*=` desugars to. + MulAssign::mul_assign(&mut a, b); + sink(a.value); // $ MISSING: hasValueFlow=34 + + let mut a = MyInt { value: 0 }; + let b = MyInt { value: source(35) }; + a *= b; + sink(a.value); // $ MISSING: hasValueFlow=35 + + // Tests for deref operator. + let a = MyInt { value: source(27) }; + // The line below is what the prefix `*` desugars to. + let c = *Deref::deref(&a); + sink(c); // $ MISSING: hasValueFlow=27 + + let a = MyInt { value: source(28) }; + let c = *a; + sink(c); // $ MISSING: hasValueFlow=28 } trait MyTrait { diff --git a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected index 63abc4c7f417..bb1ac8947730 100644 --- a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected +++ b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected @@ -7,75 +7,83 @@ | main.rs:38:23:38:31 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:39:5:39:22 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:39:10:39:21 | a.get_data() | main.rs:30:5:32:5 | fn get_data | -| main.rs:44:5:44:39 | ... .set_data(...) | main.rs:26:5:28:5 | fn set_data | -| main.rs:44:30:44:38 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:45:5:45:22 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:45:10:45:21 | a.get_data() | main.rs:30:5:32:5 | fn get_data | -| main.rs:49:5:49:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:53:13:53:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:54:5:54:14 | data_in(...) | main.rs:48:1:50:1 | fn data_in | -| main.rs:62:13:62:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:63:13:63:27 | pass_through(...) | main.rs:57:1:59:1 | fn pass_through | -| main.rs:64:5:64:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:68:13:71:6 | pass_through(...) | main.rs:57:1:59:1 | fn pass_through | -| main.rs:70:9:70:18 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:72:5:72:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:76:13:76:22 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:82:13:82:27 | pass_through(...) | main.rs:78:5:80:5 | fn pass_through | -| main.rs:83:5:83:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:95:9:95:15 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:102:13:102:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:117:13:117:25 | mn.get_data() | main.rs:98:5:104:5 | fn get_data | -| main.rs:118:5:118:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:123:13:123:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:124:5:124:17 | mn.data_in(...) | main.rs:94:5:96:5 | fn data_in | -| main.rs:129:13:129:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:130:13:130:30 | mn.data_through(...) | main.rs:106:5:112:5 | fn data_through | -| main.rs:131:5:131:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:136:13:136:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:137:5:137:26 | ...::data_in(...) | main.rs:94:5:96:5 | fn data_in | -| main.rs:142:13:142:22 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:143:13:143:39 | ...::data_through(...) | main.rs:106:5:112:5 | fn data_through | -| main.rs:144:5:144:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:161:13:161:34 | ...::new(...) | main.rs:154:5:157:5 | fn new | -| main.rs:161:24:161:33 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:163:5:163:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:176:28:176:36 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:179:5:179:17 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:182:28:182:36 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:184:5:184:17 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:186:28:186:36 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:188:13:188:20 | a.add(...) | main.rs:169:5:172:5 | fn add | -| main.rs:189:5:189:17 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:211:28:211:36 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:213:30:213:53 | ...::take_self(...) | main.rs:201:5:203:5 | fn take_self | -| main.rs:214:5:214:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:217:28:217:37 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:218:30:218:55 | ...::take_second(...) | main.rs:205:5:207:5 | fn take_second | -| main.rs:219:5:219:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:222:28:222:37 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:223:30:223:53 | ...::take_self(...) | main.rs:201:5:203:5 | fn take_self | -| main.rs:224:5:224:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:228:13:228:21 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:229:5:229:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:234:13:234:26 | async_source(...) | main.rs:227:1:231:1 | fn async_source | -| main.rs:235:5:235:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:238:17:238:25 | source(...) | main.rs:1:1:3:1 | fn source | -| main.rs:239:9:239:15 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:242:5:242:17 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:246:13:246:55 | ...::block_on(...) | file://:0:0:0:0 | repo:https://github.com/rust-lang/futures-rs:futures-executor::_::crate::local_pool::block_on | -| main.rs:246:41:246:54 | async_source(...) | main.rs:227:1:231:1 | fn async_source | -| main.rs:247:5:247:11 | sink(...) | main.rs:5:1:7:1 | fn sink | -| main.rs:249:5:249:62 | ...::block_on(...) | file://:0:0:0:0 | repo:https://github.com/rust-lang/futures-rs:futures-executor::_::crate::local_pool::block_on | -| main.rs:249:33:249:61 | test_async_await_async_part(...) | main.rs:233:1:243:1 | fn test_async_await_async_part | -| main.rs:253:5:253:22 | data_out_of_call(...) | main.rs:16:1:19:1 | fn data_out_of_call | -| main.rs:254:5:254:35 | data_out_of_call_side_effect1(...) | main.rs:35:1:40:1 | fn data_out_of_call_side_effect1 | -| main.rs:255:5:255:35 | data_out_of_call_side_effect2(...) | main.rs:42:1:46:1 | fn data_out_of_call_side_effect2 | -| main.rs:256:5:256:21 | data_in_to_call(...) | main.rs:52:1:55:1 | fn data_in_to_call | -| main.rs:257:5:257:23 | data_through_call(...) | main.rs:61:1:65:1 | fn data_through_call | -| main.rs:258:5:258:34 | data_through_nested_function(...) | main.rs:75:1:84:1 | fn data_through_nested_function | -| main.rs:260:5:260:24 | data_out_of_method(...) | main.rs:115:1:119:1 | fn data_out_of_method | -| main.rs:261:5:261:28 | data_in_to_method_call(...) | main.rs:121:1:125:1 | fn data_in_to_method_call | -| main.rs:262:5:262:25 | data_through_method(...) | main.rs:127:1:132:1 | fn data_through_method | -| main.rs:264:5:264:31 | test_operator_overloading(...) | main.rs:175:1:190:1 | fn test_operator_overloading | -| main.rs:265:5:265:22 | test_async_await(...) | main.rs:245:1:250:1 | fn test_async_await | +| main.rs:44:5:48:24 | ... .set_data(...) | main.rs:26:5:28:5 | fn set_data | +| main.rs:48:15:48:23 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:49:5:49:22 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:49:10:49:21 | a.get_data() | main.rs:30:5:32:5 | fn get_data | +| main.rs:53:5:53:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:57:13:57:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:58:5:58:14 | data_in(...) | main.rs:52:1:54:1 | fn data_in | +| main.rs:66:13:66:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:67:13:67:27 | pass_through(...) | main.rs:61:1:63:1 | fn pass_through | +| main.rs:68:5:68:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:72:13:75:6 | pass_through(...) | main.rs:61:1:63:1 | fn pass_through | +| main.rs:74:9:74:18 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:76:5:76:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:80:13:80:22 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:86:13:86:27 | pass_through(...) | main.rs:82:5:84:5 | fn pass_through | +| main.rs:87:5:87:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:99:9:99:15 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:106:13:106:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:121:13:121:25 | mn.get_data() | main.rs:102:5:108:5 | fn get_data | +| main.rs:122:5:122:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:127:13:127:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:128:5:128:17 | mn.data_in(...) | main.rs:98:5:100:5 | fn data_in | +| main.rs:133:13:133:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:134:13:134:30 | mn.data_through(...) | main.rs:110:5:116:5 | fn data_through | +| main.rs:135:5:135:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:140:13:140:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:141:5:141:26 | ...::data_in(...) | main.rs:98:5:100:5 | fn data_in | +| main.rs:146:13:146:22 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:147:13:147:39 | ...::data_through(...) | main.rs:110:5:116:5 | fn data_through | +| main.rs:148:5:148:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:165:13:165:34 | ...::new(...) | main.rs:158:5:161:5 | fn new | +| main.rs:165:24:165:33 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:167:5:167:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:195:28:195:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:198:5:198:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:201:28:201:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:203:5:203:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:205:28:205:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:207:13:207:20 | a.add(...) | main.rs:173:5:176:5 | fn add | +| main.rs:208:5:208:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:212:28:212:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:215:5:215:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:218:28:218:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:220:5:220:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:223:28:223:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:226:5:226:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:228:28:228:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:230:5:230:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:252:28:252:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:254:30:254:53 | ...::take_self(...) | main.rs:242:5:244:5 | fn take_self | +| main.rs:255:5:255:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:258:28:258:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:259:30:259:55 | ...::take_second(...) | main.rs:246:5:248:5 | fn take_second | +| main.rs:260:5:260:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:263:28:263:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:264:30:264:53 | ...::take_self(...) | main.rs:242:5:244:5 | fn take_self | +| main.rs:265:5:265:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:269:13:269:21 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:270:5:270:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:275:13:275:26 | async_source(...) | main.rs:268:1:272:1 | fn async_source | +| main.rs:276:5:276:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:279:17:279:25 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:280:9:280:15 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:283:5:283:17 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:287:13:287:55 | ...::block_on(...) | file://:0:0:0:0 | repo:https://github.com/rust-lang/futures-rs:futures-executor::_::crate::local_pool::block_on | +| main.rs:287:41:287:54 | async_source(...) | main.rs:268:1:272:1 | fn async_source | +| main.rs:288:5:288:11 | sink(...) | main.rs:5:1:7:1 | fn sink | +| main.rs:290:5:290:62 | ...::block_on(...) | file://:0:0:0:0 | repo:https://github.com/rust-lang/futures-rs:futures-executor::_::crate::local_pool::block_on | +| main.rs:290:33:290:61 | test_async_await_async_part(...) | main.rs:274:1:284:1 | fn test_async_await_async_part | +| main.rs:294:5:294:22 | data_out_of_call(...) | main.rs:16:1:19:1 | fn data_out_of_call | +| main.rs:295:5:295:35 | data_out_of_call_side_effect1(...) | main.rs:35:1:40:1 | fn data_out_of_call_side_effect1 | +| main.rs:296:5:296:35 | data_out_of_call_side_effect2(...) | main.rs:42:1:50:1 | fn data_out_of_call_side_effect2 | +| main.rs:297:5:297:21 | data_in_to_call(...) | main.rs:56:1:59:1 | fn data_in_to_call | +| main.rs:298:5:298:23 | data_through_call(...) | main.rs:65:1:69:1 | fn data_through_call | +| main.rs:299:5:299:34 | data_through_nested_function(...) | main.rs:79:1:88:1 | fn data_through_nested_function | +| main.rs:301:5:301:24 | data_out_of_method(...) | main.rs:119:1:123:1 | fn data_out_of_method | +| main.rs:302:5:302:28 | data_in_to_method_call(...) | main.rs:125:1:129:1 | fn data_in_to_method_call | +| main.rs:303:5:303:25 | data_through_method(...) | main.rs:131:1:136:1 | fn data_through_method | +| main.rs:305:5:305:31 | test_operator_overloading(...) | main.rs:193:1:231:1 | fn test_operator_overloading | +| main.rs:306:5:306:22 | test_async_await(...) | main.rs:286:1:291:1 | fn test_async_await | From ce1c9fbec17e80b0d8d14036887824065a06e4b3 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 6 Jun 2025 13:03:38 +0200 Subject: [PATCH 02/11] Rust: Account for arity in operator overloading For instance the binary `&` is overloadable but the prefix `&` is not. Similarly, `*` has a different target depending on if it's prefix or infix. --- .../rust/elements/internal/OperationImpl.qll | 145 +++++++++--------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll index c1ba794e8e43..e45aa4c86114 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll @@ -8,75 +8,81 @@ private import rust private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl /** - * Holds if the operator `op` is overloaded to a trait with the canonical path - * `path` and the method name `method`. + * Holds if the operator `op` with arity `arity` is overloaded to a trait with + * the canonical path `path` and the method name `method`. */ -private predicate isOverloaded(string op, string path, string method) { - // Negation - op = "-" and path = "core::ops::arith::Neg" and method = "neg" - or - // Not - op = "!" and path = "core::ops::bit::Not" and method = "not" - or - // Dereference - op = "*" and path = "core::ops::Deref" and method = "deref" - or - // Comparison operators - op = "==" and path = "core::cmp::PartialEq" and method = "eq" - or - op = "!=" and path = "core::cmp::PartialEq" and method = "ne" - or - op = "<" and path = "core::cmp::PartialOrd" and method = "lt" - or - op = "<=" and path = "core::cmp::PartialOrd" and method = "le" - or - op = ">" and path = "core::cmp::PartialOrd" and method = "gt" - or - op = ">=" and path = "core::cmp::PartialOrd" and method = "ge" - or - // Arithmetic operators - op = "+" and path = "core::ops::arith::Add" and method = "add" - or - op = "-" and path = "core::ops::arith::Sub" and method = "sub" - or - op = "*" and path = "core::ops::arith::Mul" and method = "mul" - or - op = "/" and path = "core::ops::arith::Div" and method = "div" - or - op = "%" and path = "core::ops::arith::Rem" and method = "rem" - or - // Arithmetic assignment expressions - op = "+=" and path = "core::ops::arith::AddAssign" and method = "add_assign" - or - op = "-=" and path = "core::ops::arith::SubAssign" and method = "sub_assign" - or - op = "*=" and path = "core::ops::arith::MulAssign" and method = "mul_assign" - or - op = "/=" and path = "core::ops::arith::DivAssign" and method = "div_assign" - or - op = "%=" and path = "core::ops::arith::RemAssign" and method = "rem_assign" - or - // Bitwise operators - op = "&" and path = "core::ops::bit::BitAnd" and method = "bitand" - or - op = "|" and path = "core::ops::bit::BitOr" and method = "bitor" - or - op = "^" and path = "core::ops::bit::BitXor" and method = "bitxor" - or - op = "<<" and path = "core::ops::bit::Shl" and method = "shl" - or - op = ">>" and path = "core::ops::bit::Shr" and method = "shr" - or - // Bitwise assignment operators - op = "&=" and path = "core::ops::bit::BitAndAssign" and method = "bitand_assign" - or - op = "|=" and path = "core::ops::bit::BitOrAssign" and method = "bitor_assign" - or - op = "^=" and path = "core::ops::bit::BitXorAssign" and method = "bitxor_assign" - or - op = "<<=" and path = "core::ops::bit::ShlAssign" and method = "shl_assign" - or - op = ">>=" and path = "core::ops::bit::ShrAssign" and method = "shr_assign" +private predicate isOverloaded(string op, int arity, string path, string method) { + arity = 1 and + ( + // Negation + op = "-" and path = "core::ops::arith::Neg" and method = "neg" + or + // Not + op = "!" and path = "core::ops::bit::Not" and method = "not" + or + // Dereference + op = "*" and path = "core::ops::Deref" and method = "deref" + ) + or + arity = 2 and + ( + // Comparison operators + op = "==" and path = "core::cmp::PartialEq" and method = "eq" + or + op = "!=" and path = "core::cmp::PartialEq" and method = "ne" + or + op = "<" and path = "core::cmp::PartialOrd" and method = "lt" + or + op = "<=" and path = "core::cmp::PartialOrd" and method = "le" + or + op = ">" and path = "core::cmp::PartialOrd" and method = "gt" + or + op = ">=" and path = "core::cmp::PartialOrd" and method = "ge" + or + // Arithmetic operators + op = "+" and path = "core::ops::arith::Add" and method = "add" + or + op = "-" and path = "core::ops::arith::Sub" and method = "sub" + or + op = "*" and path = "core::ops::arith::Mul" and method = "mul" + or + op = "/" and path = "core::ops::arith::Div" and method = "div" + or + op = "%" and path = "core::ops::arith::Rem" and method = "rem" + or + // Arithmetic assignment expressions + op = "+=" and path = "core::ops::arith::AddAssign" and method = "add_assign" + or + op = "-=" and path = "core::ops::arith::SubAssign" and method = "sub_assign" + or + op = "*=" and path = "core::ops::arith::MulAssign" and method = "mul_assign" + or + op = "/=" and path = "core::ops::arith::DivAssign" and method = "div_assign" + or + op = "%=" and path = "core::ops::arith::RemAssign" and method = "rem_assign" + or + // Bitwise operators + op = "&" and path = "core::ops::bit::BitAnd" and method = "bitand" + or + op = "|" and path = "core::ops::bit::BitOr" and method = "bitor" + or + op = "^" and path = "core::ops::bit::BitXor" and method = "bitxor" + or + op = "<<" and path = "core::ops::bit::Shl" and method = "shl" + or + op = ">>" and path = "core::ops::bit::Shr" and method = "shr" + or + // Bitwise assignment operators + op = "&=" and path = "core::ops::bit::BitAndAssign" and method = "bitand_assign" + or + op = "|=" and path = "core::ops::bit::BitOrAssign" and method = "bitor_assign" + or + op = "^=" and path = "core::ops::bit::BitXorAssign" and method = "bitxor_assign" + or + op = "<<=" and path = "core::ops::bit::ShlAssign" and method = "shl_assign" + or + op = ">>=" and path = "core::ops::bit::ShrAssign" and method = "shr_assign" + ) } /** @@ -109,7 +115,8 @@ module Impl { * trait `trait`. */ predicate isOverloaded(Trait trait, string methodName) { - isOverloaded(this.getOperatorName(), trait.getCanonicalPath(), methodName) + isOverloaded(this.getOperatorName(), this.getNumberOfOperands(), trait.getCanonicalPath(), + methodName) } } } From 47864781c189b81917bfae39e3c5f11ee41ef411 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 6 Jun 2025 13:42:29 +0200 Subject: [PATCH 03/11] Rust: Add abstraction over all kinds of calls --- .../lib/codeql/rust/controlflow/CfgNodes.qll | 25 ++++ rust/ql/lib/codeql/rust/elements/Call.qll | 7 + .../rust/elements/internal/CallImpl.qll | 128 ++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 rust/ql/lib/codeql/rust/elements/Call.qll create mode 100644 rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll diff --git a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll index a118cf6b4720..0c4ce51f6192 100644 --- a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll +++ b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll @@ -4,6 +4,7 @@ */ private import rust +private import codeql.rust.elements.Call private import ControlFlowGraph private import internal.ControlFlowGraphImpl as CfgImpl private import internal.CfgNodes @@ -162,6 +163,30 @@ final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode { */ final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCallExprCfgNode { } +/** + * A CFG node that calls a function. + * + * This class abstract over the different ways in which a function can be called in Rust. + */ +final class CallCfgNode extends ExprCfgNode { + private Call node; + + CallCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `Call`. */ + Call getCall() { result = node } + + /** Gets the receiver of this call if it is a method call. */ + ExprCfgNode getReceiver() { + any(ChildMapping mapping).hasCfgChild(node, node.getReceiver(), this, result) + } + + /** Gets the `i`th argument of this call, if any. */ + ExprCfgNode getArgument(int i) { + any(ChildMapping mapping).hasCfgChild(node, node.getArgument(i), this, result) + } +} + /** * A function call expression. For example: * ```rust diff --git a/rust/ql/lib/codeql/rust/elements/Call.qll b/rust/ql/lib/codeql/rust/elements/Call.qll new file mode 100644 index 000000000000..d09fe3350545 --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/Call.qll @@ -0,0 +1,7 @@ +/** + * Call. + */ + +private import internal.CallImpl + +final class Call = Impl::Call; diff --git a/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll new file mode 100644 index 000000000000..dad65d2c824b --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll @@ -0,0 +1,128 @@ +private import rust +private import codeql.rust.internal.PathResolution +private import codeql.rust.internal.TypeInference as TypeInference +private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl +private import codeql.rust.elements.Operation + +module Impl { + /** + * An expression that calls a function. + * + * This class abstract over the different ways in which a function can be called in Rust. + */ + abstract class Call extends ExprImpl::Expr { + Call() { this.fromSource() } + + /** Gets the number of arguments _excluding_ any `self` argument. */ + abstract int getNumberOfArguments(); + + /** Gets the receiver of this call if it is a method call. */ + abstract Expr getReceiver(); + + /** Holds if the call has a receiver that might be implicitly borrowed. */ + abstract predicate receiverImplicitlyBorrowed(); + + /** Gets the trait targeted by this call, if any. */ + abstract Trait getTrait(); + + /** Gets the name of the method called if this call is a method call. */ + abstract string getMethodName(); + + /** Gets the `i`th argument of this call, if any. */ + abstract Expr getArgument(int i); + + /** Gets the static target of this call, if any. */ + Function getStaticTarget() { + result = TypeInference::resolveMethodCallTarget(this) + or + not exists(TypeInference::resolveMethodCallTarget(this)) and + result = this.(CallExpr).getStaticTarget() + } + } + + /** Holds if the call expression dispatches to a trait method. */ + private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) { + exists(Path path, Function f | + path = call.getFunction().(PathExpr).getPath() and + f = resolvePath(path) and + f.getParamList().hasSelfParam() and + qualifier = path.getQualifier() and + path.getSegment().getIdentifier().getText() = methodName + ) + } + + private class CallExprCall extends Call instanceof CallExpr { + CallExprCall() { not callIsMethodCall(this, _, _) } + + override string getMethodName() { none() } + + override Expr getReceiver() { none() } + + override Trait getTrait() { none() } + + override predicate receiverImplicitlyBorrowed() { none() } + + override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() } + + override Expr getArgument(int i) { result = super.getArgList().getArg(i) } + } + + private class CallExprMethodCall extends Call instanceof CallExpr { + Path qualifier; + string methodName; + + CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) } + + override string getMethodName() { result = methodName } + + override Expr getReceiver() { result = super.getArgList().getArg(0) } + + override Trait getTrait() { + result = resolvePath(qualifier) and + // When the qualifier is `Self` and resolves to a trait, it's inside a + // trait method's default implementation. This is not a dispatch whose + // target is inferred from the type of the receiver, but should always + // resolve to the function in the trait block as path resolution does. + qualifier.toString() != "Self" + } + + override predicate receiverImplicitlyBorrowed() { none() } + + override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() - 1 } + + override Expr getArgument(int i) { result = super.getArgList().getArg(i + 1) } + } + + private class MethodCallExprCall extends Call instanceof MethodCallExpr { + override string getMethodName() { result = super.getIdentifier().getText() } + + override Expr getReceiver() { result = this.(MethodCallExpr).getReceiver() } + + override Trait getTrait() { none() } + + override predicate receiverImplicitlyBorrowed() { any() } + + override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() } + + override Expr getArgument(int i) { result = super.getArgList().getArg(i) } + } + + private class OperatorCall extends Call instanceof Operation { + Trait trait; + string methodName; + + OperatorCall() { super.isOverloaded(trait, methodName) } + + override string getMethodName() { result = methodName } + + override Expr getReceiver() { result = super.getOperand(0) } + + override Trait getTrait() { result = trait } + + override predicate receiverImplicitlyBorrowed() { none() } + + override int getNumberOfArguments() { result = super.getNumberOfOperands() - 1 } + + override Expr getArgument(int i) { result = super.getOperand(1) and i = 0 } + } +} From 7684e01c3a20429cd7fa5b516bac68e4db967a28 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 6 Jun 2025 13:44:14 +0200 Subject: [PATCH 04/11] Rust: Use `Call` in type inference --- .../codeql/rust/internal/TypeInference.qll | 215 +++--------------- 1 file changed, 35 insertions(+), 180 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 1699f7c20ae4..b92793faac02 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -8,6 +8,7 @@ private import TypeMention private import codeql.typeinference.internal.TypeInference private import codeql.rust.frameworks.stdlib.Stdlib private import codeql.rust.frameworks.stdlib.Builtins as Builtins +private import codeql.rust.elements.Call class Type = T::Type; @@ -496,20 +497,17 @@ private Type inferPathExprType(PathExpr pe, TypePath path) { * like `foo::bar(baz)` and `foo.bar(baz)`. */ private module CallExprBaseMatchingInput implements MatchingInputSig { - private predicate paramPos(ParamList pl, Param p, int pos, boolean inMethod) { - p = pl.getParam(pos) and - if pl.hasSelfParam() then inMethod = true else inMethod = false - } + private predicate paramPos(ParamList pl, Param p, int pos) { p = pl.getParam(pos) } private newtype TDeclarationPosition = TSelfDeclarationPosition() or - TPositionalDeclarationPosition(int pos, boolean inMethod) { paramPos(_, _, pos, inMethod) } or + TPositionalDeclarationPosition(int pos) { paramPos(_, _, pos) } or TReturnDeclarationPosition() class DeclarationPosition extends TDeclarationPosition { predicate isSelf() { this = TSelfDeclarationPosition() } - int asPosition(boolean inMethod) { this = TPositionalDeclarationPosition(result, inMethod) } + int asPosition() { this = TPositionalDeclarationPosition(result) } predicate isReturn() { this = TReturnDeclarationPosition() } @@ -517,7 +515,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { this.isSelf() and result = "self" or - result = this.asPosition(_).toString() + result = this.asPosition().toString() or this.isReturn() and result = "(return)" @@ -550,7 +548,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { override Type getParameterType(DeclarationPosition dpos, TypePath path) { exists(int pos | result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and - dpos = TPositionalDeclarationPosition(pos, false) + dpos = TPositionalDeclarationPosition(pos) ) } @@ -573,7 +571,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { override Type getParameterType(DeclarationPosition dpos, TypePath path) { exists(int p | result = this.getTupleField(p).getTypeRepr().(TypeMention).resolveTypeAt(path) and - dpos = TPositionalDeclarationPosition(p, false) + dpos = TPositionalDeclarationPosition(p) ) } @@ -606,9 +604,9 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { } override Type getParameterType(DeclarationPosition dpos, TypePath path) { - exists(Param p, int i, boolean inMethod | - paramPos(this.getParamList(), p, i, inMethod) and - dpos = TPositionalDeclarationPosition(i, inMethod) and + exists(Param p, int i | + paramPos(this.getParamList(), p, i) and + dpos = TPositionalDeclarationPosition(i) and result = inferAnnotatedType(p.getPat(), path) ) or @@ -640,108 +638,36 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { } } - private predicate argPos(CallExprBase call, Expr e, int pos, boolean isMethodCall) { - exists(ArgList al | - e = al.getArg(pos) and - call.getArgList() = al and - if call instanceof MethodCallExpr then isMethodCall = true else isMethodCall = false - ) - } - - private newtype TAccessPosition = - TSelfAccessPosition() or - TPositionalAccessPosition(int pos, boolean isMethodCall) { argPos(_, _, pos, isMethodCall) } or - TReturnAccessPosition() - - class AccessPosition extends TAccessPosition { - predicate isSelf() { this = TSelfAccessPosition() } - - int asPosition(boolean isMethodCall) { this = TPositionalAccessPosition(result, isMethodCall) } - - predicate isReturn() { this = TReturnAccessPosition() } - - string toString() { - this.isSelf() and - result = "self" - or - result = this.asPosition(_).toString() - or - this.isReturn() and - result = "(return)" - } - } + class AccessPosition = DeclarationPosition; private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl - abstract class Access extends Expr { - abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); - - abstract AstNode getNodeAt(AccessPosition apos); - - abstract Type getInferredType(AccessPosition apos, TypePath path); - - abstract Declaration getTarget(); - } - - private class CallExprBaseAccess extends Access instanceof CallExprBase { - private TypeMention getMethodTypeArg(int i) { - result = this.(MethodCallExpr).getGenericArgList().getTypeArg(i) - } - - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + final class Access extends Call { + Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { exists(TypeMention arg | result = arg.resolveTypeAt(path) | arg = getExplicitTypeArgMention(CallExprImpl::getFunctionPath(this), apos.asTypeParam()) or - arg = this.getMethodTypeArg(apos.asMethodTypeArgumentPosition()) + arg = + this.(MethodCallExpr).getGenericArgList().getTypeArg(apos.asMethodTypeArgumentPosition()) ) } - override AstNode getNodeAt(AccessPosition apos) { - exists(int p, boolean isMethodCall | - argPos(this, result, p, isMethodCall) and - apos = TPositionalAccessPosition(p, isMethodCall) - ) + AstNode getNodeAt(AccessPosition apos) { + result = this.getArgument(apos.asPosition()) or - result = this.(MethodCallExpr).getReceiver() and - apos = TSelfAccessPosition() + result = this.getReceiver() and apos.isSelf() or - result = this and - apos = TReturnAccessPosition() + result = this and apos.isReturn() } - override Type getInferredType(AccessPosition apos, TypePath path) { + Type getInferredType(AccessPosition apos, TypePath path) { result = inferType(this.getNodeAt(apos), path) } - override Declaration getTarget() { - result = CallExprImpl::getResolvedFunction(this) - or + Declaration getTarget() { result = inferMethodCallTarget(this) // mutual recursion; resolving method calls requires resolving types and vice versa - } - } - - private class OperationAccess extends Access instanceof Operation { - OperationAccess() { super.isOverloaded(_, _) } - - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - // The syntax for operators does not allow type arguments. - none() - } - - override AstNode getNodeAt(AccessPosition apos) { - result = super.getOperand(0) and apos = TSelfAccessPosition() - or - result = super.getOperand(1) and apos = TPositionalAccessPosition(0, true) or - result = this and apos = TReturnAccessPosition() - } - - override Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) - } - - override Declaration getTarget() { - result = inferMethodCallTarget(this) // mutual recursion; resolving method calls requires resolving types and vice versa + result = CallExprImpl::getResolvedFunction(this) } } @@ -749,16 +675,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { apos.isSelf() and dpos.isSelf() or - exists(int pos, boolean isMethodCall | pos = apos.asPosition(isMethodCall) | - pos = 0 and - isMethodCall = false and - dpos.isSelf() - or - isMethodCall = false and - pos = dpos.asPosition(true) + 1 - or - pos = dpos.asPosition(isMethodCall) - ) + apos.asPosition() = dpos.asPosition() or apos.isReturn() and dpos.isReturn() @@ -1180,31 +1097,18 @@ private Type inferIndexExprType(IndexExpr ie, TypePath path) { ) } -private module MethodCall { - /** An expression that calls a method. */ - abstract private class MethodCallImpl extends Expr { - /** Gets the name of the method targeted. */ - abstract string getMethodName(); - - /** Gets the number of arguments _excluding_ the `self` argument. */ - abstract int getArity(); - - /** Gets the trait targeted by this method call, if any. */ - Trait getTrait() { none() } - - /** Gets the type of the receiver of the method call at `path`. */ - abstract Type getTypeAt(TypePath path); +final class MethodCall extends Call { + MethodCall() { + exists(this.getReceiver()) and + // We want the method calls that don't have a path to a concrete method in + // an impl block. We need to exclude calls like `MyType::my_method(..)`. + (this instanceof CallExpr implies exists(this.getTrait())) } - final class MethodCall = MethodCallImpl; - - private class MethodCallExprMethodCall extends MethodCallImpl instanceof MethodCallExpr { - override string getMethodName() { result = super.getIdentifier().getText() } - - override int getArity() { result = super.getArgList().getNumberOfArgs() } - - pragma[nomagic] - override Type getTypeAt(TypePath path) { + /** Gets the type of the receiver of the method call at `path`. */ + Type getTypeAt(TypePath path) { + if this.receiverImplicitlyBorrowed() + then exists(TypePath path0 | result = inferType(super.getReceiver(), path0) | path0.isCons(TRefTypeParameter(), path) or @@ -1212,59 +1116,10 @@ private module MethodCall { not (path0.isEmpty() and result = TRefType()) and path = path0 ) - } - } - - private class CallExprMethodCall extends MethodCallImpl instanceof CallExpr { - TraitItemNode trait; - string methodName; - Expr receiver; - - CallExprMethodCall() { - receiver = this.getArg(0) and - exists(Path path, Function f | - path = this.getFunction().(PathExpr).getPath() and - f = resolvePath(path) and - f.getParamList().hasSelfParam() and - trait = resolvePath(path.getQualifier()) and - trait.getAnAssocItem() = f and - path.getSegment().getIdentifier().getText() = methodName - ) - } - - override string getMethodName() { result = methodName } - - override int getArity() { result = super.getArgList().getNumberOfArgs() - 1 } - - override Trait getTrait() { result = trait } - - pragma[nomagic] - override Type getTypeAt(TypePath path) { result = inferType(receiver, path) } - } - - private class OperationMethodCall extends MethodCallImpl instanceof Operation { - TraitItemNode trait; - string methodName; - - OperationMethodCall() { super.isOverloaded(trait, methodName) } - - override string getMethodName() { result = methodName } - - override int getArity() { result = this.(Operation).getNumberOfOperands() - 1 } - - override Trait getTrait() { result = trait } - - pragma[nomagic] - override Type getTypeAt(TypePath path) { - result = inferType(this.(BinaryExpr).getLhs(), path) - or - result = inferType(this.(PrefixExpr).getExpr(), path) - } + else result = inferType(super.getReceiver(), path) } } -import MethodCall - /** * Holds if a method for `type` with the name `name` and the arity `arity` * exists in `impl`. @@ -1293,7 +1148,7 @@ private module IsInstantiationOfInput implements IsInstantiationOfInputSig Date: Fri, 6 Jun 2025 14:16:25 +0200 Subject: [PATCH 05/11] Rust: Fix canonical path for Deref trait --- .../rust/elements/internal/OperationImpl.qll | 2 +- .../test/library-tests/type-inference/main.rs | 6 ++--- .../type-inference/type-inference.expected | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll index e45aa4c86114..71f861b013dd 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll @@ -21,7 +21,7 @@ private predicate isOverloaded(string op, int arity, string path, string method) op = "!" and path = "core::ops::bit::Not" and method = "not" or // Dereference - op = "*" and path = "core::ops::Deref" and method = "deref" + op = "*" and path = "core::ops::deref::Deref" and method = "deref" ) or arity = 2 and diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index b4c4ecdab2cd..0c9172ad3df9 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1098,9 +1098,9 @@ mod method_call_type_conversion { println!("{:?}", x5.m1()); // $ method=m1 println!("{:?}", x5.0); // $ fieldof=S - let x6 = &S(S2); + let x6 = &S(S2); // $ SPURIOUS: type=x6:&T.&T.S // explicit dereference - println!("{:?}", (*x6).m1()); // $ method=m1 + println!("{:?}", (*x6).m1()); // $ method=m1 method=deref let x7 = S(&S2); // Non-implicit dereference with nested borrow in order to test that the @@ -1191,7 +1191,7 @@ mod borrowed_typed { x.f2(); // $ method=f2 S::f3(&x); - let n = **&&true; // $ type=n:bool + let n = **&&true; // $ type=n:bool method=deref // In this example the type of `flag` must be inferred at the call to // `flip` and flow through the borrow in the argument. diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 4d4c3e92311c..03f73a8091d7 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -1352,22 +1352,40 @@ inferType | main.rs:1099:26:1099:27 | x5 | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1099:26:1099:29 | x5.0 | | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:13:1101:14 | x6 | | file://:0:0:0:0 | & | +| main.rs:1101:13:1101:14 | x6 | &T | file://:0:0:0:0 | & | | main.rs:1101:13:1101:14 | x6 | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1101:13:1101:14 | x6 | &T.&T | main.rs:1057:5:1058:19 | S | +| main.rs:1101:13:1101:14 | x6 | &T.&T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:13:1101:14 | x6 | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:18:1101:23 | &... | | file://:0:0:0:0 | & | +| main.rs:1101:18:1101:23 | &... | &T | file://:0:0:0:0 | & | | main.rs:1101:18:1101:23 | &... | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1101:18:1101:23 | &... | &T.&T | main.rs:1057:5:1058:19 | S | +| main.rs:1101:18:1101:23 | &... | &T.&T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:18:1101:23 | &... | &T.T | main.rs:1060:5:1061:14 | S2 | +| main.rs:1101:19:1101:23 | S(...) | | file://:0:0:0:0 | & | | main.rs:1101:19:1101:23 | S(...) | | main.rs:1057:5:1058:19 | S | +| main.rs:1101:19:1101:23 | S(...) | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1101:19:1101:23 | S(...) | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:19:1101:23 | S(...) | T | main.rs:1060:5:1061:14 | S2 | | main.rs:1101:21:1101:22 | S2 | | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:18:1103:23 | "{:?}\\n" | | {EXTERNAL LOCATION} | str | +| main.rs:1103:26:1103:30 | (...) | | file://:0:0:0:0 | & | | main.rs:1103:26:1103:30 | (...) | | main.rs:1057:5:1058:19 | S | +| main.rs:1103:26:1103:30 | (...) | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1103:26:1103:30 | (...) | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:26:1103:30 | (...) | T | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:26:1103:35 | ... .m1() | | main.rs:1060:5:1061:14 | S2 | +| main.rs:1103:27:1103:29 | * ... | | file://:0:0:0:0 | & | | main.rs:1103:27:1103:29 | * ... | | main.rs:1057:5:1058:19 | S | +| main.rs:1103:27:1103:29 | * ... | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1103:27:1103:29 | * ... | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:27:1103:29 | * ... | T | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:28:1103:29 | x6 | | file://:0:0:0:0 | & | +| main.rs:1103:28:1103:29 | x6 | &T | file://:0:0:0:0 | & | | main.rs:1103:28:1103:29 | x6 | &T | main.rs:1057:5:1058:19 | S | +| main.rs:1103:28:1103:29 | x6 | &T.&T | main.rs:1057:5:1058:19 | S | +| main.rs:1103:28:1103:29 | x6 | &T.&T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1103:28:1103:29 | x6 | &T.T | main.rs:1060:5:1061:14 | S2 | | main.rs:1105:13:1105:14 | x7 | | main.rs:1057:5:1058:19 | S | | main.rs:1105:13:1105:14 | x7 | T | file://:0:0:0:0 | & | @@ -1531,15 +1549,21 @@ inferType | main.rs:1192:15:1192:16 | &x | &T | main.rs:1168:5:1168:13 | S | | main.rs:1192:16:1192:16 | x | | main.rs:1168:5:1168:13 | S | | main.rs:1194:13:1194:13 | n | | {EXTERNAL LOCATION} | bool | +| main.rs:1194:13:1194:13 | n | | file://:0:0:0:0 | & | | main.rs:1194:17:1194:24 | * ... | | {EXTERNAL LOCATION} | bool | +| main.rs:1194:17:1194:24 | * ... | | file://:0:0:0:0 | & | | main.rs:1194:18:1194:24 | * ... | | file://:0:0:0:0 | & | | main.rs:1194:18:1194:24 | * ... | &T | {EXTERNAL LOCATION} | bool | +| main.rs:1194:18:1194:24 | * ... | &T | file://:0:0:0:0 | & | | main.rs:1194:19:1194:24 | &... | | file://:0:0:0:0 | & | | main.rs:1194:19:1194:24 | &... | &T | file://:0:0:0:0 | & | | main.rs:1194:19:1194:24 | &... | &T.&T | {EXTERNAL LOCATION} | bool | +| main.rs:1194:19:1194:24 | &... | &T.&T | file://:0:0:0:0 | & | | main.rs:1194:20:1194:24 | &true | | file://:0:0:0:0 | & | | main.rs:1194:20:1194:24 | &true | &T | {EXTERNAL LOCATION} | bool | +| main.rs:1194:20:1194:24 | &true | &T | file://:0:0:0:0 | & | | main.rs:1194:21:1194:24 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:1194:21:1194:24 | true | | file://:0:0:0:0 | & | | main.rs:1198:13:1198:20 | mut flag | | main.rs:1157:5:1160:5 | MyFlag | | main.rs:1198:24:1198:41 | ...::default(...) | | main.rs:1157:5:1160:5 | MyFlag | | main.rs:1199:22:1199:30 | &mut flag | | file://:0:0:0:0 | & | From fecd445e78c807d57c93e8cb423ea20d3fc10b3b Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 6 Jun 2025 14:18:28 +0200 Subject: [PATCH 06/11] Rust: Use `Call` in data flow --- .../rust/dataflow/internal/DataFlowImpl.qll | 50 ++++++------------- .../dataflow/internal/FlowSummaryImpl.qll | 2 +- .../codeql/rust/dataflow/internal/Node.qll | 21 ++++---- .../dataflow/global/inline-flow.expected | 18 +++++++ .../library-tests/dataflow/global/main.rs | 2 +- .../dataflow/global/viableCallable.expected | 4 ++ 6 files changed, 51 insertions(+), 46 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index d0f7378bd3a1..2cf9cc216681 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -8,6 +8,7 @@ private import codeql.util.Boolean private import codeql.dataflow.DataFlow private import codeql.dataflow.internal.DataFlowImpl private import rust +private import codeql.rust.elements.Call private import SsaImpl as SsaImpl private import codeql.rust.controlflow.internal.Scope as Scope private import codeql.rust.internal.PathResolution @@ -55,11 +56,7 @@ final class DataFlowCallable extends TDataFlowCallable { final class DataFlowCall extends TDataFlowCall { /** Gets the underlying call in the CFG, if any. */ - CallExprCfgNode asCallExprCfgNode() { result = this.asCallBaseExprCfgNode() } - - MethodCallExprCfgNode asMethodCallExprCfgNode() { result = this.asCallBaseExprCfgNode() } - - CallExprBaseCfgNode asCallBaseExprCfgNode() { this = TCall(result) } + CallCfgNode asCallCfgNode() { this = TCall(result) } predicate isSummaryCall( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver @@ -68,7 +65,7 @@ final class DataFlowCall extends TDataFlowCall { } DataFlowCallable getEnclosingCallable() { - result = TCfgScope(this.asCallBaseExprCfgNode().getExpr().getEnclosingCfgScope()) + result = TCfgScope(this.asCallCfgNode().getExpr().getEnclosingCfgScope()) or exists(FlowSummaryImpl::Public::SummarizedCallable c | this.isSummaryCall(c, _) and @@ -77,7 +74,7 @@ final class DataFlowCall extends TDataFlowCall { } string toString() { - result = this.asCallBaseExprCfgNode().toString() + result = this.asCallCfgNode().toString() or exists( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver @@ -87,7 +84,7 @@ final class DataFlowCall extends TDataFlowCall { ) } - Location getLocation() { result = this.asCallBaseExprCfgNode().getLocation() } + Location getLocation() { result = this.asCallCfgNode().getLocation() } } /** @@ -135,38 +132,23 @@ final class ParameterPosition extends TParameterPosition { */ final class ArgumentPosition extends ParameterPosition { /** Gets the argument of `call` at this position, if any. */ - Expr getArgument(CallExprBase call) { - result = call.getArgList().getArg(this.getPosition()) + Expr getArgument(Call call) { + result = call.getArgument(this.getPosition()) or - this.isSelf() and - result = call.(MethodCallExpr).getReceiver() + result = call.getReceiver() and this.isSelf() } } -/** Holds if `call` invokes a qualified path that resolves to a method. */ -private predicate callToMethod(CallExpr call) { - exists(Path path | - path = call.getFunction().(PathExpr).getPath() and - path.hasQualifier() and - resolvePath(path).(Function).getParamList().hasSelfParam() - ) -} - /** * Holds if `arg` is an argument of `call` at the position `pos`. * * Note that this does not hold for the receiever expression of a method call * as the synthetic `ReceiverNode` is the argument for the `self` parameter. */ -predicate isArgumentForCall(ExprCfgNode arg, CallExprBaseCfgNode call, ParameterPosition pos) { - if callToMethod(call.(CallExprCfgNode).getCallExpr()) - then - // The first argument is for the `self` parameter - arg = call.getArgument(0) and pos.isSelf() - or - // Succeeding arguments are shifted left - arg = call.getArgument(pos.getPosition() + 1) - else arg = call.getArgument(pos.getPosition()) +predicate isArgumentForCall(ExprCfgNode arg, CallCfgNode call, ParameterPosition pos) { + call.getArgument(pos.getPosition()) = arg + or + call.getReceiver() = arg and pos.isSelf() and not call.getCall().receiverImplicitlyBorrowed() } /** Provides logic related to SSA. */ @@ -419,9 +401,9 @@ module RustDataFlow implements InputSig { /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall call) { - result.asCfgScope() = call.asCallBaseExprCfgNode().getCallExprBase().getStaticTarget() + result.asCfgScope() = call.asCallCfgNode().getCall().getStaticTarget() or - result.asLibraryCallable().getACall() = call.asCallBaseExprCfgNode().getCallExprBase() + result.asLibraryCallable().getACall() = call.asCallCfgNode().getCall() } /** @@ -812,7 +794,7 @@ module RustDataFlow implements InputSig { */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { ( - receiver.asExpr() = call.asCallExprCfgNode().getFunction() and + receiver.asExpr() = call.asCallCfgNode().(CallExprCfgNode).getFunction() and // All calls to complex expressions and local variable accesses are lambda call. exists(Expr f | f = receiver.asExpr().getExpr() | f instanceof PathExpr implies f = any(Variable v).getAnAccess() @@ -976,7 +958,7 @@ private module Cached { cached newtype TDataFlowCall = - TCall(CallExprBaseCfgNode c) { Stages::DataFlowStage::ref() } or + TCall(CallCfgNode c) { Stages::DataFlowStage::ref() } or TSummaryCall( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver ) { diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll index 62cc47dfc0d3..ba91518eab68 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll @@ -153,7 +153,7 @@ private import Make as Impl private module StepsInput implements Impl::Private::StepsInputSig { DataFlowCall getACall(Public::SummarizedCallable sc) { - result.asCallBaseExprCfgNode().getCallExprBase() = sc.(LibraryCallable).getACall() + result.asCallCfgNode().getCall() = sc.(LibraryCallable).getACall() } RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/Node.qll b/rust/ql/lib/codeql/rust/dataflow/internal/Node.qll index 67782f0b7e00..939cb45a0ca5 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/Node.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/Node.qll @@ -224,13 +224,13 @@ abstract class ArgumentNode extends Node { } final class ExprArgumentNode extends ArgumentNode, ExprNode { - private CallExprBaseCfgNode call_; + private CallCfgNode call_; private RustDataFlow::ArgumentPosition pos_; ExprArgumentNode() { isArgumentForCall(n, call_, pos_) } override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) { - call.asCallBaseExprCfgNode() = call_ and pos = pos_ + call.asCallCfgNode() = call_ and pos = pos_ } } @@ -239,7 +239,7 @@ final class ExprArgumentNode extends ArgumentNode, ExprNode { * has taken place. */ final class ReceiverNode extends ArgumentNode, TReceiverNode { - private MethodCallExprCfgNode n; + private CallCfgNode n; ReceiverNode() { this = TReceiverNode(n, false) } @@ -248,7 +248,7 @@ final class ReceiverNode extends ArgumentNode, TReceiverNode { MethodCallExprCfgNode getMethodCall() { result = n } override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) { - call.asMethodCallExprCfgNode() = n and pos = TSelfParameterPosition() + call.asCallCfgNode() = n and pos = TSelfParameterPosition() } override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() } @@ -281,7 +281,7 @@ final class ClosureArgumentNode extends ArgumentNode, ExprNode { ClosureArgumentNode() { lambdaCallExpr(call_, _, this.asExpr()) } override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) { - call.asCallExprCfgNode() = call_ and + call.asCallCfgNode() = call_ and pos.isClosureSelf() } } @@ -330,11 +330,11 @@ abstract class OutNode extends Node { } final private class ExprOutNode extends ExprNode, OutNode { - ExprOutNode() { this.asExpr() instanceof CallExprBaseCfgNode } + ExprOutNode() { this.asExpr() instanceof CallCfgNode } /** Gets the underlying call CFG node that includes this out node. */ override DataFlowCall getCall(ReturnKind kind) { - result.asCallBaseExprCfgNode() = this.getCfgNode() and + result.asCallCfgNode() = this.getCfgNode() and kind = TNormalReturnKind() } } @@ -404,7 +404,7 @@ final class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { } final class ReceiverPostUpdateNode extends PostUpdateNode, TReceiverNode { - private MethodCallExprCfgNode n; + private CallCfgNode n; ReceiverPostUpdateNode() { this = TReceiverNode(n, true) } @@ -467,11 +467,12 @@ newtype TNode = any(FieldExprCfgNode access).getContainer(), // any(TryExprCfgNode try).getExpr(), // any(PrefixExprCfgNode pe | pe.getOperatorName() = "*").getExpr(), // - any(AwaitExprCfgNode a).getExpr(), any(MethodCallExprCfgNode mc).getReceiver(), // + any(AwaitExprCfgNode a).getExpr(), // + any(MethodCallExprCfgNode mc).getReceiver(), // getPostUpdateReverseStep(any(PostUpdateNode n).getPreUpdateNode().asExpr(), _) ] } or - TReceiverNode(MethodCallExprCfgNode mc, Boolean isPost) or + TReceiverNode(CallCfgNode mc, Boolean isPost) { mc.getCall().receiverImplicitlyBorrowed() } or TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or TClosureSelfReferenceNode(CfgScope c) { lambdaCreationExpr(c, _) } or 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 53bbf61e3b68..451d5996de57 100644 --- a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected @@ -85,6 +85,14 @@ edges | main.rs:175:9:175:35 | MyInt {...} [MyInt] | main.rs:173:42:176:5 | { ... } [MyInt] | provenance | | | main.rs:175:24:175:27 | self [MyInt] | main.rs:175:24:175:33 | self.value | provenance | | | main.rs:175:24:175:33 | self.value | main.rs:175:9:175:35 | MyInt {...} [MyInt] | provenance | | +| main.rs:195:9:195:9 | a [MyInt] | main.rs:197:13:197:13 | a [MyInt] | provenance | | +| main.rs:195:13:195:38 | MyInt {...} [MyInt] | main.rs:195:9:195:9 | a [MyInt] | provenance | | +| main.rs:195:28:195:36 | source(...) | main.rs:195:13:195:38 | MyInt {...} [MyInt] | provenance | | +| main.rs:197:9:197:9 | c [MyInt] | main.rs:198:10:198:10 | c [MyInt] | provenance | | +| main.rs:197:13:197:13 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | provenance | | +| main.rs:197:13:197:13 | a [MyInt] | main.rs:197:13:197:17 | ... + ... [MyInt] | provenance | | +| main.rs:197:13:197:17 | ... + ... [MyInt] | main.rs:197:9:197:9 | c [MyInt] | provenance | | +| main.rs:198:10:198:10 | c [MyInt] | main.rs:198:10:198:16 | c.value | provenance | | | main.rs:205:9:205:9 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | provenance | | | main.rs:205:9:205:9 | a [MyInt] | main.rs:207:13:207:20 | a.add(...) [MyInt] | provenance | | | main.rs:205:13:205:38 | MyInt {...} [MyInt] | main.rs:205:9:205:9 | a [MyInt] | provenance | | @@ -213,6 +221,14 @@ nodes | main.rs:175:9:175:35 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | | main.rs:175:24:175:27 | self [MyInt] | semmle.label | self [MyInt] | | main.rs:175:24:175:33 | self.value | semmle.label | self.value | +| main.rs:195:9:195:9 | a [MyInt] | semmle.label | a [MyInt] | +| main.rs:195:13:195:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | +| main.rs:195:28:195:36 | source(...) | semmle.label | source(...) | +| main.rs:197:9:197:9 | c [MyInt] | semmle.label | c [MyInt] | +| main.rs:197:13:197:13 | a [MyInt] | semmle.label | a [MyInt] | +| main.rs:197:13:197:17 | ... + ... [MyInt] | semmle.label | ... + ... [MyInt] | +| main.rs:198:10:198:10 | c [MyInt] | semmle.label | c [MyInt] | +| main.rs:198:10:198:16 | c.value | semmle.label | c.value | | main.rs:205:9:205:9 | a [MyInt] | semmle.label | a [MyInt] | | main.rs:205:13:205:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] | | main.rs:205:28:205:36 | source(...) | semmle.label | source(...) | @@ -262,6 +278,7 @@ subpaths | main.rs:134:29:134:29 | a | main.rs:110:27:110:32 | ...: i64 | main.rs:110:42:116:5 | { ... } | main.rs:134:13:134:30 | mn.data_through(...) | | main.rs:147:38:147:38 | a | main.rs:110:27:110:32 | ...: i64 | main.rs:110:42:116:5 | { ... } | main.rs:147:13:147:39 | ...::data_through(...) | | main.rs:165:24:165:33 | source(...) | main.rs:159:12:159:17 | ...: i64 | main.rs:159:28:161:5 | { ... } [MyInt] | main.rs:165:13:165:34 | ...::new(...) [MyInt] | +| main.rs:197:13:197:13 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | main.rs:173:42:176:5 | { ... } [MyInt] | main.rs:197:13:197:17 | ... + ... [MyInt] | | main.rs:205:9:205:9 | a [MyInt] | main.rs:173:12:173:15 | SelfParam [MyInt] | main.rs:173:42:176:5 | { ... } [MyInt] | main.rs:207:13:207:20 | a.add(...) [MyInt] | | main.rs:254:49:254:49 | a [MyInt] | main.rs:242:18:242:21 | SelfParam [MyInt] | main.rs:242:48:244:5 | { ... } [MyInt] | main.rs:254:30:254:53 | ...::take_self(...) [MyInt] | | main.rs:259:54:259:54 | b [MyInt] | main.rs:246:26:246:37 | ...: MyInt [MyInt] | main.rs:246:49:248:5 | { ... } [MyInt] | main.rs:259:30:259:55 | ...::take_second(...) [MyInt] | @@ -280,6 +297,7 @@ testFailures | main.rs:135:10:135:10 | b | main.rs:133:13:133:21 | source(...) | main.rs:135:10:135:10 | b | $@ | main.rs:133:13:133:21 | source(...) | source(...) | | main.rs:148:10:148:10 | b | main.rs:146:13:146:22 | source(...) | main.rs:148:10:148:10 | b | $@ | main.rs:146:13:146:22 | source(...) | source(...) | | main.rs:167:10:167:10 | m | main.rs:165:24:165:33 | source(...) | main.rs:167:10:167:10 | m | $@ | main.rs:165:24:165:33 | source(...) | source(...) | +| main.rs:198:10:198:16 | c.value | main.rs:195:28:195:36 | source(...) | main.rs:198:10:198:16 | c.value | $@ | main.rs:195:28:195:36 | source(...) | source(...) | | main.rs:208:10:208:16 | d.value | main.rs:205:28:205:36 | source(...) | main.rs:208:10:208:16 | d.value | $@ | main.rs:205:28:205:36 | source(...) | source(...) | | main.rs:255:10:255:10 | c | main.rs:252:28:252:36 | source(...) | main.rs:255:10:255:10 | c | $@ | main.rs:252:28:252:36 | source(...) | source(...) | | main.rs:260:10:260:10 | c | main.rs:258:28:258:37 | source(...) | main.rs:260:10:260:10 | c | $@ | main.rs:258:28:258:37 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/global/main.rs b/rust/ql/test/library-tests/dataflow/global/main.rs index a495ca392fcb..6ca8f20f027c 100644 --- a/rust/ql/test/library-tests/dataflow/global/main.rs +++ b/rust/ql/test/library-tests/dataflow/global/main.rs @@ -195,7 +195,7 @@ fn test_operator_overloading() { let a = MyInt { value: source(5) }; let b = MyInt { value: 2 }; let c = a + b; - sink(c.value); // $ MISSING: hasValueFlow=5 + sink(c.value); // $ hasValueFlow=5 let a = MyInt { value: 2 }; let b = MyInt { value: source(6) }; diff --git a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected index bb1ac8947730..822ce4e0a323 100644 --- a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected +++ b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected @@ -41,8 +41,10 @@ | main.rs:165:24:165:33 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:167:5:167:11 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:195:28:195:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:197:13:197:17 | ... + ... | main.rs:173:5:176:5 | fn add | | main.rs:198:5:198:17 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:201:28:201:36 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:202:13:202:17 | ... + ... | main.rs:173:5:176:5 | fn add | | main.rs:203:5:203:17 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:205:28:205:36 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:207:13:207:20 | a.add(...) | main.rs:173:5:176:5 | fn add | @@ -50,10 +52,12 @@ | main.rs:212:28:212:37 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:215:5:215:17 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:218:28:218:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:219:5:219:10 | ... *= ... | main.rs:180:5:182:5 | fn mul_assign | | main.rs:220:5:220:17 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:223:28:223:37 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:226:5:226:11 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:228:28:228:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:229:13:229:14 | * ... | main.rs:188:5:190:5 | fn deref | | main.rs:230:5:230:11 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:252:28:252:36 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:254:30:254:53 | ...::take_self(...) | main.rs:242:5:244:5 | fn take_self | From 3463ebd8ce11141123966d4971df10093211f94d Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 9 Jun 2025 11:20:57 +0200 Subject: [PATCH 07/11] Rust: Adapt data flow consistency queries to `!` being a call The exact same problem occurs in Ruby, hence the `multipleArgumentCallExclude` implementation is adapted from Ruby's. --- .../rust/dataflow/internal/DataFlowConsistency.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowConsistency.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowConsistency.qll index f0dc961a9f93..909d275dc11b 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowConsistency.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowConsistency.qll @@ -1,5 +1,8 @@ import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow private import rust +private import codeql.rust.controlflow.ControlFlowGraph +private import codeql.rust.controlflow.internal.Splitting +private import codeql.rust.controlflow.CfgNodes as CfgNodes private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import codeql.rust.dataflow.internal.Node as Node @@ -26,6 +29,17 @@ private module Input implements InputSig { } predicate missingLocationExclude(RustDataFlow::Node n) { not exists(n.asExpr().getLocation()) } + + predicate multipleArgumentCallExclude(Node::ArgumentNode arg, DataFlowCall call) { + // An argument such as `x` in `if !x { ... }` has two successors (and hence + // two calls); one for each Boolean outcome of `x`. + exists(CfgNodes::ExprCfgNode n | + arg.isArgumentOf(call, _) and + n = call.asCallCfgNode() and + arg.asExpr().getASuccessor(any(ConditionalSuccessor c)).getASuccessor*() = n and + n.getASplit() instanceof ConditionalCompletionSplitting::ConditionalCompletionSplit + ) + } } import MakeConsistency From 03c9a78bfb4cdf0a7ecb62ba78ac41eb43165a95 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 11 Jun 2025 13:46:29 +0200 Subject: [PATCH 08/11] Rust: Simplify accessDeclarationPositionMatch --- rust/ql/lib/codeql/rust/internal/TypeInference.qll | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index b92793faac02..e34208809005 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -672,13 +672,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { } predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos.isSelf() and - dpos.isSelf() - or - apos.asPosition() = dpos.asPosition() - or - apos.isReturn() and - dpos.isReturn() + apos = dpos } bindingset[apos, target, path, t] From f138f77cc10f39c42fa56f8d2a79ffd91e81f4f6 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 11 Jun 2025 15:08:41 +0200 Subject: [PATCH 09/11] Rust: Only adjust access type for method call expressions --- rust/ql/lib/codeql/rust/internal/TypeInference.qll | 13 ++++++++----- .../codeql/typeinference/internal/TypeInference.qll | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index e34208809005..9d7fd46d1600 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -675,12 +675,13 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { apos = dpos } - bindingset[apos, target, path, t] + bindingset[a, apos, target, path, t] pragma[inline_late] predicate adjustAccessType( - AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj + Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, + Type tAdj ) { - if apos.isSelf() + if apos.isSelf() and a.receiverImplicitlyBorrowed() then exists(Type selfParamType | selfParamType = target.getParameterType(TSelfDeclarationPosition(), TypePath::nil()) @@ -844,11 +845,13 @@ private module FieldExprMatchingInput implements MatchingInputSig { apos = dpos } - bindingset[apos, target, path, t] + bindingset[a, apos, target, path, t] pragma[inline_late] predicate adjustAccessType( - AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj + Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, + Type tAdj ) { + exists(a) and exists(target) and if apos.isSelf() then diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 823459e83bb4..bb15bfb6c88e 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -847,9 +847,10 @@ module Make1 Input1> { * the inferred type of `42` is `int`, but it should be adjusted to `int?` * when matching against `M`. */ - bindingset[apos, target, path, t] + bindingset[a, apos, target, path, t] default predicate adjustAccessType( - AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj + Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, + Type tAdj ) { pathAdj = path and tAdj = t @@ -876,7 +877,7 @@ module Make1 Input1> { target = a.getTarget() and exists(TypePath path0, Type t0 | t0 = a.getInferredType(apos, path0) and - adjustAccessType(apos, target, path0, t0, path, t) + adjustAccessType(a, apos, target, path0, t0, path, t) ) } From 8cde1eefb2e7c57578ea24b6c03de014ab26aee0 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Jun 2025 11:08:20 +0200 Subject: [PATCH 10/11] Rust: Remove `Access` from `adjustAccessType` --- .../codeql/rust/internal/TypeInference.qll | 52 ++++++++++++++----- .../typeinference/internal/TypeInference.qll | 7 ++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 9d7fd46d1600..a7b862a1aa94 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -1,5 +1,6 @@ /** Provides functionality for inferring types. */ +private import codeql.util.Boolean private import rust private import PathResolution private import Type @@ -638,7 +639,28 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { } } - class AccessPosition = DeclarationPosition; + private newtype TAccessPosition = + TSelfAccessPosition(Boolean implicitlyBorrowed) or + TPositionalAccessPosition(int pos) { exists(TPositionalDeclarationPosition(pos)) } or + TReturnAccessPosition() + + class AccessPosition extends TAccessPosition { + predicate isSelf(boolean implicitlyBorrowed) { this = TSelfAccessPosition(implicitlyBorrowed) } + + int asPosition() { this = TPositionalAccessPosition(result) } + + predicate isReturn() { this = TReturnAccessPosition() } + + string toString() { + this.isSelf(_) and + result = "self" + or + result = this.asPosition().toString() + or + this.isReturn() and + result = "(return)" + } + } private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl @@ -655,7 +677,8 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { AstNode getNodeAt(AccessPosition apos) { result = this.getArgument(apos.asPosition()) or - result = this.getReceiver() and apos.isSelf() + result = this.getReceiver() and + if this.receiverImplicitlyBorrowed() then apos.isSelf(true) else apos.isSelf(false) or result = this and apos.isReturn() } @@ -672,16 +695,19 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { } predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos + apos.isSelf(_) and dpos.isSelf() + or + apos.asPosition() = dpos.asPosition() + or + apos.isReturn() and dpos.isReturn() } - bindingset[a, apos, target, path, t] + bindingset[apos, target, path, t] pragma[inline_late] predicate adjustAccessType( - Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, - Type tAdj + AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj ) { - if apos.isSelf() and a.receiverImplicitlyBorrowed() + if apos.isSelf(true) then exists(Type selfParamType | selfParamType = target.getParameterType(TSelfDeclarationPosition(), TypePath::nil()) @@ -741,7 +767,7 @@ private Type inferCallExprBaseType(AstNode n, TypePath path) { n = a.getNodeAt(apos) and result = CallExprBaseMatching::inferAccessType(a, apos, path0) | - if apos.isSelf() + if apos.isSelf(_) then exists(Type receiverType | receiverType = inferType(n) | if receiverType = TRefType() @@ -845,13 +871,11 @@ private module FieldExprMatchingInput implements MatchingInputSig { apos = dpos } - bindingset[a, apos, target, path, t] + bindingset[apos, target, path, t] pragma[inline_late] predicate adjustAccessType( - Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, - Type tAdj + AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj ) { - exists(a) and exists(target) and if apos.isSelf() then @@ -1220,7 +1244,7 @@ private module Cached { cached predicate receiverHasImplicitDeref(AstNode receiver) { exists(CallExprBaseMatchingInput::Access a, CallExprBaseMatchingInput::AccessPosition apos | - apos.isSelf() and + apos.isSelf(true) and receiver = a.getNodeAt(apos) and inferType(receiver) = TRefType() and CallExprBaseMatching::inferAccessType(a, apos, TypePath::nil()) != TRefType() @@ -1231,7 +1255,7 @@ private module Cached { cached predicate receiverHasImplicitBorrow(AstNode receiver) { exists(CallExprBaseMatchingInput::Access a, CallExprBaseMatchingInput::AccessPosition apos | - apos.isSelf() and + apos.isSelf(true) and receiver = a.getNodeAt(apos) and CallExprBaseMatching::inferAccessType(a, apos, TypePath::nil()) = TRefType() and inferType(receiver) != TRefType() diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index bb15bfb6c88e..823459e83bb4 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -847,10 +847,9 @@ module Make1 Input1> { * the inferred type of `42` is `int`, but it should be adjusted to `int?` * when matching against `M`. */ - bindingset[a, apos, target, path, t] + bindingset[apos, target, path, t] default predicate adjustAccessType( - Access a, AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, - Type tAdj + AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj ) { pathAdj = path and tAdj = t @@ -877,7 +876,7 @@ module Make1 Input1> { target = a.getTarget() and exists(TypePath path0, Type t0 | t0 = a.getInferredType(apos, path0) and - adjustAccessType(a, apos, target, path0, t0, path, t) + adjustAccessType(apos, target, path0, t0, path, t) ) } From 2dd2f2e72bfdf3dd47255fbc1c78200d3b4614db Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Jun 2025 14:12:27 +0200 Subject: [PATCH 11/11] Rust: Address review comments --- rust/ql/lib/codeql/rust/elements/Call.qll | 2 +- rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/Call.qll b/rust/ql/lib/codeql/rust/elements/Call.qll index d09fe3350545..a65fb3dadb07 100644 --- a/rust/ql/lib/codeql/rust/elements/Call.qll +++ b/rust/ql/lib/codeql/rust/elements/Call.qll @@ -1,5 +1,5 @@ /** - * Call. + * This module provides the public class `Call`. */ private import internal.CallImpl diff --git a/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll index dad65d2c824b..27dfd2a93fcf 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll @@ -8,11 +8,9 @@ module Impl { /** * An expression that calls a function. * - * This class abstract over the different ways in which a function can be called in Rust. + * This class abstracts over the different ways in which a function can be called in Rust. */ abstract class Call extends ExprImpl::Expr { - Call() { this.fromSource() } - /** Gets the number of arguments _excluding_ any `self` argument. */ abstract int getNumberOfArguments();