From 9a35febe80df3c4e36b53ccfa8dea903aa55093b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 3 Mar 2025 17:20:58 +0000 Subject: [PATCH 001/311] Rust: Query framework and basic tests. --- .../CWE-798/HardcodedCryptographicValue.ql | 21 ++++++ .../HardcodedCryptographicValue.expected | 0 .../CWE-798/HardcodedCryptographicValue.qlref | 2 + .../query-tests/security/CWE-798/options.yml | 6 ++ .../security/CWE-798/test_cipher.rs | 66 +++++++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql create mode 100644 rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected create mode 100644 rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref create mode 100644 rust/ql/test/query-tests/security/CWE-798/options.yml create mode 100644 rust/ql/test/query-tests/security/CWE-798/test_cipher.rs diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql new file mode 100644 index 000000000000..717831bba2b5 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -0,0 +1,21 @@ +/** + * @name Hard-coded cryptographic value + * @description Using hardcoded keys, passwords, salts or initialization + * vectors is not secure. + * @kind problem + * @problem.severity warning + * @security-severity TODO + * @precision high + * @id rust/hardcoded-crytographic-value + * @tags security + * external/cwe/cwe-259 + * external/cwe/cwe-321 + * external/cwe/cwe-798 + * external/cwe/cwe-1204 + */ + +import rust + +from Locatable e +where none() +select e, "" diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref new file mode 100644 index 000000000000..99053e9bf1a9 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref @@ -0,0 +1,2 @@ +query: queries/security/CWE-798/HardcodedCryptographicValue.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/rust/ql/test/query-tests/security/CWE-798/options.yml b/rust/ql/test/query-tests/security/CWE-798/options.yml new file mode 100644 index 000000000000..07dc5e9922ea --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-798/options.yml @@ -0,0 +1,6 @@ +qltest_cargo_check: true +qltest_dependencies: + - cipher = { version = "0.4.4" } + - rabbit = { version = "0.4.1" } + - aes = { version = "0.8.4" } + - cfb-mode = { version = "0.8.2" } diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs new file mode 100644 index 000000000000..532fe523c07c --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -0,0 +1,66 @@ + +use cipher::{consts::*, StreamCipher, AsyncStreamCipher, KeyInit, KeyIvInit, BlockEncrypt}; +use rabbit::{Rabbit, RabbitKeyOnly}; +use aes::Aes256; + +// --- tests --- + +fn test_stream_cipher_rabbit( + key: &[u8;16], iv: &[u8;16], plaintext: &str +) { + let mut data = plaintext.as_bytes().to_vec(); + + // rabbit + + let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit::Key::from_slice(key)); + rabbit_cipher1.apply_keystream(&mut data); + + let const1: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher2 = RabbitKeyOnly::new(rabbit::Key::from_slice(const1)); + rabbit_cipher2.apply_keystream(&mut data); + + let mut rabbit_cipher3 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(iv)); + rabbit_cipher3.apply_keystream(&mut data); + + let const2: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const2), rabbit::Iv::from_slice(iv)); + rabbit_cipher4.apply_keystream(&mut data); + + let const3: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const3)); + rabbit_cipher5.apply_keystream(&mut data); + + let const4: &[u8;16] = &[0u8;16]; // (unused, so good) +} + +fn test_block_cipher_aes( + key: &[u8], iv: &[u8], key256: &[u8;32], + block128: &mut [u8;16], input: &[u8], output: &mut [u8] +) { + // aes + + let aes_cipher1 = Aes256::new(key256.into()); + aes_cipher1.encrypt_block(block128.into()); + + let const1 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher2 = Aes256::new(const1.into()); + aes_cipher2.encrypt_block(block128.into()); + + let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); + aes_cipher3.encrypt_block(block128.into()); + + let const2 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher4 = Aes256::new_from_slice(const2).unwrap(); + aes_cipher4.encrypt_block(block128.into()); + + let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); + _ = aes_cipher5.encrypt_b2b(input, output).unwrap(); + + let const3 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher6 = cfb_mode::Encryptor::::new(const3.into(), iv.into()); + _ = aes_cipher6.encrypt_b2b(input, output).unwrap(); + + let const4 = &[0u8; 16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const4.into()); + _ = aes_cipher7.encrypt_b2b(input, output).unwrap(); +} From bd75f0187b88823b41dd9767b05a081306f29b61 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:44:59 +0000 Subject: [PATCH 002/311] Rust: More test cases. --- .../query-tests/security/CWE-798/options.yml | 2 + .../security/CWE-798/test_cipher.rs | 92 ++++++++++++++++--- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-798/options.yml b/rust/ql/test/query-tests/security/CWE-798/options.yml index 07dc5e9922ea..aff715ea271b 100644 --- a/rust/ql/test/query-tests/security/CWE-798/options.yml +++ b/rust/ql/test/query-tests/security/CWE-798/options.yml @@ -3,4 +3,6 @@ qltest_dependencies: - cipher = { version = "0.4.4" } - rabbit = { version = "0.4.1" } - aes = { version = "0.8.4" } + - aes-gcm = { version = "0.10.3" } - cfb-mode = { version = "0.8.2" } + - base64 = { version = "0.22.1" } diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index 532fe523c07c..748b9f3e012a 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -22,19 +22,40 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher3 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(iv)); rabbit_cipher3.apply_keystream(&mut data); - let const2: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const2), rabbit::Iv::from_slice(iv)); + let const4: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const4), rabbit::Iv::from_slice(iv)); rabbit_cipher4.apply_keystream(&mut data); - let const3: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const3)); + let const5: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const5)); rabbit_cipher5.apply_keystream(&mut data); - let const4: &[u8;16] = &[0u8;16]; // (unused, so good) + // various expressions of constant arrays + + let const6: &[u8;16] = &[0u8;16]; // (unused, so good) + + let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher7 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const7)); + rabbit_cipher7.apply_keystream(&mut data); + + let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); + rabbit_cipher8.apply_keystream(&mut data); + + let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let const9_conv = unsafe { const9.align_to::().1 }; // convert [u16;8] -> [u8;8] + let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); + rabbit_cipher9.apply_keystream(&mut data); + + let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher10 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const10)); + rabbit_cipher10.apply_keystream(&mut data); } +use base64::Engine; + fn test_block_cipher_aes( - key: &[u8], iv: &[u8], key256: &[u8;32], + key: &[u8], iv: &[u8], key256: &[u8;32], key_str: &str, block128: &mut [u8;16], input: &[u8], output: &mut [u8] ) { // aes @@ -42,8 +63,8 @@ fn test_block_cipher_aes( let aes_cipher1 = Aes256::new(key256.into()); aes_cipher1.encrypt_block(block128.into()); - let const1 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher2 = Aes256::new(const1.into()); + let const2 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher2 = Aes256::new(const2.into()); aes_cipher2.encrypt_block(block128.into()); let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); @@ -56,11 +77,58 @@ fn test_block_cipher_aes( let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); _ = aes_cipher5.encrypt_b2b(input, output).unwrap(); - let const3 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher6 = cfb_mode::Encryptor::::new(const3.into(), iv.into()); + let const6 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher6 = cfb_mode::Encryptor::::new(const6.into(), iv.into()); _ = aes_cipher6.encrypt_b2b(input, output).unwrap(); - let const4 = &[0u8; 16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const4.into()); + let const7 = &[0u8; 16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const7.into()); _ = aes_cipher7.encrypt_b2b(input, output).unwrap(); + + // various string conversions + + let key8: &[u8] = key_str.as_bytes(); + let aes_cipher8 = cfb_mode::Encryptor::::new(key8.into(), iv.into()); + _ = aes_cipher8.encrypt_b2b(input, output).unwrap(); + + let key9: &[u8] = "1234567890123456".as_bytes(); // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let aes_cipher9 = cfb_mode::Encryptor::::new(key9.into(), iv.into()); + _ = aes_cipher9.encrypt_b2b(input, output).unwrap(); + + let key10: [u8; 32] = match base64::engine::general_purpose::STANDARD.decode(key_str) { + Ok(x) => x.try_into().unwrap(), + Err(_) => "1234567890123456".as_bytes().try_into().unwrap() // $ MISSING: Alert[rust/hardcoded-crytographic-value] + }; + let aes_cipher10 = Aes256::new(&key10.into()); + aes_cipher10.encrypt_block(block128.into()); + + if let Ok(const11) = base64::engine::general_purpose::STANDARD.decode("1234567890123456") { // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let key11: [u8; 32] = const11.try_into().unwrap(); + let aes_cipher11 = Aes256::new(&key11.into()); + aes_cipher11.encrypt_block(block128.into()); + } +} + +use aes_gcm::aead::{Aead, AeadCore, OsRng}; +use aes_gcm::{Aes256Gcm, Key, Nonce}; + +fn test_aes_gcm( +) { + // aes (GCM) + + let key1 = Aes256Gcm::generate_key(aes_gcm::aead::OsRng); + let nonce1 = Aes256Gcm::generate_nonce(aes_gcm::aead::OsRng); + let cipher1 = Aes256Gcm::new(&key1); + let _ = cipher1.encrypt(&nonce1, b"plaintext".as_ref()).unwrap(); + + let key2: [u8;32] = [0;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let nonce2 = [0;12]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let cipher2 = Aes256Gcm::new(&key2.into()); + let _ = cipher2.encrypt(&nonce2.into(), b"plaintext".as_ref()).unwrap(); + + let key3_array: &[u8;32] = &[0xff;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let key3 = Key::::from_slice(key3_array); + let nonce3: [u8;12] = [0xff;12]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let cipher3 = Aes256Gcm::new(&key3); + let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); } From 9fb00daeecb423f2b1beab21472dc40dd35eb0c8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 3 Mar 2025 19:43:55 +0000 Subject: [PATCH 003/311] Rust: Implement the query (with one source, one sink model). --- .../rustcrypto/rustcrypto.model.yml | 1 + .../HardcodedCryptographicValueExtensions.qll | 57 +++++++++++++++++++ .../CWE-798/HardcodedCryptographicValue.ql | 37 ++++++++++-- .../HardcodedCryptographicValue.expected | 16 ++++++ .../security/CWE-798/test_cipher.rs | 4 +- 5 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll diff --git a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml index fe3fd67a8fd4..baf21e9d6cc6 100644 --- a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml @@ -8,3 +8,4 @@ extensions: - ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::chain_update", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::digest", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/stainless-steel/md5:md5", "crate::compute", "Argument[0]", "hasher-input", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "crate::KeyInit::new_from_slice", "Argument[0]", "credentials-key", "manual"] diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll new file mode 100644 index 000000000000..006f4fd81392 --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -0,0 +1,57 @@ +/** + * Provides classes and predicates for reasoning about hardcoded cryptographic value + * vulnerabilities. + */ + +import rust +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.security.SensitiveData + +/** + * Provides default sources, sinks and barriers for detecting hardcoded cryptographic + * value vulnerabilities, as well as extension points for adding your own. + */ +module HardcodedCryptographicValue { + /** + * A data flow source for hardcoded cryptographic value vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for hardcoded cryptographic value vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { + /** + * Gets the kind of credential this sink is interpreted as, + * for example "password", "key", "iv", "salt". + */ + abstract string getKind(); + } + + /** + * A barrier for hardcoded cryptographic value vulnerabilities. + */ + abstract class Barrier extends DataFlow::Node { } + + /** + * A literal, considered as a flow source. + */ + private class LiteralSource extends Source { + LiteralSource() { this.asExpr().getExpr() instanceof LiteralExpr } + } + + /** + * A sink for hardcoded cryptographic value from model data. + */ + private class ModelsAsDataSinks extends Sink { + string kind; + + ModelsAsDataSinks() { + kind = ["password", "key", "iv", "salt"] and + sinkNode(this, "credentials-" + kind) + } + + override string getKind() { result = kind } + } +} diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 717831bba2b5..2ec8ea8c257a 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -2,7 +2,7 @@ * @name Hard-coded cryptographic value * @description Using hardcoded keys, passwords, salts or initialization * vectors is not secure. - * @kind problem + * @kind path-problem * @problem.severity warning * @security-severity TODO * @precision high @@ -15,7 +15,36 @@ */ import rust +import codeql.rust.security.HardcodedCryptographicValueExtensions +import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.TaintTracking +import codeql.rust.dataflow.internal.DataFlowImpl -from Locatable e -where none() -select e, "" +/** + * A taint-tracking configuration for hardcoded cryptographic value vulnerabilities. + */ +module HardcodedCryptographicValueConfig implements DataFlow::ConfigSig { + import HardcodedCryptographicValue + + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + + predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { + // flow out from reference content at sinks. + isSink(node) and + c.getAReadContent() instanceof ReferenceContent + } +} + +module HardcodedCryptographicValueFlow = TaintTracking::Global; + +import HardcodedCryptographicValueFlow::PathGraph + +from + HardcodedCryptographicValueFlow::PathNode source, HardcodedCryptographicValueFlow::PathNode sink +where HardcodedCryptographicValueFlow::flowPath(source, sink) +select source.getNode(), source, sink, "This hard-coded value is used as $@.", sink, + sink.getNode().(HardcodedCryptographicValueConfig::Sink).getKind() diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index e69de29bb2d1..4e3e67e41e0e 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -0,0 +1,16 @@ +#select +| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | key | +edges +| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | +| test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | +| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | +| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | +| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:54 Sink:MaD:54 Sink:MaD:54 | +nodes +| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | +| test_cipher.rs:73:18:73:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | +| test_cipher.rs:73:20:73:22 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:74:23:74:44 | ...::new_from_slice | semmle.label | ...::new_from_slice | +| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | +subpaths diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index 748b9f3e012a..cfd07d688a1b 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -70,8 +70,8 @@ fn test_block_cipher_aes( let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); aes_cipher3.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher4 = Aes256::new_from_slice(const2).unwrap(); + let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let aes_cipher4 = Aes256::new_from_slice(const2).unwrap(); // $ Sink aes_cipher4.encrypt_block(block128.into()); let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); From a6e106e025ad51c11f8fe4c5abef38c65317b4b6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 4 Mar 2025 16:02:33 +0000 Subject: [PATCH 004/311] Rust: Model more sinks + flows. --- .../rust/frameworks/genericarray.model.yml | 9 + .../rustcrypto/rustcrypto.model.yml | 31 ++++ .../HardcodedCryptographicValue.expected | 162 +++++++++++++++++- .../security/CWE-798/test_cipher.rs | 20 +-- 4 files changed, 211 insertions(+), 11 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/frameworks/genericarray.model.yml diff --git a/rust/ql/lib/codeql/rust/frameworks/genericarray.model.yml b/rust/ql/lib/codeql/rust/frameworks/genericarray.model.yml new file mode 100644 index 000000000000..29a72e2666c2 --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/genericarray.model.yml @@ -0,0 +1,9 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: summaryModel + data: + - ["repo:https://github.com/fizyk20/generic-array.git:generic-array", "::from_slice", "Argument[0].Reference", "ReturnValue.Reference", "value", "manual"] + - ["repo:https://github.com/fizyk20/generic-array.git:generic-array", "::from_mut_slice", "Argument[0].Reference", "ReturnValue.Reference", "value", "manual"] + - ["repo:https://github.com/fizyk20/generic-array.git:generic-array", "::try_from_slice", "Argument[0].Reference", "ReturnValue.Field[crate::result::Result::Ok(0)].Reference", "value", "manual"] + - ["repo:https://github.com/fizyk20/generic-array.git:generic-array", "::try_from_mut_slice", "Argument[0].Reference", "ReturnValue.Field[crate::result::Result::Ok(0)].Reference", "value", "manual"] diff --git a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml index baf21e9d6cc6..5b5b42ca3092 100644 --- a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml @@ -8,4 +8,35 @@ extensions: - ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::chain_update", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::digest", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/stainless-steel/md5:md5", "crate::compute", "Argument[0]", "hasher-input", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[1]", "credentials-iv", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new_from_slice", "Argument[1]", "credentials-iv", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "crate::KeyInit::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "crate::KeyInit::new", "Argument[1]", "credentials-iv", "manual"] - ["repo:https://github.com/RustCrypto/traits:crypto-common", "crate::KeyInit::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "crate::KeyInit::new_from_slice", "Argument[1]", "credentials-iv", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new", "Argument[1]", "credentials-iv", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new_from_slices", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new_from_slices", "Argument[1]", "credentials-iv", "manual"] diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 4e3e67e41e0e..f7ab5392e758 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -1,12 +1,172 @@ #select +| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | key | +| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | key | +| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | iv | +| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | +| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | +| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | key | edges +| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | +| test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | +| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | +| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | +| test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | +| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | +| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:82 Sink:MaD:82 Sink:MaD:82 | +| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | +| test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | +| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | +| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:83 Sink:MaD:83 Sink:MaD:83 | +| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:37:9:37:14 | const7 [element] | test_cipher.rs:38:74:38:79 | const7 [element] | provenance | | +| test_cipher.rs:37:27:37:74 | [...] [element] | test_cipher.rs:37:9:37:14 | const7 [element] | provenance | | +| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:38:74:38:79 | const7 [element] | test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | provenance | | +| test_cipher.rs:41:9:41:14 | const8 [&ref, element] | test_cipher.rs:42:73:42:78 | const8 [&ref, element] | provenance | | +| test_cipher.rs:41:28:41:76 | &... [&ref, element] | test_cipher.rs:41:9:41:14 | const8 [&ref, element] | provenance | | +| test_cipher.rs:41:29:41:76 | [...] [element] | test_cipher.rs:41:28:41:76 | &... [&ref, element] | provenance | | +| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:42:73:42:78 | const8 [&ref, element] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:54 Sink:MaD:54 Sink:MaD:54 | +| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:84 Sink:MaD:84 Sink:MaD:84 | nodes +| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | +| test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | +| test_cipher.rs:18:30:18:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:19:30:19:47 | ...::new | semmle.label | ...::new | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | +| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | +| test_cipher.rs:25:28:25:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | +| test_cipher.rs:25:30:25:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:26:30:26:40 | ...::new | semmle.label | ...::new | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | +| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | +| test_cipher.rs:29:28:29:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | +| test_cipher.rs:29:30:29:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | +| test_cipher.rs:37:9:37:14 | const7 [element] | semmle.label | const7 [element] | +| test_cipher.rs:37:27:37:74 | [...] [element] | semmle.label | [...] [element] | +| test_cipher.rs:37:28:37:28 | 0 | semmle.label | 0 | +| test_cipher.rs:37:31:37:31 | 0 | semmle.label | 0 | +| test_cipher.rs:37:34:37:34 | 0 | semmle.label | 0 | +| test_cipher.rs:37:37:37:37 | 0 | semmle.label | 0 | +| test_cipher.rs:37:40:37:40 | 0 | semmle.label | 0 | +| test_cipher.rs:37:43:37:43 | 0 | semmle.label | 0 | +| test_cipher.rs:37:46:37:46 | 0 | semmle.label | 0 | +| test_cipher.rs:37:49:37:49 | 0 | semmle.label | 0 | +| test_cipher.rs:37:52:37:52 | 0 | semmle.label | 0 | +| test_cipher.rs:37:55:37:55 | 0 | semmle.label | 0 | +| test_cipher.rs:37:58:37:58 | 0 | semmle.label | 0 | +| test_cipher.rs:37:61:37:61 | 0 | semmle.label | 0 | +| test_cipher.rs:37:64:37:64 | 0 | semmle.label | 0 | +| test_cipher.rs:37:67:37:67 | 0 | semmle.label | 0 | +| test_cipher.rs:37:70:37:70 | 0 | semmle.label | 0 | +| test_cipher.rs:37:73:37:73 | 0 | semmle.label | 0 | +| test_cipher.rs:38:30:38:47 | ...::new | semmle.label | ...::new | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | semmle.label | &const7 [&ref, element] | +| test_cipher.rs:38:74:38:79 | const7 [element] | semmle.label | const7 [element] | +| test_cipher.rs:41:9:41:14 | const8 [&ref, element] | semmle.label | const8 [&ref, element] | +| test_cipher.rs:41:28:41:76 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:41:29:41:76 | [...] [element] | semmle.label | [...] [element] | +| test_cipher.rs:41:30:41:30 | 0 | semmle.label | 0 | +| test_cipher.rs:41:33:41:33 | 0 | semmle.label | 0 | +| test_cipher.rs:41:36:41:36 | 0 | semmle.label | 0 | +| test_cipher.rs:41:39:41:39 | 0 | semmle.label | 0 | +| test_cipher.rs:41:42:41:42 | 0 | semmle.label | 0 | +| test_cipher.rs:41:45:41:45 | 0 | semmle.label | 0 | +| test_cipher.rs:41:48:41:48 | 0 | semmle.label | 0 | +| test_cipher.rs:41:51:41:51 | 0 | semmle.label | 0 | +| test_cipher.rs:41:54:41:54 | 0 | semmle.label | 0 | +| test_cipher.rs:41:57:41:57 | 0 | semmle.label | 0 | +| test_cipher.rs:41:60:41:60 | 0 | semmle.label | 0 | +| test_cipher.rs:41:63:41:63 | 0 | semmle.label | 0 | +| test_cipher.rs:41:66:41:66 | 0 | semmle.label | 0 | +| test_cipher.rs:41:69:41:69 | 0 | semmle.label | 0 | +| test_cipher.rs:41:72:41:72 | 0 | semmle.label | 0 | +| test_cipher.rs:41:75:41:75 | 0 | semmle.label | 0 | +| test_cipher.rs:42:30:42:47 | ...::new | semmle.label | ...::new | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:42:73:42:78 | const8 [&ref, element] | semmle.label | const8 [&ref, element] | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index cfd07d688a1b..cfa20ab13c26 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -15,31 +15,31 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit::Key::from_slice(key)); rabbit_cipher1.apply_keystream(&mut data); - let const1: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher2 = RabbitKeyOnly::new(rabbit::Key::from_slice(const1)); + let const1: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher2 = RabbitKeyOnly::new(rabbit::Key::from_slice(const1)); // $ Sink rabbit_cipher2.apply_keystream(&mut data); let mut rabbit_cipher3 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(iv)); rabbit_cipher3.apply_keystream(&mut data); - let const4: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const4), rabbit::Iv::from_slice(iv)); + let const4: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const4), rabbit::Iv::from_slice(iv)); // $ Sink rabbit_cipher4.apply_keystream(&mut data); - let const5: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const5)); + let const5: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const5)); // $ Sink rabbit_cipher5.apply_keystream(&mut data); // various expressions of constant arrays let const6: &[u8;16] = &[0u8;16]; // (unused, so good) - let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher7 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const7)); + let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher7 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const7)); // $ Sink rabbit_cipher7.apply_keystream(&mut data); - let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); + let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); // $ Sink rabbit_cipher8.apply_keystream(&mut data); let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] From aacbfc0fd88af543a665bc7d2fa27b884091e98c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:38:04 +0000 Subject: [PATCH 005/311] Rust: Improve alert messages. --- .../HardcodedCryptographicValueExtensions.qll | 34 ++++++--- .../CWE-798/HardcodedCryptographicValue.ql | 2 +- .../HardcodedCryptographicValue.expected | 72 +++++++++---------- 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 006f4fd81392..246d138f91b9 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -8,6 +8,26 @@ private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.security.SensitiveData +/** + * A kind of cryptographic value. + */ +class CryptographicValueKind extends string { + CryptographicValueKind() { this = ["password", "key", "iv", "salt"] } + + /** + * Gets a description of this value kind for user-facing messages. + */ + string getDescription() { + this = "password" and result = "a password" + or + this = "key" and result = "a key" + or + this = "iv" and result = "an initialization vector" + or + this = "salt" and result = "a salt" + } +} + /** * Provides default sources, sinks and barriers for detecting hardcoded cryptographic * value vulnerabilities, as well as extension points for adding your own. @@ -23,10 +43,9 @@ module HardcodedCryptographicValue { */ abstract class Sink extends DataFlow::Node { /** - * Gets the kind of credential this sink is interpreted as, - * for example "password", "key", "iv", "salt". + * Gets the kind of credential this sink is interpreted as. */ - abstract string getKind(); + abstract CryptographicValueKind getKind(); } /** @@ -45,13 +64,10 @@ module HardcodedCryptographicValue { * A sink for hardcoded cryptographic value from model data. */ private class ModelsAsDataSinks extends Sink { - string kind; + CryptographicValueKind kind; - ModelsAsDataSinks() { - kind = ["password", "key", "iv", "salt"] and - sinkNode(this, "credentials-" + kind) - } + ModelsAsDataSinks() { sinkNode(this, "credentials-" + kind) } - override string getKind() { result = kind } + override CryptographicValueKind getKind() { result = kind } } } diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 2ec8ea8c257a..716604ee4844 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -47,4 +47,4 @@ from HardcodedCryptographicValueFlow::PathNode source, HardcodedCryptographicValueFlow::PathNode sink where HardcodedCryptographicValueFlow::flowPath(source, sink) select source.getNode(), source, sink, "This hard-coded value is used as $@.", sink, - sink.getNode().(HardcodedCryptographicValueConfig::Sink).getKind() + sink.getNode().(HardcodedCryptographicValueConfig::Sink).getKind().getDescription() diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index f7ab5392e758..9a52e7e2f5d4 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -1,40 +1,40 @@ #select -| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | key | -| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | key | -| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | iv | -| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | key | -| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | key | -| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | key | +| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | +| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | +| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | +| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | From 055baf2769bda0d87bdffc853095038cbe4807c8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:46:51 +0000 Subject: [PATCH 006/311] Rust: Improve results on arrays (less duplication). --- .../HardcodedCryptographicValueExtensions.qll | 12 ++ .../CWE-798/HardcodedCryptographicValue.ql | 7 + .../HardcodedCryptographicValue.expected | 138 +++--------------- 3 files changed, 41 insertions(+), 116 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 246d138f91b9..f7f26032b518 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -60,6 +60,18 @@ module HardcodedCryptographicValue { LiteralSource() { this.asExpr().getExpr() instanceof LiteralExpr } } + /** + * An array initialized from a list of literals, considered as a single flow source. For example: + * ``` + * `[0, 0, 0, 0]` + * ``` + */ + private class ArrayListSource extends Source { + ArrayListSource() { + this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr + } + } + /** * A sink for hardcoded cryptographic value from model data. */ diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 716604ee4844..441c22f679a2 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -32,6 +32,13 @@ module HardcodedCryptographicValueConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + predicate isBarrierIn(DataFlow::Node node) { + // make sources barriers so that we only report the closest instance + // (this combined with sources for `ArrayListExpr` means we only get one source in + // case like `[0, 0, 0, 0]`) + isSource(node) + } + predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { // flow out from reference content at sinks. isSink(node) and diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 9a52e7e2f5d4..2ed68852eb55 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -2,38 +2,8 @@ | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | -| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | -| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | +| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | @@ -54,48 +24,16 @@ edges | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:83 Sink:MaD:83 Sink:MaD:83 | | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | -| test_cipher.rs:37:9:37:14 | const7 [element] | test_cipher.rs:38:74:38:79 | const7 [element] | provenance | | -| test_cipher.rs:37:27:37:74 | [...] [element] | test_cipher.rs:37:9:37:14 | const7 [element] | provenance | | -| test_cipher.rs:37:28:37:28 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:31:37:31 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:34:37:34 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:37:37:37 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:40:37:40 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:43:37:43 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:46:37:46 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:49:37:49 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:52:37:52 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:55:37:55 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:58:37:58 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:61:37:61 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:64:37:64 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:67:37:67 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:70:37:70 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:37:73:37:73 | 0 | test_cipher.rs:37:27:37:74 | [...] [element] | provenance | | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | -| test_cipher.rs:38:74:38:79 | const7 [element] | test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | provenance | | -| test_cipher.rs:41:9:41:14 | const8 [&ref, element] | test_cipher.rs:42:73:42:78 | const8 [&ref, element] | provenance | | -| test_cipher.rs:41:28:41:76 | &... [&ref, element] | test_cipher.rs:41:9:41:14 | const8 [&ref, element] | provenance | | -| test_cipher.rs:41:29:41:76 | [...] [element] | test_cipher.rs:41:28:41:76 | &... [&ref, element] | provenance | | -| test_cipher.rs:41:30:41:30 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:33:41:33 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:36:41:36 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:39:41:39 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:42:41:42 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:45:41:45 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:48:41:48 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:51:41:51 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:54:41:54 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:57:41:57 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:60:41:60 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:63:41:63 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:66:41:66 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:69:41:69 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:72:41:72 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:41:75:41:75 | 0 | test_cipher.rs:41:29:41:76 | [...] [element] | provenance | | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | -| test_cipher.rs:42:73:42:78 | const8 [&ref, element] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | +| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:58 Sink:MaD:58 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:0 | +| test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | +| test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | +| test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | +| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:58 Sink:MaD:58 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:0 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | @@ -123,50 +61,18 @@ nodes | test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | -| test_cipher.rs:37:9:37:14 | const7 [element] | semmle.label | const7 [element] | -| test_cipher.rs:37:27:37:74 | [...] [element] | semmle.label | [...] [element] | -| test_cipher.rs:37:28:37:28 | 0 | semmle.label | 0 | -| test_cipher.rs:37:31:37:31 | 0 | semmle.label | 0 | -| test_cipher.rs:37:34:37:34 | 0 | semmle.label | 0 | -| test_cipher.rs:37:37:37:37 | 0 | semmle.label | 0 | -| test_cipher.rs:37:40:37:40 | 0 | semmle.label | 0 | -| test_cipher.rs:37:43:37:43 | 0 | semmle.label | 0 | -| test_cipher.rs:37:46:37:46 | 0 | semmle.label | 0 | -| test_cipher.rs:37:49:37:49 | 0 | semmle.label | 0 | -| test_cipher.rs:37:52:37:52 | 0 | semmle.label | 0 | -| test_cipher.rs:37:55:37:55 | 0 | semmle.label | 0 | -| test_cipher.rs:37:58:37:58 | 0 | semmle.label | 0 | -| test_cipher.rs:37:61:37:61 | 0 | semmle.label | 0 | -| test_cipher.rs:37:64:37:64 | 0 | semmle.label | 0 | -| test_cipher.rs:37:67:37:67 | 0 | semmle.label | 0 | -| test_cipher.rs:37:70:37:70 | 0 | semmle.label | 0 | -| test_cipher.rs:37:73:37:73 | 0 | semmle.label | 0 | +| test_cipher.rs:37:9:37:14 | const7 | semmle.label | const7 | +| test_cipher.rs:37:27:37:74 | [...] | semmle.label | [...] | | test_cipher.rs:38:30:38:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | -| test_cipher.rs:38:73:38:79 | &const7 [&ref, element] | semmle.label | &const7 [&ref, element] | -| test_cipher.rs:38:74:38:79 | const7 [element] | semmle.label | const7 [element] | -| test_cipher.rs:41:9:41:14 | const8 [&ref, element] | semmle.label | const8 [&ref, element] | -| test_cipher.rs:41:28:41:76 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:41:29:41:76 | [...] [element] | semmle.label | [...] [element] | -| test_cipher.rs:41:30:41:30 | 0 | semmle.label | 0 | -| test_cipher.rs:41:33:41:33 | 0 | semmle.label | 0 | -| test_cipher.rs:41:36:41:36 | 0 | semmle.label | 0 | -| test_cipher.rs:41:39:41:39 | 0 | semmle.label | 0 | -| test_cipher.rs:41:42:41:42 | 0 | semmle.label | 0 | -| test_cipher.rs:41:45:41:45 | 0 | semmle.label | 0 | -| test_cipher.rs:41:48:41:48 | 0 | semmle.label | 0 | -| test_cipher.rs:41:51:41:51 | 0 | semmle.label | 0 | -| test_cipher.rs:41:54:41:54 | 0 | semmle.label | 0 | -| test_cipher.rs:41:57:41:57 | 0 | semmle.label | 0 | -| test_cipher.rs:41:60:41:60 | 0 | semmle.label | 0 | -| test_cipher.rs:41:63:41:63 | 0 | semmle.label | 0 | -| test_cipher.rs:41:66:41:66 | 0 | semmle.label | 0 | -| test_cipher.rs:41:69:41:69 | 0 | semmle.label | 0 | -| test_cipher.rs:41:72:41:72 | 0 | semmle.label | 0 | -| test_cipher.rs:41:75:41:75 | 0 | semmle.label | 0 | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | semmle.label | &const7 [&ref] | +| test_cipher.rs:38:74:38:79 | const7 | semmle.label | const7 | +| test_cipher.rs:41:9:41:14 | const8 [&ref] | semmle.label | const8 [&ref] | +| test_cipher.rs:41:28:41:76 | &... [&ref] | semmle.label | &... [&ref] | +| test_cipher.rs:41:29:41:76 | [...] | semmle.label | [...] | | test_cipher.rs:42:30:42:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | -| test_cipher.rs:42:73:42:78 | const8 [&ref, element] | semmle.label | const8 [&ref, element] | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | semmle.label | const8 [&ref] | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | From ac94ac6584cc0a8ab4e4c59793b412229b254a18 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 16:25:27 +0000 Subject: [PATCH 007/311] Rust: Model even more sinks + flows. --- .../rustcrypto/rustcrypto.model.yml | 2 + .../frameworks/stdlib/lang-core.model.yml | 4 + .../HardcodedCryptographicValueExtensions.qll | 4 +- .../HardcodedCryptographicValue.expected | 123 ++++++++++++++++++ .../security/CWE-798/test_cipher.rs | 32 ++--- 5 files changed, 148 insertions(+), 17 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml index 5b5b42ca3092..2047cfa9ebcd 100644 --- a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml @@ -40,3 +40,5 @@ extensions: - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new", "Argument[1]", "credentials-iv", "manual"] - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new_from_slices", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/traits:crypto-common", "<_ as crate::KeyIvInit>::new_from_slices", "Argument[1]", "credentials-iv", "manual"] + - ["repo:https://github.com/RustCrypto/AEADs:aes-gcm", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:aead", "<_ as crate::Aead>::encrypt", "Argument[0]", "credentials-nonce", "manual"] diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml index 062576e46bb4..d8bbe389eaa4 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml @@ -3,6 +3,10 @@ extensions: pack: codeql/rust-all extensible: summaryModel data: + # Conversions + - ["lang:core", "<_ as crate::convert::Into>::into", "Argument[self].Element", "ReturnValue.Element", "taint", "manual"] + - ["lang:core", "<_ as crate::convert::Into>::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"] + - ["lang:core", "<[_]>::align_to", "Argument[self].Element", "ReturnValue.Field[0,1,2].Reference.Element", "taint", "manual"] # Fmt - ["lang:alloc", "crate::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"] # Iterator diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index f7f26032b518..fbabffc3e28d 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -12,7 +12,7 @@ private import codeql.rust.security.SensitiveData * A kind of cryptographic value. */ class CryptographicValueKind extends string { - CryptographicValueKind() { this = ["password", "key", "iv", "salt"] } + CryptographicValueKind() { this = ["password", "key", "iv", "nonce", "salt"] } /** * Gets a description of this value kind for user-facing messages. @@ -24,6 +24,8 @@ class CryptographicValueKind extends string { or this = "iv" and result = "an initialization vector" or + this = "nonce" and result = "a nonce" + or this = "salt" and result = "a salt" } } diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 2ed68852eb55..0d29ab6921c7 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -4,7 +4,15 @@ | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | +| test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:47:30:47:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:47:30:47:47 | ...::new | a key | +| test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:67:23:67:33 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:67:23:67:33 | ...::new | a key | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | +| test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:81:23:81:61 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:81:23:81:61 | ...::new | a key | +| test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:85:23:85:61 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:85:23:85:61 | ...::new | an initialization vector | +| test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:126:19:126:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:126:19:126:32 | ...::new | a key | +| test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:127:21:127:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:127:21:127:27 | encrypt | a nonce | +| test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:132:19:132:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:132:19:132:32 | ...::new | a key | +| test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:133:21:133:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:133:21:133:27 | encrypt | a nonce | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | @@ -34,11 +42,65 @@ edges | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:58 Sink:MaD:58 | | test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:0 | +| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:37 | const9 | provenance | | +| test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:9:45:14 | const9 | provenance | | +| test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | provenance | | +| test_cipher.rs:46:32:46:37 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:103 | +| test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | provenance | | +| test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | provenance | | +| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:40 | const2 [&ref, element] | provenance | | +| test_cipher.rs:66:18:66:26 | &... [&ref, element] | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | provenance | | +| test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | test_cipher.rs:66:18:66:26 | &... [&ref, element] | provenance | | +| test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | provenance | | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:76 Sink:MaD:76 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:84 Sink:MaD:84 Sink:MaD:84 | +| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:68 | const6 [&ref, element] | provenance | | +| test_cipher.rs:80:18:80:26 | &... [&ref, element] | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | provenance | | +| test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | test_cipher.rs:80:18:80:26 | &... [&ref, element] | provenance | | +| test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | provenance | | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:86 Sink:MaD:86 | +| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:80 | const7 [&ref, element] | provenance | | +| test_cipher.rs:84:18:84:27 | &... [&ref, element] | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | provenance | | +| test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | test_cipher.rs:84:18:84:27 | &... [&ref, element] | provenance | | +| test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | provenance | | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:87 Sink:MaD:87 | +| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:38 | key2 [element] | provenance | | +| test_cipher.rs:124:25:124:30 | [0; 32] [element] | test_cipher.rs:124:9:124:12 | key2 [element] | provenance | | +| test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:124:25:124:30 | [0; 32] [element] | provenance | | +| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:35 | nonce2 [element] | provenance | | +| test_cipher.rs:125:18:125:23 | [0; 12] [element] | test_cipher.rs:125:9:125:14 | nonce2 [element] | provenance | | +| test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:18:125:23 | [0; 12] [element] | provenance | | +| test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | +| test_cipher.rs:126:35:126:38 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:126:35:126:45 | key2.into(...) [element] | test_cipher.rs:126:34:126:45 | &... [&ref, element] | provenance | | +| test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | +| test_cipher.rs:127:30:127:35 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | test_cipher.rs:127:29:127:42 | &... [&ref, element] | provenance | | +| test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | provenance | | +| test_cipher.rs:129:32:129:41 | &... [&ref, element] | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | provenance | | +| test_cipher.rs:129:33:129:41 | [0xff; 32] [element] | test_cipher.rs:129:32:129:41 | &... [&ref, element] | provenance | | +| test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:129:33:129:41 | [0xff; 32] [element] | provenance | | +| test_cipher.rs:130:9:130:12 | key3 [&ref, element] | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | provenance | | +| test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | provenance | | +| test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:35 | nonce3 [element] | provenance | | +| test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | test_cipher.rs:131:9:131:14 | nonce3 [element] | provenance | | +| test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | provenance | | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 Sink:MaD:90 | +| test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | +| test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | +| test_cipher.rs:133:30:133:35 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | @@ -73,10 +135,71 @@ nodes | test_cipher.rs:42:30:42:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | | test_cipher.rs:42:73:42:78 | const8 [&ref] | semmle.label | const8 [&ref] | +| test_cipher.rs:45:9:45:14 | const9 | semmle.label | const9 | +| test_cipher.rs:45:27:45:50 | [...] | semmle.label | [...] | +| test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | semmle.label | const9_conv [&ref, element] | +| test_cipher.rs:46:32:46:37 | const9 | semmle.label | const9 | +| test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | semmle.label | const9.align_to(...) [tuple.1, &ref, element] | +| test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | semmle.label | ... .1 [&ref, element] | +| test_cipher.rs:47:30:47:47 | ...::new | semmle.label | ...::new | +| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | semmle.label | const9_conv [&ref, element] | +| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | +| test_cipher.rs:66:18:66:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | +| test_cipher.rs:66:20:66:22 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:67:23:67:33 | ...::new | semmle.label | ...::new | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | +| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | semmle.label | const2.into(...) [element] | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | | test_cipher.rs:73:20:73:22 | 0u8 | semmle.label | 0u8 | | test_cipher.rs:74:23:74:44 | ...::new_from_slice | semmle.label | ...::new_from_slice | | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | +| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | semmle.label | const6 [&ref, element] | +| test_cipher.rs:80:18:80:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | +| test_cipher.rs:80:20:80:22 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:81:23:81:61 | ...::new | semmle.label | ...::new | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | semmle.label | const6 [&ref, element] | +| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | semmle.label | const6.into(...) [element] | +| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | semmle.label | const7 [&ref, element] | +| test_cipher.rs:84:18:84:27 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | +| test_cipher.rs:84:20:84:22 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:85:23:85:61 | ...::new | semmle.label | ...::new | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | semmle.label | const7 [&ref, element] | +| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | semmle.label | const7.into(...) [element] | +| test_cipher.rs:124:9:124:12 | key2 [element] | semmle.label | key2 [element] | +| test_cipher.rs:124:25:124:30 | [0; 32] [element] | semmle.label | [0; 32] [element] | +| test_cipher.rs:124:26:124:26 | 0 | semmle.label | 0 | +| test_cipher.rs:125:9:125:14 | nonce2 [element] | semmle.label | nonce2 [element] | +| test_cipher.rs:125:18:125:23 | [0; 12] [element] | semmle.label | [0; 12] [element] | +| test_cipher.rs:125:19:125:19 | 0 | semmle.label | 0 | +| test_cipher.rs:126:19:126:32 | ...::new | semmle.label | ...::new | +| test_cipher.rs:126:34:126:45 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:126:35:126:38 | key2 [element] | semmle.label | key2 [element] | +| test_cipher.rs:126:35:126:45 | key2.into(...) [element] | semmle.label | key2.into(...) [element] | +| test_cipher.rs:127:21:127:27 | encrypt | semmle.label | encrypt | +| test_cipher.rs:127:29:127:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:127:30:127:35 | nonce2 [element] | semmle.label | nonce2 [element] | +| test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | semmle.label | nonce2.into(...) [element] | +| test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | semmle.label | key3_array [&ref, element] | +| test_cipher.rs:129:32:129:41 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:129:33:129:41 | [0xff; 32] [element] | semmle.label | [0xff; 32] [element] | +| test_cipher.rs:129:34:129:37 | 0xff | semmle.label | 0xff | +| test_cipher.rs:130:9:130:12 | key3 [&ref, element] | semmle.label | key3 [&ref, element] | +| test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | semmle.label | key3_array [&ref, element] | +| test_cipher.rs:131:9:131:14 | nonce3 [element] | semmle.label | nonce3 [element] | +| test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | semmle.label | [0xff; 12] [element] | +| test_cipher.rs:131:28:131:31 | 0xff | semmle.label | 0xff | +| test_cipher.rs:132:19:132:32 | ...::new | semmle.label | ...::new | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | semmle.label | &key3 [&ref, &ref, element] | +| test_cipher.rs:132:35:132:38 | key3 [&ref, element] | semmle.label | key3 [&ref, element] | +| test_cipher.rs:133:21:133:27 | encrypt | semmle.label | encrypt | +| test_cipher.rs:133:29:133:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:133:30:133:35 | nonce3 [element] | semmle.label | nonce3 [element] | +| test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | semmle.label | nonce3.into(...) [element] | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index cfa20ab13c26..d85fffcf58a2 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -42,9 +42,9 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); // $ Sink rabbit_cipher8.apply_keystream(&mut data); - let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] let const9_conv = unsafe { const9.align_to::().1 }; // convert [u16;8] -> [u8;8] - let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); + let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); // $ Sink rabbit_cipher9.apply_keystream(&mut data); let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ MISSING: Alert[rust/hardcoded-crytographic-value] @@ -63,8 +63,8 @@ fn test_block_cipher_aes( let aes_cipher1 = Aes256::new(key256.into()); aes_cipher1.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher2 = Aes256::new(const2.into()); + let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let aes_cipher2 = Aes256::new(const2.into()); // $ Sink aes_cipher2.encrypt_block(block128.into()); let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); @@ -77,12 +77,12 @@ fn test_block_cipher_aes( let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); _ = aes_cipher5.encrypt_b2b(input, output).unwrap(); - let const6 = &[0u8;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher6 = cfb_mode::Encryptor::::new(const6.into(), iv.into()); + let const6 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let aes_cipher6 = cfb_mode::Encryptor::::new(const6.into(), iv.into()); // $ Sink _ = aes_cipher6.encrypt_b2b(input, output).unwrap(); - let const7 = &[0u8; 16]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const7.into()); + let const7 = &[0u8; 16]; // $ Alert[rust/hardcoded-crytographic-value] + let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const7.into()); // $ Sink _ = aes_cipher7.encrypt_b2b(input, output).unwrap(); // various string conversions @@ -121,14 +121,14 @@ fn test_aes_gcm( let cipher1 = Aes256Gcm::new(&key1); let _ = cipher1.encrypt(&nonce1, b"plaintext".as_ref()).unwrap(); - let key2: [u8;32] = [0;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let nonce2 = [0;12]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let cipher2 = Aes256Gcm::new(&key2.into()); - let _ = cipher2.encrypt(&nonce2.into(), b"plaintext".as_ref()).unwrap(); + let key2: [u8;32] = [0;32]; // $ Alert[rust/hardcoded-crytographic-value] + let nonce2 = [0;12]; // $ Alert[rust/hardcoded-crytographic-value] + let cipher2 = Aes256Gcm::new(&key2.into()); // $ Sink + let _ = cipher2.encrypt(&nonce2.into(), b"plaintext".as_ref()).unwrap(); // $ Sink - let key3_array: &[u8;32] = &[0xff;32]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let key3_array: &[u8;32] = &[0xff;32]; // $ Alert[rust/hardcoded-crytographic-value] let key3 = Key::::from_slice(key3_array); - let nonce3: [u8;12] = [0xff;12]; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let cipher3 = Aes256Gcm::new(&key3); - let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); + let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hardcoded-crytographic-value] + let cipher3 = Aes256Gcm::new(&key3); // $ Sink + let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); // $ Sink } From b4a6063e203222ea4319380f01e380fd1a0754ca Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 17:13:51 +0000 Subject: [PATCH 008/311] Rust: Add std::mem::zeroed as a source. --- .../frameworks/stdlib/lang-core.model.yml | 5 ++++ .../HardcodedCryptographicValueExtensions.qll | 11 ++++++-- .../HardcodedCryptographicValue.expected | 28 ++++++++++++++----- .../security/CWE-798/test_cipher.rs | 4 +-- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml index d8bbe389eaa4..37f574dd2b85 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml @@ -1,4 +1,9 @@ extensions: + - addsTo: + pack: codeql/rust-all + extensible: sourceModel + data: + - ["lang:core", "crate::mem::zeroed", "ReturnValue.Element", "constant-source", "manual"] - addsTo: pack: codeql/rust-all extensible: summaryModel diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index fbabffc3e28d..4d6210cb97b5 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -69,9 +69,14 @@ module HardcodedCryptographicValue { * ``` */ private class ArrayListSource extends Source { - ArrayListSource() { - this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr - } + ArrayListSource() { this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr } + } + + /** + * An externally modeled source for constant values. + */ + private class ModeledSource extends Source { + ModeledSource() { sourceNode(this, "constant-source") } } /** diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 0d29ab6921c7..a09f89d21276 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -5,6 +5,7 @@ | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:47:30:47:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:47:30:47:47 | ...::new | a key | +| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key | | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:67:23:67:33 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:67:23:67:33 | ...::new | a key | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:81:23:81:61 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:81:23:81:61 | ...::new | a key | @@ -45,16 +46,22 @@ edges | test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:37 | const9 | provenance | | | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:9:45:14 | const9 | provenance | | | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | provenance | | -| test_cipher.rs:46:32:46:37 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:103 | +| test_cipher.rs:46:32:46:37 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:104 | | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | provenance | | | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | provenance | | | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | +| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:101 | +| test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | +| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:40 | const2 [&ref, element] | provenance | | | test_cipher.rs:66:18:66:26 | &... [&ref, element] | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | test_cipher.rs:66:18:66:26 | &... [&ref, element] | provenance | | | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:76 Sink:MaD:76 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | @@ -65,13 +72,13 @@ edges | test_cipher.rs:80:18:80:26 | &... [&ref, element] | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | provenance | | | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | test_cipher.rs:80:18:80:26 | &... [&ref, element] | provenance | | | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:86 Sink:MaD:86 | | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:80 | const7 [&ref, element] | provenance | | | test_cipher.rs:84:18:84:27 | &... [&ref, element] | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | provenance | | | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | test_cipher.rs:84:18:84:27 | &... [&ref, element] | provenance | | | test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:87 Sink:MaD:87 | | test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:38 | key2 [element] | provenance | | | test_cipher.rs:124:25:124:30 | [0; 32] [element] | test_cipher.rs:124:9:124:12 | key2 [element] | provenance | | @@ -80,10 +87,10 @@ edges | test_cipher.rs:125:18:125:23 | [0; 12] [element] | test_cipher.rs:125:9:125:14 | nonce2 [element] | provenance | | | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:18:125:23 | [0; 12] [element] | provenance | | | test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | -| test_cipher.rs:126:35:126:38 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:126:35:126:38 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | test_cipher.rs:126:34:126:45 | &... [&ref, element] | provenance | | | test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | -| test_cipher.rs:127:30:127:35 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:127:30:127:35 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | test_cipher.rs:127:29:127:42 | &... [&ref, element] | provenance | | | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | provenance | | | test_cipher.rs:129:32:129:41 | &... [&ref, element] | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | provenance | | @@ -99,7 +106,7 @@ edges | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 Sink:MaD:90 | | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | -| test_cipher.rs:133:30:133:35 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:101 | +| test_cipher.rs:133:30:133:35 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | @@ -144,6 +151,13 @@ nodes | test_cipher.rs:47:30:47:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | semmle.label | const9_conv [&ref, element] | +| test_cipher.rs:50:9:50:15 | const10 [element] | semmle.label | const10 [element] | +| test_cipher.rs:50:37:50:52 | ...::zeroed | semmle.label | ...::zeroed | +| test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | semmle.label | ...::zeroed(...) [element] | +| test_cipher.rs:51:31:51:48 | ...::new | semmle.label | ...::new | +| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | semmle.label | &const10 [&ref, element] | +| test_cipher.rs:51:75:51:81 | const10 [element] | semmle.label | const10 [element] | | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | | test_cipher.rs:66:18:66:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index d85fffcf58a2..cf96cf047b5f 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -47,8 +47,8 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); // $ Sink rabbit_cipher9.apply_keystream(&mut data); - let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ MISSING: Alert[rust/hardcoded-crytographic-value] - let mut rabbit_cipher10 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const10)); + let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ Alert[rust/hardcoded-crytographic-value] + let mut rabbit_cipher10 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const10)); // $ Sink rabbit_cipher10.apply_keystream(&mut data); } From 95be12ed80f96af4df5d8658037630485e42975b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 17:45:34 +0000 Subject: [PATCH 009/311] Rust: Add qhelp and examples. --- .../CWE-798/HardcodedCryptographicValue.qhelp | 58 +++++++++++++++++++ .../CWE-798/HardcodedCryptographicValueBad.rs | 2 + .../HardcodedCryptographicValueGood.rs | 2 + 3 files changed, 62 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp create mode 100644 rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs create mode 100644 rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueGood.rs diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp new file mode 100644 index 000000000000..408d4bd002a8 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp @@ -0,0 +1,58 @@ + + + + +

+Hardcoded passwords, keys, initialization vectors and salts should not be used for cryptographic operations. +

+
    +
  • + Attackers can easily recover hardcoded values if they have access to the source code or compiled executable. +
  • +
  • + Some hardcoded values may be easily guessable. +
  • +
  • + Hardcoded values may leave cryptographic operations vulnerable to dictionary attacks, rainbow tables, and other forms of cryptanalysis. +
  • +
+ +
+ + +

+Use randomly generated key material, initialization vectors and salts. Use strong passwords that are not hardcoded in source code. +

+ +
+ + +

+The following example shows instantiating a cipher with hardcoded key material, making the encrypted data vulnerable to recovery. +

+ + + +

+In the fixed code below, the key material is randomly generated and not hardcoded, which protects the encrypted data against recovery. A real application would also need a strategy for secure key management after the key has been generated. +

+ + + +
+ + +
  • +OWASP: Use of hard-coded password. +
  • +
  • +OWASP: Key Management Cheat Sheet. +
  • +
  • +O'Reilly: Using Salts, Nonces, and Initialization Vectors. +
  • + +
    +
    diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs new file mode 100644 index 000000000000..c1923df1730f --- /dev/null +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs @@ -0,0 +1,2 @@ +let key: [u8;32] = [0;32]; // BAD: Using hardcoded keys for encryption +let cipher = Aes256Gcm::new(&key.into()); diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueGood.rs b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueGood.rs new file mode 100644 index 000000000000..06dc1af836d5 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueGood.rs @@ -0,0 +1,2 @@ +let key = Aes256Gcm::generate_key(aes_gcm::aead::OsRng); // GOOD: Using randomly generated keys for encryption +let cipher = Aes256Gcm::new(&key); From e564c410439eb8898ec829ca6487883ca8122bc5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:36:55 +0000 Subject: [PATCH 010/311] Rust: Compute security-severity tag. --- .../src/queries/security/CWE-798/HardcodedCryptographicValue.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 441c22f679a2..49e8b0cf3422 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -4,7 +4,7 @@ * vectors is not secure. * @kind path-problem * @problem.severity warning - * @security-severity TODO + * @security-severity 9.8 * @precision high * @id rust/hardcoded-crytographic-value * @tags security From 952e417d13b6a18f01386e3d7773ebad76c5b8a3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:46:37 +0000 Subject: [PATCH 011/311] Rust: Tweak some wording. --- .../rust/security/HardcodedCryptographicValueExtensions.qll | 2 +- .../security/CWE-798/HardcodedCryptographicValue.qhelp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 4d6210cb97b5..32f64051fcb3 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -80,7 +80,7 @@ module HardcodedCryptographicValue { } /** - * A sink for hardcoded cryptographic value from model data. + * An externally modeled sink for hardcoded cryptographic value vulnerabilities. */ private class ModelsAsDataSinks extends Sink { CryptographicValueKind kind; diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp index 408d4bd002a8..b44a98013c89 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp @@ -12,10 +12,10 @@ Hardcoded passwords, keys, initialization vectors and salts should not be used f Attackers can easily recover hardcoded values if they have access to the source code or compiled executable.
  • - Some hardcoded values may be easily guessable. + Some hardcoded values are easily guessable.
  • - Hardcoded values may leave cryptographic operations vulnerable to dictionary attacks, rainbow tables, and other forms of cryptanalysis. + Use of hardcoded values may leave cryptographic operations vulnerable to dictionary attacks, rainbow tables, and other forms of cryptanalysis.
  • @@ -23,7 +23,7 @@ Hardcoded passwords, keys, initialization vectors and salts should not be used f

    -Use randomly generated key material, initialization vectors and salts. Use strong passwords that are not hardcoded in source code. +Use randomly generated key material, initialization vectors and salts. Use strong passwords that are not hardcoded.

    From 9af2d0218b777520f33f0a836bfc0efbdc172430 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:48:26 +0000 Subject: [PATCH 012/311] Rust: Add the new sinks to stats. --- rust/ql/src/queries/summary/Stats.qll | 3 +++ rust/ql/test/query-tests/diagnostics/SummaryStats.expected | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 4054b0bc1326..bc6e38ba67a9 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -11,6 +11,7 @@ private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency private import codeql.rust.security.SqlInjectionExtensions private import codeql.rust.security.CleartextLoggingExtensions +private import codeql.rust.security.HardcodedCryptographicValueExtensions /** * Gets a count of the total number of lines of code in the database. @@ -62,6 +63,8 @@ string getAQuerySinkKind(DataFlow::Node n) { n instanceof SqlInjection::Sink and result = "SqlInjection" or n instanceof CleartextLogging::Sink and result = "CleartextLogging" + or + n instanceof HardcodedCryptographicValue::Sink and result = "HardcodedCryptographicValue" } /** diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 7abbbba7c1bb..c87c80da8c7a 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -14,7 +14,7 @@ | Macro calls - resolved | 8 | | Macro calls - total | 9 | | Macro calls - unresolved | 1 | -| Taint edges - number of edges | 1471 | +| Taint edges - number of edges | 1475 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | From 42e7d1e983465b4da3ced5805e21c51efec84aaa Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 6 Mar 2025 19:09:01 +0000 Subject: [PATCH 013/311] Rust: Fix typo. --- .../CWE-798/HardcodedCryptographicValue.ql | 2 +- .../security/CWE-798/test_cipher.rs | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 49e8b0cf3422..3fb9d4d74a2d 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -6,7 +6,7 @@ * @problem.severity warning * @security-severity 9.8 * @precision high - * @id rust/hardcoded-crytographic-value + * @id rust/hardcoded-cryptographic-value * @tags security * external/cwe/cwe-259 * external/cwe/cwe-321 diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index cf96cf047b5f..7a5ef0572fd9 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -15,18 +15,18 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit::Key::from_slice(key)); rabbit_cipher1.apply_keystream(&mut data); - let const1: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let const1: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher2 = RabbitKeyOnly::new(rabbit::Key::from_slice(const1)); // $ Sink rabbit_cipher2.apply_keystream(&mut data); let mut rabbit_cipher3 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(iv)); rabbit_cipher3.apply_keystream(&mut data); - let const4: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let const4: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const4), rabbit::Iv::from_slice(iv)); // $ Sink rabbit_cipher4.apply_keystream(&mut data); - let const5: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-crytographic-value] + let const5: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const5)); // $ Sink rabbit_cipher5.apply_keystream(&mut data); @@ -34,20 +34,20 @@ fn test_stream_cipher_rabbit( let const6: &[u8;16] = &[0u8;16]; // (unused, so good) - let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] + let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher7 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const7)); // $ Sink rabbit_cipher7.apply_keystream(&mut data); - let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] + let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); // $ Sink rabbit_cipher8.apply_keystream(&mut data); - let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-crytographic-value] + let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] let const9_conv = unsafe { const9.align_to::().1 }; // convert [u16;8] -> [u8;8] let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); // $ Sink rabbit_cipher9.apply_keystream(&mut data); - let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ Alert[rust/hardcoded-crytographic-value] + let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ Alert[rust/hardcoded-cryptographic-value] let mut rabbit_cipher10 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const10)); // $ Sink rabbit_cipher10.apply_keystream(&mut data); } @@ -63,25 +63,25 @@ fn test_block_cipher_aes( let aes_cipher1 = Aes256::new(key256.into()); aes_cipher1.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] let aes_cipher2 = Aes256::new(const2.into()); // $ Sink aes_cipher2.encrypt_block(block128.into()); let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); aes_cipher3.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] let aes_cipher4 = Aes256::new_from_slice(const2).unwrap(); // $ Sink aes_cipher4.encrypt_block(block128.into()); let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); _ = aes_cipher5.encrypt_b2b(input, output).unwrap(); - let const6 = &[0u8;32]; // $ Alert[rust/hardcoded-crytographic-value] + let const6 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] let aes_cipher6 = cfb_mode::Encryptor::::new(const6.into(), iv.into()); // $ Sink _ = aes_cipher6.encrypt_b2b(input, output).unwrap(); - let const7 = &[0u8; 16]; // $ Alert[rust/hardcoded-crytographic-value] + let const7 = &[0u8; 16]; // $ Alert[rust/hardcoded-cryptographic-value] let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const7.into()); // $ Sink _ = aes_cipher7.encrypt_b2b(input, output).unwrap(); @@ -91,18 +91,18 @@ fn test_block_cipher_aes( let aes_cipher8 = cfb_mode::Encryptor::::new(key8.into(), iv.into()); _ = aes_cipher8.encrypt_b2b(input, output).unwrap(); - let key9: &[u8] = "1234567890123456".as_bytes(); // $ MISSING: Alert[rust/hardcoded-crytographic-value] + let key9: &[u8] = "1234567890123456".as_bytes(); // $ MISSING: Alert[rust/hardcoded-cryptographic-value] let aes_cipher9 = cfb_mode::Encryptor::::new(key9.into(), iv.into()); _ = aes_cipher9.encrypt_b2b(input, output).unwrap(); let key10: [u8; 32] = match base64::engine::general_purpose::STANDARD.decode(key_str) { Ok(x) => x.try_into().unwrap(), - Err(_) => "1234567890123456".as_bytes().try_into().unwrap() // $ MISSING: Alert[rust/hardcoded-crytographic-value] + Err(_) => "1234567890123456".as_bytes().try_into().unwrap() // $ MISSING: Alert[rust/hardcoded-cryptographic-value] }; let aes_cipher10 = Aes256::new(&key10.into()); aes_cipher10.encrypt_block(block128.into()); - if let Ok(const11) = base64::engine::general_purpose::STANDARD.decode("1234567890123456") { // $ MISSING: Alert[rust/hardcoded-crytographic-value] + if let Ok(const11) = base64::engine::general_purpose::STANDARD.decode("1234567890123456") { // $ MISSING: Alert[rust/hardcoded-cryptographic-value] let key11: [u8; 32] = const11.try_into().unwrap(); let aes_cipher11 = Aes256::new(&key11.into()); aes_cipher11.encrypt_block(block128.into()); @@ -121,14 +121,14 @@ fn test_aes_gcm( let cipher1 = Aes256Gcm::new(&key1); let _ = cipher1.encrypt(&nonce1, b"plaintext".as_ref()).unwrap(); - let key2: [u8;32] = [0;32]; // $ Alert[rust/hardcoded-crytographic-value] - let nonce2 = [0;12]; // $ Alert[rust/hardcoded-crytographic-value] + let key2: [u8;32] = [0;32]; // $ Alert[rust/hardcoded-cryptographic-value] + let nonce2 = [0;12]; // $ Alert[rust/hardcoded-cryptographic-value] let cipher2 = Aes256Gcm::new(&key2.into()); // $ Sink let _ = cipher2.encrypt(&nonce2.into(), b"plaintext".as_ref()).unwrap(); // $ Sink - let key3_array: &[u8;32] = &[0xff;32]; // $ Alert[rust/hardcoded-crytographic-value] + let key3_array: &[u8;32] = &[0xff;32]; // $ Alert[rust/hardcoded-cryptographic-value] let key3 = Key::::from_slice(key3_array); - let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hardcoded-crytographic-value] + let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hardcoded-cryptographic-value] let cipher3 = Aes256Gcm::new(&key3); // $ Sink let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); // $ Sink } From 19416a9ee3038a6c3d4bb62ce25af6c7d83c5972 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:43:34 +0000 Subject: [PATCH 014/311] Rust: Correct test results. --- .../diagnostics/SummaryStats.expected | 6 +-- .../HardcodedCryptographicValue.expected | 39 ++++++++----------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index b9a96cdecfdc..972c5f261772 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -14,11 +14,7 @@ | Macro calls - resolved | 8 | | Macro calls - total | 9 | | Macro calls - unresolved | 1 | -<<<<<<< HEAD -| Taint edges - number of edges | 1475 | -======= -| Taint edges - number of edges | 1670 | ->>>>>>> main +| Taint edges - number of edges | 1674 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index a09f89d21276..a8ce502c403a 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -19,49 +19,49 @@ edges | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:82 Sink:MaD:82 Sink:MaD:82 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:83 Sink:MaD:83 Sink:MaD:83 | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:58 Sink:MaD:58 | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:60 Sink:MaD:60 | | test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:0 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:58 Sink:MaD:58 | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:60 Sink:MaD:60 | | test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:0 | -| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:37 | const9 | provenance | | +| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:104 | | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:9:45:14 | const9 | provenance | | | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | provenance | | -| test_cipher.rs:46:32:46:37 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:104 | | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | provenance | | | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | provenance | | -| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:101 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | -| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:58 Sink:MaD:58 Sink:MaD:58 | +| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:40 | const2 [&ref, element] | provenance | | +| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:66:18:66:26 | &... [&ref, element] | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | test_cipher.rs:66:18:66:26 | &... [&ref, element] | provenance | | | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:76 Sink:MaD:76 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | @@ -69,28 +69,28 @@ edges | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:84 Sink:MaD:84 Sink:MaD:84 | | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:68 | const6 [&ref, element] | provenance | | +| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:80:18:80:26 | &... [&ref, element] | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | provenance | | | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | test_cipher.rs:80:18:80:26 | &... [&ref, element] | provenance | | | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:86 Sink:MaD:86 | | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:80 | const7 [&ref, element] | provenance | | +| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:103 | | test_cipher.rs:84:18:84:27 | &... [&ref, element] | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | provenance | | | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | test_cipher.rs:84:18:84:27 | &... [&ref, element] | provenance | | | test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:87 Sink:MaD:87 | -| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:38 | key2 [element] | provenance | | +| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:124:25:124:30 | [0; 32] [element] | test_cipher.rs:124:9:124:12 | key2 [element] | provenance | | | test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:124:25:124:30 | [0; 32] [element] | provenance | | -| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:35 | nonce2 [element] | provenance | | +| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:125:18:125:23 | [0; 12] [element] | test_cipher.rs:125:9:125:14 | nonce2 [element] | provenance | | | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:18:125:23 | [0; 12] [element] | provenance | | | test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | -| test_cipher.rs:126:35:126:38 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | test_cipher.rs:126:34:126:45 | &... [&ref, element] | provenance | | | test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | -| test_cipher.rs:127:30:127:35 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | test_cipher.rs:127:29:127:42 | &... [&ref, element] | provenance | | | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | provenance | | | test_cipher.rs:129:32:129:41 | &... [&ref, element] | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | provenance | | @@ -99,14 +99,13 @@ edges | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | provenance | | | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | provenance | | | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | -| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:35 | nonce3 [element] | provenance | | +| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | test_cipher.rs:131:9:131:14 | nonce3 [element] | provenance | | | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | provenance | | | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 Sink:MaD:90 | | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | -| test_cipher.rs:133:30:133:35 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:102 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | @@ -145,7 +144,6 @@ nodes | test_cipher.rs:45:9:45:14 | const9 | semmle.label | const9 | | test_cipher.rs:45:27:45:50 | [...] | semmle.label | [...] | | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | semmle.label | const9_conv [&ref, element] | -| test_cipher.rs:46:32:46:37 | const9 | semmle.label | const9 | | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | semmle.label | const9.align_to(...) [tuple.1, &ref, element] | | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | semmle.label | ... .1 [&ref, element] | | test_cipher.rs:47:30:47:47 | ...::new | semmle.label | ...::new | @@ -193,11 +191,9 @@ nodes | test_cipher.rs:125:19:125:19 | 0 | semmle.label | 0 | | test_cipher.rs:126:19:126:32 | ...::new | semmle.label | ...::new | | test_cipher.rs:126:34:126:45 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:126:35:126:38 | key2 [element] | semmle.label | key2 [element] | | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | semmle.label | key2.into(...) [element] | | test_cipher.rs:127:21:127:27 | encrypt | semmle.label | encrypt | | test_cipher.rs:127:29:127:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:127:30:127:35 | nonce2 [element] | semmle.label | nonce2 [element] | | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | semmle.label | nonce2.into(...) [element] | | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | semmle.label | key3_array [&ref, element] | | test_cipher.rs:129:32:129:41 | &... [&ref, element] | semmle.label | &... [&ref, element] | @@ -214,6 +210,5 @@ nodes | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | semmle.label | key3 [&ref, element] | | test_cipher.rs:133:21:133:27 | encrypt | semmle.label | encrypt | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:133:30:133:35 | nonce3 [element] | semmle.label | nonce3 [element] | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | semmle.label | nonce3.into(...) [element] | subpaths From c63c1be11ca844b686cb71c16cb0e45f668d6450 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 7 Mar 2025 16:12:31 +0000 Subject: [PATCH 015/311] Rust: Accept integration test .expected changes. --- rust/ql/integration-tests/hello-project/summary.expected | 2 +- .../ql/integration-tests/hello-workspace/summary.cargo.expected | 2 +- .../hello-workspace/summary.rust-project.expected | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 2ffb1f4e34f7..68ee47035bc1 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -14,7 +14,7 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 1670 | +| Taint edges - number of edges | 1674 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index d08ce1a41166..caf7b2b8cd9c 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -14,7 +14,7 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 1670 | +| Taint edges - number of edges | 1674 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected index d08ce1a41166..caf7b2b8cd9c 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -14,7 +14,7 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 1670 | +| Taint edges - number of edges | 1674 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | From 3dc35f1fabe6435eb65a38b5aa21f4326a3563d7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:02:26 +0000 Subject: [PATCH 016/311] Rust: Accept more test changes. --- .../dataflow/local/DataFlowStep.expected | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index e403311345cc..26ffdc13df64 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1946,6 +1946,10 @@ models | 1058 | Summary: lang:std; crate::thread::current::set_current; Argument[0]; ReturnValue.Field[crate::result::Result::Err(0)]; value | | 1059 | Summary: lang:std; crate::thread::current::try_with_current; Argument[0].ReturnValue; ReturnValue; value | | 1060 | Summary: lang:std; crate::thread::with_current_name; Argument[0].ReturnValue; ReturnValue; value | +| 1061 | Summary: repo:https://github.com/fizyk20/generic-array.git:generic-array; ::from_mut_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 1062 | Summary: repo:https://github.com/fizyk20/generic-array.git:generic-array; ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 1063 | Summary: repo:https://github.com/fizyk20/generic-array.git:generic-array; ::try_from_mut_slice; Argument[0].Reference; ReturnValue.Field[crate::result::Result::Ok(0)].Reference; value | +| 1064 | Summary: repo:https://github.com/fizyk20/generic-array.git:generic-array; ::try_from_slice; Argument[0].Reference; ReturnValue.Field[crate::result::Result::Ok(0)].Reference; value | storeStep | file://:0:0:0:0 | [summary] to write: Argument[0].Field[crate::option::Option::Some(0)] in lang:core::_::::zip_with | Some | file://:0:0:0:0 | [post] [summary param] 0 in lang:core::_::::zip_with | | file://:0:0:0:0 | [summary] to write: Argument[0].Parameter[0].Reference in lang:alloc::_::::retain | &ref | file://:0:0:0:0 | [summary] to write: Argument[0].Parameter[0] in lang:alloc::_::::retain | @@ -2034,6 +2038,7 @@ storeStep | file://:0:0:0:0 | [summary] to write: Argument[self].Reference.Reference in lang:std::_::<&[u8] as crate::io::Read>::read_to_end | &ref | file://:0:0:0:0 | [summary] to write: Argument[self].Reference in lang:std::_::<&[u8] as crate::io::Read>::read_to_end | | file://:0:0:0:0 | [summary] to write: Argument[self].Reference.Reference in lang:std::_::<&[u8] as crate::io::Read>::read_to_string | &ref | file://:0:0:0:0 | [summary] to write: Argument[self].Reference in lang:std::_::<&[u8] as crate::io::Read>::read_to_string | | file://:0:0:0:0 | [summary] to write: Argument[self].Reference.Reference in lang:std::_::<&[u8] as crate::io::copy::BufferedReaderSpec>::copy_to | &ref | file://:0:0:0:0 | [summary] to write: Argument[self].Reference in lang:std::_::<&[u8] as crate::io::copy::BufferedReaderSpec>::copy_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Element in lang:core::_::<_ as crate::convert::Into>::into | element | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<_ as crate::convert::Into>::into | | file://:0:0:0:0 | [summary] to write: ReturnValue.Element in lang:core::_::::collect | element | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::collect | | file://:0:0:0:0 | [summary] to write: ReturnValue.Element in lang:core::_::crate::cmp::minmax | element | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::crate::cmp::minmax | | file://:0:0:0:0 | [summary] to write: ReturnValue.Element in lang:core::_::crate::cmp::minmax_by | element | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::crate::cmp::minmax_by | @@ -2071,12 +2076,20 @@ storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0] in lang:core::_::::overflowing_div_euclid | tuple.0 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::overflowing_div_euclid | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0] in lang:std::_::::into_parts | tuple.0 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::into_parts | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0].Field[crate::option::Option::Some(0)] in lang:core::_::::unzip | Some | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0] in lang:core::_::::unzip | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0].Reference in lang:core::_::<[_]>::align_to | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0] in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0].Reference.Element in lang:core::_::<[_]>::align_to | element | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[0].Reference in lang:core::_::<[_]>::align_to | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:alloc::_::::find_lower_bound_edge | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::find_lower_bound_edge | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:alloc::_::::find_upper_bound_edge | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::find_upper_bound_edge | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:core::_::<[_]>::align_to | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<[_]>::align_to | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:core::_::::unzip | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unzip | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:core::_::crate::slice::sort::shared::find_existing_run | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::crate::slice::sort::shared::find_existing_run | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:std::_::::into_parts | tuple.1 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::into_parts | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1].Field[crate::option::Option::Some(0)] in lang:core::_::::unzip | Some | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:core::_::::unzip | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1].Reference in lang:core::_::<[_]>::align_to | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1] in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1].Reference.Element in lang:core::_::<[_]>::align_to | element | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[1].Reference in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[2] in lang:core::_::<[_]>::align_to | tuple.2 | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[2].Reference in lang:core::_::<[_]>::align_to | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[2] in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[2].Reference.Element in lang:core::_::<[_]>::align_to | element | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[2].Reference in lang:core::_::<[_]>::align_to | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::option::Option::Some(0)] in lang:core::_::::then | Some | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::then | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::option::Option::Some(0)] in lang:core::_::::then_some | Some | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::then_some | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::option::Option::Some(0)] in lang:core::_::::nth_back | Some | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::nth_back | @@ -2209,6 +2222,8 @@ storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::wait_while | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::wait_while | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::try_with | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::try_with | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::crate::sys::pal::unix::cvt | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::crate::sys::pal::unix::cvt | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::bytes | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::bytes | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text_with_charset | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text_with_charset | @@ -2225,6 +2240,8 @@ storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Reference in lang:core::_::::try_insert | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:core::_::::try_insert | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Reference in lang:core::_::::as_mut | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:core::_::::as_mut | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Reference in lang:core::_::::as_ref | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:core::_::::as_ref | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:alloc::_::::borrow | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::borrow | | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:alloc::_::::borrow | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::borrow | | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:alloc::_::::borrow_mut | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::borrow_mut | @@ -2304,6 +2321,8 @@ storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:std::_::::as_file_desc | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::as_file_desc | | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:std::_::<{486}::StaticStrPayload as crate::panic::PanicPayload>::get | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::<{486}::StaticStrPayload as crate::panic::PanicPayload>::get | | file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in lang:std::_::<{491}::RewrapBox as crate::panic::PanicPayload>::get | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::<{491}::RewrapBox as crate::panic::PanicPayload>::get | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_mut_slice | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_mut_slice | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_slice | &ref | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_slice | | main.rs:97:14:97:22 | source(...) | tuple.0 | main.rs:97:13:97:26 | TupleExpr | | main.rs:97:25:97:25 | 2 | tuple.1 | main.rs:97:13:97:26 | TupleExpr | | main.rs:103:14:103:14 | 2 | tuple.0 | main.rs:103:13:103:30 | TupleExpr | @@ -2493,6 +2512,10 @@ readStep | file://:0:0:0:0 | [summary param] 0 in lang:std::_::crate::sys_common::ignore_notfound | Err | file://:0:0:0:0 | [summary] read: Argument[0].Field[crate::result::Result::Err(0)] in lang:std::_::crate::sys_common::ignore_notfound | | file://:0:0:0:0 | [summary param] 0 in lang:std::_::crate::thread::current::try_with_current | function return | file://:0:0:0:0 | [summary] read: Argument[0].ReturnValue in lang:std::_::crate::thread::current::try_with_current | | file://:0:0:0:0 | [summary param] 0 in lang:std::_::crate::thread::with_current_name | function return | file://:0:0:0:0 | [summary] read: Argument[0].ReturnValue in lang:std::_::crate::thread::with_current_name | +| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_mut_slice | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_mut_slice | +| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_slice | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::from_slice | +| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_mut_slice | +| file://:0:0:0:0 | [summary param] 0 in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | &ref | file://:0:0:0:0 | [summary] read: Argument[0].Reference in repo:https://github.com/fizyk20/generic-array.git:generic-array::_::::try_from_slice | | file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::::fold | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::::fold | | file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::crate::collections::btree::mem::replace | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::crate::collections::btree::mem::replace | | file://:0:0:0:0 | [summary param] 1 in lang:alloc::_::crate::collections::btree::mem::take_mut | function return | file://:0:0:0:0 | [summary] read: Argument[1].ReturnValue in lang:alloc::_::crate::collections::btree::mem::take_mut | @@ -2629,6 +2652,9 @@ readStep | file://:0:0:0:0 | [summary param] self in lang:core::_::<&mut _ as crate::borrow::BorrowMut>::borrow_mut | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&mut _ as crate::borrow::BorrowMut>::borrow_mut | | file://:0:0:0:0 | [summary param] self in lang:core::_::<&mut _ as crate::ops::deref::Deref>::deref | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&mut _ as crate::ops::deref::Deref>::deref | | file://:0:0:0:0 | [summary param] self in lang:core::_::<&mut _ as crate::ops::deref::DerefMut>::deref_mut | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&mut _ as crate::ops::deref::DerefMut>::deref_mut | +| file://:0:0:0:0 | [summary param] self in lang:core::_::<[_]>::align_to | element | file://:0:0:0:0 | [summary] read: Argument[self].Element in lang:core::_::<[_]>::align_to | +| file://:0:0:0:0 | [summary param] self in lang:core::_::<_ as crate::convert::Into>::into | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<_ as crate::convert::Into>::into | +| file://:0:0:0:0 | [summary param] self in lang:core::_::<_ as crate::convert::Into>::into | element | file://:0:0:0:0 | [summary] read: Argument[self].Element in lang:core::_::<_ as crate::convert::Into>::into | | file://:0:0:0:0 | [summary param] self in lang:core::_::<_ as crate::str::pattern::MultiCharEq>::matches | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<_ as crate::str::pattern::MultiCharEq>::matches | | file://:0:0:0:0 | [summary param] self in lang:core::_::::clone | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::::clone | | file://:0:0:0:0 | [summary param] self in lang:core::_::::clone | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::::clone | @@ -2923,6 +2949,7 @@ readStep | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&_ as crate::borrow::Borrow>::borrow | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Reference in lang:core::_::<&_ as crate::borrow::Borrow>::borrow | | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&mut _ as crate::borrow::Borrow>::borrow | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Reference in lang:core::_::<&mut _ as crate::borrow::Borrow>::borrow | | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<&mut _ as crate::borrow::BorrowMut>::borrow_mut | &ref | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Reference in lang:core::_::<&mut _ as crate::borrow::BorrowMut>::borrow_mut | +| file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<_ as crate::convert::Into>::into | element | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Element in lang:core::_::<_ as crate::convert::Into>::into | | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::<_ as crate::str::pattern::MultiCharEq>::matches | function return | file://:0:0:0:0 | [summary] read: Argument[self].Reference.ReturnValue in lang:core::_::<_ as crate::str::pattern::MultiCharEq>::matches | | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::::as_mut | Some | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Field[crate::option::Option::Some(0)] in lang:core::_::::as_mut | | file://:0:0:0:0 | [summary] read: Argument[self].Reference in lang:core::_::::as_ref | Some | file://:0:0:0:0 | [summary] read: Argument[self].Reference.Field[crate::option::Option::Some(0)] in lang:core::_::::as_ref | From b4e710f459636b286cc344f9e0b31c9040ab5481 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:25:15 +0000 Subject: [PATCH 017/311] Rust: Add missing models (for some platforms???). --- .../rustcrypto/rustcrypto.model.yml | 3 ++ .../HardcodedCryptographicValue.expected | 54 +++++++++---------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml index 2047cfa9ebcd..3c588473514c 100644 --- a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/rustcrypto.model.yml @@ -9,6 +9,7 @@ extensions: - ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::digest", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/stainless-steel/md5:md5", "crate::compute", "Argument[0]", "hasher-input", "manual"] - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[1]", "credentials-iv", "manual"] - ["repo:https://github.com/RustCrypto/traits:cipher", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/traits:cipher", "::new", "Argument[1]", "credentials-iv", "manual"] @@ -28,6 +29,8 @@ extensions: - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] + - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new_from_slice", "Argument[0]", "credentials-key", "manual"] - ["repo:https://github.com/RustCrypto/block-ciphers:aes", "::new", "Argument[0]", "credentials-key", "manual"] diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index a8ce502c403a..726934d5d985 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -19,78 +19,78 @@ edges | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:62 Sink:MaD:62 Sink:MaD:62 | | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:60 Sink:MaD:60 | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:61 Sink:MaD:61 | | test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:0 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:60 Sink:MaD:60 | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:61 Sink:MaD:61 | | test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:0 | -| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:104 | +| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:107 | | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:9:45:14 | const9 | provenance | | | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | provenance | | | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | provenance | | | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | provenance | | -| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | +| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | -| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:101 | +| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:104 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | -| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:60 Sink:MaD:60 Sink:MaD:60 | +| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:40 | const2 [&ref, element] | provenance | | -| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:106 | | test_cipher.rs:66:18:66:26 | &... [&ref, element] | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | test_cipher.rs:66:18:66:26 | &... [&ref, element] | provenance | | | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:102 | -| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:76 Sink:MaD:76 | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:77 Sink:MaD:77 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:84 Sink:MaD:84 Sink:MaD:84 | +| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:87 Sink:MaD:87 Sink:MaD:87 | | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:68 | const6 [&ref, element] | provenance | | -| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:106 | | test_cipher.rs:80:18:80:26 | &... [&ref, element] | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | provenance | | | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | test_cipher.rs:80:18:80:26 | &... [&ref, element] | provenance | | | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:102 | -| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:86 Sink:MaD:86 | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:89 Sink:MaD:89 | | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:80 | const7 [&ref, element] | provenance | | -| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:103 | +| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:106 | | test_cipher.rs:84:18:84:27 | &... [&ref, element] | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | provenance | | | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | test_cipher.rs:84:18:84:27 | &... [&ref, element] | provenance | | | test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:102 | -| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:87 Sink:MaD:87 | -| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:90 Sink:MaD:90 | +| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:105 | | test_cipher.rs:124:25:124:30 | [0; 32] [element] | test_cipher.rs:124:9:124:12 | key2 [element] | provenance | | | test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:124:25:124:30 | [0; 32] [element] | provenance | | -| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:105 | | test_cipher.rs:125:18:125:23 | [0; 12] [element] | test_cipher.rs:125:9:125:14 | nonce2 [element] | provenance | | | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:18:125:23 | [0; 12] [element] | provenance | | -| test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | +| test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | test_cipher.rs:126:34:126:45 | &... [&ref, element] | provenance | | -| test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | +| test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | test_cipher.rs:127:29:127:42 | &... [&ref, element] | provenance | | | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | provenance | | | test_cipher.rs:129:32:129:41 | &... [&ref, element] | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | provenance | | @@ -99,13 +99,13 @@ edges | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | provenance | | | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | provenance | | | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | -| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:102 | +| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:105 | | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | test_cipher.rs:131:9:131:14 | nonce3 [element] | provenance | | | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | provenance | | -| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 | -| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:90 Sink:MaD:90 Sink:MaD:90 Sink:MaD:90 | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 Sink:MaD:93 | | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | -| test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:91 Sink:MaD:91 Sink:MaD:91 | +| test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | From e84a98bd975a4bd23ccaa6e375b205cac0d076c5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:15:23 +0000 Subject: [PATCH 018/311] Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../security/CWE-798/HardcodedCryptographicValue.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp index b44a98013c89..f3b2d8319443 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp @@ -5,7 +5,7 @@

    -Hardcoded passwords, keys, initialization vectors and salts should not be used for cryptographic operations. +Hardcoded passwords, keys, initialization vectors, and salts should not be used for cryptographic operations.

    • @@ -23,7 +23,7 @@ Hardcoded passwords, keys, initialization vectors and salts should not be used f

      -Use randomly generated key material, initialization vectors and salts. Use strong passwords that are not hardcoded. +Use randomly generated key material, initialization vectors, and salts. Use strong passwords that are not hardcoded.

      From a34f9bef2b271019505276215e7c2d1b29e38c3a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:33:29 +0000 Subject: [PATCH 019/311] Rust: Add a test case for getrandom. --- .../HardcodedCryptographicValue.expected | 24 +++++++++++++++++++ .../query-tests/security/CWE-798/options.yml | 2 ++ .../security/CWE-798/test_cipher.rs | 9 +++++++ 3 files changed, 35 insertions(+) diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 726934d5d985..17ac5044b05b 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -14,6 +14,8 @@ | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:127:21:127:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:127:21:127:27 | encrypt | a nonce | | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:132:19:132:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:132:19:132:32 | ...::new | a key | | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:133:21:133:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:133:21:133:27 | encrypt | a nonce | +| test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:141:19:141:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:141:19:141:32 | ...::new | a key | +| test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:142:21:142:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:142:21:142:27 | encrypt | a nonce | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | @@ -107,6 +109,16 @@ edges | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | +| test_cipher.rs:137:9:137:16 | mut key4 [element] | test_cipher.rs:141:35:141:45 | key4.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | test_cipher.rs:137:9:137:16 | mut key4 [element] | provenance | | +| test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | provenance | | +| test_cipher.rs:138:9:138:18 | mut nonce4 [element] | test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | test_cipher.rs:138:9:138:18 | mut nonce4 [element] | provenance | | +| test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | provenance | | +| test_cipher.rs:141:34:141:45 | &... [&ref, element] | test_cipher.rs:141:19:141:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | +| test_cipher.rs:141:35:141:45 | key4.into(...) [element] | test_cipher.rs:141:34:141:45 | &... [&ref, element] | provenance | | +| test_cipher.rs:142:29:142:42 | &... [&ref, element] | test_cipher.rs:142:21:142:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | +| test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | test_cipher.rs:142:29:142:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | @@ -211,4 +223,16 @@ nodes | test_cipher.rs:133:21:133:27 | encrypt | semmle.label | encrypt | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | semmle.label | nonce3.into(...) [element] | +| test_cipher.rs:137:9:137:16 | mut key4 [element] | semmle.label | mut key4 [element] | +| test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | +| test_cipher.rs:137:21:137:23 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:138:9:138:18 | mut nonce4 [element] | semmle.label | mut nonce4 [element] | +| test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | semmle.label | [0u8; 12] [element] | +| test_cipher.rs:138:23:138:25 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:141:19:141:32 | ...::new | semmle.label | ...::new | +| test_cipher.rs:141:34:141:45 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:141:35:141:45 | key4.into(...) [element] | semmle.label | key4.into(...) [element] | +| test_cipher.rs:142:21:142:27 | encrypt | semmle.label | encrypt | +| test_cipher.rs:142:29:142:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | +| test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | semmle.label | nonce4.into(...) [element] | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-798/options.yml b/rust/ql/test/query-tests/security/CWE-798/options.yml index aff715ea271b..6713251d3ebd 100644 --- a/rust/ql/test/query-tests/security/CWE-798/options.yml +++ b/rust/ql/test/query-tests/security/CWE-798/options.yml @@ -6,3 +6,5 @@ qltest_dependencies: - aes-gcm = { version = "0.10.3" } - cfb-mode = { version = "0.8.2" } - base64 = { version = "0.22.1" } + - getrandom = { version = "0.3.1" } + - getrandom2 = { package = "getrandom", version = "0.2.15" } diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index 7a5ef0572fd9..a72eaebb303f 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -131,4 +131,13 @@ fn test_aes_gcm( let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hardcoded-cryptographic-value] let cipher3 = Aes256Gcm::new(&key3); // $ Sink let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); // $ Sink + + // with barrier + + let mut key4 = [0u8;32]; // $ SPURIOUS: Alert[rust/hardcoded-cryptographic-value] + let mut nonce4 = [0u8;12]; // $ SPURIOUS: Alert[rust/hardcoded-cryptographic-value] + _ = getrandom::fill(&mut key4).unwrap(); + _ = getrandom2::getrandom(&mut nonce4).unwrap(); + let cipher4 = Aes256Gcm::new(&key4.into()); // $ Sink + let _ = cipher2.encrypt(&nonce4.into(), b"plaintext".as_ref()).unwrap(); // $ Sink } From 9e54d5353743bdff81581b465c1914e3899cbee2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:40:29 +0000 Subject: [PATCH 020/311] Rust: Add barrier. --- .../HardcodedCryptographicValueExtensions.qll | 14 +++++++++++ .../HardcodedCryptographicValue.expected | 24 ------------------- .../security/CWE-798/test_cipher.rs | 8 +++---- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 32f64051fcb3..b6ed9d6091ef 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -89,4 +89,18 @@ module HardcodedCryptographicValue { override CryptographicValueKind getKind() { result = kind } } + + /** + * A call to `getrandom` that is a barrier. + */ + private class GetRandomBarrier extends Barrier { + GetRandomBarrier() { + exists(CallExpr ce | + ce.getFunction().(PathExpr).getResolvedCrateOrigin() = + "repo:https://github.com/rust-random/getrandom:getrandom" and + ce.getFunction().(PathExpr).getResolvedPath() = ["crate::fill", "crate::getrandom"] and + this.asExpr().getExpr().getParentNode*() = ce.getArgList().getArg(0) + ) + } + } } diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 17ac5044b05b..726934d5d985 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -14,8 +14,6 @@ | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:127:21:127:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:127:21:127:27 | encrypt | a nonce | | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:132:19:132:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:132:19:132:32 | ...::new | a key | | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:133:21:133:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:133:21:133:27 | encrypt | a nonce | -| test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:141:19:141:32 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:141:19:141:32 | ...::new | a key | -| test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:142:21:142:27 | encrypt | This hard-coded value is used as $@. | test_cipher.rs:142:21:142:27 | encrypt | a nonce | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | @@ -109,16 +107,6 @@ edges | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | -| test_cipher.rs:137:9:137:16 | mut key4 [element] | test_cipher.rs:141:35:141:45 | key4.into(...) [element] | provenance | MaD:105 | -| test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | test_cipher.rs:137:9:137:16 | mut key4 [element] | provenance | | -| test_cipher.rs:137:21:137:23 | 0u8 | test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:138:9:138:18 | mut nonce4 [element] | test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | provenance | MaD:105 | -| test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | test_cipher.rs:138:9:138:18 | mut nonce4 [element] | provenance | | -| test_cipher.rs:138:23:138:25 | 0u8 | test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | provenance | | -| test_cipher.rs:141:34:141:45 | &... [&ref, element] | test_cipher.rs:141:19:141:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | -| test_cipher.rs:141:35:141:45 | key4.into(...) [element] | test_cipher.rs:141:34:141:45 | &... [&ref, element] | provenance | | -| test_cipher.rs:142:29:142:42 | &... [&ref, element] | test_cipher.rs:142:21:142:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | -| test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | test_cipher.rs:142:29:142:42 | &... [&ref, element] | provenance | | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | @@ -223,16 +211,4 @@ nodes | test_cipher.rs:133:21:133:27 | encrypt | semmle.label | encrypt | | test_cipher.rs:133:29:133:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | semmle.label | nonce3.into(...) [element] | -| test_cipher.rs:137:9:137:16 | mut key4 [element] | semmle.label | mut key4 [element] | -| test_cipher.rs:137:20:137:27 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | -| test_cipher.rs:137:21:137:23 | 0u8 | semmle.label | 0u8 | -| test_cipher.rs:138:9:138:18 | mut nonce4 [element] | semmle.label | mut nonce4 [element] | -| test_cipher.rs:138:22:138:29 | [0u8; 12] [element] | semmle.label | [0u8; 12] [element] | -| test_cipher.rs:138:23:138:25 | 0u8 | semmle.label | 0u8 | -| test_cipher.rs:141:19:141:32 | ...::new | semmle.label | ...::new | -| test_cipher.rs:141:34:141:45 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:141:35:141:45 | key4.into(...) [element] | semmle.label | key4.into(...) [element] | -| test_cipher.rs:142:21:142:27 | encrypt | semmle.label | encrypt | -| test_cipher.rs:142:29:142:42 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:142:30:142:42 | nonce4.into(...) [element] | semmle.label | nonce4.into(...) [element] | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index a72eaebb303f..2bf36213176f 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -134,10 +134,10 @@ fn test_aes_gcm( // with barrier - let mut key4 = [0u8;32]; // $ SPURIOUS: Alert[rust/hardcoded-cryptographic-value] - let mut nonce4 = [0u8;12]; // $ SPURIOUS: Alert[rust/hardcoded-cryptographic-value] + let mut key4 = [0u8;32]; + let mut nonce4 = [0u8;12]; _ = getrandom::fill(&mut key4).unwrap(); _ = getrandom2::getrandom(&mut nonce4).unwrap(); - let cipher4 = Aes256Gcm::new(&key4.into()); // $ Sink - let _ = cipher2.encrypt(&nonce4.into(), b"plaintext".as_ref()).unwrap(); // $ Sink + let cipher4 = Aes256Gcm::new(&key4.into()); + let _ = cipher2.encrypt(&nonce4.into(), b"plaintext".as_ref()).unwrap(); } From 1ca5c593f9713f80973a52ee7d49055d568eb34d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:47:23 +0000 Subject: [PATCH 021/311] Rust: Replace imports of internal.DataFlowImpl where possible. --- .../ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll | 2 +- .../rust/security/HardcodedCryptographicValueExtensions.qll | 3 ++- rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll | 2 +- rust/ql/src/queries/summary/Stats.qll | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll b/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll index bfe6da7ac82c..a2e737627b5f 100644 --- a/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll @@ -5,7 +5,7 @@ import rust private import codeql.rust.dataflow.DataFlow -private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.dataflow.FlowSink private import codeql.rust.security.SensitiveData /** diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index b6ed9d6091ef..5497cc0c99da 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -5,7 +5,8 @@ import rust private import codeql.rust.dataflow.DataFlow -private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.dataflow.FlowSource +private import codeql.rust.dataflow.FlowSink private import codeql.rust.security.SensitiveData /** diff --git a/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll b/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll index 4de712080044..78b87e4715b3 100644 --- a/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll @@ -6,7 +6,7 @@ import rust private import codeql.rust.dataflow.DataFlow -private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.dataflow.FlowSink private import codeql.rust.Concepts private import codeql.util.Unit diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 04c4bcf4e179..85e3357e680e 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -4,7 +4,6 @@ import rust private import codeql.rust.dataflow.DataFlow -private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.dataflow.internal.TaintTrackingImpl private import codeql.rust.internal.AstConsistency as AstConsistency private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency From e3beacbda20020f53c883d28c3302d9e61032453 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 10 Mar 2025 19:35:59 +0000 Subject: [PATCH 022/311] Rust: Print models (temporary, to see how this differs on CI). --- .../HardcodedCryptographicValue.expected | 84 +++++++++++-------- .../CWE-798/HardcodedCryptographicValue.qlref | 4 +- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 726934d5d985..86c2812d1620 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -19,78 +19,78 @@ edges | test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | -| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | +| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | -| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | +| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:62 Sink:MaD:62 Sink:MaD:62 | -| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 | +| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:61 Sink:MaD:61 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:0 | +| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:61 Sink:MaD:61 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:0 | -| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:107 | +| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 | +| test_cipher.rs:45:9:45:14 | const9 | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | provenance | MaD:10 | | test_cipher.rs:45:27:45:50 | [...] | test_cipher.rs:45:9:45:14 | const9 | provenance | | | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | provenance | | | test_cipher.rs:46:32:46:54 | const9.align_to(...) [tuple.1, &ref, element] | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | provenance | | | test_cipher.rs:46:32:46:56 | ... .1 [&ref, element] | test_cipher.rs:46:9:46:19 | const9_conv [&ref, element] | provenance | | -| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | -| test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | test_cipher.rs:47:30:47:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | +| test_cipher.rs:47:73:47:83 | const9_conv [&ref, element] | test_cipher.rs:47:49:47:84 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | -| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:104 | +| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:9 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | -| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:61 Sink:MaD:61 Sink:MaD:61 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | +| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:40 | const2 [&ref, element] | provenance | | -| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:106 | +| test_cipher.rs:66:9:66:14 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:12 | | test_cipher.rs:66:18:66:26 | &... [&ref, element] | test_cipher.rs:66:9:66:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | test_cipher.rs:66:18:66:26 | &... [&ref, element] | provenance | | | test_cipher.rs:66:20:66:22 | 0u8 | test_cipher.rs:66:19:66:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:105 | -| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:77 Sink:MaD:77 | +| test_cipher.rs:67:35:67:40 | const2 [&ref, element] | test_cipher.rs:67:35:67:47 | const2.into(...) [element] | provenance | MaD:11 | +| test_cipher.rs:67:35:67:47 | const2.into(...) [element] | test_cipher.rs:67:23:67:33 | ...::new | provenance | MaD:2 Sink:MaD:2 | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:87 Sink:MaD:87 Sink:MaD:87 | +| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:8 Sink:MaD:8 Sink:MaD:8 | | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:68 | const6 [&ref, element] | provenance | | -| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:106 | +| test_cipher.rs:80:9:80:14 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:12 | | test_cipher.rs:80:18:80:26 | &... [&ref, element] | test_cipher.rs:80:9:80:14 | const6 [&ref, element] | provenance | | | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | test_cipher.rs:80:18:80:26 | &... [&ref, element] | provenance | | | test_cipher.rs:80:20:80:22 | 0u8 | test_cipher.rs:80:19:80:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:105 | -| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:89 Sink:MaD:89 | +| test_cipher.rs:81:63:81:68 | const6 [&ref, element] | test_cipher.rs:81:63:81:75 | const6.into(...) [element] | provenance | MaD:11 | +| test_cipher.rs:81:63:81:75 | const6.into(...) [element] | test_cipher.rs:81:23:81:61 | ...::new | provenance | MaD:7 Sink:MaD:7 | | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:80 | const7 [&ref, element] | provenance | | -| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:106 | +| test_cipher.rs:84:9:84:14 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:12 | | test_cipher.rs:84:18:84:27 | &... [&ref, element] | test_cipher.rs:84:9:84:14 | const7 [&ref, element] | provenance | | | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | test_cipher.rs:84:18:84:27 | &... [&ref, element] | provenance | | | test_cipher.rs:84:20:84:22 | 0u8 | test_cipher.rs:84:19:84:27 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:105 | -| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:90 Sink:MaD:90 | -| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:85:75:85:80 | const7 [&ref, element] | test_cipher.rs:85:75:85:87 | const7.into(...) [element] | provenance | MaD:11 | +| test_cipher.rs:85:75:85:87 | const7.into(...) [element] | test_cipher.rs:85:23:85:61 | ...::new | provenance | MaD:6 Sink:MaD:6 | +| test_cipher.rs:124:9:124:12 | key2 [element] | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | provenance | MaD:11 | | test_cipher.rs:124:25:124:30 | [0; 32] [element] | test_cipher.rs:124:9:124:12 | key2 [element] | provenance | | | test_cipher.rs:124:26:124:26 | 0 | test_cipher.rs:124:25:124:30 | [0; 32] [element] | provenance | | -| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:125:9:125:14 | nonce2 [element] | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | provenance | MaD:11 | | test_cipher.rs:125:18:125:23 | [0; 12] [element] | test_cipher.rs:125:9:125:14 | nonce2 [element] | provenance | | | test_cipher.rs:125:19:125:19 | 0 | test_cipher.rs:125:18:125:23 | [0; 12] [element] | provenance | | -| test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | +| test_cipher.rs:126:34:126:45 | &... [&ref, element] | test_cipher.rs:126:19:126:32 | ...::new | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | | test_cipher.rs:126:35:126:45 | key2.into(...) [element] | test_cipher.rs:126:34:126:45 | &... [&ref, element] | provenance | | -| test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | +| test_cipher.rs:127:29:127:42 | &... [&ref, element] | test_cipher.rs:127:21:127:27 | encrypt | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:127:30:127:42 | nonce2.into(...) [element] | test_cipher.rs:127:29:127:42 | &... [&ref, element] | provenance | | | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | provenance | | | test_cipher.rs:129:32:129:41 | &... [&ref, element] | test_cipher.rs:129:9:129:18 | key3_array [&ref, element] | provenance | | @@ -98,15 +98,29 @@ edges | test_cipher.rs:129:34:129:37 | 0xff | test_cipher.rs:129:33:129:41 | [0xff; 32] [element] | provenance | | | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | provenance | | | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | test_cipher.rs:130:9:130:12 | key3 [&ref, element] | provenance | | -| test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | provenance | MaD:0 | -| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:105 | +| test_cipher.rs:130:45:130:54 | key3_array [&ref, element] | test_cipher.rs:130:16:130:55 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | +| test_cipher.rs:131:9:131:14 | nonce3 [element] | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | provenance | MaD:11 | | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | test_cipher.rs:131:9:131:14 | nonce3 [element] | provenance | | | test_cipher.rs:131:28:131:31 | 0xff | test_cipher.rs:131:27:131:35 | [0xff; 12] [element] | provenance | | -| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 | -| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:93 Sink:MaD:93 Sink:MaD:93 Sink:MaD:93 | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | test_cipher.rs:132:19:132:32 | ...::new | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 Sink:MaD:1 | | test_cipher.rs:132:35:132:38 | key3 [&ref, element] | test_cipher.rs:132:34:132:38 | &key3 [&ref, &ref, element] | provenance | | -| test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:94 Sink:MaD:94 Sink:MaD:94 | +| test_cipher.rs:133:29:133:42 | &... [&ref, element] | test_cipher.rs:133:21:133:27 | encrypt | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:133:30:133:42 | nonce3.into(...) [element] | test_cipher.rs:133:29:133:42 | &... [&ref, element] | provenance | | +models +| 1 | Sink: repo:https://github.com/RustCrypto/AEADs:aes-gcm; ::new; credentials-key; Argument[0] | +| 2 | Sink: repo:https://github.com/RustCrypto/block-ciphers:aes; ::new; credentials-key; Argument[0] | +| 3 | Sink: repo:https://github.com/RustCrypto/traits:aead; <_ as crate::Aead>::encrypt; credentials-nonce; Argument[0] | +| 4 | Sink: repo:https://github.com/RustCrypto/traits:cipher; ::new; credentials-iv; Argument[1] | +| 5 | Sink: repo:https://github.com/RustCrypto/traits:cipher; ::new; credentials-key; Argument[0] | +| 6 | Sink: repo:https://github.com/RustCrypto/traits:crypto-common; <_ as crate::KeyIvInit>::new; credentials-iv; Argument[1] | +| 7 | Sink: repo:https://github.com/RustCrypto/traits:crypto-common; <_ as crate::KeyIvInit>::new; credentials-key; Argument[0] | +| 8 | Sink: repo:https://github.com/RustCrypto/traits:crypto-common; crate::KeyInit::new_from_slice; credentials-key; Argument[0] | +| 9 | Source: lang:core; crate::mem::zeroed; constant-source; ReturnValue.Element | +| 10 | Summary: lang:core; <[_]>::align_to; Argument[self].Element; ReturnValue.Field[0,1,2].Reference.Element; taint | +| 11 | Summary: lang:core; <_ as crate::convert::Into>::into; Argument[self].Element; ReturnValue.Element; taint | +| 12 | Summary: lang:core; <_ as crate::convert::Into>::into; Argument[self].Reference.Element; ReturnValue.Element; taint | +| 13 | Summary: repo:https://github.com/fizyk20/generic-array.git:generic-array; ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref index 99053e9bf1a9..77c0b90160ca 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.qlref @@ -1,2 +1,4 @@ query: queries/security/CWE-798/HardcodedCryptographicValue.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql From a0f4fa28b2a50a077c380646bb2828da85b3426d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 11 Mar 2025 09:30:01 +0000 Subject: [PATCH 023/311] Rust: hardcoded -> hard-coded. --- .../HardcodedCryptographicValueExtensions.qll | 12 +++---- .../CWE-798/HardcodedCryptographicValue.qhelp | 14 ++++---- .../CWE-798/HardcodedCryptographicValue.ql | 6 ++-- .../CWE-798/HardcodedCryptographicValueBad.rs | 2 +- .../security/CWE-798/test_cipher.rs | 36 +++++++++---------- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 5497cc0c99da..80fdcfd217e6 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -1,5 +1,5 @@ /** - * Provides classes and predicates for reasoning about hardcoded cryptographic value + * Provides classes and predicates for reasoning about hard-coded cryptographic value * vulnerabilities. */ @@ -32,17 +32,17 @@ class CryptographicValueKind extends string { } /** - * Provides default sources, sinks and barriers for detecting hardcoded cryptographic + * Provides default sources, sinks and barriers for detecting hard-coded cryptographic * value vulnerabilities, as well as extension points for adding your own. */ module HardcodedCryptographicValue { /** - * A data flow source for hardcoded cryptographic value vulnerabilities. + * A data flow source for hard-coded cryptographic value vulnerabilities. */ abstract class Source extends DataFlow::Node { } /** - * A data flow sink for hardcoded cryptographic value vulnerabilities. + * A data flow sink for hard-coded cryptographic value vulnerabilities. */ abstract class Sink extends DataFlow::Node { /** @@ -52,7 +52,7 @@ module HardcodedCryptographicValue { } /** - * A barrier for hardcoded cryptographic value vulnerabilities. + * A barrier for hard-coded cryptographic value vulnerabilities. */ abstract class Barrier extends DataFlow::Node { } @@ -81,7 +81,7 @@ module HardcodedCryptographicValue { } /** - * An externally modeled sink for hardcoded cryptographic value vulnerabilities. + * An externally modeled sink for hard-coded cryptographic value vulnerabilities. */ private class ModelsAsDataSinks extends Sink { CryptographicValueKind kind; diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp index f3b2d8319443..3a6813cdef09 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.qhelp @@ -5,17 +5,17 @@

      -Hardcoded passwords, keys, initialization vectors, and salts should not be used for cryptographic operations. +Hard-coded passwords, keys, initialization vectors, and salts should not be used for cryptographic operations.

      • - Attackers can easily recover hardcoded values if they have access to the source code or compiled executable. + Attackers can easily recover hard-coded values if they have access to the source code or compiled executable.
      • - Some hardcoded values are easily guessable. + Some hard-coded values are easily guessable.
      • - Use of hardcoded values may leave cryptographic operations vulnerable to dictionary attacks, rainbow tables, and other forms of cryptanalysis. + Use of hard-coded values may leave cryptographic operations vulnerable to dictionary attacks, rainbow tables, and other forms of cryptanalysis.
      @@ -23,20 +23,20 @@ Hardcoded passwords, keys, initialization vectors, and salts should not be used

      -Use randomly generated key material, initialization vectors, and salts. Use strong passwords that are not hardcoded. +Use randomly generated key material, initialization vectors, and salts. Use strong passwords that are not hard-coded.

      -The following example shows instantiating a cipher with hardcoded key material, making the encrypted data vulnerable to recovery. +The following example shows instantiating a cipher with hard-coded key material, making the encrypted data vulnerable to recovery.

      -In the fixed code below, the key material is randomly generated and not hardcoded, which protects the encrypted data against recovery. A real application would also need a strategy for secure key management after the key has been generated. +In the fixed code below, the key material is randomly generated and not hard-coded, which protects the encrypted data against recovery. A real application would also need a strategy for secure key management after the key has been generated.

      diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index 3fb9d4d74a2d..fee36ba2ab21 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -1,12 +1,12 @@ /** * @name Hard-coded cryptographic value - * @description Using hardcoded keys, passwords, salts or initialization + * @description Using hard-coded keys, passwords, salts or initialization * vectors is not secure. * @kind path-problem * @problem.severity warning * @security-severity 9.8 * @precision high - * @id rust/hardcoded-cryptographic-value + * @id rust/hard-coded-cryptographic-value * @tags security * external/cwe/cwe-259 * external/cwe/cwe-321 @@ -21,7 +21,7 @@ import codeql.rust.dataflow.TaintTracking import codeql.rust.dataflow.internal.DataFlowImpl /** - * A taint-tracking configuration for hardcoded cryptographic value vulnerabilities. + * A taint-tracking configuration for hard-coded cryptographic value vulnerabilities. */ module HardcodedCryptographicValueConfig implements DataFlow::ConfigSig { import HardcodedCryptographicValue diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs index c1923df1730f..11dacfc08c42 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValueBad.rs @@ -1,2 +1,2 @@ -let key: [u8;32] = [0;32]; // BAD: Using hardcoded keys for encryption +let key: [u8;32] = [0;32]; // BAD: Using hard-coded keys for encryption let cipher = Aes256Gcm::new(&key.into()); diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index 2bf36213176f..fc7a464e70c5 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -15,18 +15,18 @@ fn test_stream_cipher_rabbit( let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit::Key::from_slice(key)); rabbit_cipher1.apply_keystream(&mut data); - let const1: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] + let const1: &[u8;16] = &[0u8;16]; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher2 = RabbitKeyOnly::new(rabbit::Key::from_slice(const1)); // $ Sink rabbit_cipher2.apply_keystream(&mut data); let mut rabbit_cipher3 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(iv)); rabbit_cipher3.apply_keystream(&mut data); - let const4: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] + let const4: &[u8;16] = &[0u8;16]; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher4 = Rabbit::new(rabbit::Key::from_slice(const4), rabbit::Iv::from_slice(iv)); // $ Sink rabbit_cipher4.apply_keystream(&mut data); - let const5: &[u8;16] = &[0u8;16]; // $ Alert[rust/hardcoded-cryptographic-value] + let const5: &[u8;16] = &[0u8;16]; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher5 = Rabbit::new(rabbit::Key::from_slice(key), rabbit::Iv::from_slice(const5)); // $ Sink rabbit_cipher5.apply_keystream(&mut data); @@ -34,20 +34,20 @@ fn test_stream_cipher_rabbit( let const6: &[u8;16] = &[0u8;16]; // (unused, so good) - let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] + let const7: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher7 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const7)); // $ Sink rabbit_cipher7.apply_keystream(&mut data); - let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] + let const8: &[u8;16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher8 = RabbitKeyOnly::new(rabbit::Key::from_slice(const8)); // $ Sink rabbit_cipher8.apply_keystream(&mut data); - let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hardcoded-cryptographic-value] + let const9: [u16;8] = [0, 0, 0, 0, 0, 0, 0, 0]; // $ Alert[rust/hard-coded-cryptographic-value] let const9_conv = unsafe { const9.align_to::().1 }; // convert [u16;8] -> [u8;8] let mut rabbit_cipher9 = RabbitKeyOnly::new(rabbit::Key::from_slice(const9_conv)); // $ Sink rabbit_cipher9.apply_keystream(&mut data); - let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ Alert[rust/hardcoded-cryptographic-value] + let const10: [u8;16] = unsafe { std::mem::zeroed() }; // $ Alert[rust/hard-coded-cryptographic-value] let mut rabbit_cipher10 = RabbitKeyOnly::new(rabbit::Key::from_slice(&const10)); // $ Sink rabbit_cipher10.apply_keystream(&mut data); } @@ -63,25 +63,25 @@ fn test_block_cipher_aes( let aes_cipher1 = Aes256::new(key256.into()); aes_cipher1.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] + let const2 = &[0u8;32]; // $ Alert[rust/hard-coded-cryptographic-value] let aes_cipher2 = Aes256::new(const2.into()); // $ Sink aes_cipher2.encrypt_block(block128.into()); let aes_cipher3 = Aes256::new_from_slice(key256).unwrap(); aes_cipher3.encrypt_block(block128.into()); - let const2 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] + let const2 = &[0u8;32]; // $ Alert[rust/hard-coded-cryptographic-value] let aes_cipher4 = Aes256::new_from_slice(const2).unwrap(); // $ Sink aes_cipher4.encrypt_block(block128.into()); let aes_cipher5 = cfb_mode::Encryptor::::new(key.into(), iv.into()); _ = aes_cipher5.encrypt_b2b(input, output).unwrap(); - let const6 = &[0u8;32]; // $ Alert[rust/hardcoded-cryptographic-value] + let const6 = &[0u8;32]; // $ Alert[rust/hard-coded-cryptographic-value] let aes_cipher6 = cfb_mode::Encryptor::::new(const6.into(), iv.into()); // $ Sink _ = aes_cipher6.encrypt_b2b(input, output).unwrap(); - let const7 = &[0u8; 16]; // $ Alert[rust/hardcoded-cryptographic-value] + let const7 = &[0u8; 16]; // $ Alert[rust/hard-coded-cryptographic-value] let aes_cipher7 = cfb_mode::Encryptor::::new(key.into(), const7.into()); // $ Sink _ = aes_cipher7.encrypt_b2b(input, output).unwrap(); @@ -91,18 +91,18 @@ fn test_block_cipher_aes( let aes_cipher8 = cfb_mode::Encryptor::::new(key8.into(), iv.into()); _ = aes_cipher8.encrypt_b2b(input, output).unwrap(); - let key9: &[u8] = "1234567890123456".as_bytes(); // $ MISSING: Alert[rust/hardcoded-cryptographic-value] + let key9: &[u8] = "1234567890123456".as_bytes(); // $ MISSING: Alert[rust/hard-coded-cryptographic-value] let aes_cipher9 = cfb_mode::Encryptor::::new(key9.into(), iv.into()); _ = aes_cipher9.encrypt_b2b(input, output).unwrap(); let key10: [u8; 32] = match base64::engine::general_purpose::STANDARD.decode(key_str) { Ok(x) => x.try_into().unwrap(), - Err(_) => "1234567890123456".as_bytes().try_into().unwrap() // $ MISSING: Alert[rust/hardcoded-cryptographic-value] + Err(_) => "1234567890123456".as_bytes().try_into().unwrap() // $ MISSING: Alert[rust/hard-coded-cryptographic-value] }; let aes_cipher10 = Aes256::new(&key10.into()); aes_cipher10.encrypt_block(block128.into()); - if let Ok(const11) = base64::engine::general_purpose::STANDARD.decode("1234567890123456") { // $ MISSING: Alert[rust/hardcoded-cryptographic-value] + if let Ok(const11) = base64::engine::general_purpose::STANDARD.decode("1234567890123456") { // $ MISSING: Alert[rust/hard-coded-cryptographic-value] let key11: [u8; 32] = const11.try_into().unwrap(); let aes_cipher11 = Aes256::new(&key11.into()); aes_cipher11.encrypt_block(block128.into()); @@ -121,14 +121,14 @@ fn test_aes_gcm( let cipher1 = Aes256Gcm::new(&key1); let _ = cipher1.encrypt(&nonce1, b"plaintext".as_ref()).unwrap(); - let key2: [u8;32] = [0;32]; // $ Alert[rust/hardcoded-cryptographic-value] - let nonce2 = [0;12]; // $ Alert[rust/hardcoded-cryptographic-value] + let key2: [u8;32] = [0;32]; // $ Alert[rust/hard-coded-cryptographic-value] + let nonce2 = [0;12]; // $ Alert[rust/hard-coded-cryptographic-value] let cipher2 = Aes256Gcm::new(&key2.into()); // $ Sink let _ = cipher2.encrypt(&nonce2.into(), b"plaintext".as_ref()).unwrap(); // $ Sink - let key3_array: &[u8;32] = &[0xff;32]; // $ Alert[rust/hardcoded-cryptographic-value] + let key3_array: &[u8;32] = &[0xff;32]; // $ Alert[rust/hard-coded-cryptographic-value] let key3 = Key::::from_slice(key3_array); - let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hardcoded-cryptographic-value] + let nonce3: [u8;12] = [0xff;12]; // $ Alert[rust/hard-coded-cryptographic-value] let cipher3 = Aes256Gcm::new(&key3); // $ Sink let _ = cipher3.encrypt(&nonce3.into(), b"plaintext".as_ref()).unwrap(); // $ Sink From 704b3850f42d5b3750238464ccbd468d37d0af46 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 17 Mar 2025 11:24:58 +0000 Subject: [PATCH 024/311] Rust: Fix a mistake in the test. --- rust/ql/test/query-tests/security/CWE-798/test_cipher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs index fc7a464e70c5..79dfbabbd989 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_cipher.rs @@ -139,5 +139,5 @@ fn test_aes_gcm( _ = getrandom::fill(&mut key4).unwrap(); _ = getrandom2::getrandom(&mut nonce4).unwrap(); let cipher4 = Aes256Gcm::new(&key4.into()); - let _ = cipher2.encrypt(&nonce4.into(), b"plaintext".as_ref()).unwrap(); + let _ = cipher4.encrypt(&nonce4.into(), b"plaintext".as_ref()).unwrap(); } From f5daec9da0fef7b56a2b0f4df6bd2e0b59079495 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 17 Mar 2025 12:10:59 +0000 Subject: [PATCH 025/311] Rust: Fix after merge. --- .../src/queries/security/CWE-798/HardcodedCryptographicValue.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index fee36ba2ab21..cd0dca79119b 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -19,6 +19,7 @@ import codeql.rust.security.HardcodedCryptographicValueExtensions import codeql.rust.dataflow.DataFlow import codeql.rust.dataflow.TaintTracking import codeql.rust.dataflow.internal.DataFlowImpl +import codeql.rust.dataflow.internal.Content /** * A taint-tracking configuration for hard-coded cryptographic value vulnerabilities. From 07011f74601fd7fc54848a1ac53534f43ba56ca8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 17 Mar 2025 12:22:09 +0000 Subject: [PATCH 026/311] Rust: Fix more after merge. --- rust/ql/src/queries/summary/Stats.qll | 3 --- 1 file changed, 3 deletions(-) diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index c1914f68ed81..0df8a8b317f8 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -69,7 +69,6 @@ int getTaintEdgesCount() { } /** -<<<<<<< HEAD * Gets a kind of query for which `n` is a sink (if any). */ string getAQuerySinkKind(DataFlow::Node n) { @@ -81,8 +80,6 @@ string getAQuerySinkKind(DataFlow::Node n) { } /** -======= ->>>>>>> main * Gets a count of the total number of query sinks in the database. */ int getQuerySinksCount() { result = count(QuerySink s) } From f96a250ffc511b3d710ef2cb26b896c27aa520f3 Mon Sep 17 00:00:00 2001 From: Lindsay Simpkins Date: Mon, 9 Jun 2025 18:36:44 -0400 Subject: [PATCH 027/311] fix qhelp files --- .../src/Metrics/Classes/CNumberOfFunctions.qhelp | 11 +++-------- cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp | 12 ++++-------- .../src/Metrics/RefTypes/TInheritanceDepth.qhelp | 14 ++++---------- .../src/Metrics/RefTypes/TNumberOfCallables.qhelp | 12 ++++-------- java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp | 2 -- java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp | 12 ++++-------- 6 files changed, 19 insertions(+), 44 deletions(-) diff --git a/cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp b/cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp index cc62cb50f498..8ef045c70923 100644 --- a/cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp +++ b/cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp @@ -49,21 +49,16 @@ need to be part of the class. (A classic example of this is the observes, there are at least two key problems with this approach: -
        -
      • -It may be possible to generalize some of the utility functions beyond the +1. It may be possible to generalize some of the utility functions beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. -
      • -
      • -It's usually impossible for the class author to know every possible +2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility functions will end up having a different syntax to the privileged public functions in the class, negatively impacting on code consistency. -
      • -
      + To refactor a class like this, simply move its utility functions elsewhere, paring its public interface down to the bare minimum. diff --git a/cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp b/cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp index 0d560f920aa6..70c4c862fb61 100644 --- a/cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp +++ b/cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp @@ -46,21 +46,17 @@ need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: -
        -
      • -It may be possible to generalize some of the utility functions beyond the + +1. It may be possible to generalize some of the utility functions beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. -
      • -
      • -It's usually impossible for the class author to know every possible +2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility functions will end up having a different syntax to the privileged public functions in the class, negatively impacting on code consistency. -
      • -
      + To refactor a class like this, simply move its utility functions elsewhere, paring its public interface down to the bare minimum. diff --git a/java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp b/java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp index 7d78490985bf..970b1c4e19e2 100644 --- a/java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp +++ b/java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp @@ -29,14 +29,13 @@ that something is amiss, but further investigation will be needed to clarify the cause of the problem. Here are two possibilities:

      -
        - -
      • -A class and its superclass represent fundamentally the same abstraction. +

        +1. A class and its superclass represent fundamentally the same abstraction. In this case, they should generally be merged together (see the 'Collapse Hierarchy' refactoring on pp.279-80 of [Fowler]). For example, suppose that in the following class hierarchy both A and C represent fundamentally the same thing, then they should be merged together as shown: +

        @@ -48,11 +47,9 @@ the same thing, then they should be merged together as shown:
        After
        -
      • -
      • -The class hierarchy is trying to represent variation in more than one +2. The class hierarchy is trying to represent variation in more than one dimension using single inheritance. This can lead to an unnecessarily deep class hierarchy with lots of code duplication. For example, consider the following: @@ -81,9 +78,6 @@ amount of code duplication that will be necessary. For readers who are interested in this sort of approach, a good reference is [West].

        -
      • - -
      diff --git a/java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp b/java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp index 49827592849d..4f9452789a89 100644 --- a/java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp +++ b/java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp @@ -49,21 +49,17 @@ need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: -
        -
      • -It may be possible to generalize some of the utility methods beyond the + +1. It may be possible to generalize some of the utility methods beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. -
      • -
      • -It's usually impossible for the class author to know every possible +2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility methods will end up having a different syntax to the privileged public methods in the class, negatively impacting on code consistency. -
      • -
      + To refactor a class like this, simply move its utility methods elsewhere, paring its public interface down to the bare minimum. diff --git a/java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp b/java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp index befc6409449e..2934ba958b52 100644 --- a/java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp +++ b/java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp @@ -25,11 +25,9 @@ If the class is too big, you should split it into multiple smaller classes.
    • -

      If several of the fields are part of the same abstraction, you should group them into a separate class, using the 'Extract Class' refactoring described in [Fowler]. -

    diff --git a/java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp b/java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp index 3095d82049a6..eda183a287c2 100644 --- a/java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp +++ b/java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp @@ -46,21 +46,17 @@ need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: -
      -
    • -It may be possible to generalize some of the utility methods beyond the + +1. It may be possible to generalize some of the utility methods beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. -
    • -
    • -It's usually impossible for the class author to know every possible +2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility methods will end up having a different syntax to the privileged public methods in the class, negatively impacting on code consistency. -
    • -
    + To refactor a class like this, simply move its utility methods elsewhere, paring its public interface down to the bare minimum. From dc08274aa294bae0d404573370d6221dcca3e89b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:55:45 +0100 Subject: [PATCH 028/311] Rust: Update SqlxQuery, SqlxExecute from getResolvedPath -> getCanonicalPath. --- rust/ql/lib/codeql/rust/frameworks/Sqlx.qll | 14 +++++++----- .../security/CWE-089/SqlInjection.expected | 12 ---------- .../test/query-tests/security/CWE-089/sqlx.rs | 22 +++++++++---------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll index 5504993ab744..5b33f72fdf68 100644 --- a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll +++ b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll @@ -5,6 +5,8 @@ private import rust private import codeql.rust.Concepts private import codeql.rust.dataflow.DataFlow +private import codeql.rust.internal.TypeInference +private import codeql.rust.internal.Type /** * A call to `sqlx::query` and variations. @@ -14,11 +16,12 @@ private class SqlxQuery extends SqlConstruction::Range { SqlxQuery() { this.asExpr().getExpr() = call and - call.getFunction().(PathExpr).getResolvedPath() = + call.getStaticTarget().(Addressable).getCanonicalPath() = [ - "crate::query::query", "crate::query_as::query_as", "crate::query_with::query_with", - "crate::query_as_with::query_as_with", "crate::query_scalar::query_scalar", - "crate::query_scalar_with::query_scalar_with", "crate::raw_sql::raw_sql" + "sqlx_core::query::query", "sqlx_core::query_as::query_as", + "sqlx_core::query_with::query_with", "sqlx_core::query_as_with::query_as_with", + "sqlx_core::query_scalar::query_scalar", "sqlx_core::query_scalar_with::query_scalar_with", + "sqlx_core::raw_sql::raw_sql" ] } @@ -33,7 +36,8 @@ private class SqlxExecute extends SqlExecution::Range { SqlxExecute() { this.asExpr().getExpr() = call and - call.(Resolvable).getResolvedPath() = "crate::executor::Executor::execute" + call.getStaticTarget().(Addressable).getCanonicalPath() = + "sqlx_core::executor::Executor::execute" } override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index ab8e995be762..fcfa77cfda0f 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,8 +1,4 @@ #select -| sqlx.rs:66:26:66:46 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:66:26:66:46 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | -| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | @@ -24,22 +20,18 @@ edges | sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:7 | | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:66:26:66:46 | safe_query_3.as_str() | provenance | MaD:3 | | sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:3 | | sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | | sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | | sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | | sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:4 | | sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:9 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | provenance | MaD:3 | | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:3 | | sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | | sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | provenance | MaD:3 | | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:3 | | sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | | sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | -| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | provenance | MaD:3 | | sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:3 | | sqlx.rs:59:9:59:73 | res | sqlx.rs:59:17:59:72 | { ... } | provenance | | | sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:9:59:73 | res | provenance | | @@ -91,10 +83,6 @@ nodes | sqlx.rs:59:17:59:72 | ...::must_use(...) | semmle.label | ...::must_use(...) | | sqlx.rs:59:17:59:72 | MacroExpr | semmle.label | MacroExpr | | sqlx.rs:59:17:59:72 | { ... } | semmle.label | { ... } | -| sqlx.rs:66:26:66:46 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | -| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | -| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | -| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | semmle.label | unsafe_query_4.as_str() | | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | diff --git a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs index 3de58350f20c..291b04257d5a 100644 --- a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs +++ b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs @@ -61,14 +61,14 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=?"); // (prepared arguments are safe) // direct execution - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink - let _ = conn.execute(safe_query_2.as_str()).await?; // $ sql-sink - let _ = conn.execute(safe_query_3.as_str()).await?; // $ sql-sink SPURIOUS: Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=args1 + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(safe_query_2.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(safe_query_3.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=args1 if enable_remote { - let _ = conn.execute(unsafe_query_2.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_3.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_4.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_2.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_3.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_4.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 } // prepared queries @@ -103,9 +103,9 @@ async fn test_sqlx_sqlite(url: &str, enable_remote: bool) -> Result<(), sqlx::Er let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=?"); // (prepared arguments are safe) // direct execution (with extra variants) - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink if enable_remote { - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote2 + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote2 } // ... let _ = sqlx::raw_sql(safe_query_1.as_str()).execute(&mut conn).await?; // $ sql-sink @@ -176,9 +176,9 @@ async fn test_sqlx_postgres(url: &str, enable_remote: bool) -> Result<(), sqlx:: let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=$1"); // (prepared arguments are safe) // direct execution - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink if enable_remote { - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote3 + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote3 } // prepared queries From cd6975f7b743b19e533bf97de09f54ad06e454ca Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 17 Jun 2025 16:18:47 +0100 Subject: [PATCH 029/311] Rust: Update DotDotCheck from getResolvedPath -> getCanonicalPath. --- .../codeql/rust/security/TaintedPathExtensions.qll | 3 ++- .../security/CWE-022/TaintedPath.expected | 13 +++++++++++++ .../test/query-tests/security/CWE-022/src/main.rs | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll b/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll index 5f8d8b77ee82..016d79e840fc 100644 --- a/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll @@ -69,7 +69,8 @@ module SanitizerGuard { */ private class DotDotCheck extends SanitizerGuard::Range, CfgNodes::MethodCallExprCfgNode { DotDotCheck() { - this.getAstNode().(Resolvable).getResolvedPath() = "::contains" and + this.getAstNode().(CallExprBase).getStaticTarget().(Addressable).getCanonicalPath() = + "alloc::string::String::contains" and this.getArgument(0).getAstNode().(LiteralExpr).getTextValue() = ["\"..\"", "\"../\"", "\"..\\\""] } diff --git a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected index 7d8bb23d4c59..d2d38c18ec06 100644 --- a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected +++ b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected @@ -1,5 +1,6 @@ #select | src/main.rs:10:5:10:22 | ...::read_to_string | src/main.rs:6:11:6:19 | file_name | src/main.rs:10:5:10:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:6:11:6:19 | file_name | user-provided value | +| src/main.rs:20:5:20:22 | ...::read_to_string | src/main.rs:14:36:14:44 | file_name | src/main.rs:20:5:20:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:14:36:14:44 | file_name | user-provided value | | src/main.rs:45:5:45:22 | ...::read_to_string | src/main.rs:37:11:37:19 | file_path | src/main.rs:45:5:45:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:37:11:37:19 | file_path | user-provided value | | src/main.rs:59:5:59:22 | ...::read_to_string | src/main.rs:50:11:50:19 | file_path | src/main.rs:59:5:59:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:50:11:50:19 | file_path | user-provided value | edges @@ -9,6 +10,12 @@ edges | src/main.rs:8:35:8:43 | file_name | src/main.rs:8:21:8:44 | ...::from(...) | provenance | MaD:4 | | src/main.rs:8:35:8:43 | file_name | src/main.rs:8:21:8:44 | ...::from(...) | provenance | MaD:4 | | src/main.rs:10:24:10:32 | file_path | src/main.rs:10:5:10:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 | +| src/main.rs:14:36:14:44 | file_name | src/main.rs:19:35:19:43 | file_name | provenance | | +| src/main.rs:19:9:19:17 | file_path | src/main.rs:20:24:20:32 | file_path | provenance | | +| src/main.rs:19:21:19:44 | ...::from(...) | src/main.rs:19:9:19:17 | file_path | provenance | | +| src/main.rs:19:35:19:43 | file_name | src/main.rs:19:21:19:44 | ...::from(...) | provenance | MaD:4 | +| src/main.rs:19:35:19:43 | file_name | src/main.rs:19:21:19:44 | ...::from(...) | provenance | MaD:4 | +| src/main.rs:20:24:20:32 | file_path | src/main.rs:20:5:20:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 | | src/main.rs:37:11:37:19 | file_path | src/main.rs:40:52:40:60 | file_path | provenance | | | src/main.rs:40:9:40:17 | file_path | src/main.rs:45:24:45:32 | file_path | provenance | | | src/main.rs:40:21:40:62 | public_path.join(...) | src/main.rs:40:9:40:17 | file_path | provenance | | @@ -38,6 +45,12 @@ nodes | src/main.rs:8:35:8:43 | file_name | semmle.label | file_name | | src/main.rs:10:5:10:22 | ...::read_to_string | semmle.label | ...::read_to_string | | src/main.rs:10:24:10:32 | file_path | semmle.label | file_path | +| src/main.rs:14:36:14:44 | file_name | semmle.label | file_name | +| src/main.rs:19:9:19:17 | file_path | semmle.label | file_path | +| src/main.rs:19:21:19:44 | ...::from(...) | semmle.label | ...::from(...) | +| src/main.rs:19:35:19:43 | file_name | semmle.label | file_name | +| src/main.rs:20:5:20:22 | ...::read_to_string | semmle.label | ...::read_to_string | +| src/main.rs:20:24:20:32 | file_path | semmle.label | file_path | | src/main.rs:37:11:37:19 | file_path | semmle.label | file_path | | src/main.rs:40:9:40:17 | file_path | semmle.label | file_path | | src/main.rs:40:21:40:62 | public_path.join(...) | semmle.label | public_path.join(...) | diff --git a/rust/ql/test/query-tests/security/CWE-022/src/main.rs b/rust/ql/test/query-tests/security/CWE-022/src/main.rs index 7c13da08db50..7882060230df 100644 --- a/rust/ql/test/query-tests/security/CWE-022/src/main.rs +++ b/rust/ql/test/query-tests/security/CWE-022/src/main.rs @@ -11,13 +11,13 @@ fn tainted_path_handler_bad( } //#[handler] -fn tainted_path_handler_good(Query(file_name): Query) -> Result { +fn tainted_path_handler_good(Query(file_name): Query) -> Result { // $ SPURIOUS: Source=remote2 // GOOD: ensure that the filename has no path separators or parent directory references if file_name.contains("..") || file_name.contains("/") || file_name.contains("\\") { return Err(Error::from_status(StatusCode::BAD_REQUEST)); } let file_path = PathBuf::from(file_name); - fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink + fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink SPURIOUS: Alert[rust/path-injection]=remote2 } //#[handler] From 898c569f1b3287a1a33ac47d83e8f396b17af886 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 24 Jun 2025 11:37:54 +0100 Subject: [PATCH 030/311] Rust: Change note. --- .../change-notes/2025-06-24-hardcoded-cryptographic-value.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 rust/ql/src/change-notes/2025-06-24-hardcoded-cryptographic-value.md diff --git a/rust/ql/src/change-notes/2025-06-24-hardcoded-cryptographic-value.md b/rust/ql/src/change-notes/2025-06-24-hardcoded-cryptographic-value.md new file mode 100644 index 000000000000..73bd81f03408 --- /dev/null +++ b/rust/ql/src/change-notes/2025-06-24-hardcoded-cryptographic-value.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new query, `rust/hardcoded-crytographic-value`, for detecting use of hardcoded keys, passwords, salts and initialization vectors. From cce17743bb0e88808e02fd4b25753992daed13f8 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 30 Jun 2025 14:12:36 +0200 Subject: [PATCH 031/311] Ql4Ql: Re-factor the ql/mising-security-metadata query. --- ql/ql/src/codeql_ql/ast/Ast.qll | 26 ++++++++-- .../queries/style/MissingSecurityMetadata.ql | 49 +++++++------------ .../MissingSecurityMetadata.expected | 2 +- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 89bdf14d4b2a..5713e21592b8 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -202,25 +202,43 @@ class QueryDoc extends QLDoc { override string getAPrimaryQlClass() { result = "QueryDoc" } - /** Gets the @kind for the query */ + /** Gets the @kind for the query. */ string getQueryKind() { result = this.getContents().regexpCapture("(?s).*@kind ([\\w-]+)\\s.*", 1) } - /** Gets the @name for the query */ + /** Gets the @name for the query. */ string getQueryName() { result = this.getContents().regexpCapture("(?s).*@name (.+?)(?=\\n).*", 1) } - /** Gets the id part (without language) of the @id */ + /** Gets the id part (without language) of the @id. */ string getQueryId() { result = this.getContents().regexpCapture("(?s).*@id (\\w+)/([\\w\\-/]+)\\s.*", 2) } - /** Gets the language of the @id */ + /** Gets the language of the @id. */ string getQueryLanguage() { result = this.getContents().regexpCapture("(?s).*@id (\\w+)/([\\w\\-/]+)\\s.*", 1) } + + /** Gets the @precision for the query. */ + string getQueryPrecision() { + result = this.getContents().regexpCapture("(?s).*@precision ([\\w\\-]+)\\s.*", 1) + } + + /** Gets the @security-severity for the query. */ + string getQuerySecuritySeverity() { + result = this.getContents().regexpCapture("(?s).*@security\\-severity ([\\d\\.]+)\\s.*", 1) + } + + /** Gets the individual @tags for the query. */ + string getQueryTags() { + exists(string tags | tags = this.getContents().regexpCapture("(?s).*@tags ([^@]+)", 1) | + result = tags.splitAt("*").trim() and + result.regexpMatch("[\\w\\s\\-]+") + ) + } } class BlockComment extends TBlockComment, Comment { diff --git a/ql/ql/src/queries/style/MissingSecurityMetadata.ql b/ql/ql/src/queries/style/MissingSecurityMetadata.ql index 10f50fb3f990..fea75d36302c 100644 --- a/ql/ql/src/queries/style/MissingSecurityMetadata.ql +++ b/ql/ql/src/queries/style/MissingSecurityMetadata.ql @@ -10,45 +10,30 @@ import ql -predicate missingSecuritySeverity(QLDoc doc) { - exists(string s | s = doc.getContents() | - exists(string securityTag | securityTag = s.splitAt("@") | - securityTag.matches("tags%security%") - ) and - exists(string precisionTag | precisionTag = s.splitAt("@") | - precisionTag.matches("precision %") - ) and - not exists(string securitySeverity | securitySeverity = s.splitAt("@") | - securitySeverity.matches("security-severity %") - ) - ) +private predicate unInterestingLocation(File f) { + f.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") } -predicate missingSecurityTag(QLDoc doc) { - exists(string s | s = doc.getContents() | - exists(string securitySeverity | securitySeverity = s.splitAt("@") | - securitySeverity.matches("security-severity %") - ) and - exists(string precisionTag | precisionTag = s.splitAt("@") | - precisionTag.matches("precision %") - ) and - not exists(string securityTag | securityTag = s.splitAt("@") | - securityTag.matches("tags%security%") - ) - ) +predicate missingSecuritySeverity(QueryDoc doc) { + doc.getQueryTags() = "security" and + exists(doc.getQueryPrecision()) and + not exists(doc.getQuerySecuritySeverity()) +} + +predicate missingSecurityTag(QueryDoc doc) { + exists(doc.getQuerySecuritySeverity()) and + exists(doc.getQueryPrecision()) and + not doc.getQueryTags() = "security" } -from TopLevel t, string msg +from TopLevel t, QueryDoc doc, string msg where - t.getLocation().getFile().getBaseName().matches("%.ql") and - not t.getLocation() - .getFile() - .getRelativePath() - .matches("%/" + ["experimental", "examples", "test"] + "/%") and + doc = t.getQLDoc() and + not unInterestingLocation(t.getLocation().getFile()) and ( - missingSecuritySeverity(t.getQLDoc()) and + missingSecuritySeverity(doc) and msg = "This query file is missing a `@security-severity` tag." or - missingSecurityTag(t.getQLDoc()) and msg = "This query file is missing a `@tag security`." + missingSecurityTag(doc) and msg = "This query file is missing a `@tags security`." ) select t, msg diff --git a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected index 28421838ae37..af2fbd54acb0 100644 --- a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected +++ b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected @@ -1,2 +1,2 @@ -| testcases/BadNoSecurity.ql:1:1:16:9 | TopLevel | This query file is missing a `@tag security`. | +| testcases/BadNoSecurity.ql:1:1:16:9 | TopLevel | This query file is missing a `@tags security`. | | testcases/BadNoSeverity.ql:1:1:16:9 | TopLevel | This query file is missing a `@security-severity` tag. | From c46b528c0505cc1c3237b4af0490f16f14b65f89 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 30 Jun 2025 16:20:50 +0200 Subject: [PATCH 032/311] Ql4Ql: Add some quality tag testcases. --- ...QualityMaintainabilityWrongToplevel.expected | 0 .../BadQualityMaintainabilityWrongToplevel.ql | 17 +++++++++++++++++ .../BadQualityMultipleTopLevel.expected | 0 .../testcases/BadQualityMultipleTopLevel.ql | 17 +++++++++++++++++ .../testcases/BadQualityNoToplevel.expected | 0 .../testcases/BadQualityNoToplevel.ql | 16 ++++++++++++++++ .../BadQualityReliabilityWrongToplevel.expected | 0 .../BadQualityReliabilityWrongToplevel.ql | 17 +++++++++++++++++ .../testcases/GoodNotQuality.expected | 0 .../testcases/GoodNotQuality.ql | 16 ++++++++++++++++ .../GoodQualityMaintainability.expected | 0 .../testcases/GoodQualityMaintainability.ql | 17 +++++++++++++++++ .../GoodQualityMaintainabilityWithSub.expected | 0 .../GoodQualityMaintainabilityWithSub.ql | 17 +++++++++++++++++ .../testcases/GoodQualityReliability.expected | 0 .../testcases/GoodQualityReliability.ql | 16 ++++++++++++++++ .../GoodQualityReliabilityWithSub.expected | 0 .../testcases/GoodQualityReliabilityWithSub.ql | 17 +++++++++++++++++ 18 files changed, 150 insertions(+) create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql new file mode 100644 index 000000000000..3dd18771f959 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * maintainability + * error-handling + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql new file mode 100644 index 000000000000..a9a7b48b76c7 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * maintainability + * reliability + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql new file mode 100644 index 000000000000..ad2ab5c1fb57 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql @@ -0,0 +1,16 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * someothertag + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql new file mode 100644 index 000000000000..53e84fb8a196 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * reliability + * readability + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.ql new file mode 100644 index 000000000000..60b722918317 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodNotQuality.ql @@ -0,0 +1,16 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @security-severity 10.0 + * @precision very-high + * @id ql/quality-query-test + * @tags security + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.ql new file mode 100644 index 000000000000..9e152b90d458 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainability.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @security-severity 10.0 + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * maintainability + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.ql new file mode 100644 index 000000000000..7d70c8564033 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithSub.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * maintainability + * readability + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.ql new file mode 100644 index 000000000000..f3979922b0d8 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliability.ql @@ -0,0 +1,16 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * reliability + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.ql new file mode 100644 index 000000000000..ec9c4136e862 --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithSub.ql @@ -0,0 +1,17 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * reliability + * correctness + */ + +import ql + +from Class c +where none() +select c, "" From e00b5351a42dfe4b3d60e32796b86f53a1b2a3bf Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 30 Jun 2025 16:43:20 +0200 Subject: [PATCH 033/311] Ql4Ql: Add a check for quality tag consistency. --- .../queries/style/MissingQualityMetadata.ql | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 ql/ql/src/queries/style/MissingQualityMetadata.ql diff --git a/ql/ql/src/queries/style/MissingQualityMetadata.ql b/ql/ql/src/queries/style/MissingQualityMetadata.ql new file mode 100644 index 000000000000..a01b2028e572 --- /dev/null +++ b/ql/ql/src/queries/style/MissingQualityMetadata.ql @@ -0,0 +1,51 @@ +/** + * @name Missing quality metadata + * @description Quality queries should have exactly one top-level category and if sub-categories are used, the appropriate top-level category should be used. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/missing-quality-metadata + * @tags correctness + */ + +import ql + +private predicate unInterestingLocation(File f) { + f.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") +} + +private predicate hasQualityTag(QueryDoc doc) { doc.getQueryTags() = "quality" } + +private predicate incorrectTopLevelCategorisation(QueryDoc doc) { + count(string s | s = doc.getQueryTags() and s = ["maintainability", "reliability"]) != 1 +} + +private predicate reliabilitySubCategory(QueryDoc doc) { + doc.getQueryTags() = ["correctness", "performance", "concurrency", "error-handling"] +} + +private predicate maintainabilitySubCategory(QueryDoc doc) { + doc.getQueryTags() = ["readability", "useless-code", "complexity"] +} + +from TopLevel t, QueryDoc doc, string msg +where + doc = t.getQLDoc() and + not unInterestingLocation(t.getLocation().getFile()) and + hasQualityTag(doc) and + ( + incorrectTopLevelCategorisation(doc) and + msg = + "This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`." + or + maintainabilitySubCategory(doc) and + not doc.getQueryTags() = "maintainability" and + msg = + "This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag." + or + reliabilitySubCategory(doc) and + not doc.getQueryTags() = "reliability" and + msg = + "This query file has a sub-category of reliability but is missing the `@tags reliability` tag." + ) +select t, msg From 60a1d02357f423ad777132a70a4d03dd6ab50934 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 30 Jun 2025 16:44:29 +0200 Subject: [PATCH 034/311] Ql4Ql: Add MissingQualityMetadata test. --- .../MissingQualityMetadata/MissingQualityMetadata.expected | 4 ++++ .../style/MissingQualityMetadata/MissingQualityMetadata.qlref | 1 + 2 files changed, 5 insertions(+) create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected new file mode 100644 index 000000000000..6eabd28445bd --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected @@ -0,0 +1,4 @@ +| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:17:13 | TopLevel | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | +| testcases/BadQualityMultipleTopLevel.ql:1:1:17:13 | TopLevel | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | +| testcases/BadQualityNoToplevel.ql:1:1:16:13 | TopLevel | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | +| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:17:13 | TopLevel | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref new file mode 100644 index 000000000000..6d7eb26bedeb --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref @@ -0,0 +1 @@ +queries/style/MissingQualityMetadata.ql From af1c4e0896095fa28dddc05bcc4a14d64e00124d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 09:42:20 +0200 Subject: [PATCH 035/311] Ql4Ql: Share the definition of TestFile between multiple tests. --- ql/ql/src/codeql/files/FileSystem.qll | 5 +++++ ql/ql/src/queries/style/MissingQualityMetadata.ql | 6 +----- ql/ql/src/queries/style/MissingSecurityMetadata.ql | 6 +----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ql/ql/src/codeql/files/FileSystem.qll b/ql/ql/src/codeql/files/FileSystem.qll index 5a219f3b7f0c..7f64ed00b030 100644 --- a/ql/ql/src/codeql/files/FileSystem.qll +++ b/ql/ql/src/codeql/files/FileSystem.qll @@ -61,3 +61,8 @@ class File extends Container, Impl::File { /** Holds if this file was extracted from ordinary source code. */ predicate fromSource() { any() } } + +/** A test file. */ +class TestFile extends File { + TestFile() { this.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") } +} diff --git a/ql/ql/src/queries/style/MissingQualityMetadata.ql b/ql/ql/src/queries/style/MissingQualityMetadata.ql index a01b2028e572..ceed39cf717e 100644 --- a/ql/ql/src/queries/style/MissingQualityMetadata.ql +++ b/ql/ql/src/queries/style/MissingQualityMetadata.ql @@ -10,10 +10,6 @@ import ql -private predicate unInterestingLocation(File f) { - f.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") -} - private predicate hasQualityTag(QueryDoc doc) { doc.getQueryTags() = "quality" } private predicate incorrectTopLevelCategorisation(QueryDoc doc) { @@ -31,7 +27,7 @@ private predicate maintainabilitySubCategory(QueryDoc doc) { from TopLevel t, QueryDoc doc, string msg where doc = t.getQLDoc() and - not unInterestingLocation(t.getLocation().getFile()) and + not t.getLocation().getFile() instanceof TestFile and hasQualityTag(doc) and ( incorrectTopLevelCategorisation(doc) and diff --git a/ql/ql/src/queries/style/MissingSecurityMetadata.ql b/ql/ql/src/queries/style/MissingSecurityMetadata.ql index fea75d36302c..1618bed02ead 100644 --- a/ql/ql/src/queries/style/MissingSecurityMetadata.ql +++ b/ql/ql/src/queries/style/MissingSecurityMetadata.ql @@ -10,10 +10,6 @@ import ql -private predicate unInterestingLocation(File f) { - f.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") -} - predicate missingSecuritySeverity(QueryDoc doc) { doc.getQueryTags() = "security" and exists(doc.getQueryPrecision()) and @@ -29,7 +25,7 @@ predicate missingSecurityTag(QueryDoc doc) { from TopLevel t, QueryDoc doc, string msg where doc = t.getQLDoc() and - not unInterestingLocation(t.getLocation().getFile()) and + not t.getLocation().getFile() instanceof TestFile and ( missingSecuritySeverity(doc) and msg = "This query file is missing a `@security-severity` tag." From f58064e119500396b54182d5fe91050f5350571e Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 2 Jul 2025 12:01:36 +0200 Subject: [PATCH 036/311] Ql4Ql: Address review comments. --- ql/ql/src/codeql_ql/ast/Ast.qll | 4 ++-- .../queries/style/MissingQualityMetadata.ql | 18 +++++++++--------- .../queries/style/MissingSecurityMetadata.ql | 8 ++++---- .../MissingQualityMetadata.expected | 8 ++++---- .../MissingSecurityMetadata.expected | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 5713e21592b8..a7c3709ff22b 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -232,8 +232,8 @@ class QueryDoc extends QLDoc { result = this.getContents().regexpCapture("(?s).*@security\\-severity ([\\d\\.]+)\\s.*", 1) } - /** Gets the individual @tags for the query. */ - string getQueryTags() { + /** Gets the individual @tags for the query, if any. */ + string getAQueryTag() { exists(string tags | tags = this.getContents().regexpCapture("(?s).*@tags ([^@]+)", 1) | result = tags.splitAt("*").trim() and result.regexpMatch("[\\w\\s\\-]+") diff --git a/ql/ql/src/queries/style/MissingQualityMetadata.ql b/ql/ql/src/queries/style/MissingQualityMetadata.ql index ceed39cf717e..547590c01ee6 100644 --- a/ql/ql/src/queries/style/MissingQualityMetadata.ql +++ b/ql/ql/src/queries/style/MissingQualityMetadata.ql @@ -10,18 +10,18 @@ import ql -private predicate hasQualityTag(QueryDoc doc) { doc.getQueryTags() = "quality" } +private predicate hasQualityTag(QueryDoc doc) { doc.getAQueryTag() = "quality" } -private predicate incorrectTopLevelCategorisation(QueryDoc doc) { - count(string s | s = doc.getQueryTags() and s = ["maintainability", "reliability"]) != 1 +private predicate correctTopLevelCategorisation(QueryDoc doc) { + strictcount(string s | s = doc.getAQueryTag() and s = ["maintainability", "reliability"]) = 1 } private predicate reliabilitySubCategory(QueryDoc doc) { - doc.getQueryTags() = ["correctness", "performance", "concurrency", "error-handling"] + doc.getAQueryTag() = ["correctness", "performance", "concurrency", "error-handling"] } private predicate maintainabilitySubCategory(QueryDoc doc) { - doc.getQueryTags() = ["readability", "useless-code", "complexity"] + doc.getAQueryTag() = ["readability", "useless-code", "complexity"] } from TopLevel t, QueryDoc doc, string msg @@ -30,18 +30,18 @@ where not t.getLocation().getFile() instanceof TestFile and hasQualityTag(doc) and ( - incorrectTopLevelCategorisation(doc) and + not correctTopLevelCategorisation(doc) and msg = "This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`." or maintainabilitySubCategory(doc) and - not doc.getQueryTags() = "maintainability" and + not doc.getAQueryTag() = "maintainability" and msg = "This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag." or reliabilitySubCategory(doc) and - not doc.getQueryTags() = "reliability" and + not doc.getAQueryTag() = "reliability" and msg = "This query file has a sub-category of reliability but is missing the `@tags reliability` tag." ) -select t, msg +select doc, msg diff --git a/ql/ql/src/queries/style/MissingSecurityMetadata.ql b/ql/ql/src/queries/style/MissingSecurityMetadata.ql index 1618bed02ead..5ab2cd98bbe5 100644 --- a/ql/ql/src/queries/style/MissingSecurityMetadata.ql +++ b/ql/ql/src/queries/style/MissingSecurityMetadata.ql @@ -1,6 +1,6 @@ /** * @name Missing security metadata - * @description Security queries should have both a `@tag security` and a `@security-severity` tag. + * @description Security queries should have both a `@tags security` and a `@security-severity` tag. * @kind problem * @problem.severity warning * @precision very-high @@ -11,7 +11,7 @@ import ql predicate missingSecuritySeverity(QueryDoc doc) { - doc.getQueryTags() = "security" and + doc.getAQueryTag() = "security" and exists(doc.getQueryPrecision()) and not exists(doc.getQuerySecuritySeverity()) } @@ -19,7 +19,7 @@ predicate missingSecuritySeverity(QueryDoc doc) { predicate missingSecurityTag(QueryDoc doc) { exists(doc.getQuerySecuritySeverity()) and exists(doc.getQueryPrecision()) and - not doc.getQueryTags() = "security" + not doc.getAQueryTag() = "security" } from TopLevel t, QueryDoc doc, string msg @@ -32,4 +32,4 @@ where or missingSecurityTag(doc) and msg = "This query file is missing a `@tags security`." ) -select t, msg +select doc, msg diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected index 6eabd28445bd..ec4939b9c4e9 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected @@ -1,4 +1,4 @@ -| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:17:13 | TopLevel | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | -| testcases/BadQualityMultipleTopLevel.ql:1:1:17:13 | TopLevel | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | -| testcases/BadQualityNoToplevel.ql:1:1:16:13 | TopLevel | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | -| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:17:13 | TopLevel | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | +| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | +| testcases/BadQualityMultipleTopLevel.ql:1:1:11:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | +| testcases/BadQualityNoToplevel.ql:1:1:10:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | +| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | diff --git a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected index af2fbd54acb0..bc241f3f0b4f 100644 --- a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected +++ b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.expected @@ -1,2 +1,2 @@ -| testcases/BadNoSecurity.ql:1:1:16:9 | TopLevel | This query file is missing a `@tags security`. | -| testcases/BadNoSeverity.ql:1:1:16:9 | TopLevel | This query file is missing a `@security-severity` tag. | +| testcases/BadNoSecurity.ql:1:1:10:3 | QueryDoc | This query file is missing a `@tags security`. | +| testcases/BadNoSeverity.ql:1:1:10:3 | QueryDoc | This query file is missing a `@security-severity` tag. | From b79e2dd0baaa1c68f9507aeb1f37f9132ffd82dc Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 11:13:57 +0200 Subject: [PATCH 037/311] Ql4Ql: Add some more quality tag testcases. --- .../MissingQualityMetadata.expected | 2 ++ ...QualityMaintainabilityWithCrossSub.expected | 0 .../GoodQualityMaintainabilityWithCrossSub.ql | 18 ++++++++++++++++++ ...GoodQualityReliabilityWithCrossSub.expected | 0 .../GoodQualityReliabilityWithCrossSub.ql | 18 ++++++++++++++++++ 5 files changed, 38 insertions(+) create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.ql create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.expected create mode 100644 ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected index ec4939b9c4e9..9ee4bd78576e 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected @@ -2,3 +2,5 @@ | testcases/BadQualityMultipleTopLevel.ql:1:1:11:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | | testcases/BadQualityNoToplevel.ql:1:1:10:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | | testcases/BadQualityReliabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | +| testcases/GoodQualityMaintainabilityWithCrossSub.ql:1:1:12:3 | QueryDoc | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | +| testcases/GoodQualityReliabilityWithCrossSub.ql:1:1:12:3 | QueryDoc | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.ql new file mode 100644 index 000000000000..fe1f511abfff --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityMaintainabilityWithCrossSub.ql @@ -0,0 +1,18 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * maintainability + * readability + * correctness + */ + +import ql + +from Class c +where none() +select c, "" diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.expected b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.ql new file mode 100644 index 000000000000..78594e8f9c3c --- /dev/null +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/GoodQualityReliabilityWithCrossSub.ql @@ -0,0 +1,18 @@ +/** + * @name Some query + * @description Some description + * @kind problem + * @problem.severity warning + * @precision very-high + * @id ql/quality-query-test + * @tags quality + * reliability + * correctness + * readability + */ + +import ql + +from Class c +where none() +select c, "" From f810e17d9ee6956fe74bac548853aa3fa806e345 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 11:26:11 +0200 Subject: [PATCH 038/311] Ql4Ql: Address review comments and update expected test output. --- .../queries/style/MissingQualityMetadata.ql | 23 +++++++++++-------- .../MissingQualityMetadata.expected | 6 ++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/ql/ql/src/queries/style/MissingQualityMetadata.ql b/ql/ql/src/queries/style/MissingQualityMetadata.ql index 547590c01ee6..88c877186340 100644 --- a/ql/ql/src/queries/style/MissingQualityMetadata.ql +++ b/ql/ql/src/queries/style/MissingQualityMetadata.ql @@ -34,14 +34,19 @@ where msg = "This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`." or - maintainabilitySubCategory(doc) and - not doc.getAQueryTag() = "maintainability" and - msg = - "This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag." - or - reliabilitySubCategory(doc) and - not doc.getAQueryTag() = "reliability" and - msg = - "This query file has a sub-category of reliability but is missing the `@tags reliability` tag." + correctTopLevelCategorisation(doc) and + ( + doc.getAQueryTag() = "reliability" and + not reliabilitySubCategory(doc) and + maintainabilitySubCategory(doc) and + msg = + "This query file has a sub-category of maintainability but has the `@tags reliability` tag." + or + doc.getAQueryTag() = "maintainability" and + not maintainabilitySubCategory(doc) and + reliabilitySubCategory(doc) and + msg = + "This query file has a sub-category of reliability but has the `@tags maintainability` tag." + ) ) select doc, msg diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected index 9ee4bd78576e..7904870bdf64 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.expected @@ -1,6 +1,4 @@ -| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | +| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of reliability but has the `@tags maintainability` tag. | | testcases/BadQualityMultipleTopLevel.ql:1:1:11:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | | testcases/BadQualityNoToplevel.ql:1:1:10:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. | -| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | -| testcases/GoodQualityMaintainabilityWithCrossSub.ql:1:1:12:3 | QueryDoc | This query file has a sub-category of reliability but is missing the `@tags reliability` tag. | -| testcases/GoodQualityReliabilityWithCrossSub.ql:1:1:12:3 | QueryDoc | This query file has a sub-category of maintainability but is missing the `@tags maintainability` tag. | +| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of maintainability but has the `@tags reliability` tag. | From aefd941135731333afe4081819ad668f867d4798 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 11:48:56 +0200 Subject: [PATCH 039/311] Java/Javascript: Fix violations. --- java/ql/src/Language Abuse/TypeVariableHidesType.ql | 4 ++-- javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.ql | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/Language Abuse/TypeVariableHidesType.ql b/java/ql/src/Language Abuse/TypeVariableHidesType.ql index 81da0e9703e6..42d0a7bea2bf 100644 --- a/java/ql/src/Language Abuse/TypeVariableHidesType.ql +++ b/java/ql/src/Language Abuse/TypeVariableHidesType.ql @@ -6,10 +6,10 @@ * @problem.severity warning * @precision medium * @id java/type-variable-hides-type - * @tags reliability + * @tags quality + * maintainability * readability * types - * quality */ import java diff --git a/javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.ql b/javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.ql index a6142a2e6e73..6500cd157778 100644 --- a/javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.ql +++ b/javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.ql @@ -6,7 +6,7 @@ * @problem.severity warning * @precision high * @tags quality - * maintainability + * reliability * error-handling * frameworks/nodejs */ From 11c4a638bc63f6ddc5861831967afa2073636672 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 12:19:41 +0200 Subject: [PATCH 040/311] Quality tags: Clarify the quality sub-category tagging policy. --- docs/query-metadata-style-guide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 18fa5d1880f5..f6cc6f883fc1 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -157,7 +157,7 @@ Each code quality related query should have **one** of these two "top-level" cat * `@tags maintainability`–for queries that detect patterns that make it harder for developers to make changes to the code. * `@tags reliability`–for queries that detect issues that affect whether the code will perform as expected during execution. -In addition to the "top-level" categories, we will also add sub-categories to further group code quality related queries: +In addition to the "top-level" categories, we may also add sub-categories to further group code quality related queries: * `@tags maintainability`–for queries that detect patterns that make it harder for developers to make changes to the code. * `@tags readability`–for queries that detect confusing patterns that make it harder for developers to read the code. @@ -171,6 +171,7 @@ In addition to the "top-level" categories, we will also add sub-categories to fu * `@tags concurrency`-for queries that detect concurrency related issues such as race conditions, deadlocks, thread safety, etc * `@tags error-handling`-for queries that detect issues related to unsafe error handling such as uncaught exceptions, etc +You may use sub-categories from both top-level categories on the same query. However, if you only use sub-categories from a single top-level category, then you must also tag the query with that top-level category. There are also more specific `@tags` that can be added. See, the following pages for examples of the low-level tags: From fb693837e4ded37bc66bb4c975383c61ebf9aa77 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 10 Jul 2025 02:19:17 +0200 Subject: [PATCH 041/311] feat: add getASupertype() predicate in ValueOrRefType. Add the getASupertype() predicate in ValueOrRefType. --- csharp/ql/lib/semmle/code/csharp/Type.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index 9283bb3002a1..3693e8977d89 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -138,6 +138,9 @@ class ValueOrRefType extends Type, Attributable, @value_or_ref_type { /** Gets an immediate subtype of this type, if any. */ ValueOrRefType getASubType() { result.getABaseType() = this } + /** Gets an immediate supertype of this type, if any. */ + ValueOrRefType getASupertype() { this.getABaseType() = result } + /** Gets a member of this type, if any. */ Member getAMember() { result.getDeclaringType() = this } From c3c8d5db134582064ac367552980d27a8167b848 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 10 Jul 2025 05:48:52 +0200 Subject: [PATCH 042/311] Create 2025-06-10-getasupertype.md Create 2025-06-10-getasupertype.md --- csharp/ql/lib/change-notes/2025-06-10-getasupertype.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2025-06-10-getasupertype.md diff --git a/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md b/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md new file mode 100644 index 000000000000..8f91b2d3cc5b --- /dev/null +++ b/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added a new predicate, `getASupertype()`, to get a direct supertype of this type. From 99e62d66e57a752394b861f70fb413f84f42e422 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 9 May 2025 17:28:40 +0100 Subject: [PATCH 043/311] Rust: Add sensitive data patterns. --- .../internal/SensitiveDataHeuristics.qll | 23 +++++--- .../test/library-tests/sensitivedata/test.rs | 56 +++++++++---------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll index ede88ebf8149..f0b79fbbf3d7 100644 --- a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll +++ b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll @@ -54,7 +54,9 @@ module HeuristicNames { * Gets a regular expression that identifies strings that may indicate the presence of secret * or trusted data. */ - string maybeSecret() { result = "(?is).*((? Date: Fri, 9 May 2025 17:32:46 +0100 Subject: [PATCH 044/311] Rust: Combine regexs where possible (likely better performance). --- .../security/internal/SensitiveDataHeuristics.qll | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll index f0b79fbbf3d7..48681bdf89a5 100644 --- a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll +++ b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll @@ -63,8 +63,7 @@ module HeuristicNames { * user names or other account information. */ string maybeAccountInfo() { - result = "(?is).*acc(ou)?nt.*" or - result = "(?is).*(puid|user.?name|user.?id|session.?(id|key)).*" or + result = "(?is).*(acc(ou)?nt|puid|user.?(name|id)|session.?(id|key)).*" or result = "(?s).*([uU]|^|_|[a-z](?=U))([uU][iI][dD]).*" } @@ -73,11 +72,9 @@ module HeuristicNames { * a password or an authorization key. */ string maybePassword() { - result = "(?is).*pass(wd|word|code|.?phrase)(?!.*question).*" or - result = "(?is).*(auth(entication|ori[sz]ation)?).?key.*" or - result = "(?is).*([_-]|\\b)mfa([_-]|\\b).*" or - result = "(?is).*oauth.*" or - result = "(?is).*api.?(key|token).*" + result = + "(?is).*(pass(wd|word|code|.?phrase)(?!.*question)|(auth(entication|ori[sz]ation)?).?key|oauth|" + + "api.?(key|token)|([_-]|\\b)mfa([_-]|\\b)).*" } /** From a6b4a18d5102a8f9745d2bc7bf94df3c8ede1eb8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 9 May 2025 17:50:27 +0100 Subject: [PATCH 045/311] Rust: Add negative patterns. --- .../internal/SensitiveDataHeuristics.qll | 9 +++++---- .../test/library-tests/sensitivedata/test.rs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll index 48681bdf89a5..ebc3e0b0e31a 100644 --- a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll +++ b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll @@ -55,7 +55,7 @@ module HeuristicNames { * or trusted data. */ string maybeSecret() { - result = "(?is).*((? Date: Thu, 10 Jul 2025 16:54:00 +0100 Subject: [PATCH 046/311] Update qhelp: SnakeYaml is safe from version 2.0 --- java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp index 087a873dfc77..8d76255fc733 100644 --- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp +++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp @@ -64,8 +64,8 @@ Recommendations specific to particular frameworks supported by this query:

    SnakeYAML - org.yaml:snakeyaml

      -
    • Secure by Default: No
    • -
    • Recommendation: Pass an instance of org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.
    • +
    • Secure by Default: As of version 2.0.
    • +
    • Recommendation: For versions before 2.0, pass an instance of org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.

    XML Decoder - Standard Java Library

    From 123458fd2198344925eae6fcad7e244e29063d66 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:10:24 +0100 Subject: [PATCH 047/311] Sync identical files. --- .../internal/SensitiveDataHeuristics.qll | 29 +++++++++++-------- .../internal/SensitiveDataHeuristics.qll | 29 +++++++++++-------- .../internal/SensitiveDataHeuristics.qll | 29 +++++++++++-------- .../internal/SensitiveDataHeuristics.qll | 29 +++++++++++-------- 4 files changed, 68 insertions(+), 48 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll b/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll index ede88ebf8149..ebc3e0b0e31a 100644 --- a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll +++ b/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll @@ -54,15 +54,16 @@ module HeuristicNames { * Gets a regular expression that identifies strings that may indicate the presence of secret * or trusted data. */ - string maybeSecret() { result = "(?is).*((? Date: Fri, 11 Jul 2025 11:54:59 +0100 Subject: [PATCH 048/311] Add change notes. --- .../lib/change-notes/2025-07-11-sensitive-data-heuristics.md | 4 ++++ .../lib/change-notes/2025-07-11-sensitive-data-heuristics.md | 4 ++++ .../lib/change-notes/2025-07-11-sensitive-data-heuristics.md | 4 ++++ .../lib/change-notes/2025-07-11-sensitive-data-heuristics.md | 4 ++++ .../lib/change-notes/2025-07-11-sensitive-data-heuristics.md | 4 ++++ 5 files changed, 20 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md create mode 100644 python/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md create mode 100644 ruby/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md create mode 100644 rust/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md create mode 100644 swift/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md diff --git a/javascript/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md b/javascript/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md new file mode 100644 index 000000000000..22f06a998b71 --- /dev/null +++ b/javascript/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The regular expressions in `SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information. diff --git a/python/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md b/python/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md new file mode 100644 index 000000000000..22f06a998b71 --- /dev/null +++ b/python/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The regular expressions in `SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information. diff --git a/ruby/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md b/ruby/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md new file mode 100644 index 000000000000..22f06a998b71 --- /dev/null +++ b/ruby/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The regular expressions in `SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information. diff --git a/rust/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md b/rust/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md new file mode 100644 index 000000000000..22f06a998b71 --- /dev/null +++ b/rust/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The regular expressions in `SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information. diff --git a/swift/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md b/swift/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md new file mode 100644 index 000000000000..22f06a998b71 --- /dev/null +++ b/swift/ql/lib/change-notes/2025-07-11-sensitive-data-heuristics.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The regular expressions in `SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information. From 4778ef616a7109bbcb79b657e29c2c912c743ab6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:43:31 +0100 Subject: [PATCH 049/311] Rust: Add a test case for password_confirmation. --- rust/ql/test/library-tests/sensitivedata/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 87802002e8b8..dda48ea29272 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -23,7 +23,7 @@ impl MyStruct { fn get_password() -> String { get_string() } fn test_passwords( - password: &str, pass_word: &str, passwd: &str, my_password: &str, password_str: &str, + password: &str, pass_word: &str, passwd: &str, my_password: &str, password_str: &str, password_confirmation: &str, pass_phrase: &str, passphrase: &str, passPhrase: &str, backup_code: &str, auth_key: &str, authkey: &str, authKey: &str, authentication_key: &str, authenticationkey: &str, authenticationKey: &str, oauth: &str, one_time_code: &str, @@ -37,6 +37,7 @@ fn test_passwords( sink(passwd); // $ sensitive=password sink(my_password); // $ sensitive=password sink(password_str); // $ sensitive=password + sink(password_confirmation); // $ sensitive=password sink(pass_phrase); // $ sensitive=password sink(passphrase); // $ sensitive=password sink(passPhrase); // $ sensitive=password From 01ee3f70119f7f76b74b977d070ceb41063a1d33 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Sun, 6 Jul 2025 16:17:28 +0200 Subject: [PATCH 050/311] Shared: Add shared concepts library --- .../internal/SensitiveDataHeuristics.qll | 188 ++++++++++++++++++ shared/concepts/qlpack.yml | 6 + 2 files changed, 194 insertions(+) create mode 100644 shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll create mode 100644 shared/concepts/qlpack.yml diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll new file mode 100644 index 000000000000..ede88ebf8149 --- /dev/null +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -0,0 +1,188 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes and predicates for identifying strings that may indicate the presence of sensitive data. + * Such that we can share this logic across our CodeQL analysis of different languages. + * + * 'Sensitive' data in general is anything that should not be sent around in unencrypted form. + */ + +/** + * A classification of different kinds of sensitive data: + * + * - secret: generic secret or trusted data; + * - id: a user name or other account information; + * - password: a password or authorization key; + * - certificate: a certificate. + * - private: private data such as credit card numbers + * + * While classifications are represented as strings, this should not be relied upon. + * Instead, use the predicates in `SensitiveDataClassification::` to work with + * classifications. + */ +class SensitiveDataClassification extends string { + SensitiveDataClassification() { this in ["secret", "id", "password", "certificate", "private"] } +} + +/** + * Provides predicates to select the different kinds of sensitive data we support. + */ +module SensitiveDataClassification { + /** Gets the classification for secret or trusted data. */ + SensitiveDataClassification secret() { result = "secret" } + + /** Gets the classification for user names or other account information. */ + SensitiveDataClassification id() { result = "id" } + + /** Gets the classification for passwords or authorization keys. */ + SensitiveDataClassification password() { result = "password" } + + /** Gets the classification for certificates. */ + SensitiveDataClassification certificate() { result = "certificate" } + + /** Gets the classification for private data. */ + SensitiveDataClassification private() { result = "private" } +} + +/** + * INTERNAL: Do not use. + * + * Provides heuristics for identifying names related to sensitive information. + */ +module HeuristicNames { + /** + * Gets a regular expression that identifies strings that may indicate the presence of secret + * or trusted data. + */ + string maybeSecret() { result = "(?is).*((? Date: Sun, 6 Jul 2025 16:27:50 +0200 Subject: [PATCH 051/311] Use shared `SensitiveDataHeuristics` --- javascript/ql/lib/qlpack.yml | 1 + .../ql/lib/semmle/javascript/security/SensitiveActions.qll | 2 +- python/ql/lib/qlpack.yml | 1 + .../lib/semmle/python/dataflow/new/SensitiveDataSources.qll | 2 +- ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll | 2 +- .../ql/lib/codeql/ruby/security/internal/CleartextSources.qll | 4 ++-- ruby/ql/lib/qlpack.yml | 1 + rust/ql/lib/codeql/rust/security/SensitiveData.qll | 2 +- rust/ql/lib/qlpack.yml | 1 + swift/ql/lib/codeql/swift/security/SensitiveExprs.qll | 2 +- swift/ql/lib/qlpack.yml | 1 + 11 files changed, 12 insertions(+), 7 deletions(-) diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index ce5076a8e164..4703915c8801 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: javascript library: true upgrades: upgrades dependencies: + codeql/concepts: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} codeql/regex: ${workspace} diff --git a/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll b/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll index fed330e5a6f5..05a6fbc17d46 100644 --- a/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll +++ b/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll @@ -10,7 +10,7 @@ */ import javascript -import semmle.javascript.security.internal.SensitiveDataHeuristics +import codeql.concepts.internal.SensitiveDataHeuristics private import HeuristicNames /** An expression that might contain sensitive data. */ diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 80715c3da1ef..4819a6e3f1d3 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: python library: true upgrades: upgrades dependencies: + codeql/concepts: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} codeql/regex: ${workspace} diff --git a/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll b/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll index c12358f6db91..0e017c4a2295 100644 --- a/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll +++ b/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll @@ -7,7 +7,7 @@ private import python private import semmle.python.dataflow.new.DataFlow // Need to import `semmle.python.Frameworks` since frameworks can extend `SensitiveDataSource::Range` private import semmle.python.Frameworks -private import semmle.python.security.internal.SensitiveDataHeuristics as SensitiveDataHeuristics +private import codeql.concepts.internal.SensitiveDataHeuristics as SensitiveDataHeuristics private import semmle.python.ApiGraphs // We export these explicitly, so we don't also export the `HeuristicNames` module. diff --git a/ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll b/ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll index 34beb33604b7..e0dc68e7136e 100644 --- a/ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll +++ b/ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll @@ -11,7 +11,7 @@ private import codeql.ruby.AST private import codeql.ruby.DataFlow -import codeql.ruby.security.internal.SensitiveDataHeuristics +import codeql.concepts.internal.SensitiveDataHeuristics private import HeuristicNames private import codeql.ruby.CFG diff --git a/ruby/ql/lib/codeql/ruby/security/internal/CleartextSources.qll b/ruby/ql/lib/codeql/ruby/security/internal/CleartextSources.qll index 3338bbf65f70..f2867fa14bfe 100644 --- a/ruby/ql/lib/codeql/ruby/security/internal/CleartextSources.qll +++ b/ruby/ql/lib/codeql/ruby/security/internal/CleartextSources.qll @@ -8,8 +8,8 @@ private import codeql.ruby.AST private import codeql.ruby.DataFlow private import codeql.ruby.TaintTracking::TaintTracking private import codeql.ruby.dataflow.RemoteFlowSources -private import SensitiveDataHeuristics::HeuristicNames -private import SensitiveDataHeuristics +private import codeql.concepts.internal.SensitiveDataHeuristics::HeuristicNames +private import codeql.concepts.internal.SensitiveDataHeuristics private import codeql.ruby.CFG private import codeql.ruby.dataflow.SSA diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 1c2ec3fc09b4..befe2c9dcdc1 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: ruby.dbscheme upgrades: upgrades library: true dependencies: + codeql/concepts: ${workspace} codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} diff --git a/rust/ql/lib/codeql/rust/security/SensitiveData.qll b/rust/ql/lib/codeql/rust/security/SensitiveData.qll index bf3364abdb6b..4e6ba21a2d28 100644 --- a/rust/ql/lib/codeql/rust/security/SensitiveData.qll +++ b/rust/ql/lib/codeql/rust/security/SensitiveData.qll @@ -6,7 +6,7 @@ */ import rust -import internal.SensitiveDataHeuristics +import codeql.concepts.internal.SensitiveDataHeuristics private import codeql.rust.dataflow.DataFlow /** diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 6f155899d0a4..769be2c6d5d1 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: rust.dbscheme library: true upgrades: upgrades dependencies: + codeql/concepts: ${workspace} codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/regex: ${workspace} diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 044b2a054d7f..d78f9b405327 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -5,7 +5,7 @@ */ import swift -import internal.SensitiveDataHeuristics +import codeql.concepts.internal.SensitiveDataHeuristics private import codeql.swift.dataflow.DataFlow private import codeql.swift.dataflow.ExternalFlow diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 9c82e1216181..48be80bc6e20 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: swift.dbscheme upgrades: upgrades library: true dependencies: + codeql/concepts: ${workspace} codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/regex: ${workspace} From c582a9ccd6556a2b8980a78c1317af7e09e10cee Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Sun, 6 Jul 2025 16:33:08 +0200 Subject: [PATCH 052/311] Remove duplicate copies of `SensitiveDataHeuristics` --- config/identical-files.json | 7 - .../internal/SensitiveDataHeuristics.qll | 188 ------------------ .../internal/SensitiveDataHeuristics.qll | 188 ------------------ .../internal/SensitiveDataHeuristics.qll | 188 ------------------ .../internal/SensitiveDataHeuristics.qll | 188 ------------------ .../internal/SensitiveDataHeuristics.qll | 188 ------------------ 6 files changed, 947 deletions(-) delete mode 100644 javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll delete mode 100644 python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll delete mode 100644 ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll delete mode 100644 rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll delete mode 100644 swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll diff --git a/config/identical-files.json b/config/identical-files.json index 56aac5604734..a3da11e15e41 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -243,13 +243,6 @@ "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll", "rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll" ], - "SensitiveDataHeuristics Python/JS": [ - "javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll", - "python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll", - "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll", - "swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll", - "rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll" - ], "IncompleteUrlSubstringSanitization": [ "javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll", "ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll" diff --git a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll b/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll deleted file mode 100644 index ede88ebf8149..000000000000 --- a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll +++ /dev/null @@ -1,188 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates for identifying strings that may indicate the presence of sensitive data. - * Such that we can share this logic across our CodeQL analysis of different languages. - * - * 'Sensitive' data in general is anything that should not be sent around in unencrypted form. - */ - -/** - * A classification of different kinds of sensitive data: - * - * - secret: generic secret or trusted data; - * - id: a user name or other account information; - * - password: a password or authorization key; - * - certificate: a certificate. - * - private: private data such as credit card numbers - * - * While classifications are represented as strings, this should not be relied upon. - * Instead, use the predicates in `SensitiveDataClassification::` to work with - * classifications. - */ -class SensitiveDataClassification extends string { - SensitiveDataClassification() { this in ["secret", "id", "password", "certificate", "private"] } -} - -/** - * Provides predicates to select the different kinds of sensitive data we support. - */ -module SensitiveDataClassification { - /** Gets the classification for secret or trusted data. */ - SensitiveDataClassification secret() { result = "secret" } - - /** Gets the classification for user names or other account information. */ - SensitiveDataClassification id() { result = "id" } - - /** Gets the classification for passwords or authorization keys. */ - SensitiveDataClassification password() { result = "password" } - - /** Gets the classification for certificates. */ - SensitiveDataClassification certificate() { result = "certificate" } - - /** Gets the classification for private data. */ - SensitiveDataClassification private() { result = "private" } -} - -/** - * INTERNAL: Do not use. - * - * Provides heuristics for identifying names related to sensitive information. - */ -module HeuristicNames { - /** - * Gets a regular expression that identifies strings that may indicate the presence of secret - * or trusted data. - */ - string maybeSecret() { result = "(?is).*((? Date: Mon, 7 Jul 2025 11:29:13 +0200 Subject: [PATCH 053/311] Properly share `CryptoAlgorithms` and `CryptoAlgorithmNames` --- .../javascript/frameworks/CryptoLibraries.qll | 2 +- .../javascript/internal/ConceptsImports.qll | 2 +- .../javascript/security/CryptoAlgorithms.qll | 2 +- python/ql/lib/semmle/crypto/Crypto.qll | 2 +- .../python/concepts/CryptoAlgorithms.qll | 2 +- .../python/internal/ConceptsImports.qll | 2 +- .../codeql/ruby/internal/ConceptsImports.qll | 2 +- .../codeql/ruby/security/CryptoAlgorithms.qll | 2 +- ruby/ql/lib/codeql/ruby/security/OpenSSL.qll | 2 +- .../security/CryptoAlgorithms.ql | 2 +- .../codeql/rust/security/CryptoAlgorithms.qll | 2 +- .../codeql/concepts/CryptoAlgorithms.qll | 117 ++++++++++++++++++ .../internal/CryptoAlgorithmNames.qll | 84 +++++++++++++ 13 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 shared/concepts/codeql/concepts/CryptoAlgorithms.qll create mode 100644 shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index db527c03f95d..9cc76b5f5b8c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -4,7 +4,7 @@ import javascript import semmle.javascript.Concepts::Cryptography -private import semmle.javascript.security.internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames /** * A key used in a cryptographic algorithm. diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll index aba7a83437a8..3aae9c05fb5e 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll @@ -4,4 +4,4 @@ */ import semmle.javascript.dataflow.DataFlow::DataFlow as DataFlow -import semmle.javascript.security.CryptoAlgorithms as CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll index 7176c666c573..01b568d234af 100644 --- a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll @@ -4,7 +4,7 @@ * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames /** * A cryptographic algorithm. diff --git a/python/ql/lib/semmle/crypto/Crypto.qll b/python/ql/lib/semmle/crypto/Crypto.qll index 5e2bb97a0aa7..0ea453989c88 100644 --- a/python/ql/lib/semmle/crypto/Crypto.qll +++ b/python/ql/lib/semmle/crypto/Crypto.qll @@ -1,3 +1,3 @@ /** DEPRECATED: Use `semmle.python.concepts.CryptoAlgorithms` instead. */ -import semmle.python.concepts.CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms diff --git a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll index 7176c666c573..01b568d234af 100644 --- a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll +++ b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll @@ -4,7 +4,7 @@ * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames /** * A cryptographic algorithm. diff --git a/python/ql/lib/semmle/python/internal/ConceptsImports.qll b/python/ql/lib/semmle/python/internal/ConceptsImports.qll index 73ab482f829e..763b26017fbf 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsImports.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsImports.qll @@ -4,4 +4,4 @@ */ import semmle.python.dataflow.new.DataFlow -import semmle.python.concepts.CryptoAlgorithms as CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll index 478fffe56aef..c0f99aafad6c 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll @@ -4,4 +4,4 @@ */ import codeql.ruby.DataFlow -import codeql.ruby.security.CryptoAlgorithms as CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll index 7176c666c573..01b568d234af 100644 --- a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll +++ b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll @@ -4,7 +4,7 @@ * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames /** * A cryptographic algorithm. diff --git a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll index 26f6d996f144..3775657fc123 100644 --- a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll +++ b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll @@ -3,7 +3,7 @@ * an underlying OpenSSL or LibreSSL C library. */ -private import internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames private import codeql.ruby.Concepts private import codeql.ruby.DataFlow private import codeql.ruby.ApiGraphs diff --git a/ruby/ql/test/library-tests/security/CryptoAlgorithms.ql b/ruby/ql/test/library-tests/security/CryptoAlgorithms.ql index c4c42532d899..f19368e3656f 100644 --- a/ruby/ql/test/library-tests/security/CryptoAlgorithms.ql +++ b/ruby/ql/test/library-tests/security/CryptoAlgorithms.ql @@ -1,5 +1,5 @@ import codeql.ruby.AST -import codeql.ruby.security.CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms query predicate weakHashingAlgorithms(HashingAlgorithm ha) { ha.isWeak() } diff --git a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll index 7176c666c573..01b568d234af 100644 --- a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll +++ b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll @@ -4,7 +4,7 @@ * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import internal.CryptoAlgorithmNames +private import codeql.concepts.internal.CryptoAlgorithmNames /** * A cryptographic algorithm. diff --git a/shared/concepts/codeql/concepts/CryptoAlgorithms.qll b/shared/concepts/codeql/concepts/CryptoAlgorithms.qll new file mode 100644 index 000000000000..01b568d234af --- /dev/null +++ b/shared/concepts/codeql/concepts/CryptoAlgorithms.qll @@ -0,0 +1,117 @@ +/** + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +private import codeql.concepts.internal.CryptoAlgorithmNames + +/** + * A cryptographic algorithm. + */ +private newtype TCryptographicAlgorithm = + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } + +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + +/** + * A cryptographic algorithm. + */ +abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { + /** Gets a textual representation of this element. */ + string toString() { result = this.getName() } + + /** + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). + */ + abstract string getName(); + + /** + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. + */ + bindingset[name] + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } + + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); +} + +/** + * A hashing algorithm such as `MD5` or `SHA512`. + */ +class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * An encryption algorithm such as `DES` or `AES512`. + */ +class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } + + /** Holds if this algorithm is a stream cipher. */ + predicate isStreamCipher() { isStreamCipher(name) } +} + +/** + * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. + */ +class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} diff --git a/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll new file mode 100644 index 000000000000..8bb63d97876a --- /dev/null +++ b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll @@ -0,0 +1,84 @@ +/** + * Names of cryptographic algorithms, separated into strong and weak variants. + * + * The names are normalized: upper-case, no spaces, dashes or underscores. + * + * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +/** + * Holds if `name` corresponds to a strong hashing algorithm. + */ +predicate isStrongHashingAlgorithm(string name) { + name = + [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // + "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", + ] +} + +/** + * Holds if `name` corresponds to a weak hashing algorithm. + */ +predicate isWeakHashingAlgorithm(string name) { + name = + [ + "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", + "RIPEMD320", "SHA0", "SHA1" + ] +} + +/** + * Holds if `name` corresponds to a strong encryption algorithm. + */ +predicate isStrongEncryptionAlgorithm(string name) { + name = + [ + "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", + "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", + "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", + "IDEA", "RABBIT", "RSA", "SEED", "SM4" + ] +} + +/** + * Holds if `name` corresponds to a weak encryption algorithm. + */ +predicate isWeakEncryptionAlgorithm(string name) { + name = + [ + "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", + "ARCFOUR", "ARC5", "RC5" + ] +} + +/** + * Holds if `name` corresponds to a strong password hashing algorithm. + */ +predicate isStrongPasswordHashingAlgorithm(string name) { + name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] +} + +/** + * Holds if `name` corresponds to a weak password hashing algorithm. + */ +predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } + +/** + * Holds if `name` corresponds to a stream cipher. + */ +predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } From f07d8ee493179118f3bf371f88833e25db42081e Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 7 Jul 2025 11:39:12 +0200 Subject: [PATCH 054/311] Remove duplicate copies of `CryptoAlgorithms` and `CryptoAlgorithmNames` --- config/identical-files.json | 12 -- .../javascript/security/CryptoAlgorithms.qll | 114 +----------------- .../internal/CryptoAlgorithmNames.qll | 84 ------------- .../python/concepts/CryptoAlgorithms.qll | 114 +----------------- .../internal/CryptoAlgorithmNames.qll | 84 ------------- .../codeql/ruby/security/CryptoAlgorithms.qll | 114 +----------------- .../internal/CryptoAlgorithmNames.qll | 84 ------------- .../codeql/rust/security/CryptoAlgorithms.qll | 114 +----------------- .../internal/CryptoAlgorithmNames.qll | 84 ------------- 9 files changed, 4 insertions(+), 800 deletions(-) delete mode 100644 javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll delete mode 100644 python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll delete mode 100644 ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll delete mode 100644 rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll diff --git a/config/identical-files.json b/config/identical-files.json index a3da11e15e41..977f3f4a6473 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -231,18 +231,6 @@ "java/ql/src/experimental/Security/CWE/CWE-400/LocalThreadResourceAbuse.qhelp", "java/ql/src/experimental/Security/CWE/CWE-400/ThreadResourceAbuse.qhelp" ], - "CryptoAlgorithms Python/JS/Ruby": [ - "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", - "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", - "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll", - "rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll" - ], - "CryptoAlgorithmNames Python/JS/Ruby": [ - "javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll", - "python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll", - "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll", - "rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll" - ], "IncompleteUrlSubstringSanitization": [ "javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll", "ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll" diff --git a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll index 01b568d234af..f13d72312fe2 100644 --- a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll @@ -1,117 +1,5 @@ /** * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import codeql.concepts.internal.CryptoAlgorithmNames - -/** - * A cryptographic algorithm. - */ -private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } - -/** - * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. - * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. - * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. - */ -bindingset[name] -private CryptographicAlgorithm getBestAlgorithmForName(string name) { - result = - max(CryptographicAlgorithm algorithm | - algorithm.getName() = - [ - name.toUpperCase(), // the full name - name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces - name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores - ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces - | - algorithm order by algorithm.getName().length() - ) -} - -/** - * A cryptographic algorithm. - */ -abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = this.getName() } - - /** - * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). - */ - abstract string getName(); - - /** - * Holds if the name of this algorithm is the most specific match for `name`. - * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. - */ - bindingset[name] - predicate matchesName(string name) { this = getBestAlgorithmForName(name) } - - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); -} - -/** - * A hashing algorithm such as `MD5` or `SHA512`. - */ -class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * An encryption algorithm such as `DES` or `AES512`. - */ -class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } - - /** Holds if this algorithm is a stream cipher. */ - predicate isStreamCipher() { isStreamCipher(name) } -} - -/** - * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. - */ -class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} +private import codeql.concepts.CryptoAlgorithms diff --git a/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll b/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll deleted file mode 100644 index 8bb63d97876a..000000000000 --- a/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Names of cryptographic algorithms, separated into strong and weak variants. - * - * The names are normalized: upper-case, no spaces, dashes or underscores. - * - * The names are inspired by the names used in real world crypto libraries. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). - */ - -/** - * Holds if `name` corresponds to a strong hashing algorithm. - */ -predicate isStrongHashingAlgorithm(string name) { - name = - [ - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 - // and https://www.blake2.net/ - "BLAKE2", "BLAKE2B", "BLAKE2S", - // see https://github.com/BLAKE3-team/BLAKE3 - "BLAKE3", - // - "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 - "SHAKE128", "SHAKE256", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 - "SM3", - // see https://security.stackexchange.com/a/216297 - "WHIRLPOOL", - ] -} - -/** - * Holds if `name` corresponds to a weak hashing algorithm. - */ -predicate isWeakHashingAlgorithm(string name) { - name = - [ - "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", - "RIPEMD320", "SHA0", "SHA1" - ] -} - -/** - * Holds if `name` corresponds to a strong encryption algorithm. - */ -predicate isStrongEncryptionAlgorithm(string name) { - name = - [ - "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", - "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", - "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", - "IDEA", "RABBIT", "RSA", "SEED", "SM4" - ] -} - -/** - * Holds if `name` corresponds to a weak encryption algorithm. - */ -predicate isWeakEncryptionAlgorithm(string name) { - name = - [ - "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", - "ARCFOUR", "ARC5", "RC5" - ] -} - -/** - * Holds if `name` corresponds to a strong password hashing algorithm. - */ -predicate isStrongPasswordHashingAlgorithm(string name) { - name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] -} - -/** - * Holds if `name` corresponds to a weak password hashing algorithm. - */ -predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } - -/** - * Holds if `name` corresponds to a stream cipher. - */ -predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } diff --git a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll index 01b568d234af..13a03a3bd888 100644 --- a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll +++ b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll @@ -1,117 +1,5 @@ /** * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import codeql.concepts.internal.CryptoAlgorithmNames - -/** - * A cryptographic algorithm. - */ -private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } - -/** - * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. - * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. - * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. - */ -bindingset[name] -private CryptographicAlgorithm getBestAlgorithmForName(string name) { - result = - max(CryptographicAlgorithm algorithm | - algorithm.getName() = - [ - name.toUpperCase(), // the full name - name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces - name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores - ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces - | - algorithm order by algorithm.getName().length() - ) -} - -/** - * A cryptographic algorithm. - */ -abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = this.getName() } - - /** - * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). - */ - abstract string getName(); - - /** - * Holds if the name of this algorithm is the most specific match for `name`. - * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. - */ - bindingset[name] - predicate matchesName(string name) { this = getBestAlgorithmForName(name) } - - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); -} - -/** - * A hashing algorithm such as `MD5` or `SHA512`. - */ -class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * An encryption algorithm such as `DES` or `AES512`. - */ -class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } - - /** Holds if this algorithm is a stream cipher. */ - predicate isStreamCipher() { isStreamCipher(name) } -} - -/** - * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. - */ -class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} +import codeql.concepts.CryptoAlgorithms diff --git a/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll b/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll deleted file mode 100644 index 8bb63d97876a..000000000000 --- a/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Names of cryptographic algorithms, separated into strong and weak variants. - * - * The names are normalized: upper-case, no spaces, dashes or underscores. - * - * The names are inspired by the names used in real world crypto libraries. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). - */ - -/** - * Holds if `name` corresponds to a strong hashing algorithm. - */ -predicate isStrongHashingAlgorithm(string name) { - name = - [ - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 - // and https://www.blake2.net/ - "BLAKE2", "BLAKE2B", "BLAKE2S", - // see https://github.com/BLAKE3-team/BLAKE3 - "BLAKE3", - // - "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 - "SHAKE128", "SHAKE256", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 - "SM3", - // see https://security.stackexchange.com/a/216297 - "WHIRLPOOL", - ] -} - -/** - * Holds if `name` corresponds to a weak hashing algorithm. - */ -predicate isWeakHashingAlgorithm(string name) { - name = - [ - "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", - "RIPEMD320", "SHA0", "SHA1" - ] -} - -/** - * Holds if `name` corresponds to a strong encryption algorithm. - */ -predicate isStrongEncryptionAlgorithm(string name) { - name = - [ - "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", - "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", - "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", - "IDEA", "RABBIT", "RSA", "SEED", "SM4" - ] -} - -/** - * Holds if `name` corresponds to a weak encryption algorithm. - */ -predicate isWeakEncryptionAlgorithm(string name) { - name = - [ - "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", - "ARCFOUR", "ARC5", "RC5" - ] -} - -/** - * Holds if `name` corresponds to a strong password hashing algorithm. - */ -predicate isStrongPasswordHashingAlgorithm(string name) { - name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] -} - -/** - * Holds if `name` corresponds to a weak password hashing algorithm. - */ -predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } - -/** - * Holds if `name` corresponds to a stream cipher. - */ -predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } diff --git a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll index 01b568d234af..13a03a3bd888 100644 --- a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll +++ b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll @@ -1,117 +1,5 @@ /** * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import codeql.concepts.internal.CryptoAlgorithmNames - -/** - * A cryptographic algorithm. - */ -private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } - -/** - * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. - * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. - * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. - */ -bindingset[name] -private CryptographicAlgorithm getBestAlgorithmForName(string name) { - result = - max(CryptographicAlgorithm algorithm | - algorithm.getName() = - [ - name.toUpperCase(), // the full name - name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces - name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores - ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces - | - algorithm order by algorithm.getName().length() - ) -} - -/** - * A cryptographic algorithm. - */ -abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = this.getName() } - - /** - * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). - */ - abstract string getName(); - - /** - * Holds if the name of this algorithm is the most specific match for `name`. - * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. - */ - bindingset[name] - predicate matchesName(string name) { this = getBestAlgorithmForName(name) } - - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); -} - -/** - * A hashing algorithm such as `MD5` or `SHA512`. - */ -class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * An encryption algorithm such as `DES` or `AES512`. - */ -class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } - - /** Holds if this algorithm is a stream cipher. */ - predicate isStreamCipher() { isStreamCipher(name) } -} - -/** - * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. - */ -class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} +import codeql.concepts.CryptoAlgorithms diff --git a/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll b/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll deleted file mode 100644 index 8bb63d97876a..000000000000 --- a/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Names of cryptographic algorithms, separated into strong and weak variants. - * - * The names are normalized: upper-case, no spaces, dashes or underscores. - * - * The names are inspired by the names used in real world crypto libraries. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). - */ - -/** - * Holds if `name` corresponds to a strong hashing algorithm. - */ -predicate isStrongHashingAlgorithm(string name) { - name = - [ - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 - // and https://www.blake2.net/ - "BLAKE2", "BLAKE2B", "BLAKE2S", - // see https://github.com/BLAKE3-team/BLAKE3 - "BLAKE3", - // - "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 - "SHAKE128", "SHAKE256", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 - "SM3", - // see https://security.stackexchange.com/a/216297 - "WHIRLPOOL", - ] -} - -/** - * Holds if `name` corresponds to a weak hashing algorithm. - */ -predicate isWeakHashingAlgorithm(string name) { - name = - [ - "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", - "RIPEMD320", "SHA0", "SHA1" - ] -} - -/** - * Holds if `name` corresponds to a strong encryption algorithm. - */ -predicate isStrongEncryptionAlgorithm(string name) { - name = - [ - "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", - "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", - "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", - "IDEA", "RABBIT", "RSA", "SEED", "SM4" - ] -} - -/** - * Holds if `name` corresponds to a weak encryption algorithm. - */ -predicate isWeakEncryptionAlgorithm(string name) { - name = - [ - "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", - "ARCFOUR", "ARC5", "RC5" - ] -} - -/** - * Holds if `name` corresponds to a strong password hashing algorithm. - */ -predicate isStrongPasswordHashingAlgorithm(string name) { - name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] -} - -/** - * Holds if `name` corresponds to a weak password hashing algorithm. - */ -predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } - -/** - * Holds if `name` corresponds to a stream cipher. - */ -predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } diff --git a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll index 01b568d234af..13a03a3bd888 100644 --- a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll +++ b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll @@ -1,117 +1,5 @@ /** * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ -private import codeql.concepts.internal.CryptoAlgorithmNames - -/** - * A cryptographic algorithm. - */ -private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } - -/** - * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. - * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. - * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. - */ -bindingset[name] -private CryptographicAlgorithm getBestAlgorithmForName(string name) { - result = - max(CryptographicAlgorithm algorithm | - algorithm.getName() = - [ - name.toUpperCase(), // the full name - name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces - name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores - ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces - | - algorithm order by algorithm.getName().length() - ) -} - -/** - * A cryptographic algorithm. - */ -abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = this.getName() } - - /** - * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). - */ - abstract string getName(); - - /** - * Holds if the name of this algorithm is the most specific match for `name`. - * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. - */ - bindingset[name] - predicate matchesName(string name) { this = getBestAlgorithmForName(name) } - - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); -} - -/** - * A hashing algorithm such as `MD5` or `SHA512`. - */ -class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * An encryption algorithm such as `DES` or `AES512`. - */ -class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } - - /** Holds if this algorithm is a stream cipher. */ - predicate isStreamCipher() { isStreamCipher(name) } -} - -/** - * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. - */ -class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} +import codeql.concepts.CryptoAlgorithms diff --git a/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll deleted file mode 100644 index 8bb63d97876a..000000000000 --- a/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Names of cryptographic algorithms, separated into strong and weak variants. - * - * The names are normalized: upper-case, no spaces, dashes or underscores. - * - * The names are inspired by the names used in real world crypto libraries. - * - * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). - */ - -/** - * Holds if `name` corresponds to a strong hashing algorithm. - */ -predicate isStrongHashingAlgorithm(string name) { - name = - [ - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 - // and https://www.blake2.net/ - "BLAKE2", "BLAKE2B", "BLAKE2S", - // see https://github.com/BLAKE3-team/BLAKE3 - "BLAKE3", - // - "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 - "SHAKE128", "SHAKE256", - // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 - "SM3", - // see https://security.stackexchange.com/a/216297 - "WHIRLPOOL", - ] -} - -/** - * Holds if `name` corresponds to a weak hashing algorithm. - */ -predicate isWeakHashingAlgorithm(string name) { - name = - [ - "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", - "RIPEMD320", "SHA0", "SHA1" - ] -} - -/** - * Holds if `name` corresponds to a strong encryption algorithm. - */ -predicate isStrongEncryptionAlgorithm(string name) { - name = - [ - "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", - "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", - "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", - "IDEA", "RABBIT", "RSA", "SEED", "SM4" - ] -} - -/** - * Holds if `name` corresponds to a weak encryption algorithm. - */ -predicate isWeakEncryptionAlgorithm(string name) { - name = - [ - "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", - "ARCFOUR", "ARC5", "RC5" - ] -} - -/** - * Holds if `name` corresponds to a strong password hashing algorithm. - */ -predicate isStrongPasswordHashingAlgorithm(string name) { - name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] -} - -/** - * Holds if `name` corresponds to a weak password hashing algorithm. - */ -predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } - -/** - * Holds if `name` corresponds to a stream cipher. - */ -predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } From 9f59a3501c32995c7005313e5aff62f26d3e664b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:17:05 +0100 Subject: [PATCH 055/311] Rust: Revert ipaddr and fingerprint terms (too many FPs). --- .../codeql/rust/security/internal/SensitiveDataHeuristics.qll | 2 +- rust/ql/test/library-tests/sensitivedata/test.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll index ebc3e0b0e31a..910749a6c82b 100644 --- a/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll +++ b/rust/ql/lib/codeql/rust/security/internal/SensitiveDataHeuristics.qll @@ -114,7 +114,7 @@ module HeuristicNames { // Relationships - work and family "employ(er|ee)|spouse|maiden.?name|" + // Device information - "([_-]|\\b)ip.?addr|mac.?addr|finger.?print" + + "mac.?addr" + // --- ").*" } diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index dda48ea29272..74d0a0daa0a4 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -164,8 +164,8 @@ impl DeviceInfo { sink(&self.api_key); // $ sensitive=password sink(&other.api_key); // $ sensitive=password sink(&self.deviceApiToken); // $ sensitive=password - sink(&self.finger_print); // $ sensitive=private - sink(&self.ip_address); // $ sensitive=private + sink(&self.finger_print); // $ MISSING: sensitive=private + sink(&self.ip_address); // $ MISSING: sensitive=private sink(self.macaddr12); // $ sensitive=private sink(&self.mac_addr); // $ sensitive=private sink(self.mac_addr.values); // $ sensitive=private From e121579a857da542402e4362d43b0e82e08e21c7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:19:31 +0100 Subject: [PATCH 056/311] Rust: Adjust the test labels slightly. --- rust/ql/test/library-tests/sensitivedata/test.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 74d0a0daa0a4..0f4965ce2856 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -164,14 +164,17 @@ impl DeviceInfo { sink(&self.api_key); // $ sensitive=password sink(&other.api_key); // $ sensitive=password sink(&self.deviceApiToken); // $ sensitive=password - sink(&self.finger_print); // $ MISSING: sensitive=private - sink(&self.ip_address); // $ MISSING: sensitive=private sink(self.macaddr12); // $ sensitive=private sink(&self.mac_addr); // $ sensitive=private sink(self.mac_addr.values); // $ sensitive=private sink(self.mac_addr.values[0]); // $ sensitive=private sink(&self.networkMacAddress); // $ sensitive=private + // dubious (may or may not be private device info, depending on context) + + sink(&self.finger_print); + sink(&self.ip_address); + // not private device info sink(self.macro_value); From 30c6082b5d1e0c5e0630f45ccaafcf7e40cc7885 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:35:18 +0100 Subject: [PATCH 057/311] Sync identical files. --- .../javascript/security/internal/SensitiveDataHeuristics.qll | 2 +- .../semmle/python/security/internal/SensitiveDataHeuristics.qll | 2 +- .../codeql/ruby/security/internal/SensitiveDataHeuristics.qll | 2 +- .../codeql/swift/security/internal/SensitiveDataHeuristics.qll | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll b/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll index ebc3e0b0e31a..910749a6c82b 100644 --- a/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll +++ b/javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll @@ -114,7 +114,7 @@ module HeuristicNames { // Relationships - work and family "employ(er|ee)|spouse|maiden.?name|" + // Device information - "([_-]|\\b)ip.?addr|mac.?addr|finger.?print" + + "mac.?addr" + // --- ").*" } diff --git a/python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll b/python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll index ebc3e0b0e31a..910749a6c82b 100644 --- a/python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll +++ b/python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll @@ -114,7 +114,7 @@ module HeuristicNames { // Relationships - work and family "employ(er|ee)|spouse|maiden.?name|" + // Device information - "([_-]|\\b)ip.?addr|mac.?addr|finger.?print" + + "mac.?addr" + // --- ").*" } diff --git a/ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll b/ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll index ebc3e0b0e31a..910749a6c82b 100644 --- a/ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll +++ b/ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll @@ -114,7 +114,7 @@ module HeuristicNames { // Relationships - work and family "employ(er|ee)|spouse|maiden.?name|" + // Device information - "([_-]|\\b)ip.?addr|mac.?addr|finger.?print" + + "mac.?addr" + // --- ").*" } diff --git a/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll b/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll index ebc3e0b0e31a..910749a6c82b 100644 --- a/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll +++ b/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll @@ -114,7 +114,7 @@ module HeuristicNames { // Relationships - work and family "employ(er|ee)|spouse|maiden.?name|" + // Device information - "([_-]|\\b)ip.?addr|mac.?addr|finger.?print" + + "mac.?addr" + // --- ").*" } From da0742f3ec1cd1d3390ab84af2caab2b7caff5f6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:45:07 +0100 Subject: [PATCH 058/311] Rust: Update path resolution consistency .expected. --- .../PathResolutionConsistency.expected | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/sensitivedata/CONSISTENCY/PathResolutionConsistency.expected index 0533774588cc..3d4929f5ac60 100644 --- a/rust/ql/test/library-tests/sensitivedata/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/sensitivedata/CONSISTENCY/PathResolutionConsistency.expected @@ -1,27 +1,27 @@ multipleCallTargets -| test.rs:55:7:55:26 | ... .as_str() | -| test.rs:56:7:56:21 | ... .as_str() | -| test.rs:72:7:72:26 | ... .as_str() | -| test.rs:73:7:73:36 | ... .as_str() | -| test.rs:74:7:74:34 | ... .as_str() | -| test.rs:75:7:75:27 | ... .as_str() | -| test.rs:258:7:258:36 | ... .as_str() | -| test.rs:260:7:260:33 | ... .as_str() | -| test.rs:261:7:261:36 | ... .as_str() | -| test.rs:262:7:262:26 | ... .as_str() | -| test.rs:266:7:266:28 | ... .as_str() | -| test.rs:267:7:267:37 | ... .as_str() | -| test.rs:268:7:268:36 | ... .as_str() | -| test.rs:271:7:271:32 | ... .as_str() | -| test.rs:281:7:281:34 | ... .as_str() | -| test.rs:284:7:284:36 | ... .as_str() | -| test.rs:288:7:288:39 | ... .as_str() | -| test.rs:295:7:295:53 | ... .as_str() | -| test.rs:296:7:296:45 | ... .as_str() | -| test.rs:298:7:298:39 | ... .as_str() | -| test.rs:299:7:299:34 | ... .as_str() | -| test.rs:300:7:300:42 | ... .as_str() | -| test.rs:302:7:302:48 | ... .as_str() | -| test.rs:303:7:303:35 | ... .as_str() | -| test.rs:304:7:304:35 | ... .as_str() | -| test.rs:343:7:343:39 | ... .as_str() | +| test.rs:56:7:56:26 | ... .as_str() | +| test.rs:57:7:57:21 | ... .as_str() | +| test.rs:73:7:73:26 | ... .as_str() | +| test.rs:74:7:74:36 | ... .as_str() | +| test.rs:75:7:75:34 | ... .as_str() | +| test.rs:76:7:76:27 | ... .as_str() | +| test.rs:262:7:262:36 | ... .as_str() | +| test.rs:264:7:264:33 | ... .as_str() | +| test.rs:265:7:265:36 | ... .as_str() | +| test.rs:266:7:266:26 | ... .as_str() | +| test.rs:270:7:270:28 | ... .as_str() | +| test.rs:271:7:271:37 | ... .as_str() | +| test.rs:272:7:272:36 | ... .as_str() | +| test.rs:275:7:275:32 | ... .as_str() | +| test.rs:285:7:285:34 | ... .as_str() | +| test.rs:288:7:288:36 | ... .as_str() | +| test.rs:292:7:292:39 | ... .as_str() | +| test.rs:299:7:299:53 | ... .as_str() | +| test.rs:300:7:300:45 | ... .as_str() | +| test.rs:302:7:302:39 | ... .as_str() | +| test.rs:303:7:303:34 | ... .as_str() | +| test.rs:304:7:304:42 | ... .as_str() | +| test.rs:306:7:306:48 | ... .as_str() | +| test.rs:307:7:307:35 | ... .as_str() | +| test.rs:308:7:308:35 | ... .as_str() | +| test.rs:347:7:347:39 | ... .as_str() | From 21c030fa46c42b7c0fee1faa3cf769aa94f89408 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 14 Jul 2025 15:58:16 +0200 Subject: [PATCH 059/311] Rust: Expand on type inference test for tuples --- .../test/library-tests/type-inference/main.rs | 19 +- .../type-inference/type-inference.expected | 184 +++++++++--------- 2 files changed, 108 insertions(+), 95 deletions(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index a4a37e27794c..2be80169aa4e 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2334,11 +2334,11 @@ mod tuples { } pub fn f() { - let a = S1::get_pair(); // $ target=get_pair MISSING: type=a:? - let mut b = S1::get_pair(); // $ target=get_pair MISSING: type=b:? - let (c, d) = S1::get_pair(); // $ target=get_pair MISSING: type=c:? type=d:? - let (mut e, f) = S1::get_pair(); // $ target=get_pair MISSING: type=e: type=f: - let (mut g, mut h) = S1::get_pair(); // $ target=get_pair MISSING: type=g:? type=h:? + let a = S1::get_pair(); // $ target=get_pair MISSING: type=a:(T_2) + let mut b = S1::get_pair(); // $ target=get_pair MISSING: type=b:(T_2) + let (c, d) = S1::get_pair(); // $ target=get_pair MISSING: type=c:S1 type=d:S1 + let (mut e, f) = S1::get_pair(); // $ target=get_pair MISSING: type=e:S1 type=f:S1 + let (mut g, mut h) = S1::get_pair(); // $ target=get_pair MISSING: type=g:S1 type=h:S1 a.0.foo(); // $ MISSING: target=foo b.1.foo(); // $ MISSING: target=foo @@ -2348,6 +2348,15 @@ mod tuples { f.foo(); // $ MISSING: target=foo g.foo(); // $ MISSING: target=foo h.foo(); // $ MISSING: target=foo + + // Here type information must flow from `pair.0` and `pair.1` into + // `pair` and from `(a, b)` into `a` and `b` in order for the types of + // `a` and `b` to be inferred. + let a = Default::default(); // $ MISSING: target=default type=a:i64 + let b = Default::default(); // $ MISSING: target=default MISSING: type=b:bool + let pair = (a, b); // $ MISSING: type=pair:0.i64 type=pair:1.bool + let i: i64 = pair.0; + let j: bool = pair.1; } } 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 e4da3d0dd168..f19cfbfe8363 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -4059,96 +4059,100 @@ inferType | main.rs:2331:14:2331:18 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:21:2331:25 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2333:16:2333:19 | SelfParam | | main.rs:2327:5:2327:16 | S1 | -| main.rs:2357:13:2357:23 | boxed_value | | {EXTERNAL LOCATION} | Box | -| main.rs:2357:13:2357:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | -| main.rs:2357:13:2357:23 | boxed_value | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2357:27:2357:42 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2357:27:2357:42 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2357:27:2357:42 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2357:36:2357:41 | 100i32 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2360:15:2360:25 | boxed_value | | {EXTERNAL LOCATION} | Box | -| main.rs:2360:15:2360:25 | boxed_value | A | {EXTERNAL LOCATION} | Global | -| main.rs:2360:15:2360:25 | boxed_value | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2361:13:2361:19 | box 100 | | {EXTERNAL LOCATION} | Box | -| main.rs:2361:13:2361:19 | box 100 | A | {EXTERNAL LOCATION} | Global | -| main.rs:2361:13:2361:19 | box 100 | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2361:17:2361:19 | 100 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2362:26:2362:36 | "Boxed 100\\n" | | file://:0:0:0:0 | & | -| main.rs:2362:26:2362:36 | "Boxed 100\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2362:26:2362:36 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2362:26:2362:36 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2364:13:2364:17 | box ... | | {EXTERNAL LOCATION} | Box | -| main.rs:2364:13:2364:17 | box ... | A | {EXTERNAL LOCATION} | Global | -| main.rs:2364:13:2364:17 | box ... | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2366:26:2366:42 | "Boxed value: {}\\n" | | file://:0:0:0:0 | & | -| main.rs:2366:26:2366:42 | "Boxed value: {}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2366:26:2366:51 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2366:26:2366:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2371:13:2371:22 | nested_box | | {EXTERNAL LOCATION} | Box | -| main.rs:2371:13:2371:22 | nested_box | A | {EXTERNAL LOCATION} | Global | -| main.rs:2371:13:2371:22 | nested_box | T | {EXTERNAL LOCATION} | Box | -| main.rs:2371:13:2371:22 | nested_box | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2371:13:2371:22 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2371:26:2371:50 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2371:26:2371:50 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2371:26:2371:50 | ...::new(...) | T | {EXTERNAL LOCATION} | Box | -| main.rs:2371:26:2371:50 | ...::new(...) | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2371:26:2371:50 | ...::new(...) | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2371:35:2371:49 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2371:35:2371:49 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2371:35:2371:49 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2371:44:2371:48 | 42i32 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2372:15:2372:24 | nested_box | | {EXTERNAL LOCATION} | Box | -| main.rs:2372:15:2372:24 | nested_box | A | {EXTERNAL LOCATION} | Global | -| main.rs:2372:15:2372:24 | nested_box | T | {EXTERNAL LOCATION} | Box | -| main.rs:2372:15:2372:24 | nested_box | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2372:15:2372:24 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2373:13:2373:21 | box ... | | {EXTERNAL LOCATION} | Box | -| main.rs:2373:13:2373:21 | box ... | A | {EXTERNAL LOCATION} | Global | -| main.rs:2373:13:2373:21 | box ... | T | {EXTERNAL LOCATION} | Box | -| main.rs:2373:13:2373:21 | box ... | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2373:13:2373:21 | box ... | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2375:26:2375:43 | "Nested boxed: {}\\n" | | file://:0:0:0:0 | & | -| main.rs:2375:26:2375:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2375:26:2375:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2375:26:2375:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2387:16:2387:20 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:2387:16:2387:20 | SelfParam | &T | main.rs:2382:5:2384:5 | Row | -| main.rs:2387:30:2389:9 | { ... } | | {EXTERNAL LOCATION} | i64 | -| main.rs:2388:13:2388:16 | self | | file://:0:0:0:0 | & | -| main.rs:2388:13:2388:16 | self | &T | main.rs:2382:5:2384:5 | Row | -| main.rs:2388:13:2388:21 | self.data | | {EXTERNAL LOCATION} | i64 | -| main.rs:2397:26:2399:9 | { ... } | | main.rs:2392:5:2394:5 | Table | -| main.rs:2398:13:2398:38 | Table {...} | | main.rs:2392:5:2394:5 | Table | -| main.rs:2398:27:2398:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2398:27:2398:36 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2398:27:2398:36 | ...::new(...) | T | main.rs:2382:5:2384:5 | Row | -| main.rs:2401:23:2401:27 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:2401:23:2401:27 | SelfParam | &T | main.rs:2392:5:2394:5 | Table | -| main.rs:2401:30:2401:37 | property | | main.rs:2401:40:2401:59 | ImplTraitTypeRepr | -| main.rs:2401:69:2403:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2401:69:2403:9 | { ... } | | {EXTERNAL LOCATION} | i64 | -| main.rs:2402:13:2402:13 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2402:13:2402:13 | 0 | | {EXTERNAL LOCATION} | i64 | -| main.rs:2407:9:2407:15 | Some(...) | | {EXTERNAL LOCATION} | Option | -| main.rs:2407:9:2407:15 | Some(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2407:9:2410:10 | ... .map(...) | | {EXTERNAL LOCATION} | Option | -| main.rs:2407:14:2407:14 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2409:22:2409:26 | "{x}\\n" | | file://:0:0:0:0 | & | -| main.rs:2409:22:2409:26 | "{x}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2409:22:2409:26 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2409:22:2409:26 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2412:13:2412:17 | table | | main.rs:2392:5:2394:5 | Table | -| main.rs:2412:21:2412:32 | ...::new(...) | | main.rs:2392:5:2394:5 | Table | -| main.rs:2413:13:2413:18 | result | | {EXTERNAL LOCATION} | i64 | -| main.rs:2413:22:2413:26 | table | | main.rs:2392:5:2394:5 | Table | -| main.rs:2413:22:2417:14 | table.count_with(...) | | {EXTERNAL LOCATION} | i64 | -| main.rs:2416:21:2416:21 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2423:5:2423:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2424:5:2424:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2424:20:2424:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2424:41:2424:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2440:5:2440:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | +| main.rs:2358:13:2358:13 | i | | {EXTERNAL LOCATION} | i64 | +| main.rs:2358:22:2358:27 | pair.0 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2359:13:2359:13 | j | | {EXTERNAL LOCATION} | bool | +| main.rs:2359:23:2359:28 | pair.1 | | {EXTERNAL LOCATION} | bool | +| main.rs:2366:13:2366:23 | boxed_value | | {EXTERNAL LOCATION} | Box | +| main.rs:2366:13:2366:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | +| main.rs:2366:13:2366:23 | boxed_value | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2366:27:2366:42 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2366:27:2366:42 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2366:27:2366:42 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2366:36:2366:41 | 100i32 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2369:15:2369:25 | boxed_value | | {EXTERNAL LOCATION} | Box | +| main.rs:2369:15:2369:25 | boxed_value | A | {EXTERNAL LOCATION} | Global | +| main.rs:2369:15:2369:25 | boxed_value | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2370:13:2370:19 | box 100 | | {EXTERNAL LOCATION} | Box | +| main.rs:2370:13:2370:19 | box 100 | A | {EXTERNAL LOCATION} | Global | +| main.rs:2370:13:2370:19 | box 100 | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2370:17:2370:19 | 100 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2371:26:2371:36 | "Boxed 100\\n" | | file://:0:0:0:0 | & | +| main.rs:2371:26:2371:36 | "Boxed 100\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2371:26:2371:36 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2371:26:2371:36 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2373:13:2373:17 | box ... | | {EXTERNAL LOCATION} | Box | +| main.rs:2373:13:2373:17 | box ... | A | {EXTERNAL LOCATION} | Global | +| main.rs:2373:13:2373:17 | box ... | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2375:26:2375:42 | "Boxed value: {}\\n" | | file://:0:0:0:0 | & | +| main.rs:2375:26:2375:42 | "Boxed value: {}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2375:26:2375:51 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2375:26:2375:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2380:13:2380:22 | nested_box | | {EXTERNAL LOCATION} | Box | +| main.rs:2380:13:2380:22 | nested_box | A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:13:2380:22 | nested_box | T | {EXTERNAL LOCATION} | Box | +| main.rs:2380:13:2380:22 | nested_box | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:13:2380:22 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2380:26:2380:50 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2380:26:2380:50 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:26:2380:50 | ...::new(...) | T | {EXTERNAL LOCATION} | Box | +| main.rs:2380:26:2380:50 | ...::new(...) | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:26:2380:50 | ...::new(...) | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2380:35:2380:49 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2380:35:2380:49 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:35:2380:49 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2380:44:2380:48 | 42i32 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2381:15:2381:24 | nested_box | | {EXTERNAL LOCATION} | Box | +| main.rs:2381:15:2381:24 | nested_box | A | {EXTERNAL LOCATION} | Global | +| main.rs:2381:15:2381:24 | nested_box | T | {EXTERNAL LOCATION} | Box | +| main.rs:2381:15:2381:24 | nested_box | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2381:15:2381:24 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2382:13:2382:21 | box ... | | {EXTERNAL LOCATION} | Box | +| main.rs:2382:13:2382:21 | box ... | A | {EXTERNAL LOCATION} | Global | +| main.rs:2382:13:2382:21 | box ... | T | {EXTERNAL LOCATION} | Box | +| main.rs:2382:13:2382:21 | box ... | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2382:13:2382:21 | box ... | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2384:26:2384:43 | "Nested boxed: {}\\n" | | file://:0:0:0:0 | & | +| main.rs:2384:26:2384:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2384:26:2384:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2384:26:2384:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2396:16:2396:20 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:2396:16:2396:20 | SelfParam | &T | main.rs:2391:5:2393:5 | Row | +| main.rs:2396:30:2398:9 | { ... } | | {EXTERNAL LOCATION} | i64 | +| main.rs:2397:13:2397:16 | self | | file://:0:0:0:0 | & | +| main.rs:2397:13:2397:16 | self | &T | main.rs:2391:5:2393:5 | Row | +| main.rs:2397:13:2397:21 | self.data | | {EXTERNAL LOCATION} | i64 | +| main.rs:2406:26:2408:9 | { ... } | | main.rs:2401:5:2403:5 | Table | +| main.rs:2407:13:2407:38 | Table {...} | | main.rs:2401:5:2403:5 | Table | +| main.rs:2407:27:2407:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2407:27:2407:36 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2407:27:2407:36 | ...::new(...) | T | main.rs:2391:5:2393:5 | Row | +| main.rs:2410:23:2410:27 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:2410:23:2410:27 | SelfParam | &T | main.rs:2401:5:2403:5 | Table | +| main.rs:2410:30:2410:37 | property | | main.rs:2410:40:2410:59 | ImplTraitTypeRepr | +| main.rs:2410:69:2412:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2410:69:2412:9 | { ... } | | {EXTERNAL LOCATION} | i64 | +| main.rs:2411:13:2411:13 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2411:13:2411:13 | 0 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2416:9:2416:15 | Some(...) | | {EXTERNAL LOCATION} | Option | +| main.rs:2416:9:2416:15 | Some(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2416:9:2419:10 | ... .map(...) | | {EXTERNAL LOCATION} | Option | +| main.rs:2416:14:2416:14 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2418:22:2418:26 | "{x}\\n" | | file://:0:0:0:0 | & | +| main.rs:2418:22:2418:26 | "{x}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2418:22:2418:26 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2418:22:2418:26 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2421:13:2421:17 | table | | main.rs:2401:5:2403:5 | Table | +| main.rs:2421:21:2421:32 | ...::new(...) | | main.rs:2401:5:2403:5 | Table | +| main.rs:2422:13:2422:18 | result | | {EXTERNAL LOCATION} | i64 | +| main.rs:2422:22:2422:26 | table | | main.rs:2401:5:2403:5 | Table | +| main.rs:2422:22:2426:14 | table.count_with(...) | | {EXTERNAL LOCATION} | i64 | +| main.rs:2425:21:2425:21 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2432:5:2432:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2433:5:2433:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2433:20:2433:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2433:41:2433:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2449:5:2449:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:14:9:14:13 | value | T | {EXTERNAL LOCATION} | i32 | From cbde11ddc9ed3b949a54db8b43726a0aedd7e312 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 14 Jul 2025 16:12:30 +0200 Subject: [PATCH 060/311] Properly share `ConceptsShared.qll` --- config/identical-files.json | 6 - .../ql/lib/semmle/javascript/Concepts.qll | 6 +- .../javascript/internal/ConceptsImports.qll | 7 - .../javascript/internal/ConceptsShared.qll | 181 ----------------- python/ql/lib/semmle/python/Concepts.qll | 9 +- .../lib/semmle/python/frameworks/Aiohttp.qll | 10 +- .../semmle/python/frameworks/Cryptodome.qll | 33 ++-- .../semmle/python/frameworks/Cryptography.qll | 14 +- .../ql/lib/semmle/python/frameworks/Httpx.qll | 21 +- .../lib/semmle/python/frameworks/Libtaxii.qll | 4 +- .../lib/semmle/python/frameworks/Pycurl.qll | 15 +- .../lib/semmle/python/frameworks/Requests.qll | 12 +- .../ql/lib/semmle/python/frameworks/Rsa.qll | 38 ++-- .../lib/semmle/python/frameworks/Stdlib.qll | 54 +++-- .../python/frameworks/Stdlib/Urllib.qll | 12 +- .../python/frameworks/Stdlib/Urllib2.qll | 8 +- .../lib/semmle/python/frameworks/Urllib3.qll | 6 +- .../python/internal/ConceptsImports.qll | 7 - .../semmle/python/internal/ConceptsShared.qll | 181 ----------------- ruby/ql/lib/codeql/ruby/Concepts.qll | 8 +- .../codeql/ruby/frameworks/ActiveResource.qll | 14 +- .../ruby/frameworks/http_clients/Excon.qll | 6 +- .../ruby/frameworks/http_clients/Faraday.qll | 4 +- .../frameworks/http_clients/HttpClient.qll | 4 +- .../ruby/frameworks/http_clients/Httparty.qll | 6 +- .../ruby/frameworks/http_clients/NetHttp.qll | 2 +- .../ruby/frameworks/http_clients/OpenURI.qll | 15 +- .../frameworks/http_clients/RestClient.qll | 6 +- .../ruby/frameworks/http_clients/Typhoeus.qll | 6 +- .../codeql/ruby/internal/ConceptsImports.qll | 7 - .../codeql/ruby/internal/ConceptsShared.qll | 181 ----------------- ruby/ql/lib/codeql/ruby/security/OpenSSL.qll | 7 +- rust/ql/lib/codeql/rust/Concepts.qll | 7 +- .../codeql/rust/internal/ConceptsImports.qll | 7 - .../codeql/rust/internal/ConceptsShared.qll | 181 ----------------- .../codeql/concepts/ConceptsShared.qll | 187 ++++++++++++++++++ shared/concepts/qlpack.yml | 4 +- 37 files changed, 373 insertions(+), 903 deletions(-) delete mode 100644 javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll delete mode 100644 javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll delete mode 100644 python/ql/lib/semmle/python/internal/ConceptsImports.qll delete mode 100644 python/ql/lib/semmle/python/internal/ConceptsShared.qll delete mode 100644 ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll delete mode 100644 ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll delete mode 100644 rust/ql/lib/codeql/rust/internal/ConceptsImports.qll delete mode 100644 rust/ql/lib/codeql/rust/internal/ConceptsShared.qll create mode 100644 shared/concepts/codeql/concepts/ConceptsShared.qll diff --git a/config/identical-files.json b/config/identical-files.json index 977f3f4a6473..89beb48acd40 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -235,12 +235,6 @@ "javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll", "ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll" ], - "Concepts Python/Ruby/JS": [ - "python/ql/lib/semmle/python/internal/ConceptsShared.qll", - "ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll", - "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll", - "rust/ql/lib/codeql/rust/internal/ConceptsShared.qll" - ], "ApiGraphModels": [ "javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll", "ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll", diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index 3fce9f6f34a0..76c67156d1ca 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -5,7 +5,11 @@ */ import javascript +private import semmle.javascript.dataflow.internal.sharedlib.DataFlowArg private import codeql.threatmodels.ThreatModels +private import codeql.concepts.ConceptsShared + +private module ConceptsShared = ConceptsMake; /** * A data flow source, for a specific threat-model. @@ -206,7 +210,7 @@ abstract class PersistentWriteAccess extends DataFlow::Node { * Provides models for cryptographic things. */ module Cryptography { - private import semmle.javascript.internal.ConceptsShared::Cryptography as SC + private import ConceptsShared::Cryptography as SC /** * A data-flow node that is an application of a cryptographic algorithm. For example, diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll deleted file mode 100644 index 3aae9c05fb5e..000000000000 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsImports.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file contains imports required for the JavaScript version of `ConceptsShared.qll`. - * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. - */ - -import semmle.javascript.dataflow.DataFlow::DataFlow as DataFlow -import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll deleted file mode 100644 index 1b13e4ebb17e..000000000000 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Provides Concepts which are shared across languages. - * - * Each language has a language specific `Concepts.qll` file that can import the - * shared concepts from this file. A language can either re-export the concept directly, - * or can add additional member-predicates that are needed for that language. - * - * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from - * each language, but we will maintain a discipline of moving those concepts to - * `ConceptsShared.qll` ASAP. - */ - -private import ConceptsImports - -/** - * Provides models for cryptographic concepts. - * - * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into - * consideration for the `isWeak` member predicate. So RSA is always considered - * secure, although using a low number of bits will actually make it insecure. We plan - * to improve our libraries in the future to more precisely capture this aspect. - */ -module Cryptography { - class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; - - class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; - - class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; - - class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; - - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CryptographicOperation::Range` instead. - */ - class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - DataFlow::Node getInitialization() { result = super.getInitialization() } - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - BlockMode getBlockMode() { result = super.getBlockMode() } - } - - /** Provides classes for modeling new applications of a cryptographic algorithms. */ - module CryptographicOperation { - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CryptographicOperation` instead. - */ - abstract class Range extends DataFlow::Node { - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - abstract DataFlow::Node getInitialization(); - - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - abstract CryptographicAlgorithm getAlgorithm(); - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - abstract DataFlow::Node getAnInput(); - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - abstract BlockMode getBlockMode(); - } - } - - /** - * A cryptographic block cipher mode of operation. This can be used to encrypt - * data of arbitrary length using a block encryption algorithm. - */ - class BlockMode extends string { - BlockMode() { - this = - [ - "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", - "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final - "EAX" // https://en.wikipedia.org/wiki/EAX_mode - ] - } - - /** Holds if this block mode is considered to be insecure. */ - predicate isWeak() { this = "ECB" } - - /** Holds if the given string appears to match this block mode. */ - bindingset[s] - predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } - } -} - -/** Provides classes for modeling HTTP-related APIs. */ -module Http { - /** Provides classes for modeling HTTP clients. */ - module Client { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `Http::Client::Request::Range` instead. - */ - class Request extends DataFlow::Node instanceof Request::Range { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } - - /** Gets a string that identifies the framework used for this request. */ - string getFramework() { result = super.getFramework() } - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ) { - super.disablesCertificateValidation(disablingNode, argumentOrigin) - } - } - - /** Provides a class for modeling new HTTP requests. */ - module Request { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `Http::Client::Request` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - abstract DataFlow::Node getAUrlPart(); - - /** Gets a string that identifies the framework used for this request. */ - abstract string getFramework(); - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - abstract predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ); - } - } - } -} diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 27f622c7c868..16524aaf1dbd 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -6,11 +6,16 @@ private import python private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.internal.DataFlowImplSpecific private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.Files private import semmle.python.Frameworks private import semmle.python.security.internal.EncryptionKeySizes private import codeql.threatmodels.ThreatModels +private import codeql.concepts.ConceptsShared + +private module ConceptsShared = ConceptsMake; /** * A data flow source, for a specific threat-model. @@ -1617,7 +1622,7 @@ module Http { } } - import semmle.python.internal.ConceptsShared::Http::Client as Client + import ConceptsShared::Http::Client as Client // TODO: investigate whether we should treat responses to client requests as // remote-flow-sources in general. } @@ -1725,5 +1730,5 @@ module Cryptography { } } - import semmle.python.internal.ConceptsShared::Cryptography + import ConceptsShared::Cryptography } diff --git a/python/ql/lib/semmle/python/frameworks/Aiohttp.qll b/python/ql/lib/semmle/python/frameworks/Aiohttp.qll index 2f5b0393c5f3..43185efef771 100644 --- a/python/ql/lib/semmle/python/frameworks/Aiohttp.qll +++ b/python/ql/lib/semmle/python/frameworks/Aiohttp.qll @@ -758,7 +758,7 @@ module AiohttpClientModel { private API::Node instance() { result = classRef().getReturn() } /** A method call on a ClientSession that sends off a request */ - private class OutgoingRequestCall extends Http::Client::Request::Range, API::CallNode { + private class OutgoingRequestCall extends Http::Client::Request::Range instanceof API::CallNode { string methodName; OutgoingRequestCall() { @@ -767,13 +767,13 @@ module AiohttpClientModel { } override DataFlow::Node getAUrlPart() { - result = this.getArgByName("url") + result = super.getArgByName("url") or methodName in [Http::httpVerbLower(), "ws_connect"] and - result = this.getArg(0) + result = super.getArg(0) or methodName = "request" and - result = this.getArg(1) + result = super.getArg(1) } override string getFramework() { result = "aiohttp.ClientSession" } @@ -781,7 +781,7 @@ module AiohttpClientModel { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - exists(API::Node param | param = this.getKeywordParameter(["ssl", "verify_ssl"]) | + exists(API::Node param | param = super.getKeywordParameter(["ssl", "verify_ssl"]) | disablingNode = param.asSink() and argumentOrigin = param.getAValueReachingSink() and // aiohttp.client treats `None` as the default and all other "falsey" values as `False`. diff --git a/python/ql/lib/semmle/python/frameworks/Cryptodome.qll b/python/ql/lib/semmle/python/frameworks/Cryptodome.qll index 4dc193b13866..81025e27d782 100644 --- a/python/ql/lib/semmle/python/frameworks/Cryptodome.qll +++ b/python/ql/lib/semmle/python/frameworks/Cryptodome.qll @@ -107,8 +107,7 @@ private module CryptodomeModel { /** * A cryptographic operation on an instance from the `Cipher` subpackage of `Cryptodome`/`Crypto`. */ - class CryptodomeGenericCipherOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::CallCfgNode + class CryptodomeGenericCipherOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode { string methodName; string cipherName; @@ -134,31 +133,31 @@ private module CryptodomeModel { override DataFlow::Node getAnInput() { methodName = "encrypt" and - result in [this.getArg(0), this.getArgByName(["message", "plaintext"])] + result in [super.getArg(0), super.getArgByName(["message", "plaintext"])] or methodName = "decrypt" and - result in [this.getArg(0), this.getArgByName("ciphertext")] + result in [super.getArg(0), super.getArgByName("ciphertext")] or // for the following methods, method signatures can be found in // https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html methodName = "update" and - result in [this.getArg(0), this.getArgByName("data")] + result in [super.getArg(0), super.getArgByName("data")] or // although `mac_tag` is used as the parameter name in the spec above, some implementations use `received_mac_tag`, for an example, see // https://github.com/Legrandin/pycryptodome/blob/5dace638b70ac35bb5d9b565f3e75f7869c9d851/lib/Crypto/Cipher/ChaCha20_Poly1305.py#L207 methodName = "verify" and - result in [this.getArg(0), this.getArgByName(["mac_tag", "received_mac_tag"])] + result in [super.getArg(0), super.getArgByName(["mac_tag", "received_mac_tag"])] or methodName = "hexverify" and - result in [this.getArg(0), this.getArgByName("mac_tag_hex")] + result in [super.getArg(0), super.getArgByName("mac_tag_hex")] or methodName = "encrypt_and_digest" and - result in [this.getArg(0), this.getArgByName("plaintext")] + result in [super.getArg(0), super.getArgByName("plaintext")] or methodName = "decrypt_and_verify" and result in [ - this.getArg(0), this.getArgByName("ciphertext"), this.getArg(1), - this.getArgByName("mac_tag") + super.getArg(0), super.getArgByName("ciphertext"), super.getArg(1), + super.getArgByName("mac_tag") ] } @@ -180,8 +179,7 @@ private module CryptodomeModel { /** * A cryptographic operation on an instance from the `Signature` subpackage of `Cryptodome`/`Crypto`. */ - class CryptodomeGenericSignatureOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::CallCfgNode + class CryptodomeGenericSignatureOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode { API::CallNode newCall; string methodName; @@ -206,13 +204,13 @@ private module CryptodomeModel { override DataFlow::Node getAnInput() { methodName = "sign" and - result in [this.getArg(0), this.getArgByName("msg_hash")] // Cryptodome.Hash instance + result in [super.getArg(0), super.getArgByName("msg_hash")] // Cryptodome.Hash instance or methodName = "verify" and ( - result in [this.getArg(0), this.getArgByName("msg_hash")] // Cryptodome.Hash instance + result in [super.getArg(0), super.getArgByName("msg_hash")] // Cryptodome.Hash instance or - result in [this.getArg(1), this.getArgByName("signature")] + result in [super.getArg(1), super.getArgByName("signature")] ) } @@ -222,8 +220,7 @@ private module CryptodomeModel { /** * A cryptographic operation on an instance from the `Hash` subpackage of `Cryptodome`/`Crypto`. */ - class CryptodomeGenericHashOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::CallCfgNode + class CryptodomeGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode { API::CallNode newCall; string hashName; @@ -244,7 +241,7 @@ private module CryptodomeModel { override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) } - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } + override DataFlow::Node getAnInput() { result in [super.getArg(0), super.getArgByName("data")] } override Cryptography::BlockMode getBlockMode() { none() } } diff --git a/python/ql/lib/semmle/python/frameworks/Cryptography.qll b/python/ql/lib/semmle/python/frameworks/Cryptography.qll index 41d69d064d73..8996f2d2c08c 100644 --- a/python/ql/lib/semmle/python/frameworks/Cryptography.qll +++ b/python/ql/lib/semmle/python/frameworks/Cryptography.qll @@ -206,8 +206,7 @@ private module CryptographyModel { /** * An encrypt or decrypt operation from `cryptography.hazmat.primitives.ciphers`. */ - class CryptographyGenericCipherOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::MethodCallNode + class CryptographyGenericCipherOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::MethodCallNode { API::CallNode init; string algorithmName; @@ -225,7 +224,9 @@ private module CryptographyModel { result.matchesName(algorithmName) } - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } + override DataFlow::Node getAnInput() { + result in [super.getArg(0), super.getArgByName("data")] + } override Cryptography::BlockMode getBlockMode() { result = modeName } } @@ -263,8 +264,7 @@ private module CryptographyModel { /** * An hashing operation from `cryptography.hazmat.primitives.hashes`. */ - class CryptographyGenericHashOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::MethodCallNode + class CryptographyGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::MethodCallNode { API::CallNode init; string algorithmName; @@ -280,7 +280,9 @@ private module CryptographyModel { result.matchesName(algorithmName) } - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } + override DataFlow::Node getAnInput() { + result in [super.getArg(0), super.getArgByName("data")] + } override Cryptography::BlockMode getBlockMode() { none() } } diff --git a/python/ql/lib/semmle/python/frameworks/Httpx.qll b/python/ql/lib/semmle/python/frameworks/Httpx.qll index fee9a840a193..bca1c25b4deb 100644 --- a/python/ql/lib/semmle/python/frameworks/Httpx.qll +++ b/python/ql/lib/semmle/python/frameworks/Httpx.qll @@ -26,7 +26,7 @@ module HttpxModel { * * See https://www.python-httpx.org/api/ */ - private class RequestCall extends Http::Client::Request::Range, API::CallNode { + private class RequestCall extends Http::Client::Request::Range instanceof API::CallNode { string methodName; RequestCall() { @@ -35,11 +35,11 @@ module HttpxModel { } override DataFlow::Node getAUrlPart() { - result = this.getArgByName("url") + result = super.getArgByName("url") or if methodName in ["request", "stream"] - then result = this.getArg(1) - else result = this.getArg(0) + then result = super.getArg(1) + else result = super.getArg(0) } override string getFramework() { result = "httpx" } @@ -47,8 +47,8 @@ module HttpxModel { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - disablingNode = this.getKeywordParameter("verify").asSink() and - argumentOrigin = this.getKeywordParameter("verify").getAValueReachingSink() and + disablingNode = super.getKeywordParameter("verify").asSink() and + argumentOrigin = super.getKeywordParameter("verify").getAValueReachingSink() and // unlike `requests`, httpx treats `None` as turning off verify (and not as the default) argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false // TODO: Handling of insecure SSLContext passed to verify argument @@ -69,7 +69,8 @@ module HttpxModel { } /** A method call on a Client that sends off a request */ - private class OutgoingRequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class OutgoingRequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode + { string methodName; OutgoingRequestCall() { @@ -78,11 +79,11 @@ module HttpxModel { } override DataFlow::Node getAUrlPart() { - result = this.getArgByName("url") + result = super.getArgByName("url") or if methodName in ["request", "stream"] - then result = this.getArg(1) - else result = this.getArg(0) + then result = super.getArg(1) + else result = super.getArg(0) } override string getFramework() { result = "httpx.[Async]Client" } diff --git a/python/ql/lib/semmle/python/frameworks/Libtaxii.qll b/python/ql/lib/semmle/python/frameworks/Libtaxii.qll index 5df0e7127ecf..65dbb79566c9 100644 --- a/python/ql/lib/semmle/python/frameworks/Libtaxii.qll +++ b/python/ql/lib/semmle/python/frameworks/Libtaxii.qll @@ -22,13 +22,13 @@ private module Libtaxii { * A call to `libtaxii.common.parse`. * When the `allow_url` parameter value is set to `True`, there is an SSRF vulnerability.. */ - private class ParseCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class ParseCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { ParseCall() { this = API::moduleImport("libtaxii").getMember("common").getMember("parse").getACall() and this.getArgByName("allow_url").getALocalSource().asExpr() = any(True t) } - override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("s")] } + override DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("s")] } override string getFramework() { result = "libtaxii.common.parse" } diff --git a/python/ql/lib/semmle/python/frameworks/Pycurl.qll b/python/ql/lib/semmle/python/frameworks/Pycurl.qll index 9ce97388662a..7280eec5f61c 100644 --- a/python/ql/lib/semmle/python/frameworks/Pycurl.qll +++ b/python/ql/lib/semmle/python/frameworks/Pycurl.qll @@ -52,14 +52,15 @@ module Pycurl { * * See http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt. */ - private class OutgoingRequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class OutgoingRequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode + { OutgoingRequestCall() { this = setopt().getACall() and this.getArg(0).asCfgNode().(AttrNode).getName() = "URL" } override DataFlow::Node getAUrlPart() { - result in [this.getArg(1), this.getArgByName("value")] + result in [super.getArg(1), super.getArgByName("value")] } override string getFramework() { result = "pycurl.Curl" } @@ -77,7 +78,7 @@ module Pycurl { * * See http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt. */ - private class CurlSslCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class CurlSslCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { CurlSslCall() { this = setopt().getACall() and this.getArg(0).asCfgNode().(AttrNode).getName() = ["SSL_VERIFYPEER", "SSL_VERIFYHOST"] @@ -90,13 +91,13 @@ module Pycurl { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - sslverifypeer().getAValueReachableFromSource() = this.getArg(0) and + sslverifypeer().getAValueReachableFromSource() = super.getArg(0) and ( - this.getArg(1).asExpr().(IntegerLiteral).getValue() = 0 + super.getArg(1).asExpr().(IntegerLiteral).getValue() = 0 or - this.getArg(1).asExpr().(BooleanLiteral).booleanValue() = false + super.getArg(1).asExpr().(BooleanLiteral).booleanValue() = false ) and - (disablingNode = this and argumentOrigin = this.getArg(1)) + (disablingNode = this and argumentOrigin = super.getArg(1)) } } } diff --git a/python/ql/lib/semmle/python/frameworks/Requests.qll b/python/ql/lib/semmle/python/frameworks/Requests.qll index e47ac10df3e5..4c8038787c96 100644 --- a/python/ql/lib/semmle/python/frameworks/Requests.qll +++ b/python/ql/lib/semmle/python/frameworks/Requests.qll @@ -29,7 +29,7 @@ module Requests { * * See https://requests.readthedocs.io/en/latest/api/#requests.request */ - private class OutgoingRequestCall extends Http::Client::Request::Range, API::CallNode { + private class OutgoingRequestCall extends Http::Client::Request::Range instanceof API::CallNode { string methodName; OutgoingRequestCall() { @@ -50,20 +50,20 @@ module Requests { } override DataFlow::Node getAUrlPart() { - result = this.getArgByName("url") + result = super.getArgByName("url") or not methodName = "request" and - result = this.getArg(0) + result = super.getArg(0) or methodName = "request" and - result = this.getArg(1) + result = super.getArg(1) } override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - disablingNode = this.getKeywordParameter("verify").asSink() and - argumentOrigin = this.getKeywordParameter("verify").getAValueReachingSink() and + disablingNode = super.getKeywordParameter("verify").asSink() and + argumentOrigin = super.getKeywordParameter("verify").getAValueReachingSink() and // requests treats `None` as the default and all other "falsey" values as `False`. argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false and not argumentOrigin.asExpr() instanceof None diff --git a/python/ql/lib/semmle/python/frameworks/Rsa.qll b/python/ql/lib/semmle/python/frameworks/Rsa.qll index 0f0dd2d3d927..75fb4e3a6338 100644 --- a/python/ql/lib/semmle/python/frameworks/Rsa.qll +++ b/python/ql/lib/semmle/python/frameworks/Rsa.qll @@ -34,7 +34,8 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.encrypt */ - class RsaEncryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode { + class RsaEncryptCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode + { RsaEncryptCall() { this = API::moduleImport("rsa").getMember("encrypt").getACall() } override DataFlow::Node getInitialization() { result = this } @@ -42,7 +43,7 @@ private module Rsa { override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" } override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("message")] + result in [super.getArg(0), super.getArgByName("message")] } override Cryptography::BlockMode getBlockMode() { none() } @@ -53,14 +54,17 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.decrypt */ - class RsaDecryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode { + class RsaDecryptCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode + { RsaDecryptCall() { this = API::moduleImport("rsa").getMember("decrypt").getACall() } override DataFlow::Node getInitialization() { result = this } override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" } - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("crypto")] } + override DataFlow::Node getAnInput() { + result in [super.getArg(0), super.getArgByName("crypto")] + } override Cryptography::BlockMode getBlockMode() { none() } } @@ -70,7 +74,8 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign */ - class RsaSignCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode { + class RsaSignCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode + { RsaSignCall() { this = API::moduleImport("rsa").getMember("sign").getACall() } override DataFlow::Node getInitialization() { result = this } @@ -81,14 +86,14 @@ private module Rsa { or // hashing part exists(StringLiteral str, DataFlow::Node hashNameArg | - hashNameArg in [this.getArg(2), this.getArgByName("hash_method")] and + hashNameArg in [super.getArg(2), super.getArgByName("hash_method")] and DataFlow::exprNode(str) = hashNameArg.getALocalSource() and result.matchesName(str.getText()) ) } override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("message")] + result in [super.getArg(0), super.getArgByName("message")] } override Cryptography::BlockMode getBlockMode() { none() } @@ -99,7 +104,8 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.verify */ - class RsaVerifyCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode { + class RsaVerifyCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode + { RsaVerifyCall() { this = API::moduleImport("rsa").getMember("verify").getACall() } override DataFlow::Node getInitialization() { result = this } @@ -111,9 +117,9 @@ private module Rsa { } override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("message")] + result in [super.getArg(0), super.getArgByName("message")] or - result in [this.getArg(1), this.getArgByName("signature")] + result in [super.getArg(1), super.getArgByName("signature")] } override Cryptography::BlockMode getBlockMode() { none() } @@ -124,8 +130,7 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.compute_hash */ - class RsaComputeHashCall extends Cryptography::CryptographicOperation::Range, - DataFlow::CallCfgNode + class RsaComputeHashCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode { RsaComputeHashCall() { this = API::moduleImport("rsa").getMember("compute_hash").getACall() } @@ -133,14 +138,14 @@ private module Rsa { override Cryptography::CryptographicAlgorithm getAlgorithm() { exists(StringLiteral str, DataFlow::Node hashNameArg | - hashNameArg in [this.getArg(1), this.getArgByName("method_name")] and + hashNameArg in [super.getArg(1), super.getArgByName("method_name")] and DataFlow::exprNode(str) = hashNameArg.getALocalSource() and result.matchesName(str.getText()) ) } override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("message")] + result in [super.getArg(0), super.getArgByName("message")] } override Cryptography::BlockMode getBlockMode() { none() } @@ -151,7 +156,8 @@ private module Rsa { * * See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign_hash */ - class RsaSignHashCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode { + class RsaSignHashCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode + { RsaSignHashCall() { this = API::moduleImport("rsa").getMember("sign_hash").getACall() } override DataFlow::Node getInitialization() { result = this } @@ -159,7 +165,7 @@ private module Rsa { override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" } override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("hash_value")] + result in [super.getArg(0), super.getArgByName("hash_value")] } override Cryptography::BlockMode getBlockMode() { none() } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 4a3c346fb016..ceb2f1952a02 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2385,15 +2385,16 @@ module StdlibPrivate { } /** A method call on a HttpConnection that sends off a request */ - private class RequestCall extends Http::Client::Request::Range, DataFlow::MethodCallNode { + private class RequestCall extends Http::Client::Request::Range instanceof DataFlow::MethodCallNode + { RequestCall() { this.calls(instance(_), ["request", "_send_request", "putrequest"]) } - DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] } + DataFlow::Node getUrlArg() { result in [super.getArg(1), super.getArgByName("url")] } override DataFlow::Node getAUrlPart() { result = this.getUrlArg() or - this.getObject() = instance(result) + super.getObject() = instance(result) } override string getFramework() { result = "http.client.HTTP[S]Connection" } @@ -2430,7 +2431,8 @@ module StdlibPrivate { // a request method exists(RequestCall call | nodeFrom = call.getUrlArg() and - nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = call.getObject() + nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = + call.(DataFlow::MethodCallNode).getObject() ) or // `getresponse` call @@ -2797,7 +2799,7 @@ module StdlibPrivate { /** * A hashing operation by supplying initial data when calling the `hashlib.new` function. */ - class HashlibNewCall extends Cryptography::CryptographicOperation::Range, API::CallNode { + class HashlibNewCall extends Cryptography::CryptographicOperation::Range instanceof API::CallNode { string hashName; HashlibNewCall() { @@ -2810,7 +2812,7 @@ module StdlibPrivate { override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) } - override DataFlow::Node getAnInput() { result = this.getParameter(1, "data").asSink() } + override DataFlow::Node getAnInput() { result = super.getParameter(1, "data").asSink() } override Cryptography::BlockMode getBlockMode() { none() } } @@ -2818,7 +2820,8 @@ module StdlibPrivate { /** * A hashing operation by using the `update` method on the result of calling the `hashlib.new` function. */ - class HashlibNewUpdateCall extends Cryptography::CryptographicOperation::Range, API::CallNode { + class HashlibNewUpdateCall extends Cryptography::CryptographicOperation::Range instanceof API::CallNode + { API::CallNode init; string hashName; @@ -2831,7 +2834,7 @@ module StdlibPrivate { override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) } - override DataFlow::Node getAnInput() { result = this.getArg(0) } + override DataFlow::Node getAnInput() { result = super.getArg(0) } override Cryptography::BlockMode getBlockMode() { none() } } @@ -2848,8 +2851,7 @@ module StdlibPrivate { * (such as `hashlib.md5`). `hashlib.new` is not included, since it is handled by * `HashlibNewCall` and `HashlibNewUpdateCall`. */ - abstract class HashlibGenericHashOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::CallCfgNode + abstract class HashlibGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode { string hashName; API::Node hashClass; @@ -2876,7 +2878,7 @@ module StdlibPrivate { override DataFlow::Node getInitialization() { result = init } - override DataFlow::Node getAnInput() { result = this.getArg(0) } + override DataFlow::Node getAnInput() { result = this.(DataFlow::CallCfgNode).getArg(0) } } /** @@ -2888,24 +2890,28 @@ module StdlibPrivate { // we only want to model calls to classes such as `hashlib.md5()` if initial data // is passed as an argument this = hashClass.getACall() and - exists([this.getArg(0), this.getArgByName("string")]) + exists( + [ + this.(DataFlow::CallCfgNode).getArg(0), + this.(DataFlow::CallCfgNode).getArgByName("string") + ] + ) } override DataFlow::Node getInitialization() { result = this } override DataFlow::Node getAnInput() { - result = this.getArg(0) + result = this.(DataFlow::CallCfgNode).getArg(0) or // in Python 3.9, you are allowed to use `hashlib.md5(string=)`. - result = this.getArgByName("string") + result = this.(DataFlow::CallCfgNode).getArgByName("string") } } // --------------------------------------------------------------------------- // hmac // --------------------------------------------------------------------------- - abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range, - API::CallNode + abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range instanceof API::CallNode { abstract API::Node getDigestArg(); @@ -2937,14 +2943,16 @@ module StdlibPrivate { HmacNewCall() { this = getHmacConstructorCall(digestArg) and // we only want to consider it as an cryptographic operation if the input is available - exists(this.getParameter(1, "msg").asSink()) + exists(this.(API::CallNode).getParameter(1, "msg").asSink()) } override DataFlow::Node getInitialization() { result = this } override API::Node getDigestArg() { result = digestArg } - override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() } + override DataFlow::Node getAnInput() { + result = this.(API::CallNode).getParameter(1, "msg").asSink() + } } /** @@ -2965,7 +2973,9 @@ module StdlibPrivate { override API::Node getDigestArg() { result = digestArg } - override DataFlow::Node getAnInput() { result = this.getParameter(0, "msg").asSink() } + override DataFlow::Node getAnInput() { + result = this.(API::CallNode).getParameter(0, "msg").asSink() + } } /** @@ -2978,9 +2988,11 @@ module StdlibPrivate { override DataFlow::Node getInitialization() { result = this } - override API::Node getDigestArg() { result = this.getParameter(2, "digest") } + override API::Node getDigestArg() { result = this.(API::CallNode).getParameter(2, "digest") } - override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() } + override DataFlow::Node getAnInput() { + result = this.(API::CallNode).getParameter(1, "msg").asSink() + } } // --------------------------------------------------------------------------- diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll index fc385a2f8ed9..6b5764e55925 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll @@ -31,12 +31,14 @@ private module Urllib { * See * - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.Request */ - private class RequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class RequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { RequestCall() { this = API::moduleImport("urllib").getMember("request").getMember("Request").getACall() } - override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] } + override DataFlow::Node getAUrlPart() { + result in [super.getArg(0), super.getArgByName("url")] + } override string getFramework() { result = "urllib.request.Request" } @@ -53,12 +55,14 @@ private module Urllib { * See * - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.urlopen */ - private class UrlOpenCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class UrlOpenCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { UrlOpenCall() { this = API::moduleImport("urllib").getMember("request").getMember("urlopen").getACall() } - override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] } + override DataFlow::Node getAUrlPart() { + result in [super.getArg(0), super.getArgByName("url")] + } override string getFramework() { result = "urllib.request.urlopen" } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib2.qll b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib2.qll index d440b1852c93..39f2a336d85e 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib2.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib2.qll @@ -20,10 +20,10 @@ private module Urllib2 { * See * - https://docs.python.org/2/library/urllib2.html#urllib2.Request */ - private class RequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class RequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { RequestCall() { this = API::moduleImport("urllib2").getMember("Request").getACall() } - override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] } + override DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("url")] } override string getFramework() { result = "urllib2.Request" } @@ -40,10 +40,10 @@ private module Urllib2 { * See * - https://docs.python.org/2/library/urllib2.html#urllib2.urlopen */ - private class UrlOpenCall extends Http::Client::Request::Range, DataFlow::CallCfgNode { + private class UrlOpenCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { UrlOpenCall() { this = API::moduleImport("urllib2").getMember("urlopen").getACall() } - override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] } + override DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("url")] } override string getFramework() { result = "urllib2.urlopen" } diff --git a/python/ql/lib/semmle/python/frameworks/Urllib3.qll b/python/ql/lib/semmle/python/frameworks/Urllib3.qll index ee35fc9af0a9..02705527e574 100644 --- a/python/ql/lib/semmle/python/frameworks/Urllib3.qll +++ b/python/ql/lib/semmle/python/frameworks/Urllib3.qll @@ -54,7 +54,7 @@ module Urllib3 { * - https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html#urllib3.request.RequestMethods * - https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool.urlopen */ - private class RequestCall extends Http::Client::Request::Range, API::CallNode { + private class RequestCall extends Http::Client::Request::Range instanceof API::CallNode { RequestCall() { this = classRef() @@ -63,7 +63,9 @@ module Urllib3 { .getACall() } - override DataFlow::Node getAUrlPart() { result in [this.getArg(1), this.getArgByName("url")] } + override DataFlow::Node getAUrlPart() { + result in [super.getArg(1), super.getArgByName("url")] + } override string getFramework() { result = "urllib3.PoolManager" } diff --git a/python/ql/lib/semmle/python/internal/ConceptsImports.qll b/python/ql/lib/semmle/python/internal/ConceptsImports.qll deleted file mode 100644 index 763b26017fbf..000000000000 --- a/python/ql/lib/semmle/python/internal/ConceptsImports.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file contains imports required for the Python version of `ConceptsShared.qll`. - * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. - */ - -import semmle.python.dataflow.new.DataFlow -import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll deleted file mode 100644 index 1b13e4ebb17e..000000000000 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Provides Concepts which are shared across languages. - * - * Each language has a language specific `Concepts.qll` file that can import the - * shared concepts from this file. A language can either re-export the concept directly, - * or can add additional member-predicates that are needed for that language. - * - * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from - * each language, but we will maintain a discipline of moving those concepts to - * `ConceptsShared.qll` ASAP. - */ - -private import ConceptsImports - -/** - * Provides models for cryptographic concepts. - * - * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into - * consideration for the `isWeak` member predicate. So RSA is always considered - * secure, although using a low number of bits will actually make it insecure. We plan - * to improve our libraries in the future to more precisely capture this aspect. - */ -module Cryptography { - class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; - - class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; - - class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; - - class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; - - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CryptographicOperation::Range` instead. - */ - class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - DataFlow::Node getInitialization() { result = super.getInitialization() } - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - BlockMode getBlockMode() { result = super.getBlockMode() } - } - - /** Provides classes for modeling new applications of a cryptographic algorithms. */ - module CryptographicOperation { - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CryptographicOperation` instead. - */ - abstract class Range extends DataFlow::Node { - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - abstract DataFlow::Node getInitialization(); - - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - abstract CryptographicAlgorithm getAlgorithm(); - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - abstract DataFlow::Node getAnInput(); - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - abstract BlockMode getBlockMode(); - } - } - - /** - * A cryptographic block cipher mode of operation. This can be used to encrypt - * data of arbitrary length using a block encryption algorithm. - */ - class BlockMode extends string { - BlockMode() { - this = - [ - "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", - "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final - "EAX" // https://en.wikipedia.org/wiki/EAX_mode - ] - } - - /** Holds if this block mode is considered to be insecure. */ - predicate isWeak() { this = "ECB" } - - /** Holds if the given string appears to match this block mode. */ - bindingset[s] - predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } - } -} - -/** Provides classes for modeling HTTP-related APIs. */ -module Http { - /** Provides classes for modeling HTTP clients. */ - module Client { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `Http::Client::Request::Range` instead. - */ - class Request extends DataFlow::Node instanceof Request::Range { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } - - /** Gets a string that identifies the framework used for this request. */ - string getFramework() { result = super.getFramework() } - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ) { - super.disablesCertificateValidation(disablingNode, argumentOrigin) - } - } - - /** Provides a class for modeling new HTTP requests. */ - module Request { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `Http::Client::Request` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - abstract DataFlow::Node getAUrlPart(); - - /** Gets a string that identifies the framework used for this request. */ - abstract string getFramework(); - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - abstract predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ); - } - } - } -} diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index bd6faaacd69e..2ddcb433e1be 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -7,10 +7,14 @@ private import codeql.ruby.AST private import codeql.ruby.CFG private import codeql.ruby.DataFlow +private import codeql.ruby.dataflow.internal.DataFlowImplSpecific private import codeql.ruby.Frameworks private import codeql.ruby.dataflow.RemoteFlowSources private import codeql.ruby.ApiGraphs private import codeql.ruby.Regexp as RE +private import codeql.concepts.ConceptsShared + +private module ConceptsShared = ConceptsMake; /** * A data-flow node that constructs a SQL statement. @@ -682,7 +686,7 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { - import codeql.ruby.internal.ConceptsShared::Http::Client as SC + import ConceptsShared::Http::Client as SC /** * A method call that makes an outgoing HTTP request. @@ -1041,7 +1045,7 @@ module Cryptography { // modify that part of the shared concept... which means we have to explicitly // re-export everything else. // Using SC shorthand for "Shared Cryptography" - import codeql.ruby.internal.ConceptsShared::Cryptography as SC + import ConceptsShared::Cryptography as SC class CryptographicAlgorithm = SC::CryptographicAlgorithm; diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll index 122202c63b78..a034ad43f023 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll @@ -183,8 +183,7 @@ module ActiveResource { CollectionSource getCollection() { result = collection } } - private class ModelClassMethodCallAsHttpRequest extends Http::Client::Request::Range, - ModelClassMethodCall + private class ModelClassMethodCallAsHttpRequest extends Http::Client::Request::Range instanceof ModelClassMethodCall { ModelClassMethodCallAsHttpRequest() { this.getMethodName() = ["all", "build", "create", "create!", "find", "first", "last"] @@ -195,20 +194,19 @@ module ActiveResource { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - this.getModelClass().disablesCertificateValidation(disablingNode) and + super.getModelClass().disablesCertificateValidation(disablingNode) and // TODO: highlight real argument origin argumentOrigin = disablingNode } override DataFlow::Node getAUrlPart() { - result = this.getModelClass().getASiteAssignment().getAUrlPart() + result = super.getModelClass().getASiteAssignment().getAUrlPart() } override DataFlow::Node getResponseBody() { result = this } } - private class ModelInstanceMethodCallAsHttpRequest extends Http::Client::Request::Range, - ModelInstanceMethodCall + private class ModelInstanceMethodCallAsHttpRequest extends Http::Client::Request::Range instanceof ModelInstanceMethodCall { ModelInstanceMethodCallAsHttpRequest() { this.getMethodName() = @@ -223,13 +221,13 @@ module ActiveResource { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - this.getModelClass().disablesCertificateValidation(disablingNode) and + super.getModelClass().disablesCertificateValidation(disablingNode) and // TODO: highlight real argument origin argumentOrigin = disablingNode } override DataFlow::Node getAUrlPart() { - result = this.getModelClass().getASiteAssignment().getAUrlPart() + result = super.getModelClass().getASiteAssignment().getAUrlPart() } override DataFlow::Node getResponseBody() { result = this } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Excon.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Excon.qll index adf7384183e1..e2ba1eb48fec 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Excon.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Excon.qll @@ -23,7 +23,7 @@ private import codeql.ruby.DataFlow * TODO: pipelining, streaming responses * https://github.com/excon/excon/blob/master/README.md */ -class ExconHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class ExconHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; API::Node connectionNode; DataFlow::Node connectionUse; @@ -54,9 +54,9 @@ class ExconHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode // For one-off requests, the URL is in the first argument of the request method call. // For connection re-use, the URL is split between the first argument of the `new` call // and the `path` keyword argument of the request method call. - result = this.getArgument(0) and not result.asExpr().getExpr() instanceof Pair + result = super.getArgument(0) and not result.asExpr().getExpr() instanceof Pair or - result = this.getKeywordArgument("path") + result = super.getKeywordArgument("path") or result = connectionUse.(DataFlow::CallNode).getArgument(0) } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Faraday.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Faraday.qll index 834180a7ee49..961732da0d08 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Faraday.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Faraday.qll @@ -22,7 +22,7 @@ private import codeql.ruby.DataFlow * connection.get("/").body * ``` */ -class FaradayHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class FaradayHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; API::Node connectionNode; DataFlow::Node connectionUse; @@ -47,7 +47,7 @@ class FaradayHttpRequest extends Http::Client::Request::Range, DataFlow::CallNod override DataFlow::Node getResponseBody() { result = requestNode.getAMethodCall("body") } override DataFlow::Node getAUrlPart() { - result = this.getArgument(0) or + result = super.getArgument(0) or result = connectionUse.(DataFlow::CallNode).getArgument(0) or result = connectionUse.(DataFlow::CallNode).getKeywordArgument("url") } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/HttpClient.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/HttpClient.qll index c766ef96f23a..3fcd9b36703b 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/HttpClient.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/HttpClient.qll @@ -14,7 +14,7 @@ private import codeql.ruby.DataFlow * HTTPClient.get_content("http://example.com") * ``` */ -class HttpClientRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class HttpClientRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; API::Node connectionNode; string method; @@ -34,7 +34,7 @@ class HttpClientRequest extends Http::Client::Request::Range, DataFlow::CallNode ] } - override DataFlow::Node getAUrlPart() { result = this.getArgument(0) } + override DataFlow::Node getAUrlPart() { result = super.getArgument(0) } override DataFlow::Node getResponseBody() { // The `get_content` and `post_content` methods return the response body as diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Httparty.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Httparty.qll index e9f94f771f1a..fd0838c3f975 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Httparty.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Httparty.qll @@ -23,7 +23,7 @@ private import codeql.ruby.DataFlow * MyClass.new("http://example.com") * ``` */ -class HttpartyRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class HttpartyRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; HttpartyRequest() { @@ -33,7 +33,7 @@ class HttpartyRequest extends Http::Client::Request::Range, DataFlow::CallNode { .getReturn(["get", "head", "delete", "options", "post", "put", "patch"]) } - override DataFlow::Node getAUrlPart() { result = this.getArgument(0) } + override DataFlow::Node getAUrlPart() { result = super.getArgument(0) } override DataFlow::Node getResponseBody() { // If HTTParty can recognise the response type, it will parse and return it @@ -49,7 +49,7 @@ class HttpartyRequest extends Http::Client::Request::Range, DataFlow::CallNode { /** Gets the value that controls certificate validation, if any. */ DataFlow::Node getCertificateValidationControllingValue() { - result = this.getKeywordArgumentIncludeHashArgument(["verify", "verify_peer"]) + result = super.getKeywordArgumentIncludeHashArgument(["verify", "verify_peer"]) } cached diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/NetHttp.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/NetHttp.qll index e09917ae21ab..3a0b484e5465 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/NetHttp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/NetHttp.qll @@ -18,7 +18,7 @@ private import codeql.ruby.DataFlow * response = req.get("/") * ``` */ -class NetHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class NetHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { private DataFlow::CallNode request; private API::Node requestNode; private boolean returnsResponseBody; diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/OpenURI.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/OpenURI.qll index 8ccb744f84e1..38d6aced09f9 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/OpenURI.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/OpenURI.qll @@ -18,7 +18,7 @@ private import codeql.ruby.frameworks.Core * URI.parse("http://example.com").open.read * ``` */ -class OpenUriRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class OpenUriRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; OpenUriRequest() { @@ -30,7 +30,7 @@ class OpenUriRequest extends Http::Client::Request::Range, DataFlow::CallNode { this = requestNode.asSource() } - override DataFlow::Node getAUrlPart() { result = this.getArgument(0) } + override DataFlow::Node getAUrlPart() { result = super.getArgument(0) } override DataFlow::Node getResponseBody() { result = requestNode.getAMethodCall(["read", "readlines"]) @@ -38,7 +38,7 @@ class OpenUriRequest extends Http::Client::Request::Range, DataFlow::CallNode { /** Gets the value that controls certificate validation, if any. */ DataFlow::Node getCertificateValidationControllingValue() { - result = this.getKeywordArgumentIncludeHashArgument("ssl_verify_mode") + result = super.getKeywordArgumentIncludeHashArgument("ssl_verify_mode") } cached @@ -60,11 +60,10 @@ class OpenUriRequest extends Http::Client::Request::Range, DataFlow::CallNode { * Kernel.open("http://example.com").read * ``` */ -class OpenUriKernelOpenRequest extends Http::Client::Request::Range, DataFlow::CallNode instanceof KernelMethodCall -{ +class OpenUriKernelOpenRequest extends Http::Client::Request::Range instanceof KernelMethodCall { OpenUriKernelOpenRequest() { this.getMethodName() = "open" } - override DataFlow::Node getAUrlPart() { result = this.getArgument(0) } + override DataFlow::Node getAUrlPart() { result = super.getArgument(0) } override DataFlow::CallNode getResponseBody() { result.asExpr().getExpr().(MethodCall).getMethodName() in ["read", "readlines"] and @@ -73,14 +72,14 @@ class OpenUriKernelOpenRequest extends Http::Client::Request::Range, DataFlow::C /** Gets the value that controls certificate validation, if any. */ DataFlow::Node getCertificateValidationControllingValue() { - result = this.getKeywordArgument("ssl_verify_mode") + result = super.getKeywordArgument("ssl_verify_mode") or // using a hashliteral exists( DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p, DataFlow::Node key | // can't flow to argument 0, since that's the URL - optionsNode.flowsTo(this.getArgument(any(int i | i > 0))) and + optionsNode.flowsTo(super.getArgument(any(int i | i > 0))) and p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and key.asExpr() = p.getKey() and key.getALocalSource().asExpr().getConstantValue().isStringlikeValue("ssl_verify_mode") and diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/RestClient.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/RestClient.qll index cac94f7166f2..268233c27def 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/RestClient.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/RestClient.qll @@ -16,7 +16,7 @@ private import codeql.ruby.DataFlow * RestClient::Request.execute(url: "http://example.com").body * ``` */ -class RestClientHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class RestClientHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; API::Node connectionNode; @@ -37,9 +37,9 @@ class RestClientHttpRequest extends Http::Client::Request::Range, DataFlow::Call } override DataFlow::Node getAUrlPart() { - result = this.getKeywordArgument("url") + result = super.getKeywordArgument("url") or - result = this.getArgument(0) and + result = super.getArgument(0) and // this rules out the alternative above not result.asExpr().getExpr() instanceof Pair } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Typhoeus.qll b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Typhoeus.qll index 2eae03a77481..19d3db23ece6 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Typhoeus.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Typhoeus.qll @@ -14,7 +14,7 @@ private import codeql.ruby.DataFlow * Typhoeus.get("http://example.com").body * ``` */ -class TyphoeusHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode { +class TyphoeusHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode { API::Node requestNode; boolean directResponse; @@ -31,7 +31,7 @@ class TyphoeusHttpRequest extends Http::Client::Request::Range, DataFlow::CallNo ) } - override DataFlow::Node getAUrlPart() { result = this.getArgument(0) } + override DataFlow::Node getAUrlPart() { result = super.getArgument(0) } override DataFlow::Node getResponseBody() { directResponse = true and @@ -43,7 +43,7 @@ class TyphoeusHttpRequest extends Http::Client::Request::Range, DataFlow::CallNo /** Gets the value that controls certificate validation, if any. */ DataFlow::Node getCertificateValidationControllingValue() { - result = this.getKeywordArgumentIncludeHashArgument("ssl_verifypeer") + result = super.getKeywordArgumentIncludeHashArgument("ssl_verifypeer") } cached diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll deleted file mode 100644 index c0f99aafad6c..000000000000 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsImports.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file contains imports required for the Ruby version of `ConceptsShared.qll`. - * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. - */ - -import codeql.ruby.DataFlow -import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll deleted file mode 100644 index 1b13e4ebb17e..000000000000 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Provides Concepts which are shared across languages. - * - * Each language has a language specific `Concepts.qll` file that can import the - * shared concepts from this file. A language can either re-export the concept directly, - * or can add additional member-predicates that are needed for that language. - * - * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from - * each language, but we will maintain a discipline of moving those concepts to - * `ConceptsShared.qll` ASAP. - */ - -private import ConceptsImports - -/** - * Provides models for cryptographic concepts. - * - * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into - * consideration for the `isWeak` member predicate. So RSA is always considered - * secure, although using a low number of bits will actually make it insecure. We plan - * to improve our libraries in the future to more precisely capture this aspect. - */ -module Cryptography { - class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; - - class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; - - class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; - - class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; - - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CryptographicOperation::Range` instead. - */ - class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - DataFlow::Node getInitialization() { result = super.getInitialization() } - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - BlockMode getBlockMode() { result = super.getBlockMode() } - } - - /** Provides classes for modeling new applications of a cryptographic algorithms. */ - module CryptographicOperation { - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CryptographicOperation` instead. - */ - abstract class Range extends DataFlow::Node { - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - abstract DataFlow::Node getInitialization(); - - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - abstract CryptographicAlgorithm getAlgorithm(); - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - abstract DataFlow::Node getAnInput(); - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - abstract BlockMode getBlockMode(); - } - } - - /** - * A cryptographic block cipher mode of operation. This can be used to encrypt - * data of arbitrary length using a block encryption algorithm. - */ - class BlockMode extends string { - BlockMode() { - this = - [ - "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", - "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final - "EAX" // https://en.wikipedia.org/wiki/EAX_mode - ] - } - - /** Holds if this block mode is considered to be insecure. */ - predicate isWeak() { this = "ECB" } - - /** Holds if the given string appears to match this block mode. */ - bindingset[s] - predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } - } -} - -/** Provides classes for modeling HTTP-related APIs. */ -module Http { - /** Provides classes for modeling HTTP clients. */ - module Client { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `Http::Client::Request::Range` instead. - */ - class Request extends DataFlow::Node instanceof Request::Range { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } - - /** Gets a string that identifies the framework used for this request. */ - string getFramework() { result = super.getFramework() } - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ) { - super.disablesCertificateValidation(disablingNode, argumentOrigin) - } - } - - /** Provides a class for modeling new HTTP requests. */ - module Request { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `Http::Client::Request` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - abstract DataFlow::Node getAUrlPart(); - - /** Gets a string that identifies the framework used for this request. */ - abstract string getFramework(); - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - abstract predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ); - } - } - } -} diff --git a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll index 3775657fc123..40b3ac036cc1 100644 --- a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll +++ b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll @@ -544,8 +544,7 @@ private class CipherNode extends DataFlow::Node { } /** An operation using the OpenSSL library that uses a cipher. */ -private class CipherOperation extends Cryptography::CryptographicOperation::Range, - DataFlow::CallNode +private class CipherOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallNode { private CipherNode cipherNode; @@ -564,8 +563,8 @@ private class CipherOperation extends Cryptography::CryptographicOperation::Rang } override DataFlow::Node getAnInput() { - this.getMethodName() = "update" and - result = this.getArgument(0) + super.getMethodName() = "update" and + result = super.getArgument(0) } override Cryptography::BlockMode getBlockMode() { diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 73dd629cef88..20247e088752 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -5,11 +5,16 @@ */ private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.Locations private import codeql.threatmodels.ThreatModels private import codeql.rust.Frameworks private import codeql.rust.dataflow.FlowSource private import codeql.rust.controlflow.ControlFlowGraph as Cfg private import codeql.rust.controlflow.CfgNodes as CfgNodes +private import codeql.concepts.ConceptsShared + +private module ConceptsShared = ConceptsMake; /** * A data flow source for a specific threat-model. @@ -302,7 +307,7 @@ module SqlSanitization { * Provides models for cryptographic things. */ module Cryptography { - private import codeql.rust.internal.ConceptsShared::Cryptography as SC + import ConceptsShared::Cryptography as SC final class CryptographicOperation = SC::CryptographicOperation; diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll deleted file mode 100644 index 341f3ade509f..000000000000 --- a/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file contains imports required for the Rust version of `ConceptsShared.qll`. - * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. - */ - -import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow -import codeql.rust.security.CryptoAlgorithms as CryptoAlgorithms diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll deleted file mode 100644 index 1b13e4ebb17e..000000000000 --- a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Provides Concepts which are shared across languages. - * - * Each language has a language specific `Concepts.qll` file that can import the - * shared concepts from this file. A language can either re-export the concept directly, - * or can add additional member-predicates that are needed for that language. - * - * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from - * each language, but we will maintain a discipline of moving those concepts to - * `ConceptsShared.qll` ASAP. - */ - -private import ConceptsImports - -/** - * Provides models for cryptographic concepts. - * - * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into - * consideration for the `isWeak` member predicate. So RSA is always considered - * secure, although using a low number of bits will actually make it insecure. We plan - * to improve our libraries in the future to more precisely capture this aspect. - */ -module Cryptography { - class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; - - class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; - - class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; - - class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; - - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CryptographicOperation::Range` instead. - */ - class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - DataFlow::Node getInitialization() { result = super.getInitialization() } - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - BlockMode getBlockMode() { result = super.getBlockMode() } - } - - /** Provides classes for modeling new applications of a cryptographic algorithms. */ - module CryptographicOperation { - /** - * A data flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CryptographicOperation` instead. - */ - abstract class Range extends DataFlow::Node { - /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ - abstract DataFlow::Node getInitialization(); - - /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - abstract CryptographicAlgorithm getAlgorithm(); - - /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - abstract DataFlow::Node getAnInput(); - - /** - * Gets the block mode used to perform this cryptographic operation. - * - * This predicate is only expected to have a result if two conditions hold: - * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and - * 2. The algorithm used is a block cipher (not a stream cipher). - * - * If either of these conditions do not hold, then this predicate should have no result. - */ - abstract BlockMode getBlockMode(); - } - } - - /** - * A cryptographic block cipher mode of operation. This can be used to encrypt - * data of arbitrary length using a block encryption algorithm. - */ - class BlockMode extends string { - BlockMode() { - this = - [ - "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", - "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final - "EAX" // https://en.wikipedia.org/wiki/EAX_mode - ] - } - - /** Holds if this block mode is considered to be insecure. */ - predicate isWeak() { this = "ECB" } - - /** Holds if the given string appears to match this block mode. */ - bindingset[s] - predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } - } -} - -/** Provides classes for modeling HTTP-related APIs. */ -module Http { - /** Provides classes for modeling HTTP clients. */ - module Client { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `Http::Client::Request::Range` instead. - */ - class Request extends DataFlow::Node instanceof Request::Range { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } - - /** Gets a string that identifies the framework used for this request. */ - string getFramework() { result = super.getFramework() } - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ) { - super.disablesCertificateValidation(disablingNode, argumentOrigin) - } - } - - /** Provides a class for modeling new HTTP requests. */ - module Request { - /** - * A data flow node that makes an outgoing HTTP request. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `Http::Client::Request` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets a data flow node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - abstract DataFlow::Node getAUrlPart(); - - /** Gets a string that identifies the framework used for this request. */ - abstract string getFramework(); - - /** - * Holds if this request is made using a mode that disables SSL/TLS - * certificate validation, where `disablingNode` represents the point at - * which the validation was disabled, and `argumentOrigin` represents the origin - * of the argument that disabled the validation (which could be the same node as - * `disablingNode`). - */ - abstract predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ); - } - } - } -} diff --git a/shared/concepts/codeql/concepts/ConceptsShared.qll b/shared/concepts/codeql/concepts/ConceptsShared.qll new file mode 100644 index 000000000000..2a400fa07135 --- /dev/null +++ b/shared/concepts/codeql/concepts/ConceptsShared.qll @@ -0,0 +1,187 @@ +/** + * Provides Concepts which are shared across languages. + * + * Each language has a language specific `Concepts.qll` file that can import the + * shared concepts from this file. A language can either re-export the concept directly, + * or can add additional member-predicates that are needed for that language. + * + * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from + * each language, but we will maintain a discipline of moving those concepts to + * `ConceptsShared.qll` ASAP. + */ + +private import CryptoAlgorithms as CA +private import codeql.dataflow.DataFlow as DF +private import codeql.util.Location + +module ConceptsMake DataFlowLang> { + final private class DataFlowNode = DataFlowLang::Node; + + /** + * Provides models for cryptographic concepts. + * + * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into + * consideration for the `isWeak` member predicate. So RSA is always considered + * secure, although using a low number of bits will actually make it insecure. We plan + * to improve our libraries in the future to more precisely capture this aspect. + */ + module Cryptography { + class CryptographicAlgorithm = CA::CryptographicAlgorithm; + + class EncryptionAlgorithm = CA::EncryptionAlgorithm; + + class HashingAlgorithm = CA::HashingAlgorithm; + + class PasswordHashingAlgorithm = CA::PasswordHashingAlgorithm; + + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. + */ + class CryptographicOperation extends DataFlowNode instanceof CryptographicOperation::Range { + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } + + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + DataFlowNode getInitialization() { result = super.getInitialization() } + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + DataFlowNode getAnInput() { result = super.getAnInput() } + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + BlockMode getBlockMode() { result = super.getBlockMode() } + } + + /** Provides classes for modeling new applications of a cryptographic algorithms. */ + module CryptographicOperation { + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CryptographicOperation` instead. + */ + abstract class Range extends DataFlowNode { + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + abstract DataFlowNode getInitialization(); + + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + abstract CryptographicAlgorithm getAlgorithm(); + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + abstract DataFlowNode getAnInput(); + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + abstract BlockMode getBlockMode(); + } + } + + /** + * A cryptographic block cipher mode of operation. This can be used to encrypt + * data of arbitrary length using a block encryption algorithm. + */ + class BlockMode extends string { + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } + + /** Holds if this block mode is considered to be insecure. */ + predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } + } + } + + /** Provides classes for modeling HTTP-related APIs. */ + module Http { + /** Provides classes for modeling HTTP clients. */ + module Client { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `Http::Client::Request::Range` instead. + */ + class Request extends DataFlowNode instanceof Request::Range { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + DataFlowNode getAUrlPart() { result = super.getAUrlPart() } + + /** Gets a string that identifies the framework used for this request. */ + string getFramework() { result = super.getFramework() } + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + predicate disablesCertificateValidation( + DataFlowNode disablingNode, DataFlowNode argumentOrigin + ) { + super.disablesCertificateValidation(disablingNode, argumentOrigin) + } + } + + /** Provides a class for modeling new HTTP requests. */ + module Request { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `Http::Client::Request` instead. + */ + abstract class Range extends DataFlowNode { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + abstract DataFlowNode getAUrlPart(); + + /** Gets a string that identifies the framework used for this request. */ + abstract string getFramework(); + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + abstract predicate disablesCertificateValidation( + DataFlowNode disablingNode, DataFlowNode argumentOrigin + ); + } + } + } + } +} diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index 547196c217d7..2b8a40fc79a0 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -2,5 +2,7 @@ name: codeql/concepts version: 0.0.0-dev groups: shared library: true -dependencies: null +dependencies: + codeql/dataflow: ${workspace} + codeql/util: ${workspace} warnOnImplicitThis: true From 199587095a76e5de060785dcd1206ec6bef90fb6 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 7 Jul 2025 11:55:50 +0200 Subject: [PATCH 061/311] Add overlay annotations --- shared/concepts/codeql/concepts/ConceptsShared.qll | 2 ++ shared/concepts/codeql/concepts/CryptoAlgorithms.qll | 2 ++ .../concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll | 2 ++ .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 2 ++ 4 files changed, 8 insertions(+) diff --git a/shared/concepts/codeql/concepts/ConceptsShared.qll b/shared/concepts/codeql/concepts/ConceptsShared.qll index 2a400fa07135..fe3722eb3dde 100644 --- a/shared/concepts/codeql/concepts/ConceptsShared.qll +++ b/shared/concepts/codeql/concepts/ConceptsShared.qll @@ -9,6 +9,8 @@ * each language, but we will maintain a discipline of moving those concepts to * `ConceptsShared.qll` ASAP. */ +overlay[local?] +module; private import CryptoAlgorithms as CA private import codeql.dataflow.DataFlow as DF diff --git a/shared/concepts/codeql/concepts/CryptoAlgorithms.qll b/shared/concepts/codeql/concepts/CryptoAlgorithms.qll index 01b568d234af..23a45027cf14 100644 --- a/shared/concepts/codeql/concepts/CryptoAlgorithms.qll +++ b/shared/concepts/codeql/concepts/CryptoAlgorithms.qll @@ -3,6 +3,8 @@ * * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ +overlay[local?] +module; private import codeql.concepts.internal.CryptoAlgorithmNames diff --git a/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll index 8bb63d97876a..efcd870c724a 100644 --- a/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll +++ b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll @@ -7,6 +7,8 @@ * * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). */ +overlay[local?] +module; /** * Holds if `name` corresponds to a strong hashing algorithm. diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index ede88ebf8149..c50d1341c778 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -6,6 +6,8 @@ * * 'Sensitive' data in general is anything that should not be sent around in unencrypted form. */ +overlay[local?] +module; /** * A classification of different kinds of sensitive data: From 03a9a1688e18e6c77d4309c0fe7f4bd57bfd3547 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 14 Jul 2025 16:37:05 +0200 Subject: [PATCH 062/311] Rust: Add type inference for tuples --- rust/ql/lib/codeql/rust/internal/Type.qll | 45 +- .../codeql/rust/internal/TypeInference.qll | 51 +- .../lib/codeql/rust/internal/TypeMention.qll | 12 + .../test/library-tests/type-inference/main.rs | 34 +- .../type-inference/pattern_matching.rs | 34 +- .../type-inference/type-inference.expected | 434 ++++++++++++++++++ 6 files changed, 571 insertions(+), 39 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index 77337138a84f..ca49f3c258df 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -9,14 +9,17 @@ private import codeql.rust.elements.internal.generated.Synth cached newtype TType = - TUnit() or - TStruct(Struct s) { Stages::TypeInferenceStage::ref() } or + TTuple(int arity) { + exists(any(TupleTypeRepr t).getField(arity)) and Stages::TypeInferenceStage::ref() + } or + TStruct(Struct s) or TEnum(Enum e) or TTrait(Trait t) or TArrayType() or // todo: add size? TRefType() or // todo: add mut? TImplTraitType(ImplTraitTypeRepr impl) or TSliceType() or + TTupleTypeParameter(int i) { exists(TTuple(i)) } or TTypeParamTypeParameter(TypeParam t) or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or TArrayTypeParameter() or @@ -56,8 +59,8 @@ abstract class Type extends TType { } /** The unit type `()`. */ -class UnitType extends Type, TUnit { - UnitType() { this = TUnit() } +class UnitType extends Type, TTuple { + UnitType() { this = TTuple(0) } override StructField getStructField(string name) { none() } @@ -70,6 +73,25 @@ class UnitType extends Type, TUnit { override Location getLocation() { result instanceof EmptyLocation } } +/** A tuple type `(T, ...)`. */ +class TupleType extends Type, TTuple { + private int arity; + + TupleType() { this = TTuple(arity) and arity > 0 } + + override StructField getStructField(string name) { none() } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(i) and i < arity } + + int getArity() { result = arity } + + override string toString() { result = "(T_" + arity + ")" } + + override Location getLocation() { result instanceof EmptyLocation } +} + abstract private class StructOrEnumType extends Type { abstract ItemNode asItemNode(); } @@ -329,6 +351,21 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara override Location getLocation() { result = typeAlias.getLocation() } } +/** + * A tuple type parameter. For instance the `T` in `(T, U)`. + * + * Since tuples are structural their parameters can be represented simply as + * their positional index. + */ +class TupleTypeParameter extends TypeParameter, TTupleTypeParameter { + override string toString() { result = this.getIndex().toString() } + + override Location getLocation() { result instanceof EmptyLocation } + + /** Gets the index of this tuple type parameter. */ + int getIndex() { this = TTupleTypeParameter(result) } +} + /** An implicit array type parameter. */ class ArrayTypeParameter extends TypeParameter, TArrayTypeParameter { override string toString() { result = "[T;...]" } diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 5ebb8eaa3175..1d2e7ee02de8 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -103,6 +103,9 @@ private module Input1 implements InputSig1 { node = tp0.(SelfTypeParameter).getTrait() or node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr() ) + or + kind = 2 and + id = tp0.(TupleTypeParameter).getIndex() | tp0 order by kind, id ) @@ -229,7 +232,7 @@ private Type inferLogicalOperationType(AstNode n, TypePath path) { private Type inferAssignmentOperationType(AstNode n, TypePath path) { n instanceof AssignmentOperation and path.isEmpty() and - result = TUnit() + result instanceof UnitType } pragma[nomagic] @@ -321,6 +324,14 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat prefix1.isEmpty() and prefix2 = TypePath::singleton(TRefTypeParameter()) or + exists(int i | + prefix1.isEmpty() and + prefix2 = TypePath::singleton(TTupleTypeParameter(i)) + | + n1 = n2.(TupleExpr).getField(i) or + n1 = n2.(TuplePat).getField(i) + ) + or exists(BlockExpr be | n1 = be and n2 = be.getStmtList().getTailExpr() and @@ -534,6 +545,12 @@ private Type inferStructExprType(AstNode n, TypePath path) { ) } +pragma[nomagic] +private Type inferTupleExprRootType(TupleExpr te) { + // `typeEquality` handles the non-root case + result = TTuple(te.getNumberOfFields()) +} + pragma[nomagic] private Type inferPathExprType(PathExpr pe, TypePath path) { // nullary struct/variant constructors @@ -1055,6 +1072,31 @@ private Type inferFieldExprType(AstNode n, TypePath path) { ) } +pragma[nomagic] +private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) { + exists(int i, TypePath path0 | + fe.getIdentifier().getText() = i.toString() and + result = inferType(fe.getContainer(), path0) and + path0.isCons(TTupleTypeParameter(i), path) and + fe.getIdentifier().getText() = i.toString() + ) +} + +/** Infers the type of `t` in `t.n` when `t` is a tuple. */ +private Type inferTupleContainerExprType(Expr e, TypePath path) { + // NOTE: For a field expression `t.n` where `n` is a number `t` might both be + // a tuple struct or a tuple. It is only correct to let type information flow + // from `t.n` to tuple type parameters of `t` in the latter case. Hence we + // include the condition that the root type of `t` must be a tuple type. + exists(int i, TypePath path0, FieldExpr fe | + e = fe.getContainer() and + fe.getIdentifier().getText() = i.toString() and + inferType(fe.getContainer()) instanceof TupleType and + result = inferType(fe, path0) and + path = TypePath::cons(TTupleTypeParameter(i), path0) + ) +} + /** Gets the root type of the reference node `ref`. */ pragma[nomagic] private Type inferRefNodeType(AstNode ref) { @@ -1943,12 +1985,19 @@ private module Cached { or result = inferStructExprType(n, path) or + result = inferTupleExprRootType(n) and + path.isEmpty() + or result = inferPathExprType(n, path) or result = inferCallExprBaseType(n, path) or result = inferFieldExprType(n, path) or + result = inferTupleIndexExprType(n, path) + or + result = inferTupleContainerExprType(n, path) + or result = inferRefNodeType(n) and path.isEmpty() or diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index 6dd69ef49fc5..a40c068b4894 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -14,6 +14,18 @@ abstract class TypeMention extends AstNode { final Type resolveType() { result = this.resolveTypeAt(TypePath::nil()) } } +class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr { + override Type resolveTypeAt(TypePath path) { + path.isEmpty() and + result = TTuple(super.getNumberOfFields()) + or + exists(TypePath suffix, int i | + result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and + path = TypePath::cons(TTupleTypeParameter(i), suffix) + ) + } +} + class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr { override Type resolveTypeAt(TypePath path) { path.isEmpty() and diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 2be80169aa4e..583f4349df6f 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2334,27 +2334,27 @@ mod tuples { } pub fn f() { - let a = S1::get_pair(); // $ target=get_pair MISSING: type=a:(T_2) - let mut b = S1::get_pair(); // $ target=get_pair MISSING: type=b:(T_2) - let (c, d) = S1::get_pair(); // $ target=get_pair MISSING: type=c:S1 type=d:S1 - let (mut e, f) = S1::get_pair(); // $ target=get_pair MISSING: type=e:S1 type=f:S1 - let (mut g, mut h) = S1::get_pair(); // $ target=get_pair MISSING: type=g:S1 type=h:S1 - - a.0.foo(); // $ MISSING: target=foo - b.1.foo(); // $ MISSING: target=foo - c.foo(); // $ MISSING: target=foo - d.foo(); // $ MISSING: target=foo - e.foo(); // $ MISSING: target=foo - f.foo(); // $ MISSING: target=foo - g.foo(); // $ MISSING: target=foo - h.foo(); // $ MISSING: target=foo + let a = S1::get_pair(); // $ target=get_pair type=a:(T_2) + let mut b = S1::get_pair(); // $ target=get_pair type=b:(T_2) + let (c, d) = S1::get_pair(); // $ target=get_pair type=c:S1 type=d:S1 + let (mut e, f) = S1::get_pair(); // $ target=get_pair type=e:S1 type=f:S1 + let (mut g, mut h) = S1::get_pair(); // $ target=get_pair type=g:S1 type=h:S1 + + a.0.foo(); // $ target=foo + b.1.foo(); // $ target=foo + c.foo(); // $ target=foo + d.foo(); // $ target=foo + e.foo(); // $ target=foo + f.foo(); // $ target=foo + g.foo(); // $ target=foo + h.foo(); // $ target=foo // Here type information must flow from `pair.0` and `pair.1` into // `pair` and from `(a, b)` into `a` and `b` in order for the types of // `a` and `b` to be inferred. - let a = Default::default(); // $ MISSING: target=default type=a:i64 - let b = Default::default(); // $ MISSING: target=default MISSING: type=b:bool - let pair = (a, b); // $ MISSING: type=pair:0.i64 type=pair:1.bool + let a = Default::default(); // $ target=default type=a:i64 + let b = Default::default(); // $ target=default type=b:bool + let pair = (a, b); // $ type=pair:0.i64 type=pair:1.bool let i: i64 = pair.0; let j: bool = pair.1; } diff --git a/rust/ql/test/library-tests/type-inference/pattern_matching.rs b/rust/ql/test/library-tests/type-inference/pattern_matching.rs index 9da38e6ea57d..91774706c46f 100755 --- a/rust/ql/test/library-tests/type-inference/pattern_matching.rs +++ b/rust/ql/test/library-tests/type-inference/pattern_matching.rs @@ -446,13 +446,13 @@ pub fn tuple_patterns() { // TuplePat - Tuple patterns match tuple { (1, 2, 3.0) => { - let exact_tuple = tuple; // $ MISSING: type=exact_tuple:? + let exact_tuple = tuple; // $ type=exact_tuple:(T_3) println!("Exact tuple: {:?}", exact_tuple); } (a, b, c) => { - let first_elem = a; // $ MISSING: type=first_elem:i32 - let second_elem = b; // $ MISSING: type=second_elem:i64 - let third_elem = c; // $ MISSING: type=third_elem:f32 + let first_elem = a; // $ type=first_elem:i32 + let second_elem = b; // $ type=second_elem:i64 + let third_elem = c; // $ type=third_elem:f32 println!("Tuple: ({}, {}, {})", first_elem, second_elem, third_elem); } } @@ -460,7 +460,7 @@ pub fn tuple_patterns() { // With rest pattern match tuple { (first, ..) => { - let tuple_first = first; // $ MISSING: type=tuple_first:i32 + let tuple_first = first; // $ type=tuple_first:i32 println!("First element: {}", tuple_first); } } @@ -469,7 +469,7 @@ pub fn tuple_patterns() { let unit = (); match unit { () => { - let unit_value = unit; // $ MISSING: type=unit_value:? + let unit_value = unit; // $ type=unit_value:() println!("Unit value: {:?}", unit_value); } } @@ -478,7 +478,7 @@ pub fn tuple_patterns() { let single = (42i32,); match single { (x,) => { - let single_elem = x; // $ MISSING: type=single_elem:i32 + let single_elem = x; // $ type=single_elem:i32 println!("Single element tuple: {}", single_elem); } } @@ -499,8 +499,8 @@ pub fn parenthesized_patterns() { let tuple = (1i32, 2i32); match tuple { (x, (y)) => { - let paren_x = x; // $ MISSING: type=paren_x:i32 - let paren_y = y; // $ MISSING: type=paren_y:i32 + let paren_x = x; // $ type=paren_x:i32 + let paren_y = y; // $ type=paren_y:i32 println!("Parenthesized in tuple: {}, {}", paren_x, paren_y); } } @@ -630,7 +630,7 @@ pub fn rest_patterns() { // RestPat - Rest patterns (..) match tuple { (first, ..) => { - let rest_first = first; // $ MISSING: type=rest_first:i32 + let rest_first = first; // $ type=rest_first:i32 println!("First with rest: {}", rest_first); } } @@ -644,7 +644,7 @@ pub fn rest_patterns() { match tuple { (first, .., last) => { - let rest_start = first; // $ MISSING: type=rest_start:i32 + let rest_start = first; // $ type=rest_start:i32 let rest_end = last; // $ MISSING: type=rest_end:u8 println!("First and last: {}, {}", rest_start, rest_end); } @@ -719,9 +719,9 @@ pub fn patterns_in_let_statements() { let tuple = (1i32, 2i64, 3.0f32); let (a, b, c) = tuple; // TuplePat in let - let let_a = a; // $ MISSING: type=let_a:i32 - let let_b = b; // $ MISSING: type=let_b:i64 - let let_c = c; // $ MISSING: type=let_c:f32 + let let_a = a; // $ type=let_a:i32 + let let_b = b; // $ type=let_b:i64 + let let_c = c; // $ type=let_c:f32 let array = [1i32, 2, 3, 4, 5]; let [first, .., last] = array; // SlicePat in let @@ -759,8 +759,8 @@ pub fn patterns_in_function_parameters() { } fn extract_tuple((first, _, third): (i32, f64, bool)) -> (i32, bool) { - let param_first = first; // $ MISSING: type=param_first:i32 - let param_third = third; // $ MISSING: type=param_third:bool + let param_first = first; // $ type=param_first:i32 + let param_third = third; // $ type=param_third:bool (param_first, param_third) } @@ -772,7 +772,7 @@ pub fn patterns_in_function_parameters() { let red = extract_color(color); // $ target=extract_color type=red:u8 let tuple = (42i32, 3.14f64, true); - let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple MISSING: type=tuple_extracted:? + let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple type=tuple_extracted:0.i32 type=tuple_extracted:1.bool } #[rustfmt::skip] 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 f19cfbfe8363..6a9776d9d705 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3409,9 +3409,11 @@ inferType | main.rs:2066:31:2066:31 | x | | main.rs:2064:5:2067:5 | Self [trait MyFrom2] | | main.rs:2071:21:2071:25 | value | | {EXTERNAL LOCATION} | i64 | | main.rs:2071:33:2071:33 | _ | | {EXTERNAL LOCATION} | i64 | +| main.rs:2071:48:2073:9 | { ... } | | file://:0:0:0:0 | () | | main.rs:2072:13:2072:17 | value | | {EXTERNAL LOCATION} | i64 | | main.rs:2078:21:2078:25 | value | | {EXTERNAL LOCATION} | bool | | main.rs:2078:34:2078:34 | _ | | {EXTERNAL LOCATION} | i64 | +| main.rs:2078:49:2084:9 | { ... } | | file://:0:0:0:0 | () | | main.rs:2079:13:2083:13 | if value {...} else {...} | | {EXTERNAL LOCATION} | i32 | | main.rs:2079:16:2079:20 | value | | {EXTERNAL LOCATION} | bool | | main.rs:2079:22:2081:13 | { ... } | | {EXTERNAL LOCATION} | i32 | @@ -3483,10 +3485,13 @@ inferType | main.rs:2131:13:2131:13 | z | | {EXTERNAL LOCATION} | i64 | | main.rs:2131:22:2131:43 | ...::my_from(...) | | {EXTERNAL LOCATION} | i64 | | main.rs:2131:38:2131:42 | 73i64 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2132:9:2132:34 | ...::my_from2(...) | | file://:0:0:0:0 | () | | main.rs:2132:23:2132:27 | 73i64 | | {EXTERNAL LOCATION} | i64 | | main.rs:2132:30:2132:33 | 0i64 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2133:9:2133:33 | ...::my_from2(...) | | file://:0:0:0:0 | () | | main.rs:2133:23:2133:26 | true | | {EXTERNAL LOCATION} | bool | | main.rs:2133:29:2133:32 | 0i64 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2134:9:2134:38 | ...::my_from2(...) | | file://:0:0:0:0 | () | | main.rs:2134:27:2134:31 | 73i64 | | {EXTERNAL LOCATION} | i64 | | main.rs:2134:34:2134:37 | 0i64 | | {EXTERNAL LOCATION} | i64 | | main.rs:2136:9:2136:22 | ...::f1(...) | | {EXTERNAL LOCATION} | i64 | @@ -3921,6 +3926,21 @@ inferType | main.rs:2253:22:2253:34 | map1.values() | V.T | file://:0:0:0:0 | & | | main.rs:2253:22:2253:34 | map1.values() | V.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2254:13:2254:24 | TuplePat | | {EXTERNAL LOCATION} | Item | +| main.rs:2254:13:2254:24 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2254:13:2254:24 | TuplePat | 0 | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 0.&T | {EXTERNAL LOCATION} | i32 | +| main.rs:2254:13:2254:24 | TuplePat | 1 | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 1.&T | {EXTERNAL LOCATION} | Box | +| main.rs:2254:13:2254:24 | TuplePat | 1.&T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2254:13:2254:24 | TuplePat | 1.&T.T | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 1.&T.T.&T | {EXTERNAL LOCATION} | str | +| main.rs:2254:14:2254:16 | key | | file://:0:0:0:0 | & | +| main.rs:2254:14:2254:16 | key | &T | {EXTERNAL LOCATION} | i32 | +| main.rs:2254:19:2254:23 | value | | file://:0:0:0:0 | & | +| main.rs:2254:19:2254:23 | value | &T | {EXTERNAL LOCATION} | Box | +| main.rs:2254:19:2254:23 | value | &T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2254:19:2254:23 | value | &T.T | file://:0:0:0:0 | & | +| main.rs:2254:19:2254:23 | value | &T.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2254:29:2254:32 | map1 | | {EXTERNAL LOCATION} | HashMap | | main.rs:2254:29:2254:32 | map1 | K | {EXTERNAL LOCATION} | i32 | | main.rs:2254:29:2254:32 | map1 | S | {EXTERNAL LOCATION} | RandomState | @@ -3935,6 +3955,21 @@ inferType | main.rs:2254:29:2254:39 | map1.iter() | V.T | file://:0:0:0:0 | & | | main.rs:2254:29:2254:39 | map1.iter() | V.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2255:13:2255:24 | TuplePat | | {EXTERNAL LOCATION} | Item | +| main.rs:2255:13:2255:24 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2255:13:2255:24 | TuplePat | 0 | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 0.&T | {EXTERNAL LOCATION} | i32 | +| main.rs:2255:13:2255:24 | TuplePat | 1 | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 1.&T | {EXTERNAL LOCATION} | Box | +| main.rs:2255:13:2255:24 | TuplePat | 1.&T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2255:13:2255:24 | TuplePat | 1.&T.T | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 1.&T.T.&T | {EXTERNAL LOCATION} | str | +| main.rs:2255:14:2255:16 | key | | file://:0:0:0:0 | & | +| main.rs:2255:14:2255:16 | key | &T | {EXTERNAL LOCATION} | i32 | +| main.rs:2255:19:2255:23 | value | | file://:0:0:0:0 | & | +| main.rs:2255:19:2255:23 | value | &T | {EXTERNAL LOCATION} | Box | +| main.rs:2255:19:2255:23 | value | &T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2255:19:2255:23 | value | &T.T | file://:0:0:0:0 | & | +| main.rs:2255:19:2255:23 | value | &T.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2255:29:2255:33 | &map1 | | file://:0:0:0:0 | & | | main.rs:2255:29:2255:33 | &map1 | &T | {EXTERNAL LOCATION} | HashMap | | main.rs:2255:29:2255:33 | &map1 | &T.K | {EXTERNAL LOCATION} | i32 | @@ -4056,12 +4091,86 @@ inferType | main.rs:2322:13:2322:15 | x14 | | {EXTERNAL LOCATION} | i32 | | main.rs:2322:19:2322:48 | foo::<...>(...) | | {EXTERNAL LOCATION} | i32 | | main.rs:2322:30:2322:47 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2330:35:2332:9 | { ... } | | file://:0:0:0:0 | (T_2) | +| main.rs:2330:35:2332:9 | { ... } | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2330:35:2332:9 | { ... } | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2331:13:2331:26 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| main.rs:2331:13:2331:26 | TupleExpr | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2331:13:2331:26 | TupleExpr | 1 | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:14:2331:18 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:21:2331:25 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2333:16:2333:19 | SelfParam | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:13:2337:13 | a | | file://:0:0:0:0 | (T_2) | +| main.rs:2337:13:2337:13 | a | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:13:2337:13 | a | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:17:2337:30 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | +| main.rs:2337:17:2337:30 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:17:2337:30 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:17:2338:17 | b | | file://:0:0:0:0 | (T_2) | +| main.rs:2338:17:2338:17 | b | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:17:2338:17 | b | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:21:2338:34 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | +| main.rs:2338:21:2338:34 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:21:2338:34 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:13:2339:18 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2339:13:2339:18 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:13:2339:18 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:14:2339:14 | c | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:17:2339:17 | d | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:22:2339:35 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | +| main.rs:2339:22:2339:35 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:22:2339:35 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:13:2340:22 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2340:13:2340:22 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:13:2340:22 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:18:2340:18 | e | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:21:2340:21 | f | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:26:2340:39 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | +| main.rs:2340:26:2340:39 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:26:2340:39 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:13:2341:26 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2341:13:2341:26 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:13:2341:26 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:18:2341:18 | g | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:25:2341:25 | h | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:30:2341:43 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | +| main.rs:2341:30:2341:43 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:30:2341:43 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2343:9:2343:9 | a | | file://:0:0:0:0 | (T_2) | +| main.rs:2343:9:2343:9 | a | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2343:9:2343:9 | a | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2343:9:2343:11 | a.0 | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2344:9:2344:9 | b | | file://:0:0:0:0 | (T_2) | +| main.rs:2344:9:2344:9 | b | 0 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2344:9:2344:9 | b | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2344:9:2344:11 | b.1 | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2345:9:2345:9 | c | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2346:9:2346:9 | d | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2347:9:2347:9 | e | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2348:9:2348:9 | f | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2349:9:2349:9 | g | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2350:9:2350:9 | h | | main.rs:2327:5:2327:16 | S1 | +| main.rs:2355:13:2355:13 | a | | {EXTERNAL LOCATION} | i64 | +| main.rs:2355:17:2355:34 | ...::default(...) | | {EXTERNAL LOCATION} | i64 | +| main.rs:2356:13:2356:13 | b | | {EXTERNAL LOCATION} | bool | +| main.rs:2356:17:2356:34 | ...::default(...) | | {EXTERNAL LOCATION} | bool | +| main.rs:2357:13:2357:16 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2357:13:2357:16 | pair | 0 | {EXTERNAL LOCATION} | i64 | +| main.rs:2357:13:2357:16 | pair | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2357:20:2357:25 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| main.rs:2357:20:2357:25 | TupleExpr | 0 | {EXTERNAL LOCATION} | i64 | +| main.rs:2357:20:2357:25 | TupleExpr | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2357:21:2357:21 | a | | {EXTERNAL LOCATION} | i64 | +| main.rs:2357:24:2357:24 | b | | {EXTERNAL LOCATION} | bool | | main.rs:2358:13:2358:13 | i | | {EXTERNAL LOCATION} | i64 | +| main.rs:2358:22:2358:25 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2358:22:2358:25 | pair | 0 | {EXTERNAL LOCATION} | i64 | +| main.rs:2358:22:2358:25 | pair | 1 | {EXTERNAL LOCATION} | bool | | main.rs:2358:22:2358:27 | pair.0 | | {EXTERNAL LOCATION} | i64 | | main.rs:2359:13:2359:13 | j | | {EXTERNAL LOCATION} | bool | +| main.rs:2359:23:2359:26 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2359:23:2359:26 | pair | 0 | {EXTERNAL LOCATION} | i64 | +| main.rs:2359:23:2359:26 | pair | 1 | {EXTERNAL LOCATION} | bool | | main.rs:2359:23:2359:28 | pair.1 | | {EXTERNAL LOCATION} | bool | | main.rs:2366:13:2366:23 | boxed_value | | {EXTERNAL LOCATION} | Box | | main.rs:2366:13:2366:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | @@ -4154,6 +4263,7 @@ inferType | main.rs:2433:41:2433:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | | main.rs:2449:5:2449:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | +| pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () | | pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:14:9:14:13 | value | T | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:14:17:14:24 | Some(...) | | {EXTERNAL LOCATION} | Option | @@ -4171,11 +4281,13 @@ inferType | pattern_matching.rs:17:18:17:25 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:17:18:17:25 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:17:20:17:23 | mesg | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:19:5:25:5 | match value { ... } | | file://:0:0:0:0 | () | | pattern_matching.rs:19:11:19:15 | value | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:19:11:19:15 | value | T | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:20:9:20:18 | Some(...) | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:20:9:20:18 | Some(...) | T | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:20:14:20:17 | mesg | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:20:23:23:9 | { ... } | | file://:0:0:0:0 | () | | pattern_matching.rs:21:17:21:20 | mesg | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:21:24:21:27 | mesg | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:22:22:22:29 | "{mesg}\\n" | | file://:0:0:0:0 | & | @@ -4185,6 +4297,7 @@ inferType | pattern_matching.rs:22:24:22:27 | mesg | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:24:9:24:12 | None | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:24:9:24:12 | None | T | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:24:17:24:18 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:26:9:26:12 | mesg | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:26:16:26:20 | value | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:26:16:26:20 | value | T | {EXTERNAL LOCATION} | i32 | @@ -4293,6 +4406,7 @@ inferType | pattern_matching.rs:58:17:58:22 | value1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:59:13:59:13 | y | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:59:17:59:22 | value2 | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:60:9:60:10 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:63:9:63:23 | my_tuple_struct | | pattern_matching.rs:6:1:6:37 | MyTupleStruct | | pattern_matching.rs:63:9:63:23 | my_tuple_struct | T1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:63:9:63:23 | my_tuple_struct | T2 | {EXTERNAL LOCATION} | bool | @@ -4313,6 +4427,7 @@ inferType | pattern_matching.rs:65:17:65:22 | value1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:66:13:66:13 | y | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:66:17:66:22 | value2 | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:67:9:67:10 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:70:9:70:16 | my_enum1 | | pattern_matching.rs:8:1:11:1 | MyEnum | | pattern_matching.rs:70:9:70:16 | my_enum1 | T1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:70:9:70:16 | my_enum1 | T2 | {EXTERNAL LOCATION} | bool | @@ -4333,6 +4448,7 @@ inferType | pattern_matching.rs:76:21:76:26 | value1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:77:17:77:17 | y | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:77:21:77:26 | value2 | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:78:13:78:14 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:80:9:80:40 | ...::Variant2(...) | | pattern_matching.rs:8:1:11:1 | MyEnum | | pattern_matching.rs:80:9:80:40 | ...::Variant2(...) | T1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:80:9:80:40 | ...::Variant2(...) | T2 | {EXTERNAL LOCATION} | bool | @@ -4342,6 +4458,7 @@ inferType | pattern_matching.rs:81:21:81:26 | value1 | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:82:17:82:17 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:82:21:82:26 | value2 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:83:13:83:14 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:87:9:87:22 | my_nested_enum | | pattern_matching.rs:8:1:11:1 | MyEnum | | pattern_matching.rs:87:9:87:22 | my_nested_enum | T1 | pattern_matching.rs:1:1:4:1 | MyRecordStruct | | pattern_matching.rs:87:9:87:22 | my_nested_enum | T1.T1 | {EXTERNAL LOCATION} | i32 | @@ -4362,6 +4479,7 @@ inferType | pattern_matching.rs:90:21:90:22 | 42 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:91:21:91:28 | "string" | | file://:0:0:0:0 | & | | pattern_matching.rs:91:21:91:28 | "string" | &T | {EXTERNAL LOCATION} | str | +| pattern_matching.rs:95:5:109:5 | match my_nested_enum { ... } | | file://:0:0:0:0 | () | | pattern_matching.rs:95:11:95:24 | my_nested_enum | | pattern_matching.rs:8:1:11:1 | MyEnum | | pattern_matching.rs:95:11:95:24 | my_nested_enum | T1 | pattern_matching.rs:1:1:4:1 | MyRecordStruct | | pattern_matching.rs:95:11:95:24 | my_nested_enum | T1.T1 | {EXTERNAL LOCATION} | i32 | @@ -4382,6 +4500,7 @@ inferType | pattern_matching.rs:99:25:99:25 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:100:25:100:25 | y | | file://:0:0:0:0 | & | | pattern_matching.rs:100:25:100:25 | y | &T | {EXTERNAL LOCATION} | str | +| pattern_matching.rs:102:14:107:9 | { ... } | | file://:0:0:0:0 | () | | pattern_matching.rs:103:17:103:17 | a | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:103:21:103:26 | value1 | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:104:17:104:17 | b | | {EXTERNAL LOCATION} | i32 | @@ -4390,12 +4509,14 @@ inferType | pattern_matching.rs:105:17:105:17 | c | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:105:21:105:21 | y | | file://:0:0:0:0 | & | | pattern_matching.rs:105:21:105:21 | y | &T | {EXTERNAL LOCATION} | str | +| pattern_matching.rs:106:13:106:14 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:108:9:108:9 | _ | | pattern_matching.rs:8:1:11:1 | MyEnum | | pattern_matching.rs:108:9:108:9 | _ | T1 | pattern_matching.rs:1:1:4:1 | MyRecordStruct | | pattern_matching.rs:108:9:108:9 | _ | T1.T1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:108:9:108:9 | _ | T1.T2 | file://:0:0:0:0 | & | | pattern_matching.rs:108:9:108:9 | _ | T1.T2.&T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:108:9:108:9 | _ | T2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:108:14:108:15 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:111:9:111:12 | opt1 | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:111:9:111:12 | opt1 | T | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:111:16:111:39 | Some(...) | | {EXTERNAL LOCATION} | Option | @@ -4430,6 +4551,7 @@ inferType | pattern_matching.rs:127:45:127:48 | opt3 | T | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:129:9:129:9 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:132:5:132:8 | None | | {EXTERNAL LOCATION} | Option | +| pattern_matching.rs:132:5:132:8 | None | T | file://:0:0:0:0 | () | | pattern_matching.rs:169:9:169:13 | value | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:169:17:169:21 | 42i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:171:11:171:15 | value | | {EXTERNAL LOCATION} | i32 | @@ -4910,33 +5032,142 @@ inferType | pattern_matching.rs:438:22:438:49 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:438:22:438:49 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:438:37:438:49 | wrapped_value | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:9:444:13 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:444:9:444:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:9:444:13 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:9:444:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:444:9:444:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:444:9:444:13 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:444:18:444:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:24:444:27 | 2i64 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:444:24:444:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:444:30:444:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:444:30:444:35 | 3.0f32 | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:447:11:447:15 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:447:11:447:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:447:11:447:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:447:11:447:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:447:11:447:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:447:11:447:15 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:448:9:448:19 | TuplePat | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:448:9:448:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:448:10:448:10 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:448:13:448:13 | 2 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:448:13:448:13 | 2 | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:448:16:448:18 | 3.0 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:448:16:448:18 | 3.0 | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:449:31:449:35 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:449:31:449:35 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:31:449:35 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:31:449:35 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:449:31:449:35 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:449:31:449:35 | tuple | 2 | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:450:22:450:40 | "Exact tuple: {:?}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:450:22:450:40 | "Exact tuple: {:?}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:450:22:450:53 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:450:22:450:53 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:450:43:450:53 | exact_tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:452:9:452:17 | TuplePat | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:452:9:452:17 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:452:10:452:10 | a | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:13:452:13 | b | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:13:452:13 | b | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:452:16:452:16 | c | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:452:16:452:16 | c | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:453:17:453:26 | first_elem | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:453:30:453:30 | a | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:454:17:454:27 | second_elem | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:454:17:454:27 | second_elem | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:454:31:454:31 | b | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:454:31:454:31 | b | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:455:17:455:26 | third_elem | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:455:17:455:26 | third_elem | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:455:30:455:30 | c | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:455:30:455:30 | c | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:456:22:456:42 | "Tuple: ({}, {}, {})\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:456:22:456:42 | "Tuple: ({}, {}, {})\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:456:22:456:79 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:456:22:456:79 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:456:45:456:54 | first_elem | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:456:57:456:67 | second_elem | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:456:57:456:67 | second_elem | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:456:70:456:79 | third_elem | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:456:70:456:79 | third_elem | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:461:11:461:15 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:461:11:461:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:461:11:461:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:461:11:461:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:461:11:461:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:461:11:461:15 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:462:9:462:19 | TuplePat | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:462:9:462:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:462:10:462:14 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:17:462:18 | .. | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:17:462:18 | .. | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:463:17:463:27 | tuple_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:463:31:463:35 | first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:464:22:464:40 | "First element: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:464:22:464:40 | "First element: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:464:22:464:53 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:464:22:464:53 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:464:43:464:53 | tuple_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:469:9:469:12 | unit | | file://:0:0:0:0 | () | +| pattern_matching.rs:469:16:469:17 | TupleExpr | | file://:0:0:0:0 | () | +| pattern_matching.rs:470:11:470:14 | unit | | file://:0:0:0:0 | () | +| pattern_matching.rs:471:9:471:10 | TuplePat | | file://:0:0:0:0 | () | +| pattern_matching.rs:472:17:472:26 | unit_value | | file://:0:0:0:0 | () | +| pattern_matching.rs:472:30:472:33 | unit | | file://:0:0:0:0 | () | | pattern_matching.rs:473:22:473:39 | "Unit value: {:?}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:473:22:473:39 | "Unit value: {:?}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:473:22:473:51 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:473:22:473:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:473:42:473:51 | unit_value | | file://:0:0:0:0 | () | +| pattern_matching.rs:478:9:478:14 | single | | file://:0:0:0:0 | (T_1) | +| pattern_matching.rs:478:9:478:14 | single | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:478:18:478:25 | TupleExpr | | file://:0:0:0:0 | (T_1) | +| pattern_matching.rs:478:18:478:25 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:478:19:478:23 | 42i32 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:479:11:479:16 | single | | file://:0:0:0:0 | (T_1) | +| pattern_matching.rs:479:11:479:16 | single | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:480:9:480:12 | TuplePat | | file://:0:0:0:0 | (T_1) | +| pattern_matching.rs:480:9:480:12 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:480:10:480:10 | x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:481:17:481:27 | single_elem | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:481:31:481:31 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:482:22:482:47 | "Single element tuple: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:482:22:482:47 | "Single element tuple: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:482:22:482:60 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:482:22:482:60 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:482:50:482:60 | single_elem | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:488:9:488:13 | value | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:488:17:488:21 | 42i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:491:11:491:15 | value | | {EXTERNAL LOCATION} | i32 | @@ -4949,12 +5180,33 @@ inferType | pattern_matching.rs:494:22:494:61 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:494:22:494:61 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:494:51:494:61 | paren_bound | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:9:499:13 | tuple | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:499:9:499:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:9:499:13 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:17:499:28 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:499:17:499:28 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:17:499:28 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:18:499:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:24:499:27 | 2i32 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:500:11:500:15 | tuple | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:500:11:500:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:500:11:500:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:9:501:16 | TuplePat | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:501:9:501:16 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:9:501:16 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:10:501:10 | x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:13:501:15 | (...) | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:14:501:14 | y | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:502:17:502:23 | paren_x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:502:27:502:27 | x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:503:17:503:23 | paren_y | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:503:27:503:27 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:504:22:504:53 | "Parenthesized in tuple: {}, {... | | file://:0:0:0:0 | & | | pattern_matching.rs:504:22:504:53 | "Parenthesized in tuple: {}, {... | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:504:22:504:71 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:504:22:504:71 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:504:56:504:62 | paren_x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:504:65:504:71 | paren_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:510:9:510:13 | slice | | file://:0:0:0:0 | & | | pattern_matching.rs:510:9:510:13 | slice | &T | file://:0:0:0:0 | [] | | pattern_matching.rs:510:9:510:13 | slice | &T | file://:0:0:0:0 | [] | @@ -5173,22 +5425,81 @@ inferType | pattern_matching.rs:621:22:621:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:621:38:621:51 | range_or_value | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:623:9:623:9 | _ | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:628:9:628:13 | tuple | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:628:9:628:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:628:9:628:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:628:9:628:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:628:9:628:13 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 3 | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:628:18:628:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:628:24:628:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:628:30:628:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:628:38:628:40 | 4u8 | | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:631:11:631:15 | tuple | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:631:11:631:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:631:11:631:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:631:11:631:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:631:11:631:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:632:9:632:19 | TuplePat | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:632:9:632:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:632:10:632:14 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:632:17:632:18 | .. | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:633:17:633:26 | rest_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:633:30:633:34 | first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:634:22:634:42 | "First with rest: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:634:22:634:42 | "First with rest: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:634:22:634:54 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:634:22:634:54 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:634:45:634:54 | rest_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:638:11:638:15 | tuple | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:638:11:638:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:638:11:638:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:638:11:638:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:638:11:638:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:639:9:639:18 | TuplePat | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:639:9:639:18 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:639:10:639:11 | .. | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:639:14:639:17 | last | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:640:17:640:25 | rest_last | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:640:29:640:32 | last | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:641:22:641:41 | "Last with rest: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:641:22:641:41 | "Last with rest: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:641:22:641:52 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:641:22:641:52 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:641:44:641:52 | rest_last | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:645:11:645:15 | tuple | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:645:11:645:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:645:11:645:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:645:11:645:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:645:11:645:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:646:9:646:25 | TuplePat | | file://:0:0:0:0 | (T_4) | +| pattern_matching.rs:646:9:646:25 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:646:10:646:14 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:646:17:646:18 | .. | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:646:21:646:24 | last | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:647:17:647:26 | rest_start | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:647:30:647:34 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:648:17:648:24 | rest_end | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:648:28:648:31 | last | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:649:22:649:45 | "First and last: {}, {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:649:22:649:45 | "First and last: {}, {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:649:22:649:67 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:649:22:649:67 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:649:48:649:57 | rest_start | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:649:60:649:67 | rest_end | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:654:9:654:13 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:654:17:654:38 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:654:28:654:29 | 10 | | {EXTERNAL LOCATION} | i32 | @@ -5211,6 +5522,14 @@ inferType | pattern_matching.rs:682:21:682:25 | 10i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:682:21:682:25 | 10i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:682:28:682:28 | x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:687:9:687:20 | complex_data | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:687:9:687:20 | complex_data | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:687:9:687:20 | complex_data | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:687:9:687:20 | complex_data | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:687:24:687:79 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:687:25:687:44 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:687:36:687:36 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:687:42:687:42 | 2 | | {EXTERNAL LOCATION} | i32 | @@ -5223,6 +5542,14 @@ inferType | pattern_matching.rs:687:73:687:73 | 0 | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:687:76:687:76 | 0 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:687:76:687:76 | 0 | | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:689:11:689:22 | complex_data | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:689:11:689:22 | complex_data | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:689:11:689:22 | complex_data | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:689:11:689:22 | complex_data | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:691:9:691:61 | TuplePat | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:691:9:691:61 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:691:9:691:61 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:691:9:691:61 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:691:10:691:26 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:691:21:691:21 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:691:24:691:24 | y | | {EXTERNAL LOCATION} | i32 | @@ -5246,11 +5573,27 @@ inferType | pattern_matching.rs:697:17:697:24 | nested_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:697:27:697:34 | nested_g | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:697:37:697:44 | nested_b | | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:701:9:701:41 | TuplePat | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:701:9:701:41 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:9:701:41 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:9:701:41 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:701:9:701:71 | ... \| ... | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:10:701:24 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:701:18:701:18 | x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:701:27:701:40 | ...::None | | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:27:701:40 | ...::None | T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:701:45:701:71 | TuplePat | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:701:45:701:71 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:45:701:71 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:45:701:71 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:46:701:67 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:701:57:701:57 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:701:61:701:61 | 0 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:701:70:701:70 | _ | | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:70:701:70 | _ | T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:702:17:702:29 | alt_complex_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:702:33:702:33 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:703:22:703:50 | "Alternative complex: x={:?}\\n... | | file://:0:0:0:0 | & | @@ -5258,10 +5601,26 @@ inferType | pattern_matching.rs:703:22:703:65 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:703:22:703:65 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:703:53:703:65 | alt_complex_x | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:706:9:706:13 | other | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:706:9:706:13 | other | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:706:9:706:13 | other | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:706:9:706:13 | other | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:707:17:707:29 | other_complex | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:707:17:707:29 | other_complex | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:707:17:707:29 | other_complex | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:707:17:707:29 | other_complex | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:707:33:707:37 | other | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:707:33:707:37 | other | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:707:33:707:37 | other | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:707:33:707:37 | other | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:708:22:708:47 | "Other complex data: {:?}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:708:22:708:47 | "Other complex data: {:?}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:708:22:708:62 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:708:22:708:62 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| pattern_matching.rs:708:50:708:62 | other_complex | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:708:50:708:62 | other_complex | 0 | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:708:50:708:62 | other_complex | 1 | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:708:50:708:62 | other_complex | 1.T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:715:9:715:13 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:715:17:715:38 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:715:28:715:29 | 10 | | {EXTERNAL LOCATION} | i32 | @@ -5274,9 +5633,34 @@ inferType | pattern_matching.rs:717:17:717:17 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:718:9:718:13 | let_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:718:17:718:17 | y | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:720:9:720:13 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:720:9:720:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:720:9:720:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:720:9:720:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:720:18:720:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:720:24:720:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:720:30:720:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:721:9:721:17 | TuplePat | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:721:9:721:17 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:721:9:721:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:721:9:721:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:721:10:721:10 | a | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:721:13:721:13 | b | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:721:16:721:16 | c | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:721:21:721:25 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:721:21:721:25 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:721:21:721:25 | tuple | 1 | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:721:21:721:25 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:722:9:722:13 | let_a | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:722:17:722:17 | a | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:723:9:723:13 | let_b | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:723:17:723:17 | b | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:724:9:724:13 | let_c | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:724:17:724:17 | c | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:726:9:726:13 | array | | file://:0:0:0:0 | [] | | pattern_matching.rs:726:9:726:13 | array | [T;...] | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:726:17:726:34 | [...] | | file://:0:0:0:0 | [] | @@ -5325,10 +5709,16 @@ inferType | pattern_matching.rs:750:22:750:35 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:750:30:750:30 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:750:33:750:33 | y | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:750:59:754:5 | { ... } | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:750:59:754:5 | { ... } | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:750:59:754:5 | { ... } | 1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:751:13:751:19 | param_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:751:23:751:23 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:752:13:752:19 | param_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:752:23:752:23 | y | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:753:9:753:26 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:753:9:753:26 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:753:9:753:26 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:753:10:753:16 | param_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:753:19:753:25 | param_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:756:22:756:35 | Color(...) | | pattern_matching.rs:142:1:143:25 | Color | @@ -5339,10 +5729,35 @@ inferType | pattern_matching.rs:757:13:757:19 | param_r | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:757:23:757:23 | r | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:758:9:758:15 | param_r | | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:761:22:761:38 | TuplePat | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:761:22:761:38 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:761:22:761:38 | TuplePat | 1 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:761:22:761:38 | TuplePat | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:761:23:761:27 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:761:30:761:30 | _ | | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:761:33:761:37 | third | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:761:74:765:5 | { ... } | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:761:74:765:5 | { ... } | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:761:74:765:5 | { ... } | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:762:13:762:23 | param_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:762:27:762:31 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:763:13:763:23 | param_third | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:763:27:763:31 | third | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:764:9:764:34 | TupleExpr | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:764:9:764:34 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:764:9:764:34 | TupleExpr | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:764:10:764:20 | param_first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:764:23:764:33 | param_third | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:768:9:768:13 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:768:17:768:37 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:768:28:768:28 | 5 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:768:34:768:35 | 10 | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:9:769:17 | extracted | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:769:9:769:17 | extracted | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:9:769:17 | extracted | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:21:769:40 | extract_point(...) | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:769:21:769:40 | extract_point(...) | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:21:769:40 | extract_point(...) | 1 | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:769:35:769:39 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:771:9:771:13 | color | | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:771:17:771:35 | Color(...) | | pattern_matching.rs:142:1:143:25 | Color | @@ -5355,9 +5770,27 @@ inferType | pattern_matching.rs:772:9:772:11 | red | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:772:15:772:34 | extract_color(...) | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:772:29:772:33 | color | | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:774:9:774:13 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:774:9:774:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:774:9:774:13 | tuple | 1 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:774:9:774:13 | tuple | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:774:17:774:38 | TupleExpr | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 1 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 2 | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:774:18:774:22 | 42i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:774:25:774:31 | 3.14f64 | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:774:34:774:37 | true | | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:9:775:23 | tuple_extracted | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:775:9:775:23 | tuple_extracted | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:9:775:23 | tuple_extracted | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | | file://:0:0:0:0 | (T_2) | +| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:41:775:45 | tuple | | file://:0:0:0:0 | (T_3) | +| pattern_matching.rs:775:41:775:45 | tuple | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:41:775:45 | tuple | 1 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:775:41:775:45 | tuple | 2 | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:781:23:781:42 | (...) | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:781:23:781:42 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:781:34:781:34 | 1 | | {EXTERNAL LOCATION} | i32 | @@ -5437,4 +5870,5 @@ inferType | pattern_matching.rs:807:38:807:44 | guard_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:809:9:809:9 | _ | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:814:5:814:7 | f(...) | | {EXTERNAL LOCATION} | Option | +| pattern_matching.rs:814:5:814:7 | f(...) | T | file://:0:0:0:0 | () | testFailures From 26dae8144c571f8d1ed3328ec7d287e37dbb07e2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:24:06 +0100 Subject: [PATCH 063/311] Rust: Make rust/summary/query-sinks less noisy and thus more useful. This is the one in the DCA meta queries output, not the grand total used in metrics. --- rust/ql/src/queries/summary/QuerySinks.ql | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql index a94ab2f8e804..714f5a8ab745 100644 --- a/rust/ql/src/queries/summary/QuerySinks.ql +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -2,7 +2,8 @@ * @name Query Sinks * @description Lists query sinks that are found in the database. Query sinks are flow sinks that * are used as possible locations for query results. Cryptographic operations are - * excluded (see `rust/summary/cryptographic-operations` instead). + * excluded (see `rust/summary/cryptographic-operations` instead), as are certain + * sink types that are ubiquitous in most code. * @kind problem * @problem.severity info * @id rust/summary/query-sinks @@ -13,6 +14,11 @@ import rust import codeql.rust.dataflow.DataFlow import codeql.rust.Concepts import Stats +import codeql.rust.security.AccessInvalidPointerExtensions +import codeql.rust.security.CleartextLoggingExtensions from QuerySink s +where + not s instanceof AccessInvalidPointer::Sink and + not s instanceof CleartextLogging::Sink select s, "Sink for " + concat(s.getSinkType(), ", ") + "." From 29cceeba1ac2f4e00cc11c0929f08fee0b5f37f8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 14 Jul 2025 18:08:58 +0100 Subject: [PATCH 064/311] C++: Don't use asExpr to mark the sink in 'cpp/uncontrolled-process-operation'. --- cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql index aedb21da5167..7d2513d25e33 100644 --- a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql +++ b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql @@ -23,7 +23,7 @@ predicate isProcessOperationExplanation(DataFlow::Node arg, string processOperat exists(int processOperationArg, FunctionCall call | isProcessOperationArgument(processOperation, processOperationArg) and call.getTarget().getName() = processOperation and - call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()] + call.getArgument(processOperationArg) = arg.asIndirectExpr() ) } From 7c04c9f969ccfc85d03e938d2d44bd436a4d7b90 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 15 Jul 2025 09:50:15 +0200 Subject: [PATCH 065/311] Rust: Store arity in tuple type parameters Type parameters are required to belong to a single type only. Since we store the arity for tuple types, we need to store the arity in tuple type parameters as well such that we can associate them to the tuple type of the same arity. --- rust/ql/lib/codeql/rust/internal/Type.qll | 19 +- .../codeql/rust/internal/TypeInference.qll | 25 +- .../lib/codeql/rust/internal/TypeMention.qll | 2 +- .../test/library-tests/type-inference/main.rs | 2 +- .../type-inference/pattern_matching.rs | 8 +- .../type-inference/type-inference.expected | 459 +++++++++--------- 6 files changed, 253 insertions(+), 262 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index ca49f3c258df..f9db78035348 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -10,7 +10,8 @@ private import codeql.rust.elements.internal.generated.Synth cached newtype TType = TTuple(int arity) { - exists(any(TupleTypeRepr t).getField(arity)) and Stages::TypeInferenceStage::ref() + arity = any(TupleTypeRepr t).getNumberOfFields() and + Stages::TypeInferenceStage::ref() } or TStruct(Struct s) or TEnum(Enum e) or @@ -19,7 +20,7 @@ newtype TType = TRefType() or // todo: add mut? TImplTraitType(ImplTraitTypeRepr impl) or TSliceType() or - TTupleTypeParameter(int i) { exists(TTuple(i)) } or + TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or TTypeParamTypeParameter(TypeParam t) or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or TArrayTypeParameter() or @@ -83,7 +84,7 @@ class TupleType extends Type, TTuple { override TupleField getTupleField(int i) { none() } - override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(i) and i < arity } + override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(arity, i) } int getArity() { result = arity } @@ -358,12 +359,20 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara * their positional index. */ class TupleTypeParameter extends TypeParameter, TTupleTypeParameter { - override string toString() { result = this.getIndex().toString() } + private int arity; + private int index; + + TupleTypeParameter() { this = TTupleTypeParameter(arity, index) } + + override string toString() { result = index.toString() + "(" + arity + ")" } override Location getLocation() { result instanceof EmptyLocation } /** Gets the index of this tuple type parameter. */ - int getIndex() { this = TTupleTypeParameter(result) } + int getIndex() { result = index } + + /** Gets the arity of this tuple type parameter. */ + int getArity() { result = arity } } /** An implicit array type parameter. */ diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 1d2e7ee02de8..8f2a2ca2ae1c 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -104,8 +104,12 @@ private module Input1 implements InputSig1 { node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr() ) or - kind = 2 and - id = tp0.(TupleTypeParameter).getIndex() + exists(TupleTypeParameter ttp, int maxArity | + maxArity = max(int i | i = any(TupleType tt).getArity()) and + tp0 = ttp and + kind = 2 and + id = ttp.getArity() * maxArity + ttp.getIndex() + ) | tp0 order by kind, id ) @@ -324,11 +328,14 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat prefix1.isEmpty() and prefix2 = TypePath::singleton(TRefTypeParameter()) or - exists(int i | + exists(int i, int arity | prefix1.isEmpty() and - prefix2 = TypePath::singleton(TTupleTypeParameter(i)) + prefix2 = TypePath::singleton(TTupleTypeParameter(arity, i)) | - n1 = n2.(TupleExpr).getField(i) or + arity = n2.(TupleExpr).getNumberOfFields() and + n1 = n2.(TupleExpr).getField(i) + or + arity = n2.(TuplePat).getNumberOfFields() and n1 = n2.(TuplePat).getField(i) ) or @@ -1077,7 +1084,7 @@ private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) { exists(int i, TypePath path0 | fe.getIdentifier().getText() = i.toString() and result = inferType(fe.getContainer(), path0) and - path0.isCons(TTupleTypeParameter(i), path) and + path0.isCons(TTupleTypeParameter(_, i), path) and fe.getIdentifier().getText() = i.toString() ) } @@ -1088,12 +1095,12 @@ private Type inferTupleContainerExprType(Expr e, TypePath path) { // a tuple struct or a tuple. It is only correct to let type information flow // from `t.n` to tuple type parameters of `t` in the latter case. Hence we // include the condition that the root type of `t` must be a tuple type. - exists(int i, TypePath path0, FieldExpr fe | + exists(int i, TypePath path0, FieldExpr fe, int arity | e = fe.getContainer() and fe.getIdentifier().getText() = i.toString() and - inferType(fe.getContainer()) instanceof TupleType and + arity = inferType(fe.getContainer()).(TupleType).getArity() and result = inferType(fe, path0) and - path = TypePath::cons(TTupleTypeParameter(i), path0) + path = TypePath::cons(TTupleTypeParameter(arity, i), path0) // FIXME: ) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index a40c068b4894..a70d25e9a908 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -21,7 +21,7 @@ class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr { or exists(TypePath suffix, int i | result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and - path = TypePath::cons(TTupleTypeParameter(i), suffix) + path = TypePath::cons(TTupleTypeParameter(super.getNumberOfFields(), i), suffix) ) } } diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 583f4349df6f..03efbfc9b4ff 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2354,7 +2354,7 @@ mod tuples { // `a` and `b` to be inferred. let a = Default::default(); // $ target=default type=a:i64 let b = Default::default(); // $ target=default type=b:bool - let pair = (a, b); // $ type=pair:0.i64 type=pair:1.bool + let pair = (a, b); // $ type=pair:0(2).i64 type=pair:1(2).bool let i: i64 = pair.0; let j: bool = pair.1; } diff --git a/rust/ql/test/library-tests/type-inference/pattern_matching.rs b/rust/ql/test/library-tests/type-inference/pattern_matching.rs index 91774706c46f..396428eedc0f 100755 --- a/rust/ql/test/library-tests/type-inference/pattern_matching.rs +++ b/rust/ql/test/library-tests/type-inference/pattern_matching.rs @@ -460,7 +460,7 @@ pub fn tuple_patterns() { // With rest pattern match tuple { (first, ..) => { - let tuple_first = first; // $ type=tuple_first:i32 + let tuple_first = first; // $ MISSING: type=tuple_first:i32 println!("First element: {}", tuple_first); } } @@ -630,7 +630,7 @@ pub fn rest_patterns() { // RestPat - Rest patterns (..) match tuple { (first, ..) => { - let rest_first = first; // $ type=rest_first:i32 + let rest_first = first; // $ MISSING: type=rest_first:i32 println!("First with rest: {}", rest_first); } } @@ -644,7 +644,7 @@ pub fn rest_patterns() { match tuple { (first, .., last) => { - let rest_start = first; // $ type=rest_start:i32 + let rest_start = first; // $ MISSING: type=rest_start:i32 let rest_end = last; // $ MISSING: type=rest_end:u8 println!("First and last: {}, {}", rest_start, rest_end); } @@ -772,7 +772,7 @@ pub fn patterns_in_function_parameters() { let red = extract_color(color); // $ target=extract_color type=red:u8 let tuple = (42i32, 3.14f64, true); - let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple type=tuple_extracted:0.i32 type=tuple_extracted:1.bool + let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple type=tuple_extracted:0(2).i32 type=tuple_extracted:1(2).bool } #[rustfmt::skip] 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 6a9776d9d705..b6f5e24244d6 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3927,13 +3927,13 @@ inferType | main.rs:2253:22:2253:34 | map1.values() | V.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2254:13:2254:24 | TuplePat | | {EXTERNAL LOCATION} | Item | | main.rs:2254:13:2254:24 | TuplePat | | file://:0:0:0:0 | (T_2) | -| main.rs:2254:13:2254:24 | TuplePat | 0 | file://:0:0:0:0 | & | -| main.rs:2254:13:2254:24 | TuplePat | 0.&T | {EXTERNAL LOCATION} | i32 | -| main.rs:2254:13:2254:24 | TuplePat | 1 | file://:0:0:0:0 | & | -| main.rs:2254:13:2254:24 | TuplePat | 1.&T | {EXTERNAL LOCATION} | Box | -| main.rs:2254:13:2254:24 | TuplePat | 1.&T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2254:13:2254:24 | TuplePat | 1.&T.T | file://:0:0:0:0 | & | -| main.rs:2254:13:2254:24 | TuplePat | 1.&T.T.&T | {EXTERNAL LOCATION} | str | +| main.rs:2254:13:2254:24 | TuplePat | 0(2) | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 0(2).&T | {EXTERNAL LOCATION} | i32 | +| main.rs:2254:13:2254:24 | TuplePat | 1(2) | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 1(2).&T | {EXTERNAL LOCATION} | Box | +| main.rs:2254:13:2254:24 | TuplePat | 1(2).&T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2254:13:2254:24 | TuplePat | 1(2).&T.T | file://:0:0:0:0 | & | +| main.rs:2254:13:2254:24 | TuplePat | 1(2).&T.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2254:14:2254:16 | key | | file://:0:0:0:0 | & | | main.rs:2254:14:2254:16 | key | &T | {EXTERNAL LOCATION} | i32 | | main.rs:2254:19:2254:23 | value | | file://:0:0:0:0 | & | @@ -3956,13 +3956,13 @@ inferType | main.rs:2254:29:2254:39 | map1.iter() | V.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2255:13:2255:24 | TuplePat | | {EXTERNAL LOCATION} | Item | | main.rs:2255:13:2255:24 | TuplePat | | file://:0:0:0:0 | (T_2) | -| main.rs:2255:13:2255:24 | TuplePat | 0 | file://:0:0:0:0 | & | -| main.rs:2255:13:2255:24 | TuplePat | 0.&T | {EXTERNAL LOCATION} | i32 | -| main.rs:2255:13:2255:24 | TuplePat | 1 | file://:0:0:0:0 | & | -| main.rs:2255:13:2255:24 | TuplePat | 1.&T | {EXTERNAL LOCATION} | Box | -| main.rs:2255:13:2255:24 | TuplePat | 1.&T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2255:13:2255:24 | TuplePat | 1.&T.T | file://:0:0:0:0 | & | -| main.rs:2255:13:2255:24 | TuplePat | 1.&T.T.&T | {EXTERNAL LOCATION} | str | +| main.rs:2255:13:2255:24 | TuplePat | 0(2) | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 0(2).&T | {EXTERNAL LOCATION} | i32 | +| main.rs:2255:13:2255:24 | TuplePat | 1(2) | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 1(2).&T | {EXTERNAL LOCATION} | Box | +| main.rs:2255:13:2255:24 | TuplePat | 1(2).&T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2255:13:2255:24 | TuplePat | 1(2).&T.T | file://:0:0:0:0 | & | +| main.rs:2255:13:2255:24 | TuplePat | 1(2).&T.T.&T | {EXTERNAL LOCATION} | str | | main.rs:2255:14:2255:16 | key | | file://:0:0:0:0 | & | | main.rs:2255:14:2255:16 | key | &T | {EXTERNAL LOCATION} | i32 | | main.rs:2255:19:2255:23 | value | | file://:0:0:0:0 | & | @@ -4092,57 +4092,57 @@ inferType | main.rs:2322:19:2322:48 | foo::<...>(...) | | {EXTERNAL LOCATION} | i32 | | main.rs:2322:30:2322:47 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | | main.rs:2330:35:2332:9 | { ... } | | file://:0:0:0:0 | (T_2) | -| main.rs:2330:35:2332:9 | { ... } | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2330:35:2332:9 | { ... } | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2330:35:2332:9 | { ... } | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2330:35:2332:9 | { ... } | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:13:2331:26 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| main.rs:2331:13:2331:26 | TupleExpr | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2331:13:2331:26 | TupleExpr | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2331:13:2331:26 | TupleExpr | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2331:13:2331:26 | TupleExpr | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:14:2331:18 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2331:21:2331:25 | S1 {...} | | main.rs:2327:5:2327:16 | S1 | | main.rs:2333:16:2333:19 | SelfParam | | main.rs:2327:5:2327:16 | S1 | | main.rs:2337:13:2337:13 | a | | file://:0:0:0:0 | (T_2) | -| main.rs:2337:13:2337:13 | a | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2337:13:2337:13 | a | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:13:2337:13 | a | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:13:2337:13 | a | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2337:17:2337:30 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | -| main.rs:2337:17:2337:30 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2337:17:2337:30 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:17:2337:30 | ...::get_pair(...) | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2337:17:2337:30 | ...::get_pair(...) | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2338:17:2338:17 | b | | file://:0:0:0:0 | (T_2) | -| main.rs:2338:17:2338:17 | b | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2338:17:2338:17 | b | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:17:2338:17 | b | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:17:2338:17 | b | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2338:21:2338:34 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | -| main.rs:2338:21:2338:34 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2338:21:2338:34 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:21:2338:34 | ...::get_pair(...) | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2338:21:2338:34 | ...::get_pair(...) | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2339:13:2339:18 | TuplePat | | file://:0:0:0:0 | (T_2) | -| main.rs:2339:13:2339:18 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2339:13:2339:18 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:13:2339:18 | TuplePat | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:13:2339:18 | TuplePat | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2339:14:2339:14 | c | | main.rs:2327:5:2327:16 | S1 | | main.rs:2339:17:2339:17 | d | | main.rs:2327:5:2327:16 | S1 | | main.rs:2339:22:2339:35 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | -| main.rs:2339:22:2339:35 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2339:22:2339:35 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:22:2339:35 | ...::get_pair(...) | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2339:22:2339:35 | ...::get_pair(...) | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2340:13:2340:22 | TuplePat | | file://:0:0:0:0 | (T_2) | -| main.rs:2340:13:2340:22 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2340:13:2340:22 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:13:2340:22 | TuplePat | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:13:2340:22 | TuplePat | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2340:18:2340:18 | e | | main.rs:2327:5:2327:16 | S1 | | main.rs:2340:21:2340:21 | f | | main.rs:2327:5:2327:16 | S1 | | main.rs:2340:26:2340:39 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | -| main.rs:2340:26:2340:39 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2340:26:2340:39 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:26:2340:39 | ...::get_pair(...) | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2340:26:2340:39 | ...::get_pair(...) | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2341:13:2341:26 | TuplePat | | file://:0:0:0:0 | (T_2) | -| main.rs:2341:13:2341:26 | TuplePat | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2341:13:2341:26 | TuplePat | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:13:2341:26 | TuplePat | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:13:2341:26 | TuplePat | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2341:18:2341:18 | g | | main.rs:2327:5:2327:16 | S1 | | main.rs:2341:25:2341:25 | h | | main.rs:2327:5:2327:16 | S1 | | main.rs:2341:30:2341:43 | ...::get_pair(...) | | file://:0:0:0:0 | (T_2) | -| main.rs:2341:30:2341:43 | ...::get_pair(...) | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2341:30:2341:43 | ...::get_pair(...) | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:30:2341:43 | ...::get_pair(...) | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2341:30:2341:43 | ...::get_pair(...) | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2343:9:2343:9 | a | | file://:0:0:0:0 | (T_2) | -| main.rs:2343:9:2343:9 | a | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2343:9:2343:9 | a | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2343:9:2343:9 | a | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2343:9:2343:9 | a | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2343:9:2343:11 | a.0 | | main.rs:2327:5:2327:16 | S1 | | main.rs:2344:9:2344:9 | b | | file://:0:0:0:0 | (T_2) | -| main.rs:2344:9:2344:9 | b | 0 | main.rs:2327:5:2327:16 | S1 | -| main.rs:2344:9:2344:9 | b | 1 | main.rs:2327:5:2327:16 | S1 | +| main.rs:2344:9:2344:9 | b | 0(2) | main.rs:2327:5:2327:16 | S1 | +| main.rs:2344:9:2344:9 | b | 1(2) | main.rs:2327:5:2327:16 | S1 | | main.rs:2344:9:2344:11 | b.1 | | main.rs:2327:5:2327:16 | S1 | | main.rs:2345:9:2345:9 | c | | main.rs:2327:5:2327:16 | S1 | | main.rs:2346:9:2346:9 | d | | main.rs:2327:5:2327:16 | S1 | @@ -4155,22 +4155,22 @@ inferType | main.rs:2356:13:2356:13 | b | | {EXTERNAL LOCATION} | bool | | main.rs:2356:17:2356:34 | ...::default(...) | | {EXTERNAL LOCATION} | bool | | main.rs:2357:13:2357:16 | pair | | file://:0:0:0:0 | (T_2) | -| main.rs:2357:13:2357:16 | pair | 0 | {EXTERNAL LOCATION} | i64 | -| main.rs:2357:13:2357:16 | pair | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2357:13:2357:16 | pair | 0(2) | {EXTERNAL LOCATION} | i64 | +| main.rs:2357:13:2357:16 | pair | 1(2) | {EXTERNAL LOCATION} | bool | | main.rs:2357:20:2357:25 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| main.rs:2357:20:2357:25 | TupleExpr | 0 | {EXTERNAL LOCATION} | i64 | -| main.rs:2357:20:2357:25 | TupleExpr | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2357:20:2357:25 | TupleExpr | 0(2) | {EXTERNAL LOCATION} | i64 | +| main.rs:2357:20:2357:25 | TupleExpr | 1(2) | {EXTERNAL LOCATION} | bool | | main.rs:2357:21:2357:21 | a | | {EXTERNAL LOCATION} | i64 | | main.rs:2357:24:2357:24 | b | | {EXTERNAL LOCATION} | bool | | main.rs:2358:13:2358:13 | i | | {EXTERNAL LOCATION} | i64 | | main.rs:2358:22:2358:25 | pair | | file://:0:0:0:0 | (T_2) | -| main.rs:2358:22:2358:25 | pair | 0 | {EXTERNAL LOCATION} | i64 | -| main.rs:2358:22:2358:25 | pair | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2358:22:2358:25 | pair | 0(2) | {EXTERNAL LOCATION} | i64 | +| main.rs:2358:22:2358:25 | pair | 1(2) | {EXTERNAL LOCATION} | bool | | main.rs:2358:22:2358:27 | pair.0 | | {EXTERNAL LOCATION} | i64 | | main.rs:2359:13:2359:13 | j | | {EXTERNAL LOCATION} | bool | | main.rs:2359:23:2359:26 | pair | | file://:0:0:0:0 | (T_2) | -| main.rs:2359:23:2359:26 | pair | 0 | {EXTERNAL LOCATION} | i64 | -| main.rs:2359:23:2359:26 | pair | 1 | {EXTERNAL LOCATION} | bool | +| main.rs:2359:23:2359:26 | pair | 0(2) | {EXTERNAL LOCATION} | i64 | +| main.rs:2359:23:2359:26 | pair | 1(2) | {EXTERNAL LOCATION} | bool | | main.rs:2359:23:2359:28 | pair.1 | | {EXTERNAL LOCATION} | bool | | main.rs:2366:13:2366:23 | boxed_value | | {EXTERNAL LOCATION} | Box | | main.rs:2366:13:2366:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | @@ -5033,67 +5033,67 @@ inferType | pattern_matching.rs:438:22:438:49 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:438:37:438:49 | wrapped_value | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:444:9:444:13 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:444:9:444:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:444:9:444:13 | tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:444:9:444:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:444:9:444:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:444:9:444:13 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:444:9:444:13 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:9:444:13 | tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:9:444:13 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:444:9:444:13 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:444:9:444:13 | tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:444:17:444:36 | TupleExpr | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:444:17:444:36 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:444:17:444:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:444:17:444:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:444:17:444:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:444:17:444:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:444:17:444:36 | TupleExpr | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:444:18:444:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:444:24:444:27 | 2i64 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:444:24:444:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:444:30:444:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:444:30:444:35 | 3.0f32 | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:447:11:447:15 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:447:11:447:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:447:11:447:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:447:11:447:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:447:11:447:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:447:11:447:15 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:447:11:447:15 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:447:11:447:15 | tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:447:11:447:15 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:447:11:447:15 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:447:11:447:15 | tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:448:9:448:19 | TuplePat | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:448:9:448:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:448:9:448:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:448:9:448:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:448:9:448:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:448:9:448:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:448:9:448:19 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:448:10:448:10 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:448:13:448:13 | 2 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:448:13:448:13 | 2 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:448:16:448:18 | 3.0 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:448:16:448:18 | 3.0 | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:449:17:449:27 | exact_tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:449:17:449:27 | exact_tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:449:17:449:27 | exact_tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:449:17:449:27 | exact_tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:449:17:449:27 | exact_tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:449:17:449:27 | exact_tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:449:17:449:27 | exact_tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:449:31:449:35 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:449:31:449:35 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:449:31:449:35 | tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:449:31:449:35 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:449:31:449:35 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:449:31:449:35 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:449:31:449:35 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:31:449:35 | tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:449:31:449:35 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:449:31:449:35 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:449:31:449:35 | tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:450:22:450:40 | "Exact tuple: {:?}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:450:22:450:40 | "Exact tuple: {:?}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:450:22:450:53 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:450:22:450:53 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:450:43:450:53 | exact_tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:450:43:450:53 | exact_tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:450:43:450:53 | exact_tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:450:43:450:53 | exact_tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:450:43:450:53 | exact_tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:450:43:450:53 | exact_tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:450:43:450:53 | exact_tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:452:9:452:17 | TuplePat | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:452:9:452:17 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:452:9:452:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:452:9:452:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:452:9:452:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:452:9:452:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:452:9:452:17 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:452:10:452:10 | a | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:452:13:452:13 | b | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:452:13:452:13 | b | | {EXTERNAL LOCATION} | i64 | @@ -5119,27 +5119,21 @@ inferType | pattern_matching.rs:456:70:456:79 | third_elem | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:456:70:456:79 | third_elem | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:461:11:461:15 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:461:11:461:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:461:11:461:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:461:11:461:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:461:11:461:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:461:11:461:15 | tuple | 2 | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:461:11:461:15 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:461:11:461:15 | tuple | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:461:11:461:15 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:461:11:461:15 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:461:11:461:15 | tuple | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:462:9:462:19 | TuplePat | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:462:9:462:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:462:9:462:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:462:9:462:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:462:9:462:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:462:9:462:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f64 | -| pattern_matching.rs:462:10:462:14 | first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:462:17:462:18 | .. | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:462:17:462:18 | .. | | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:463:17:463:27 | tuple_first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:463:31:463:35 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:462:9:462:19 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:464:22:464:40 | "First element: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:464:22:464:40 | "First element: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:464:22:464:53 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:464:22:464:53 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| pattern_matching.rs:464:43:464:53 | tuple_first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:469:9:469:12 | unit | | file://:0:0:0:0 | () | | pattern_matching.rs:469:16:469:17 | TupleExpr | | file://:0:0:0:0 | () | | pattern_matching.rs:470:11:470:14 | unit | | file://:0:0:0:0 | () | @@ -5152,14 +5146,14 @@ inferType | pattern_matching.rs:473:22:473:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:473:42:473:51 | unit_value | | file://:0:0:0:0 | () | | pattern_matching.rs:478:9:478:14 | single | | file://:0:0:0:0 | (T_1) | -| pattern_matching.rs:478:9:478:14 | single | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:478:9:478:14 | single | 0(1) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:478:18:478:25 | TupleExpr | | file://:0:0:0:0 | (T_1) | -| pattern_matching.rs:478:18:478:25 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:478:18:478:25 | TupleExpr | 0(1) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:478:19:478:23 | 42i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:479:11:479:16 | single | | file://:0:0:0:0 | (T_1) | -| pattern_matching.rs:479:11:479:16 | single | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:479:11:479:16 | single | 0(1) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:480:9:480:12 | TuplePat | | file://:0:0:0:0 | (T_1) | -| pattern_matching.rs:480:9:480:12 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:480:9:480:12 | TuplePat | 0(1) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:480:10:480:10 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:481:17:481:27 | single_elem | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:481:31:481:31 | x | | {EXTERNAL LOCATION} | i32 | @@ -5181,19 +5175,19 @@ inferType | pattern_matching.rs:494:22:494:61 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:494:51:494:61 | paren_bound | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:9:499:13 | tuple | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:499:9:499:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:499:9:499:13 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:9:499:13 | tuple | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:9:499:13 | tuple | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:17:499:28 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:499:17:499:28 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:499:17:499:28 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:17:499:28 | TupleExpr | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:499:17:499:28 | TupleExpr | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:18:499:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:499:24:499:27 | 2i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:500:11:500:15 | tuple | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:500:11:500:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:500:11:500:15 | tuple | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:500:11:500:15 | tuple | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:500:11:500:15 | tuple | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:501:9:501:16 | TuplePat | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:501:9:501:16 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:501:9:501:16 | TuplePat | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:9:501:16 | TuplePat | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:501:9:501:16 | TuplePat | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:501:10:501:10 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:501:13:501:15 | (...) | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:501:14:501:14 | y | | {EXTERNAL LOCATION} | i32 | @@ -5426,80 +5420,61 @@ inferType | pattern_matching.rs:621:38:621:51 | range_or_value | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:623:9:623:9 | _ | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:628:9:628:13 | tuple | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:628:9:628:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:628:9:628:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:628:9:628:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:628:9:628:13 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:628:9:628:13 | tuple | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:628:9:628:13 | tuple | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:628:9:628:13 | tuple | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:628:9:628:13 | tuple | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:628:17:628:41 | TupleExpr | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:628:17:628:41 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:628:17:628:41 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:628:17:628:41 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:628:17:628:41 | TupleExpr | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:628:17:628:41 | TupleExpr | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:628:18:628:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:628:24:628:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:628:30:628:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:628:38:628:40 | 4u8 | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:631:11:631:15 | tuple | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:631:11:631:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:631:11:631:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:631:11:631:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:631:11:631:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:631:11:631:15 | tuple | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:631:11:631:15 | tuple | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:631:11:631:15 | tuple | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:631:11:631:15 | tuple | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:632:9:632:19 | TuplePat | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:632:9:632:19 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:632:9:632:19 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:632:9:632:19 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:632:9:632:19 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | -| pattern_matching.rs:632:10:632:14 | first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:632:17:632:18 | .. | | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:633:17:633:26 | rest_first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:633:30:633:34 | first | | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:632:9:632:19 | TuplePat | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:634:22:634:42 | "First with rest: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:634:22:634:42 | "First with rest: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:634:22:634:54 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:634:22:634:54 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| pattern_matching.rs:634:45:634:54 | rest_first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:638:11:638:15 | tuple | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:638:11:638:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:638:11:638:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:638:11:638:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:638:11:638:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:638:11:638:15 | tuple | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:638:11:638:15 | tuple | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:638:11:638:15 | tuple | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:638:11:638:15 | tuple | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:639:9:639:18 | TuplePat | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:639:9:639:18 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:639:9:639:18 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:639:9:639:18 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:639:9:639:18 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | -| pattern_matching.rs:639:10:639:11 | .. | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:639:14:639:17 | last | | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:640:17:640:25 | rest_last | | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:640:29:640:32 | last | | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:639:9:639:18 | TuplePat | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:641:22:641:41 | "Last with rest: {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:641:22:641:41 | "Last with rest: {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:641:22:641:52 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:641:22:641:52 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| pattern_matching.rs:641:44:641:52 | rest_last | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:645:11:645:15 | tuple | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:645:11:645:15 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:645:11:645:15 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:645:11:645:15 | tuple | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:645:11:645:15 | tuple | 3 | {EXTERNAL LOCATION} | u8 | +| pattern_matching.rs:645:11:645:15 | tuple | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:645:11:645:15 | tuple | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:645:11:645:15 | tuple | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:645:11:645:15 | tuple | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:646:9:646:25 | TuplePat | | file://:0:0:0:0 | (T_4) | -| pattern_matching.rs:646:9:646:25 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:646:9:646:25 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:646:9:646:25 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:646:9:646:25 | TuplePat | 3 | {EXTERNAL LOCATION} | u8 | -| pattern_matching.rs:646:10:646:14 | first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:646:17:646:18 | .. | | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:646:21:646:24 | last | | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:647:17:647:26 | rest_start | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:647:30:647:34 | first | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:648:17:648:24 | rest_end | | {EXTERNAL LOCATION} | f32 | -| pattern_matching.rs:648:28:648:31 | last | | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 0(4) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 1(4) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 2(4) | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:646:9:646:25 | TuplePat | 3(4) | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:649:22:649:45 | "First and last: {}, {}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:649:22:649:45 | "First and last: {}, {}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:649:22:649:67 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:649:22:649:67 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| pattern_matching.rs:649:48:649:57 | rest_start | | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:649:60:649:67 | rest_end | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:654:9:654:13 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:654:17:654:38 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:654:28:654:29 | 10 | | {EXTERNAL LOCATION} | i32 | @@ -5523,13 +5498,13 @@ inferType | pattern_matching.rs:682:21:682:25 | 10i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:682:28:682:28 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:687:9:687:20 | complex_data | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:687:9:687:20 | complex_data | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:687:9:687:20 | complex_data | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:687:9:687:20 | complex_data | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:687:9:687:20 | complex_data | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:687:9:687:20 | complex_data | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:687:9:687:20 | complex_data | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:687:24:687:79 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:687:24:687:79 | TupleExpr | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:687:24:687:79 | TupleExpr | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:687:24:687:79 | TupleExpr | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:687:24:687:79 | TupleExpr | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:687:25:687:44 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:687:36:687:36 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:687:42:687:42 | 2 | | {EXTERNAL LOCATION} | i32 | @@ -5543,13 +5518,13 @@ inferType | pattern_matching.rs:687:76:687:76 | 0 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:687:76:687:76 | 0 | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:689:11:689:22 | complex_data | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:689:11:689:22 | complex_data | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:689:11:689:22 | complex_data | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:689:11:689:22 | complex_data | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:689:11:689:22 | complex_data | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:689:11:689:22 | complex_data | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:689:11:689:22 | complex_data | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:691:9:691:61 | TuplePat | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:691:9:691:61 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:691:9:691:61 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:691:9:691:61 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:691:9:691:61 | TuplePat | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:691:9:691:61 | TuplePat | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:691:9:691:61 | TuplePat | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:691:10:691:26 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:691:21:691:21 | 1 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:691:24:691:24 | y | | {EXTERNAL LOCATION} | i32 | @@ -5574,21 +5549,21 @@ inferType | pattern_matching.rs:697:27:697:34 | nested_g | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:697:37:697:44 | nested_b | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:701:9:701:41 | TuplePat | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:701:9:701:41 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:701:9:701:41 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:701:9:701:41 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:701:9:701:41 | TuplePat | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:9:701:41 | TuplePat | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:9:701:41 | TuplePat | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:9:701:71 | ... \| ... | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:701:9:701:71 | ... \| ... | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:701:9:701:71 | ... \| ... | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:701:9:701:71 | ... \| ... | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:9:701:71 | ... \| ... | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:10:701:24 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:701:18:701:18 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:701:27:701:40 | ...::None | | pattern_matching.rs:152:1:156:1 | MyOption | | pattern_matching.rs:701:27:701:40 | ...::None | T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:45:701:71 | TuplePat | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:701:45:701:71 | TuplePat | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:701:45:701:71 | TuplePat | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:701:45:701:71 | TuplePat | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:701:45:701:71 | TuplePat | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:701:45:701:71 | TuplePat | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:701:45:701:71 | TuplePat | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:701:46:701:67 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:701:57:701:57 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:701:61:701:61 | 0 | | {EXTERNAL LOCATION} | i32 | @@ -5602,25 +5577,25 @@ inferType | pattern_matching.rs:703:22:703:65 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:703:53:703:65 | alt_complex_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:706:9:706:13 | other | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:706:9:706:13 | other | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:706:9:706:13 | other | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:706:9:706:13 | other | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:706:9:706:13 | other | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:706:9:706:13 | other | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:706:9:706:13 | other | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:707:17:707:29 | other_complex | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:707:17:707:29 | other_complex | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:707:17:707:29 | other_complex | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:707:17:707:29 | other_complex | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:707:17:707:29 | other_complex | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:707:17:707:29 | other_complex | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:707:17:707:29 | other_complex | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:707:33:707:37 | other | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:707:33:707:37 | other | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:707:33:707:37 | other | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:707:33:707:37 | other | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:707:33:707:37 | other | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:707:33:707:37 | other | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:707:33:707:37 | other | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:708:22:708:47 | "Other complex data: {:?}\\n" | | file://:0:0:0:0 | & | | pattern_matching.rs:708:22:708:47 | "Other complex data: {:?}\\n" | &T | {EXTERNAL LOCATION} | str | | pattern_matching.rs:708:22:708:62 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:708:22:708:62 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | pattern_matching.rs:708:50:708:62 | other_complex | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:708:50:708:62 | other_complex | 0 | pattern_matching.rs:135:1:140:1 | Point | -| pattern_matching.rs:708:50:708:62 | other_complex | 1 | pattern_matching.rs:152:1:156:1 | MyOption | -| pattern_matching.rs:708:50:708:62 | other_complex | 1.T | pattern_matching.rs:142:1:143:25 | Color | +| pattern_matching.rs:708:50:708:62 | other_complex | 0(2) | pattern_matching.rs:135:1:140:1 | Point | +| pattern_matching.rs:708:50:708:62 | other_complex | 1(2) | pattern_matching.rs:152:1:156:1 | MyOption | +| pattern_matching.rs:708:50:708:62 | other_complex | 1(2).T | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:715:9:715:13 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:715:17:715:38 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:715:28:715:29 | 10 | | {EXTERNAL LOCATION} | i32 | @@ -5634,27 +5609,27 @@ inferType | pattern_matching.rs:718:9:718:13 | let_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:718:17:718:17 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:720:9:720:13 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:720:9:720:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:720:9:720:13 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:720:9:720:13 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:720:9:720:13 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:720:9:720:13 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:720:9:720:13 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:720:17:720:36 | TupleExpr | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:720:17:720:36 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:720:17:720:36 | TupleExpr | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:720:17:720:36 | TupleExpr | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:720:17:720:36 | TupleExpr | 2(3) | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:720:18:720:21 | 1i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:720:24:720:27 | 2i64 | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:720:30:720:35 | 3.0f32 | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:721:9:721:17 | TuplePat | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:721:9:721:17 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:721:9:721:17 | TuplePat | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:721:9:721:17 | TuplePat | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:721:9:721:17 | TuplePat | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:721:9:721:17 | TuplePat | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:721:9:721:17 | TuplePat | 2(3) | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:721:10:721:10 | a | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:721:13:721:13 | b | | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:721:16:721:16 | c | | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:721:21:721:25 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:721:21:721:25 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:721:21:721:25 | tuple | 1 | {EXTERNAL LOCATION} | i64 | -| pattern_matching.rs:721:21:721:25 | tuple | 2 | {EXTERNAL LOCATION} | f32 | +| pattern_matching.rs:721:21:721:25 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:721:21:721:25 | tuple | 1(3) | {EXTERNAL LOCATION} | i64 | +| pattern_matching.rs:721:21:721:25 | tuple | 2(3) | {EXTERNAL LOCATION} | f32 | | pattern_matching.rs:722:9:722:13 | let_a | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:722:17:722:17 | a | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:723:9:723:13 | let_b | | {EXTERNAL LOCATION} | i64 | @@ -5710,15 +5685,15 @@ inferType | pattern_matching.rs:750:30:750:30 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:750:33:750:33 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:750:59:754:5 | { ... } | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:750:59:754:5 | { ... } | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:750:59:754:5 | { ... } | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:750:59:754:5 | { ... } | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:750:59:754:5 | { ... } | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:751:13:751:19 | param_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:751:23:751:23 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:752:13:752:19 | param_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:752:23:752:23 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:753:9:753:26 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:753:9:753:26 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:753:9:753:26 | TupleExpr | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:753:9:753:26 | TupleExpr | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:753:9:753:26 | TupleExpr | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:753:10:753:16 | param_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:753:19:753:25 | param_y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:756:22:756:35 | Color(...) | | pattern_matching.rs:142:1:143:25 | Color | @@ -5730,22 +5705,22 @@ inferType | pattern_matching.rs:757:23:757:23 | r | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:758:9:758:15 | param_r | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:761:22:761:38 | TuplePat | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:761:22:761:38 | TuplePat | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:761:22:761:38 | TuplePat | 1 | {EXTERNAL LOCATION} | f64 | -| pattern_matching.rs:761:22:761:38 | TuplePat | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:761:22:761:38 | TuplePat | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:761:22:761:38 | TuplePat | 1(3) | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:761:22:761:38 | TuplePat | 2(3) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:761:23:761:27 | first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:761:30:761:30 | _ | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:761:33:761:37 | third | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:761:74:765:5 | { ... } | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:761:74:765:5 | { ... } | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:761:74:765:5 | { ... } | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:761:74:765:5 | { ... } | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:761:74:765:5 | { ... } | 1(2) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:762:13:762:23 | param_first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:762:27:762:31 | first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:763:13:763:23 | param_third | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:763:27:763:31 | third | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:764:9:764:34 | TupleExpr | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:764:9:764:34 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:764:9:764:34 | TupleExpr | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:764:9:764:34 | TupleExpr | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:764:9:764:34 | TupleExpr | 1(2) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:764:10:764:20 | param_first | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:764:23:764:33 | param_third | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:768:9:768:13 | point | | pattern_matching.rs:135:1:140:1 | Point | @@ -5753,11 +5728,11 @@ inferType | pattern_matching.rs:768:28:768:28 | 5 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:768:34:768:35 | 10 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:769:9:769:17 | extracted | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:769:9:769:17 | extracted | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:769:9:769:17 | extracted | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:9:769:17 | extracted | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:9:769:17 | extracted | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:769:21:769:40 | extract_point(...) | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:769:21:769:40 | extract_point(...) | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:769:21:769:40 | extract_point(...) | 1 | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:21:769:40 | extract_point(...) | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:769:21:769:40 | extract_point(...) | 1(2) | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:769:35:769:39 | point | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:771:9:771:13 | color | | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:771:17:771:35 | Color(...) | | pattern_matching.rs:142:1:143:25 | Color | @@ -5771,26 +5746,26 @@ inferType | pattern_matching.rs:772:15:772:34 | extract_color(...) | | {EXTERNAL LOCATION} | u8 | | pattern_matching.rs:772:29:772:33 | color | | pattern_matching.rs:142:1:143:25 | Color | | pattern_matching.rs:774:9:774:13 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:774:9:774:13 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:774:9:774:13 | tuple | 1 | {EXTERNAL LOCATION} | f64 | -| pattern_matching.rs:774:9:774:13 | tuple | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:774:9:774:13 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:774:9:774:13 | tuple | 1(3) | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:774:9:774:13 | tuple | 2(3) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:774:17:774:38 | TupleExpr | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:774:17:774:38 | TupleExpr | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:774:17:774:38 | TupleExpr | 1 | {EXTERNAL LOCATION} | f64 | -| pattern_matching.rs:774:17:774:38 | TupleExpr | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 1(3) | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:774:17:774:38 | TupleExpr | 2(3) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:774:18:774:22 | 42i32 | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:774:25:774:31 | 3.14f64 | | {EXTERNAL LOCATION} | f64 | | pattern_matching.rs:774:34:774:37 | true | | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:775:9:775:23 | tuple_extracted | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:775:9:775:23 | tuple_extracted | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:775:9:775:23 | tuple_extracted | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:9:775:23 | tuple_extracted | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:9:775:23 | tuple_extracted | 1(2) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:775:27:775:46 | extract_tuple(...) | | file://:0:0:0:0 | (T_2) | -| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 1 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 0(2) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:27:775:46 | extract_tuple(...) | 1(2) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:775:41:775:45 | tuple | | file://:0:0:0:0 | (T_3) | -| pattern_matching.rs:775:41:775:45 | tuple | 0 | {EXTERNAL LOCATION} | i32 | -| pattern_matching.rs:775:41:775:45 | tuple | 1 | {EXTERNAL LOCATION} | f64 | -| pattern_matching.rs:775:41:775:45 | tuple | 2 | {EXTERNAL LOCATION} | bool | +| pattern_matching.rs:775:41:775:45 | tuple | 0(3) | {EXTERNAL LOCATION} | i32 | +| pattern_matching.rs:775:41:775:45 | tuple | 1(3) | {EXTERNAL LOCATION} | f64 | +| pattern_matching.rs:775:41:775:45 | tuple | 2(3) | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:781:23:781:42 | (...) | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:781:23:781:42 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:781:34:781:34 | 1 | | {EXTERNAL LOCATION} | i32 | From 97e77944eb19336e5af3e842f2b9925ed7d5b296 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 15 Jul 2025 10:21:53 +0200 Subject: [PATCH 066/311] Rust: Accept test changes --- .../local/CONSISTENCY/PathResolutionConsistency.expected | 2 ++ rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 rust/ql/test/library-tests/dataflow/local/CONSISTENCY/PathResolutionConsistency.expected diff --git a/rust/ql/test/library-tests/dataflow/local/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/dataflow/local/CONSISTENCY/PathResolutionConsistency.expected new file mode 100644 index 000000000000..75c14035c455 --- /dev/null +++ b/rust/ql/test/library-tests/dataflow/local/CONSISTENCY/PathResolutionConsistency.expected @@ -0,0 +1,2 @@ +multipleCallTargets +| main.rs:445:18:445:24 | n.len() | diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index a51811179f00..b6bb529b23ee 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -979,6 +979,7 @@ readStep | main.rs:442:25:442:29 | names | file://:0:0:0:0 | element | main.rs:442:9:442:20 | TuplePat | | main.rs:444:41:444:67 | [post] \|...\| ... | main.rs:441:9:441:20 | captured default_name | main.rs:444:41:444:67 | [post] default_name | | main.rs:444:44:444:55 | this | main.rs:441:9:441:20 | captured default_name | main.rs:444:44:444:55 | default_name | +| main.rs:445:18:445:18 | [post] receiver for n | file://:0:0:0:0 | &ref | main.rs:445:18:445:18 | [post] n | | main.rs:469:13:469:13 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:469:13:469:13 | [post] b | | main.rs:470:18:470:18 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:470:18:470:18 | [post] b | | main.rs:481:10:481:11 | vs | file://:0:0:0:0 | element | main.rs:481:10:481:14 | vs[0] | @@ -1078,6 +1079,7 @@ storeStep | main.rs:429:30:429:30 | 3 | file://:0:0:0:0 | element | main.rs:429:23:429:31 | [...] | | main.rs:432:18:432:27 | source(...) | file://:0:0:0:0 | element | main.rs:432:5:432:11 | [post] mut_arr | | main.rs:444:41:444:67 | default_name | main.rs:441:9:441:20 | captured default_name | main.rs:444:41:444:67 | \|...\| ... | +| main.rs:445:18:445:18 | n | file://:0:0:0:0 | &ref | main.rs:445:18:445:18 | receiver for n | | main.rs:469:13:469:13 | b | file://:0:0:0:0 | &ref | main.rs:469:13:469:13 | receiver for b | | main.rs:470:18:470:18 | b | file://:0:0:0:0 | &ref | main.rs:470:18:470:18 | receiver for b | | main.rs:479:15:479:24 | source(...) | file://:0:0:0:0 | element | main.rs:479:14:479:34 | [...] | From 8858f213ff35e60c838c906e6f4186e3cd941843 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 15 Jul 2025 10:23:30 +0200 Subject: [PATCH 067/311] Rust: Add a change note --- rust/ql/src/change-notes/2025-07-15-type-inference-tuples.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 rust/ql/src/change-notes/2025-07-15-type-inference-tuples.md diff --git a/rust/ql/src/change-notes/2025-07-15-type-inference-tuples.md b/rust/ql/src/change-notes/2025-07-15-type-inference-tuples.md new file mode 100644 index 000000000000..bb44c45053bc --- /dev/null +++ b/rust/ql/src/change-notes/2025-07-15-type-inference-tuples.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Type inference now supports tuple types. \ No newline at end of file From df5f76872f415028951cd6d920058f54ede4931b Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 15 Jul 2025 10:18:29 +0100 Subject: [PATCH 068/311] Update docs for duplicate-key-in-dict-literal to relate. to python 3 --- .../src/Expressions/DuplicateKeyInDictionaryLiteral.py | 4 ++-- .../Expressions/DuplicateKeyInDictionaryLiteral.qhelp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py index 14804d313005..b74e3fd02362 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py @@ -1,2 +1,2 @@ -dictionary = {1:"a", 2:"b", 2:"c"} -print dictionary[2] \ No newline at end of file +dictionary = {1:"a", 2:"b", 2:"c"} # BAD: `2` key is duplicated. +print(dictionary[2]) \ No newline at end of file diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.qhelp b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.qhelp index 19c4df9a5581..3aeea4b954c3 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.qhelp +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.qhelp @@ -4,8 +4,8 @@

    Dictionary literals are constructed in the order given in the source. -This means that if a key is duplicated the second key-value pair will overwrite -the first as a dictionary can only have one value per key. +This means that if a key is duplicated, the second key-value pair will overwrite +the first; as a dictionary can only have one value per key.

    @@ -15,14 +15,14 @@ If they are then decide which value is wanted and delete the other one.

    -

    This example will output "c" because the mapping between 2 and "b" is overwritten by the -mapping from 2 to "c". The programmer may have meant to map 3 to "c" instead.

    +

    The following example will output "c", because the mapping between 2 and "b" is overwritten by the +mapping from 2 to "c". The programmer may have meant to map 3 to "c" instead.

    -
  • Python: Dictionary literals.
  • +
  • Python: Dictionary literals.
  • From 7a7db0efe8854151349e7df58d2a5d0d946d6078 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 15 Jul 2025 10:42:25 +0100 Subject: [PATCH 069/311] Update unsupported format character documentaion, fix outdated reference link --- .../ql/src/Expressions/UnsupportedFormatCharacter.qhelp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Expressions/UnsupportedFormatCharacter.qhelp b/python/ql/src/Expressions/UnsupportedFormatCharacter.qhelp index b22d59a209c5..ae2f30afcb38 100644 --- a/python/ql/src/Expressions/UnsupportedFormatCharacter.qhelp +++ b/python/ql/src/Expressions/UnsupportedFormatCharacter.qhelp @@ -3,18 +3,19 @@ "qhelp.dtd"> -

    A format string, that is the string on the left hand side of an expression like fmt % arguments, must consist of legal conversion specifiers. +

    A printf-style format string (i.e. a string that is used as the left hand side of the % operator, such as fmt % arguments) +must consist of valid conversion specifiers, such as %s, %d, etc. Otherwise, a ValueError will be raised.

    -

    Choose a legal conversion specifier.

    +

    Ensure a valid conversion specifier is used.

    -

    In format_as_tuple_incorrect, "t" is not a legal conversion specifier. +

    In the following example, format_as_tuple_incorrect, %t is not a valid conversion specifier.

    @@ -22,7 +23,7 @@ Otherwise, a ValueError will be raised.
    -
  • Python Library Reference: String Formatting.
  • +
  • Python Library Reference: printf-style String Formatting.
  • From 909f57261c59cf64def58e5e9bc4dfd26b578352 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 15 Jul 2025 13:26:46 +0100 Subject: [PATCH 070/311] Minor doc updates; updating python 2 references to python 3 and updating grammar --- python/ql/src/Exceptions/CatchingBaseException.qhelp | 6 +++--- python/ql/src/Exceptions/EmptyExcept.qhelp | 4 ++-- python/ql/src/Expressions/CallToSuperWrongClass.qhelp | 4 ++-- python/ql/src/Expressions/ExplicitCallToDel.qhelp | 2 +- .../ql/src/Expressions/IncorrectComparisonUsingIs.qhelp | 2 +- python/ql/src/Expressions/IncorrectComparisonUsingIs.ql | 2 +- python/ql/src/Functions/ConsistentReturns.qhelp | 4 ++-- python/ql/src/Functions/ConsistentReturns.ql | 4 ++-- python/ql/src/Functions/InitIsGenerator.qhelp | 2 +- .../Functions/ModificationOfParameterWithDefault.qhelp | 2 +- .../Functions/return_values/ConsistentReturns.expected | 8 ++++---- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/python/ql/src/Exceptions/CatchingBaseException.qhelp b/python/ql/src/Exceptions/CatchingBaseException.qhelp index 725f9ce465ba..bde17418aa76 100644 --- a/python/ql/src/Exceptions/CatchingBaseException.qhelp +++ b/python/ql/src/Exceptions/CatchingBaseException.qhelp @@ -45,10 +45,10 @@ leaving KeyboardInterrupt to propagate. -
  • Python Language Reference: The try statement, -Exceptions.
  • +
  • Python Language Reference: The try statement, +Exceptions.
  • M. Lutz, Learning Python, Section 35.3: Exception Design Tips and Gotchas, O'Reilly Media, 2013.
  • -
  • Python Tutorial: Errors and Exceptions.
  • +
  • Python Tutorial: Errors and Exceptions.
  • diff --git a/python/ql/src/Exceptions/EmptyExcept.qhelp b/python/ql/src/Exceptions/EmptyExcept.qhelp index 9b7ef09643fb..f968c65af196 100644 --- a/python/ql/src/Exceptions/EmptyExcept.qhelp +++ b/python/ql/src/Exceptions/EmptyExcept.qhelp @@ -7,7 +7,7 @@ The loss of information can lead to hard to debug errors and incomplete log files. It is even possible that ignoring an exception can cause a security vulnerability. An empty except block may be an indication that the programmer intended to -handle the exception but never wrote the code to do so.

    +handle the exception, but never wrote the code to do so.

    @@ -15,7 +15,7 @@ handle the exception but never wrote the code to do so.

    -

    In this example the program keeps running with the same privileges if it fails to drop to lower +

    In this example, the program keeps running with the same privileges if it fails to drop to lower privileges.

    diff --git a/python/ql/src/Expressions/CallToSuperWrongClass.qhelp b/python/ql/src/Expressions/CallToSuperWrongClass.qhelp index dc88b1bea88c..7a2516329f4a 100644 --- a/python/ql/src/Expressions/CallToSuperWrongClass.qhelp +++ b/python/ql/src/Expressions/CallToSuperWrongClass.qhelp @@ -24,7 +24,7 @@ However, this may result in incorrect object initialization if the enclosing cla

    -In this example the call to super(Vehicle, self) in Car.__init__ is incorrect as it +In this example, the call to super(Vehicle, self) in Car.__init__ is incorrect, as it passes Vehicle rather than Car as the first argument to super. As a result, super(SportsCar, self).__init__() in the SportsCar.__init__ method will not call all __init__() methods because the call to super(Vehicle, self).__init__() @@ -37,7 +37,7 @@ skips StatusSymbol.__init__(). -

  • Python Standard Library: super.
  • +
  • Python Standard Library: super.
  • Artima Developer: Things to Know About Python Super.
  • diff --git a/python/ql/src/Expressions/ExplicitCallToDel.qhelp b/python/ql/src/Expressions/ExplicitCallToDel.qhelp index 9ec18b46918e..3e6b79c929f8 100644 --- a/python/ql/src/Expressions/ExplicitCallToDel.qhelp +++ b/python/ql/src/Expressions/ExplicitCallToDel.qhelp @@ -17,7 +17,7 @@ wrap the use of the object in a with statement. -

    In the first example, rather than close the zip file in a conventional manner the programmer has called __del__. +

    In the first example, rather than close the zip file in a conventional manner, the programmer has called __del__. A safer alternative is shown in the second example.

    diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.qhelp b/python/ql/src/Expressions/IncorrectComparisonUsingIs.qhelp index b8c25fa04a24..b1df1e8b8b7c 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.qhelp +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.qhelp @@ -37,7 +37,7 @@ either of the alternatives below.
    -
  • Python Standard Library: Comparisons.
  • +
  • Python Standard Library: Comparisons.
  • diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql index 6eda4abbde21..fa0ca14669f6 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql @@ -1,6 +1,6 @@ /** * @name Comparison using is when operands support `__eq__` - * @description Comparison using 'is' when equivalence is not the same as identity + * @description Comparison using `is` when equivalence is not the same as identity * @kind problem * @tags quality * reliability diff --git a/python/ql/src/Functions/ConsistentReturns.qhelp b/python/ql/src/Functions/ConsistentReturns.qhelp index cd29062ada66..62162a2c1c48 100644 --- a/python/ql/src/Functions/ConsistentReturns.qhelp +++ b/python/ql/src/Functions/ConsistentReturns.qhelp @@ -6,7 +6,7 @@

    When a function contains both explicit returns (return value) and implicit returns -(where code falls off the end of a function) this often indicates that a return +(where code falls off the end of a function), this often indicates that a return statement has been forgotten. It is best to return an explicit return value even when returning None because this makes it easier for other developers to read your code.

    @@ -29,7 +29,7 @@ return value of None as this equates to False. However
    -
  • Python Language Reference: Function definitions. +
  • Python Language Reference: Function definitions.
  • diff --git a/python/ql/src/Functions/ConsistentReturns.ql b/python/ql/src/Functions/ConsistentReturns.ql index a1b308514562..1bc7b5724b36 100644 --- a/python/ql/src/Functions/ConsistentReturns.ql +++ b/python/ql/src/Functions/ConsistentReturns.ql @@ -1,6 +1,6 @@ /** * @name Explicit returns mixed with implicit (fall through) returns - * @description Mixing implicit and explicit returns indicates a likely error as implicit returns always return 'None'. + * @description Mixing implicit and explicit returns indicates a likely error as implicit returns always return `None`. * @kind problem * @tags quality * reliability @@ -31,4 +31,4 @@ predicate has_implicit_return(Function func) { from Function func where explicitly_returns_non_none(func) and has_implicit_return(func) select func, - "Mixing implicit and explicit returns may indicate an error as implicit returns always return None." + "Mixing implicit and explicit returns may indicate an error, as implicit returns always return None." diff --git a/python/ql/src/Functions/InitIsGenerator.qhelp b/python/ql/src/Functions/InitIsGenerator.qhelp index 113e444d1f39..d1144815c7fc 100644 --- a/python/ql/src/Functions/InitIsGenerator.qhelp +++ b/python/ql/src/Functions/InitIsGenerator.qhelp @@ -22,7 +22,7 @@ not logical in the context of an initializer.

    -
  • Python: The __init__ method.
  • +
  • Python: The __init__ method.
  • diff --git a/python/ql/src/Functions/ModificationOfParameterWithDefault.qhelp b/python/ql/src/Functions/ModificationOfParameterWithDefault.qhelp index 39bb484f8917..12714a68364d 100644 --- a/python/ql/src/Functions/ModificationOfParameterWithDefault.qhelp +++ b/python/ql/src/Functions/ModificationOfParameterWithDefault.qhelp @@ -37,7 +37,7 @@ function with a default of default=None, check if the parameter is
  • Effbot: Default Parameter Values in Python.
  • -
  • Python Language Reference: Function definitions.
  • +
  • Python Language Reference: Function definitions.
  • diff --git a/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected index 1bb6a25860be..302a327a1444 100644 --- a/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected +++ b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected @@ -1,4 +1,4 @@ -| functions_test.py:18:1:18:11 | Function cr1 | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | -| functions_test.py:22:1:22:11 | Function cr2 | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | -| functions_test.py:336:1:336:16 | Function ok_match | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | -| functions_test.py:344:1:344:17 | Function ok_match2 | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | +| functions_test.py:18:1:18:11 | Function cr1 | Mixing implicit and explicit returns may indicate an error, as implicit returns always return None. | +| functions_test.py:22:1:22:11 | Function cr2 | Mixing implicit and explicit returns may indicate an error, as implicit returns always return None. | +| functions_test.py:336:1:336:16 | Function ok_match | Mixing implicit and explicit returns may indicate an error, as implicit returns always return None. | +| functions_test.py:344:1:344:17 | Function ok_match2 | Mixing implicit and explicit returns may indicate an error, as implicit returns always return None. | From 0f5be2d0961decfcfc6a96f3b2b79cbe2805acdd Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 15 Jul 2025 13:33:57 +0100 Subject: [PATCH 071/311] Update python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py index b74e3fd02362..ea051fcd1530 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.py @@ -1,2 +1,2 @@ -dictionary = {1:"a", 2:"b", 2:"c"} # BAD: `2` key is duplicated. +dictionary = {1:"a", 2:"b", 2:"c"} # BAD: The `2` key is duplicated. print(dictionary[2]) \ No newline at end of file From 9661ee407f0ac98e4a79c6236b4f3373d9f4acfe Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 15 Jul 2025 13:51:45 +0100 Subject: [PATCH 072/311] Fix compilation of DataFlowImplConsistency.qll --- .../semmle/go/dataflow/internal/DataFlowImplConsistency.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll index 58b849858416..aa9c9da1bd13 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll @@ -4,11 +4,11 @@ */ private import go -private import DataFlowImplSpecific +private import DataFlowImplSpecific as Impl private import TaintTrackingImplSpecific private import codeql.dataflow.internal.DataFlowImplConsistency private import semmle.go.dataflow.internal.DataFlowNodes -private module Input implements InputSig { } +private module Input implements InputSig { } -module Consistency = MakeConsistency; +module Consistency = MakeConsistency; From 10a678dcbd1a9ec490e95221fc04968597be5957 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Mon, 23 Jun 2025 09:02:02 +0200 Subject: [PATCH 073/311] Java lib qlpack: Enable overlay compilation --- java/ql/lib/qlpack.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index c7a6a045451e..c27a06994b2f 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -23,3 +23,4 @@ dataExtensions: - ext/generated/*.model.yml - ext/experimental/*.model.yml warnOnImplicitThis: true +compileForOverlayEval: true From 9ef22fff8ead1738b78e820ba7313884dd38e6d0 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 15 Jul 2025 15:27:01 +0100 Subject: [PATCH 074/311] Update SnakeYaml reference to note that it is outdated --- java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp index 8d76255fc733..bf7205d535ff 100644 --- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp +++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp @@ -121,7 +121,7 @@ Alvaro Muñoz & Christian Schneider, RSAConference 2016:
  • SnakeYaml documentation on deserialization: -SnakeYaml deserialization. +SnakeYaml deserialization (not updated for new behaviour in version 2.0).
  • Hessian deserialization and related gadget chains: From 70bff4e726926afbbd587027cfd7d0293f139583 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 15 Jul 2025 20:19:22 +0200 Subject: [PATCH 075/311] C++: Fix typeid IR translation --- .../code/cpp/ir/implementation/Opcode.qll | 22 ++++++++- .../aliased_ssa/Instruction.qll | 16 ++++++ .../cpp/ir/implementation/raw/Instruction.qll | 16 ++++++ .../raw/internal/TranslatedExpr.qll | 49 +++++++++++++++++++ .../unaliased_ssa/Instruction.qll | 16 ++++++ .../library-tests/ir/ir/aliased_ir.expected | 13 +++++ .../ir/ir/aliased_ssa_consistency.expected | 1 - .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ir/raw_consistency.expected | 7 --- .../test/library-tests/ir/ir/raw_ir.expected | 28 +++++------ .../ir/ir/unaliased_ssa_consistency.expected | 1 - ...unaliased_ssa_consistency_unsound.expected | 1 - 12 files changed, 143 insertions(+), 28 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index bd1ffcd5ce15..5012f7787cf5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -92,7 +92,9 @@ private newtype TOpcode = TUninitializedGroup() or TInlineAsm() or TUnreached() or - TNewObj() + TNewObj() or + TTypeidExpr() or + TTypeidType() /** * An opcode that specifies the operation performed by an `Instruction`. @@ -1281,4 +1283,22 @@ module Opcode { class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } + + /** + * The `Opcode` for a `TypeidInstruction`. + * + * See the `TypeidExprInstruction` documentation for more details. + */ + class TypeidExpr extends UnaryOpcode, TTypeidExpr { + final override string toString() { result = "TypeidExpr" } + } + + /** + * The `Opcode` for a `TypeidTypeInstruction`. + * + * See the `TypeidTypeInstruction` documentation for more details. + */ + class TypeidType extends Opcode, TTypeidType { + final override string toString() { result = "TypeidType" } + } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 96c18a04ff7b..8ca2ace4cdca 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -2293,3 +2293,19 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends Instruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 96c18a04ff7b..8ca2ace4cdca 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -2293,3 +2293,19 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends Instruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index dea86499e7ca..2aa5eeebb6b7 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -4185,3 +4185,52 @@ class TranslatedAssumeExpr extends TranslatedSingleInstructionExpr { none() } } + +class TranslatedTypeidExpr extends TranslatedSingleInstructionExpr { + override TypeidOperator expr; + + final override Opcode getOpcode() { + exists(this.getOperand()) and + result instanceof Opcode::TypeidExpr + or + not exists(this.getOperand()) and + result instanceof Opcode::TypeidType + } + + final override Instruction getFirstInstruction(EdgeKind kind) { + result = this.getOperand().getFirstInstruction(kind) + or + not exists(this.getOperand()) and + result = this.getInstruction(OnlyInstructionTag()) and + kind instanceof GotoEdge + } + + override Instruction getALastInstructionInternal() { + result = this.getInstruction(OnlyInstructionTag()) + } + + final override TranslatedElement getChildInternal(int id) { + id = 0 and result = this.getOperand() + } + + final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { + tag = OnlyInstructionTag() and + result = this.getParent().getChildSuccessor(this, kind) + } + + final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { + child = this.getOperand() and + result = this.getInstruction(OnlyInstructionTag()) and + kind instanceof GotoEdge + } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + result = this.getOperand().getResult() and + operandTag instanceof UnaryOperandTag + } + + private TranslatedExpr getOperand() { + result = getTranslatedExpr(expr.getExpr().getFullyConverted()) + } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 96c18a04ff7b..8ca2ace4cdca 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -2293,3 +2293,19 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends Instruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 38f0a0a4f4f7..78f0bbd1e0c8 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -39983,4 +39983,17 @@ type_info_test.cpp: # 3| m3_4(unknown) = Chi : total:m3_2, partial:m3_3 # 3| r3_5(glval) = VariableAddress[x] : # 3| m3_6(int) = InitializeParameter[x] : &:r3_5 +# 3| m3_7(unknown) = Chi : total:m3_4, partial:m3_6 # 4| r4_1(glval) = VariableAddress[t1] : +# 4| r4_2(glval) = VariableAddress[x] : +# 4| r4_3(glval) = TypeidExpr : r4_2 +# 4| r4_4(type_info &) = CopyValue : r4_3 +# 4| m4_5(type_info &) = Store[t1] : &:r4_1, r4_4 +# 5| r5_1(glval) = VariableAddress[t2] : +# 5| r5_2(glval) = TypeidType : +# 5| r5_3(type_info &) = CopyValue : r5_2 +# 5| m5_4(type_info &) = Store[t2] : &:r5_1, r5_3 +# 6| v6_1(void) = NoOp : +# 3| v3_8(void) = ReturnVoid : +# 3| v3_9(void) = AliasedUse : m3_3 +# 3| v3_10(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 9cdfdd2dcd5e..e30106d35204 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,6 +1,4 @@ missingOperand -| type_info_test.cpp:4:30:4:38 | CopyValue: (reference to) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:30:5:40 | CopyValue: (reference to) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | unexpectedOperand duplicateOperand missingPhiOperand @@ -8,9 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:4:37:4:37 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:25:5:26 | VariableAddress: definition of t2 | Instruction 'VariableAddress: definition of t2' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -26,8 +21,6 @@ lostReachability backEdgeCountMismatch useNotDominatedByDefinition | ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | -| type_info_test.cpp:4:25:4:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:25:5:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index c9158233914d..68c2f3602983 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -38112,19 +38112,15 @@ type_info_test.cpp: # 3| r3_4(glval) = VariableAddress[x] : # 3| mu3_5(int) = InitializeParameter[x] : &:r3_4 # 4| r4_1(glval) = VariableAddress[t1] : - -# 4| Block 1 -# 4| r4_2(glval) = VariableAddress[x] : - -# 4| Block 2 -# 4| r4_3(type_info &) = CopyValue : -# 4| mu4_4(type_info &) = Store[t1] : &:r4_1, r4_3 -# 5| r5_1(glval) = VariableAddress[t2] : - -# 5| Block 3 -# 5| r5_2(type_info &) = CopyValue : -# 5| mu5_3(type_info &) = Store[t2] : &:r5_1, r5_2 -# 6| v6_1(void) = NoOp : -# 3| v3_6(void) = ReturnVoid : -# 3| v3_7(void) = AliasedUse : ~m? -# 3| v3_8(void) = ExitFunction : +# 4| r4_2(glval) = VariableAddress[x] : +# 4| r4_3(glval) = TypeidExpr : r4_2 +# 4| r4_4(type_info &) = CopyValue : r4_3 +# 4| mu4_5(type_info &) = Store[t1] : &:r4_1, r4_4 +# 5| r5_1(glval) = VariableAddress[t2] : +# 5| r5_2(glval) = TypeidType : +# 5| r5_3(type_info &) = CopyValue : r5_2 +# 5| mu5_4(type_info &) = Store[t2] : &:r5_1, r5_3 +# 6| v6_1(void) = NoOp : +# 3| v3_6(void) = ReturnVoid : +# 3| v3_7(void) = AliasedUse : ~m? +# 3| v3_8(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 54f11ca6111a062a9ac372dc8b3d552b696908ae Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 15 Jul 2025 20:40:57 +0200 Subject: [PATCH 076/311] C++: Fix typo in comment --- cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index 5012f7787cf5..1555b4efa1dd 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -1285,7 +1285,7 @@ module Opcode { } /** - * The `Opcode` for a `TypeidInstruction`. + * The `Opcode` for a `TypeidExprInstruction`. * * See the `TypeidExprInstruction` documentation for more details. */ From a08d5943715abd4eca69e8c3d583c00f20e05452 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 15 Jul 2025 21:31:24 +0200 Subject: [PATCH 077/311] C++: Introduce `TypeidInstruction` base class --- .../lib/semmle/code/cpp/ir/implementation/Opcode.qll | 10 ++++++++++ .../cpp/ir/implementation/aliased_ssa/Instruction.qll | 11 +++++++++-- .../code/cpp/ir/implementation/raw/Instruction.qll | 11 +++++++++-- .../ir/implementation/unaliased_ssa/Instruction.qll | 11 +++++++++-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index 1555b4efa1dd..1f0de9784708 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -93,6 +93,7 @@ private newtype TOpcode = TInlineAsm() or TUnreached() or TNewObj() or + TTypeid() or TTypeidExpr() or TTypeidType() @@ -1284,6 +1285,15 @@ module Opcode { final override string toString() { result = "NewObj" } } + /** + * The `Opcode` for a `TypeidInstruction`. + * + * See the `TypeidInstruction` documentation for more details. + */ + class Typeid extends Opcode, TTypeid { + final override string toString() { result = "Typeid" } + } + /** * The `Opcode` for a `TypeidExprInstruction`. * diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 8ca2ace4cdca..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -2294,11 +2294,18 @@ class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + /** * An instruction that returns the type info for its operand, where the * operand occurs as an expression in the AST. */ -class TypeidExprInstruction extends UnaryInstruction { +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } } @@ -2306,6 +2313,6 @@ class TypeidExprInstruction extends UnaryInstruction { * An instruction that returns the type info for its operand, where the * operand occurs as a type in the AST. */ -class TypeidTypeInstruction extends Instruction { +class TypeidTypeInstruction extends TypeidInstruction { TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 8ca2ace4cdca..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -2294,11 +2294,18 @@ class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + /** * An instruction that returns the type info for its operand, where the * operand occurs as an expression in the AST. */ -class TypeidExprInstruction extends UnaryInstruction { +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } } @@ -2306,6 +2313,6 @@ class TypeidExprInstruction extends UnaryInstruction { * An instruction that returns the type info for its operand, where the * operand occurs as a type in the AST. */ -class TypeidTypeInstruction extends Instruction { +class TypeidTypeInstruction extends TypeidInstruction { TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 8ca2ace4cdca..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -2294,11 +2294,18 @@ class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + /** * An instruction that returns the type info for its operand, where the * operand occurs as an expression in the AST. */ -class TypeidExprInstruction extends UnaryInstruction { +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } } @@ -2306,6 +2313,6 @@ class TypeidExprInstruction extends UnaryInstruction { * An instruction that returns the type info for its operand, where the * operand occurs as a type in the AST. */ -class TypeidTypeInstruction extends Instruction { +class TypeidTypeInstruction extends TypeidInstruction { TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } } From b9acaa0cbd508d5fe1b2b623cf36a743b3634bf5 Mon Sep 17 00:00:00 2001 From: James Frank Date: Tue, 15 Jul 2025 15:18:15 -0400 Subject: [PATCH 078/311] Make web.config match case insensitive --- csharp/ql/lib/semmle/code/asp/WebConfig.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/asp/WebConfig.qll b/csharp/ql/lib/semmle/code/asp/WebConfig.qll index f9106bcd1afd..384c3a013c3b 100644 --- a/csharp/ql/lib/semmle/code/asp/WebConfig.qll +++ b/csharp/ql/lib/semmle/code/asp/WebConfig.qll @@ -8,14 +8,14 @@ import csharp * A `Web.config` file. */ class WebConfigXml extends XmlFile { - WebConfigXml() { this.getName().matches("%Web.config") } + WebConfigXml() { this.getName().toLowerCase().matches("%web.config") } } /** * A `Web.config` transformation file. */ class WebConfigReleaseTransformXml extends XmlFile { - WebConfigReleaseTransformXml() { this.getName().matches("%Web.Release.config") } + WebConfigReleaseTransformXml() { this.getName().toLowerCase().matches("%web.release.config") } } /** A `` tag in an ASP.NET configuration file. */ From 529712122c00979192ecd1ff65dadc786ea7c0f5 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 15 Jul 2025 22:15:11 +0200 Subject: [PATCH 079/311] C++: Address review comments --- cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index 1f0de9784708..90afabca30de 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -93,7 +93,6 @@ private newtype TOpcode = TInlineAsm() or TUnreached() or TNewObj() or - TTypeid() or TTypeidExpr() or TTypeidType() @@ -1290,16 +1289,14 @@ module Opcode { * * See the `TypeidInstruction` documentation for more details. */ - class Typeid extends Opcode, TTypeid { - final override string toString() { result = "Typeid" } - } + abstract class Typeid extends Opcode { } /** * The `Opcode` for a `TypeidExprInstruction`. * * See the `TypeidExprInstruction` documentation for more details. */ - class TypeidExpr extends UnaryOpcode, TTypeidExpr { + class TypeidExpr extends Typeid, UnaryOpcode, TTypeidExpr { final override string toString() { result = "TypeidExpr" } } @@ -1308,7 +1305,7 @@ module Opcode { * * See the `TypeidTypeInstruction` documentation for more details. */ - class TypeidType extends Opcode, TTypeidType { + class TypeidType extends Typeid, TTypeidType { final override string toString() { result = "TypeidType" } } } From 6384cf2e4f2856d5b0e383d69ebca1cd59d35ecb Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 16 Jul 2025 00:35:14 +0200 Subject: [PATCH 080/311] Update predicate name --- csharp/ql/lib/semmle/code/csharp/Type.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index 3693e8977d89..d11b5618e806 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -139,7 +139,7 @@ class ValueOrRefType extends Type, Attributable, @value_or_ref_type { ValueOrRefType getASubType() { result.getABaseType() = this } /** Gets an immediate supertype of this type, if any. */ - ValueOrRefType getASupertype() { this.getABaseType() = result } + ValueOrRefType getASuperType() { this.getABaseType() = result } /** Gets a member of this type, if any. */ Member getAMember() { result.getDeclaringType() = this } From 8c82405b5b42233ff554442ceddb4106924be567 Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 16 Jul 2025 00:35:30 +0200 Subject: [PATCH 081/311] Update 2025-06-10-getasupertype.md --- csharp/ql/lib/change-notes/2025-06-10-getasupertype.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md b/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md index 8f91b2d3cc5b..14b086a94093 100644 --- a/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md +++ b/csharp/ql/lib/change-notes/2025-06-10-getasupertype.md @@ -1,4 +1,4 @@ --- category: feature --- -* Added a new predicate, `getASupertype()`, to get a direct supertype of this type. +* Added a new predicate, `getASuperType()`, to get a direct supertype of this type. From 4036140f4b1db352f33fa616485360c47b378c9d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 11:01:55 +0200 Subject: [PATCH 082/311] C#: Add Deserialize testcase. --- .../BinaryFormatterUntrustedInputBad.cs | 17 ++++++++++++++--- ...UnsafeDeserializationUntrustedInput.expected | 16 ++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs index 73c6c35413bc..edab176abb4a 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs @@ -1,9 +1,10 @@ -using System.Web.UI.WebControls; -using System.Runtime.Serialization.Formatters.Binary; +using System; using System.IO; +using System.Runtime.Serialization.Formatters.Binary; using System.Text; +using System.Web.UI.WebControls; -class BadBinaryFormatter +class BadBinaryFormatter1 { public static object Deserialize(TextBox textBox) { @@ -12,3 +13,13 @@ public static object Deserialize(TextBox textBox) return ds.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(textBox.Text))); } } + +class BadBinaryFormatter2 +{ + public static object Deserialize(TextBox type, TextBox data) + { + var ds = new BinaryFormatter(); + // BAD - BUT NOT DETECTED + return ds.Deserialize(new MemoryStream(Convert.FromBase64String(data.Text))); + } +} diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected index 37cba1c28bff..659a9f98c066 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected @@ -1,5 +1,5 @@ #select -| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | User-provided data | +| BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | User-provided data | | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data | | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data | | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | User-provided data | @@ -7,9 +7,9 @@ | XmlObjectSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | XmlObjectSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data | | XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream | XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | User-provided data | edges -| BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | provenance | MaD:1 | -| BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String | provenance | MaD:3 | -| BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String | BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | provenance | MaD:2 | +| BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | provenance | MaD:1 | +| BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | provenance | MaD:3 | +| BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | provenance | MaD:2 | | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | provenance | MaD:1 | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | provenance | MaD:3 | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | provenance | MaD:2 | @@ -31,10 +31,10 @@ models | 2 | Summary: System.Text; Encoding; true; GetBytes; (System.String); ; Argument[0]; ReturnValue; taint; manual | | 3 | Summary: System.Web.UI.WebControls; TextBox; false; get_Text; (); ; Argument[this]; ReturnValue; taint; manual | nodes -| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | -| BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] | -| BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | semmle.label | access to parameter textBox : TextBox | -| BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String | semmle.label | access to property Text : String | +| BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | +| BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] | +| BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | semmle.label | access to parameter textBox : TextBox | +| BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | semmle.label | access to property Text : String | | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox | From 13b40bbab49ac6cf2ae24356239704b78c7eea48 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 13:12:26 +0200 Subject: [PATCH 083/311] C#: Fix erroneous model the MemoryStream constructor (and align with the other models). --- csharp/ql/lib/ext/System.IO.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/ext/System.IO.model.yml b/csharp/ql/lib/ext/System.IO.model.yml index dcc9c70551b0..0b8b52d9e8a5 100644 --- a/csharp/ql/lib/ext/System.IO.model.yml +++ b/csharp/ql/lib/ext/System.IO.model.yml @@ -47,7 +47,7 @@ extensions: - ["System.IO", "FileStream", False, "FileStream", "(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.IO", "FileStream", False, "FileStream", "(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.IO", "FileStream", False, "FileStream", "(System.String,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,System.Int32,System.IO.FileOptions)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - - ["System.IO", "MemoryStream", False, "MemoryStream", "(System.Byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["System.IO", "MemoryStream", False, "MemoryStream", "(System.Byte[])", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "MemoryStream", False, "MemoryStream", "(System.Byte[],System.Boolean)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "MemoryStream", False, "MemoryStream", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "MemoryStream", False, "MemoryStream", "(System.Byte[],System.Int32,System.Int32,System.Boolean)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] From 8ee16f68a79c9eaf1c74151fd111c21f87e65e69 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 13:13:59 +0200 Subject: [PATCH 084/311] C#: Update test expected output. --- .../BinaryFormatterUntrustedInputBad.cs | 2 +- .../UnsafeDeserializationUntrustedInput.expected | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs index edab176abb4a..bb6c9b1de08d 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs @@ -19,7 +19,7 @@ class BadBinaryFormatter2 public static object Deserialize(TextBox type, TextBox data) { var ds = new BinaryFormatter(); - // BAD - BUT NOT DETECTED + // BAD return ds.Deserialize(new MemoryStream(Convert.FromBase64String(data.Text))); } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected index 659a9f98c066..c3377fcb04f0 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected @@ -1,5 +1,6 @@ #select | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | User-provided data | +| BinaryFormatterUntrustedInputBad.cs:23:31:23:83 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:23:73:23:76 | access to parameter data : TextBox | BinaryFormatterUntrustedInputBad.cs:23:31:23:83 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:23:73:23:76 | access to parameter data : TextBox | User-provided data | | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data | | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data | | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | User-provided data | @@ -10,6 +11,9 @@ edges | BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | provenance | MaD:1 | | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | provenance | MaD:3 | | BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | provenance | MaD:2 | +| BinaryFormatterUntrustedInputBad.cs:23:48:23:82 | call to method FromBase64String : Byte[] [element] : Object | BinaryFormatterUntrustedInputBad.cs:23:31:23:83 | object creation of type MemoryStream | provenance | MaD:1 | +| BinaryFormatterUntrustedInputBad.cs:23:73:23:76 | access to parameter data : TextBox | BinaryFormatterUntrustedInputBad.cs:23:73:23:81 | access to property Text : String | provenance | MaD:3 | +| BinaryFormatterUntrustedInputBad.cs:23:73:23:81 | access to property Text : String | BinaryFormatterUntrustedInputBad.cs:23:48:23:82 | call to method FromBase64String : Byte[] [element] : Object | provenance | MaD:4 | | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | provenance | MaD:1 | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | provenance | MaD:3 | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | provenance | MaD:2 | @@ -27,14 +31,19 @@ edges | XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | provenance | MaD:3 | | XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] | provenance | MaD:2 | models -| 1 | Summary: System.IO; MemoryStream; false; MemoryStream; (System.Byte[]); ; Argument[0]; Argument[this]; taint; manual | +| 1 | Summary: System.IO; MemoryStream; false; MemoryStream; (System.Byte[]); ; Argument[0].Element; Argument[this]; taint; manual | | 2 | Summary: System.Text; Encoding; true; GetBytes; (System.String); ; Argument[0]; ReturnValue; taint; manual | | 3 | Summary: System.Web.UI.WebControls; TextBox; false; get_Text; (); ; Argument[this]; ReturnValue; taint; manual | +| 4 | Summary: System; Convert; false; FromBase64String; (System.String); ; Argument[0]; ReturnValue.Element; taint; manual | nodes | BinaryFormatterUntrustedInputBad.cs:13:31:13:84 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | | BinaryFormatterUntrustedInputBad.cs:13:48:13:83 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] | | BinaryFormatterUntrustedInputBad.cs:13:71:13:77 | access to parameter textBox : TextBox | semmle.label | access to parameter textBox : TextBox | | BinaryFormatterUntrustedInputBad.cs:13:71:13:82 | access to property Text : String | semmle.label | access to property Text : String | +| BinaryFormatterUntrustedInputBad.cs:23:31:23:83 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | +| BinaryFormatterUntrustedInputBad.cs:23:48:23:82 | call to method FromBase64String : Byte[] [element] : Object | semmle.label | call to method FromBase64String : Byte[] [element] : Object | +| BinaryFormatterUntrustedInputBad.cs:23:73:23:76 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox | +| BinaryFormatterUntrustedInputBad.cs:23:73:23:81 | access to property Text : String | semmle.label | access to property Text : String | | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream | | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] | | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox | From 3ae69d5f3da2dbbc79a4711841ae6fb594ca8a3c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 13:47:03 +0200 Subject: [PATCH 085/311] C#: Promote the generated System.Xml.XmlDictionaryReader.CreateBinaryReader models to manual models. --- csharp/ql/lib/ext/System.Xml.model.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/csharp/ql/lib/ext/System.Xml.model.yml b/csharp/ql/lib/ext/System.Xml.model.yml index 55825304a145..235392a2ba24 100644 --- a/csharp/ql/lib/ext/System.Xml.model.yml +++ b/csharp/ql/lib/ext/System.Xml.model.yml @@ -4,6 +4,19 @@ extensions: extensible: summaryModel data: - ["System.Xml", "XmlAttributeCollection", False, "CopyTo", "(System.Xml.XmlAttribute[],System.Int32)", "", "Argument[this].Element", "Argument[0].Element", "value", "manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[3]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[3]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[5]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[1]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[1]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[3]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDocument", False, "Load", "(System.IO.Stream)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.Xml", "XmlDocument", False, "Load", "(System.IO.TextReader)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.Xml", "XmlDocument", False, "Load", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] From 064c4fca12b85eec8ab0d7e137acf7bdb7654a39 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 13:51:49 +0200 Subject: [PATCH 086/311] C#: Add models for the remaining overloads of System.Xml.XmlDictionaryReader.CreateBinaryReader. --- csharp/ql/lib/ext/System.Xml.model.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/csharp/ql/lib/ext/System.Xml.model.yml b/csharp/ql/lib/ext/System.Xml.model.yml index 235392a2ba24..efea34b40dbe 100644 --- a/csharp/ql/lib/ext/System.Xml.model.yml +++ b/csharp/ql/lib/ext/System.Xml.model.yml @@ -9,6 +9,9 @@ extensions: - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[3]", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[5]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[3]", "ReturnValue", "taint", "manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[5]", "ReturnValue", "taint", "manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.Byte[],System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0].Element", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] @@ -16,6 +19,9 @@ extensions: - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[1]", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession)", "", "Argument[3]", "ReturnValue", "taint", "df-manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[1]", "ReturnValue", "taint", "manual"] + - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose)", "", "Argument[3]", "ReturnValue", "taint", "manual"] - ["System.Xml", "XmlDictionaryReader", False, "CreateBinaryReader", "(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas)", "", "Argument[0]", "ReturnValue", "taint", "df-manual"] - ["System.Xml", "XmlDocument", False, "Load", "(System.IO.Stream)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.Xml", "XmlDocument", False, "Load", "(System.IO.TextReader)", "", "Argument[0]", "Argument[this]", "taint", "manual"] From 5c05ff843a22155ae23aa2f57c313cf512093c26 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 15:16:26 +0200 Subject: [PATCH 087/311] C#: Improve the models for System.Text.Encoding.[GetBytes|GetChars]. --- csharp/ql/lib/ext/System.Text.model.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/ql/lib/ext/System.Text.model.yml b/csharp/ql/lib/ext/System.Text.model.yml index 4a94b61109f9..0067b8b000cf 100644 --- a/csharp/ql/lib/ext/System.Text.model.yml +++ b/csharp/ql/lib/ext/System.Text.model.yml @@ -3,18 +3,18 @@ extensions: pack: codeql/csharp-all extensible: summaryModel data: - - ["System.Text", "Encoding", True, "GetBytes", "(System.Char*,System.Int32,System.Byte*,System.Int32)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetBytes", "(System.Char*,System.Int32,System.Byte*,System.Int32)", "", "Argument[0].Element", "Argument[2]", "taint", "manual"] - ["System.Text", "Encoding", True, "GetBytes", "(System.Char[])", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - ["System.Text", "Encoding", True, "GetBytes", "(System.Char[],System.Int32,System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", True, "GetBytes", "(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", True, "GetBytes", "(System.ReadOnlySpan,System.Span)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetBytes", "(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32)", "", "Argument[0].Element", "Argument[3]", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetBytes", "(System.ReadOnlySpan,System.Span)", "", "Argument[0].Element", "Argument[1]", "taint", "manual"] - ["System.Text", "Encoding", True, "GetBytes", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", False, "GetBytes", "(System.String,System.Int32,System.Int32)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", True, "GetBytes", "(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", True, "GetChars", "(System.Byte*,System.Int32,System.Char*,System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetBytes", "(System.String,System.Int32,System.Int32)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetBytes", "(System.String,System.Int32,System.Int32,System.Byte[],System.Int32)", "", "Argument[0]", "Argument[3]", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetChars", "(System.Byte*,System.Int32,System.Char*,System.Int32)", "", "Argument[0].Element", "Argument[2]", "taint", "manual"] - ["System.Text", "Encoding", True, "GetChars", "(System.Byte[])", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - ["System.Text", "Encoding", True, "GetChars", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - - ["System.Text", "Encoding", True, "GetChars", "(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] + - ["System.Text", "Encoding", True, "GetChars", "(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32)", "", "Argument[0].Element", "Argument[3]", "taint", "manual"] - ["System.Text", "Encoding", True, "GetChars", "(System.ReadOnlySpan,System.Span)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - ["System.Text", "Encoding", False, "GetString", "(System.Byte*,System.Int32)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - ["System.Text", "Encoding", True, "GetString", "(System.Byte[])", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] From 95763dd225529369d1de40c25c5dbcf7c34b21c3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 14:04:57 +0200 Subject: [PATCH 088/311] C#: Add some models for SerializationInto and SerializationInfoEnumerator. --- .../lib/ext/System.Runtime.Serialization.model.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 csharp/ql/lib/ext/System.Runtime.Serialization.model.yml diff --git a/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml b/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml new file mode 100644 index 000000000000..dc81e6f260fb --- /dev/null +++ b/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml @@ -0,0 +1,12 @@ +extensions: + - addsTo: + pack: codeql/csharp-all + extensible: summaryModel + data: + - ["System.Runtime.Serialization", "SerializationInfo", False, "AddValue", "(System.String,System.Object)", "", "Argument[1]", "Argument[this]", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfo", False, "AddValue", "(System.String,System.Object,System.Type)", "", "Argument[1]", "Argument[this]", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfo", False, "GetEnumerator", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfo", False, "GetString", "(System.String)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfo", False, "GetValue", "(System.String,System.Type)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfoEnumerator", False, "get_Current", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["System.Runtime.Serialization", "SerializationInfoEnumerator", False, "get_Value", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] From eba901f61063d88e639b762e91340106f9fb8770 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 16:11:14 +0200 Subject: [PATCH 089/311] C#: Update flow summaries expected output. --- .../dataflow/library/FlowSummaries.expected | 128 +++++++++--------- .../library/FlowSummariesFiltered.expected | 72 +++++----- 2 files changed, 97 insertions(+), 103 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index c3eb0402922c..ff615d531152 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -12371,7 +12371,7 @@ summary | System.IO;MemoryStream;CopyToAsync;(System.IO.Stream,System.Int32,System.Threading.CancellationToken);Argument[this];Argument[0];taint;manual | | System.IO;MemoryStream;FlushAsync;(System.Threading.CancellationToken);Argument[this];ReturnValue.SyntheticField[System.Threading.Tasks.Task.m_stateObject];value;dfc-generated | | System.IO;MemoryStream;GetBuffer;();Argument[this];ReturnValue;taint;df-generated | -| System.IO;MemoryStream;MemoryStream;(System.Byte[]);Argument[0];Argument[this];taint;manual | +| System.IO;MemoryStream;MemoryStream;(System.Byte[]);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Boolean);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Int32,System.Int32,System.Boolean);Argument[0].Element;Argument[this];taint;manual | @@ -17277,30 +17277,20 @@ summary | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int16);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int32);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int64);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[1];Argument[this];taint;manual | +| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[1];Argument[this];taint;manual | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.SByte);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Single);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt16);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt32);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt64);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names];ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values];ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetString;(System.String);Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetValue;(System.String,System.Type);Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;ReturnValue;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this];ReturnValue;taint;manual | +| System.Runtime.Serialization;SerializationInfo;GetString;(System.String);Argument[this];ReturnValue;taint;manual | +| System.Runtime.Serialization;SerializationInfo;GetValue;(System.String,System.Type);Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationInfo;SerializationInfo;(System.Type,System.Runtime.Serialization.IFormatterConverter);Argument[1];Argument[this];taint;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].Property[System.Runtime.Serialization.SerializationInfoEnumerator.Current];ReturnValue;value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].Property[System.Runtime.Serialization.SerializationInfoEnumerator.Current];ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._value];value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._value];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._name];value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._name];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this];ReturnValue;taint;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this];ReturnValue;taint;dfc-generated | +| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationInfoEnumerator;get_Name;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Value;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfoEnumerator;get_Value;();Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationObjectManager;SerializationObjectManager;(System.Runtime.Serialization.StreamingContext);Argument[0];Argument[this];taint;df-generated | | System.Runtime.Serialization;StreamingContext;StreamingContext;(System.Runtime.Serialization.StreamingContextStates,System.Object);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.StreamingContext._additionalContext];value;dfc-generated | | System.Runtime.Serialization;StreamingContext;get_Context;();Argument[this].SyntheticField[System.Runtime.Serialization.StreamingContext._additionalContext];ReturnValue;value;dfc-generated | @@ -18467,12 +18457,12 @@ summary | System.Text.Unicode;Utf8+TryWriteInterpolatedStringHandler;TryWriteInterpolatedStringHandler;(System.Int32,System.Int32,System.Span,System.Boolean);Argument[2];Argument[this];taint;df-generated | | System.Text.Unicode;Utf8+TryWriteInterpolatedStringHandler;TryWriteInterpolatedStringHandler;(System.Int32,System.Int32,System.Span,System.IFormatProvider,System.Boolean);Argument[2];Argument[this];taint;df-generated | | System.Text.Unicode;Utf8+TryWriteInterpolatedStringHandler;TryWriteInterpolatedStringHandler;(System.Int32,System.Int32,System.Span,System.IFormatProvider,System.Boolean);Argument[3];Argument[this];taint;df-generated | -| System.Text;ASCIIEncoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;ASCIIEncoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;ASCIIEncoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0];ReturnValue;taint;manual | -| System.Text;ASCIIEncoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;ASCIIEncoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;ASCIIEncoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;ASCIIEncoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;ASCIIEncoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;ASCIIEncoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0].Element;Argument[1];taint;manual | +| System.Text;ASCIIEncoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;ASCIIEncoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;ASCIIEncoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;ASCIIEncoding;GetChars;(System.ReadOnlySpan,System.Span);Argument[0].Element;ReturnValue;taint;manual | | System.Text;ASCIIEncoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;ASCIIEncoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | @@ -18501,18 +18491,18 @@ summary | System.Text;Encoding;CreateTranscodingStream;(System.IO.Stream,System.Text.Encoding,System.Text.Encoding,System.Boolean);Argument[2];ReturnValue;taint;df-generated | | System.Text;Encoding;Encoding;(System.Int32,System.Text.EncoderFallback,System.Text.DecoderFallback);Argument[1];Argument[this];taint;df-generated | | System.Text;Encoding;Encoding;(System.Int32,System.Text.EncoderFallback,System.Text.DecoderFallback);Argument[2];Argument[this];taint;df-generated | -| System.Text;Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | | System.Text;Encoding;GetBytes;(System.Char[]);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0];ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0].Element;Argument[1];taint;manual | | System.Text;Encoding;GetBytes;(System.String);Argument[0];ReturnValue;taint;manual | | System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | | System.Text;Encoding;GetChars;(System.Byte[]);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;Encoding;GetChars;(System.ReadOnlySpan,System.Span);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;Encoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | @@ -18703,37 +18693,37 @@ summary | System.Text;StringRuneEnumerator;GetEnumerator;();Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual | | System.Text;StringRuneEnumerator;GetEnumerator;();Argument[this];ReturnValue;value;dfc-generated | | System.Text;StringRuneEnumerator;get_Current;();Argument[this];ReturnValue;taint;df-generated | -| System.Text;UTF7Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF7Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF7Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF7Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF7Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;UTF7Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF7Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;UTF7Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;UTF7Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF7Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;UTF7Encoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF7Encoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF7Encoding;GetString;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF8Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;UTF8Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF8Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;UTF8Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0].Element;Argument[1];taint;manual | +| System.Text;UTF8Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;UTF8Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF8Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;UTF8Encoding;GetChars;(System.ReadOnlySpan,System.Span);Argument[0].Element;ReturnValue;taint;manual | | System.Text;UTF8Encoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF8Encoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF8Encoding;GetString;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF32Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF32Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF32Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UTF32Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UTF32Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;UTF32Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF32Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;UTF32Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;UTF32Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UTF32Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;UTF32Encoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF32Encoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UTF32Encoding;GetString;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UnicodeEncoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UnicodeEncoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UnicodeEncoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;UnicodeEncoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;UnicodeEncoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;UnicodeEncoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UnicodeEncoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;UnicodeEncoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;UnicodeEncoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | +| System.Text;UnicodeEncoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;UnicodeEncoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UnicodeEncoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;UnicodeEncoding;GetString;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | @@ -20868,21 +20858,27 @@ summary | System.Xml;XmlDictionary;TryLookup;(System.Int32,System.Xml.XmlDictionaryString);Argument[this];Argument[1];taint;df-generated | | System.Xml;XmlDictionary;TryLookup;(System.String,System.Xml.XmlDictionaryString);Argument[this];Argument[1];taint;df-generated | | System.Xml;XmlDictionary;TryLookup;(System.Xml.XmlDictionaryString,System.Xml.XmlDictionaryString);Argument[0];Argument[1];value;dfc-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[5];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[6];Argument[6].Parameter[delegate-self];value;hq-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[1];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[1];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[4];Argument[4].Parameter[delegate-self];value;hq-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-generated | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[5];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[0].Element;ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[3];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[5];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[6];Argument[6].Parameter[delegate-self];value;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[1];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[1];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[0];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[1];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[3];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[4];Argument[4].Parameter[delegate-self];value;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-manual | | System.Xml;XmlDictionaryReader;CreateDictionaryReader;(System.Xml.XmlReader);Argument[0];ReturnValue;value;dfc-generated | | System.Xml;XmlDictionaryReader;CreateMtomReader;(System.Byte[],System.Int32,System.Int32,System.Text.Encoding[],System.String,System.Xml.XmlDictionaryReaderQuotas,System.Int32,System.Xml.OnXmlDictionaryReaderClose);Argument[7];Argument[7].Parameter[delegate-self];value;hq-generated | | System.Xml;XmlDictionaryReader;CreateMtomReader;(System.IO.Stream,System.Text.Encoding[],System.String,System.Xml.XmlDictionaryReaderQuotas,System.Int32,System.Xml.OnXmlDictionaryReaderClose);Argument[5];Argument[5].Parameter[delegate-self];value;hq-generated | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected index 8c0a26ee4039..faf716f4d7be 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected @@ -9208,7 +9208,7 @@ | System.IO;FileSystemWatcher;remove_Error;(System.IO.ErrorEventHandler);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | System.IO;FileSystemWatcher;remove_Renamed;(System.IO.RenamedEventHandler);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | System.IO;MemoryStream;GetBuffer;();Argument[this];ReturnValue;taint;df-generated | -| System.IO;MemoryStream;MemoryStream;(System.Byte[]);Argument[0];Argument[this];taint;manual | +| System.IO;MemoryStream;MemoryStream;(System.Byte[]);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Boolean);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;Argument[this];taint;manual | | System.IO;MemoryStream;MemoryStream;(System.Byte[],System.Int32,System.Int32,System.Boolean);Argument[0].Element;Argument[this];taint;manual | @@ -13222,28 +13222,20 @@ | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int16);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int32);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Int64);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object);Argument[1];Argument[this];taint;manual | +| System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Object,System.Type);Argument[1];Argument[this];taint;manual | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.SByte);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.Single);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt16);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt32);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | | System.Runtime.Serialization;SerializationInfo;AddValue;(System.String,System.UInt64);Argument[0];Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names].Element;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._names];ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values];ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetString;(System.String);Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfo;GetValue;(System.String,System.Type);Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfo._values].Element;ReturnValue;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfo;GetEnumerator;();Argument[this];ReturnValue;taint;manual | +| System.Runtime.Serialization;SerializationInfo;GetString;(System.String);Argument[this];ReturnValue;taint;manual | +| System.Runtime.Serialization;SerializationInfo;GetValue;(System.String,System.Type);Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationInfo;SerializationInfo;(System.Type,System.Runtime.Serialization.IFormatterConverter);Argument[1];Argument[this];taint;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].Property[System.Runtime.Serialization.SerializationInfoEnumerator.Current];ReturnValue;value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].Property[System.Runtime.Serialization.SerializationInfoEnumerator.Current];ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._value];value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._value];value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._name];value;df-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue.SyntheticField[System.Runtime.Serialization.SerializationEntry._name];value;dfc-generated | +| System.Runtime.Serialization;SerializationInfoEnumerator;get_Current;();Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationInfoEnumerator;get_Name;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._members].Element;ReturnValue;value;dfc-generated | -| System.Runtime.Serialization;SerializationInfoEnumerator;get_Value;();Argument[this].SyntheticField[System.Runtime.Serialization.SerializationInfoEnumerator._data].Element;ReturnValue;value;dfc-generated | +| System.Runtime.Serialization;SerializationInfoEnumerator;get_Value;();Argument[this];ReturnValue;taint;manual | | System.Runtime.Serialization;SerializationObjectManager;SerializationObjectManager;(System.Runtime.Serialization.StreamingContext);Argument[0];Argument[this];taint;df-generated | | System.Runtime.Serialization;StreamingContext;StreamingContext;(System.Runtime.Serialization.StreamingContextStates,System.Object);Argument[1];Argument[this].SyntheticField[System.Runtime.Serialization.StreamingContext._additionalContext];value;dfc-generated | | System.Runtime.Serialization;StreamingContext;get_Context;();Argument[this].SyntheticField[System.Runtime.Serialization.StreamingContext._additionalContext];ReturnValue;value;dfc-generated | @@ -14074,18 +14066,18 @@ | System.Text;Encoding;CreateTranscodingStream;(System.IO.Stream,System.Text.Encoding,System.Text.Encoding,System.Boolean);Argument[2];ReturnValue;taint;df-generated | | System.Text;Encoding;Encoding;(System.Int32,System.Text.EncoderFallback,System.Text.DecoderFallback);Argument[1];Argument[this];taint;df-generated | | System.Text;Encoding;Encoding;(System.Int32,System.Text.EncoderFallback,System.Text.DecoderFallback);Argument[2];Argument[this];taint;df-generated | -| System.Text;Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0];ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.Char*,System.Int32,System.Byte*,System.Int32);Argument[0].Element;Argument[2];taint;manual | | System.Text;Encoding;GetBytes;(System.Char[]);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0];ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.Char[],System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0].Element;Argument[3];taint;manual | +| System.Text;Encoding;GetBytes;(System.ReadOnlySpan,System.Span);Argument[0].Element;Argument[1];taint;manual | | System.Text;Encoding;GetBytes;(System.String);Argument[0];ReturnValue;taint;manual | | System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];ReturnValue;taint;manual | -| System.Text;Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;Encoding;GetBytes;(System.String,System.Int32,System.Int32,System.Byte[],System.Int32);Argument[0];Argument[3];taint;manual | +| System.Text;Encoding;GetChars;(System.Byte*,System.Int32,System.Char*,System.Int32);Argument[0].Element;Argument[2];taint;manual | | System.Text;Encoding;GetChars;(System.Byte[]);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32);Argument[0].Element;ReturnValue;taint;manual | -| System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;ReturnValue;taint;manual | +| System.Text;Encoding;GetChars;(System.Byte[],System.Int32,System.Int32,System.Char[],System.Int32);Argument[0].Element;Argument[3];taint;manual | | System.Text;Encoding;GetChars;(System.ReadOnlySpan,System.Span);Argument[0].Element;ReturnValue;taint;manual | | System.Text;Encoding;GetDecoder;();Argument[this];ReturnValue;taint;df-generated | | System.Text;Encoding;GetEncoder;();Argument[this];ReturnValue;taint;df-generated | @@ -16194,21 +16186,27 @@ | System.Xml;XmlDeclaration;XmlDeclaration;(System.String,System.String,System.String,System.Xml.XmlDocument);Argument[2];Argument[this];taint;df-generated | | System.Xml;XmlDictionary;Add;(System.String);Argument[0];ReturnValue.SyntheticField[System.Xml.XmlDictionaryString._value];value;dfc-generated | | System.Xml;XmlDictionary;Add;(System.String);Argument[this];ReturnValue.SyntheticField[System.Xml.XmlDictionaryString._dictionary];value;dfc-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[5];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[6];Argument[6].Parameter[delegate-self];value;hq-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[1];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[1];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[4];Argument[4].Parameter[delegate-self];value;hq-generated | -| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-generated | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[5];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[0].Element;ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[3];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[5];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[6];Argument[6].Parameter[delegate-self];value;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.Byte[],System.Xml.XmlDictionaryReaderQuotas);Argument[0].Element;ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas);Argument[1];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[0];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[1];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession);Argument[3];ReturnValue;taint;df-manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[0];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[1];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[3];ReturnValue;taint;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.IXmlDictionary,System.Xml.XmlDictionaryReaderQuotas,System.Xml.XmlBinaryReaderSession,System.Xml.OnXmlDictionaryReaderClose);Argument[4];Argument[4].Parameter[delegate-self];value;manual | +| System.Xml;XmlDictionaryReader;CreateBinaryReader;(System.IO.Stream,System.Xml.XmlDictionaryReaderQuotas);Argument[0];ReturnValue;taint;df-manual | | System.Xml;XmlDictionaryReader;CreateDictionaryReader;(System.Xml.XmlReader);Argument[0];ReturnValue;value;dfc-generated | | System.Xml;XmlDictionaryReader;CreateMtomReader;(System.Byte[],System.Int32,System.Int32,System.Text.Encoding[],System.String,System.Xml.XmlDictionaryReaderQuotas,System.Int32,System.Xml.OnXmlDictionaryReaderClose);Argument[7];Argument[7].Parameter[delegate-self];value;hq-generated | | System.Xml;XmlDictionaryReader;CreateMtomReader;(System.IO.Stream,System.Text.Encoding[],System.String,System.Xml.XmlDictionaryReaderQuotas,System.Int32,System.Xml.OnXmlDictionaryReaderClose);Argument[5];Argument[5].Parameter[delegate-self];value;hq-generated | From 8f8b0428ab9505a2e28f50a8ef6746a9d79b313c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 1 Jul 2025 16:19:33 +0200 Subject: [PATCH 090/311] C#: Add change-note. --- .../ql/src/change-notes/2025-07-01-improve-summary-models.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/src/change-notes/2025-07-01-improve-summary-models.md diff --git a/csharp/ql/src/change-notes/2025-07-01-improve-summary-models.md b/csharp/ql/src/change-notes/2025-07-01-improve-summary-models.md new file mode 100644 index 000000000000..f2c8fd82bae2 --- /dev/null +++ b/csharp/ql/src/change-notes/2025-07-01-improve-summary-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Explicitly added summary models for all overloads of `System.Xml.XmlDictionaryReader.CreateBinaryReader`. Added models for some of the methods and properties in `System.Runtime.Serialization.SerializationInfo` and `System.Runtime.Serialization.SerializationInfoEnumerator`. Updated models for `System.Text.Encoding.GetBytes`, `System.Text.Encoding.GetChars` and the constructor for `System.IO.MemoryStream`. This generally improves the library modelling and thus reduces the number of false negatives. From 70bf61dc5707feaebc058d6c4a830dfbfbda69f1 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 3 Jul 2025 14:50:19 +0200 Subject: [PATCH 091/311] C#: Convert Deserialization tests to use inline expectations. --- .../CWE-502/DeserializedDelegate/DeserializedDelegate.cs | 6 +++--- .../CWE-502/DeserializedDelegate/DeserializedDelegate.qlref | 5 ++++- .../CWE-502/DeserializedDelegate/DeserializedDelegateBad.cs | 2 +- .../CWE-502/UnsafeDeserialization/BinaryFormatterBad.cs | 2 +- .../UnsafeDeserialization/DataContractJsonSerializerBad.cs | 2 +- .../UnsafeDeserialization/DataContractSerializerBad.cs | 2 +- .../CWE-502/UnsafeDeserialization/ResourceReaderBad.cs | 4 ++-- .../UnsafeDeserialization/UnsafeDeserialization.qlref | 5 ++++- .../UnsafeDeserialization/UnsafeDeserializationBad.cs | 2 +- .../CWE-502/UnsafeDeserialization/XmlObjectSerializerBad.cs | 2 +- .../CWE-502/UnsafeDeserialization/XmlSerializerBad.cs | 2 +- .../BinaryFormatterUntrustedInputBad.cs | 4 ++-- .../DataContractJsonSerializerUntrustedInputBad.cs | 2 +- .../DataContractSerializerUntrustedInputBad.cs | 2 +- .../ResourceReaderUntrustedInputBad.cs | 4 ++-- .../UnsafeDeserializationUntrustedInput.qlref | 4 +++- .../UnsafeDeserializationUntrustedInputBad.cs | 2 +- .../XmlObjectSerializerUntrustedInputBad.cs | 2 +- .../XmlSerializerUntrustedInputBad.cs | 2 +- .../Test.cs | 4 ++-- .../UnsafeDeserializationUntrustedInput.qlref | 4 +++- 21 files changed, 37 insertions(+), 27 deletions(-) diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.cs index 93dede10b15d..a2d0c24ff4c4 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.cs @@ -11,11 +11,11 @@ public static void M(FileStream fs) { var formatter = new BinaryFormatter(); // BAD - var a = (Func)formatter.Deserialize(fs); + var a = (Func)formatter.Deserialize(fs); // $ Alert[cs/deserialized-delegate] // BAD - var b = (Expression>)formatter.Deserialize(fs); + var b = (Expression>)formatter.Deserialize(fs); // $ Alert[cs/deserialized-delegate] // BAD - var c = (D)formatter.Deserialize(fs); + var c = (D)formatter.Deserialize(fs); // $ Alert[cs/deserialized-delegate] // GOOD var d = (int)formatter.Deserialize(fs); } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.qlref b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.qlref index 913c61338c47..dbfd493cef5b 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.qlref +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegate.qlref @@ -1 +1,4 @@ -Security Features/CWE-502/DeserializedDelegate.ql \ No newline at end of file +query: Security Features/CWE-502/DeserializedDelegate.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegateBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegateBad.cs index 12b2dc76987d..48c2ed2b4140 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegateBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/DeserializedDelegate/DeserializedDelegateBad.cs @@ -8,7 +8,7 @@ public static int InvokeSerialized(FileStream fs) { var formatter = new BinaryFormatter(); // BAD - var f = (Func)formatter.Deserialize(fs); + var f = (Func)formatter.Deserialize(fs); // $ Alert[cs/deserialized-delegate] return f(); } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/BinaryFormatterBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/BinaryFormatterBad.cs index 1170a37ad3b9..7fbe5499dbb7 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/BinaryFormatterBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/BinaryFormatterBad.cs @@ -7,6 +7,6 @@ public static object Deserialize(Stream s) { var ds = new BinaryFormatter(); // BAD - return ds.Deserialize(s); + return ds.Deserialize(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractJsonSerializerBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractJsonSerializerBad.cs index 1256428176c5..2e2b80cc25ae 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractJsonSerializerBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractJsonSerializerBad.cs @@ -8,6 +8,6 @@ public static object Deserialize(Type type, Stream s) { var ds = new DataContractJsonSerializer(type); // BAD - return ds.ReadObject(s); + return ds.ReadObject(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractSerializerBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractSerializerBad.cs index 35cff0b45f1d..e98bd0c0aa0b 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractSerializerBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/DataContractSerializerBad.cs @@ -8,6 +8,6 @@ public static object Deserialize(Type type, Stream s) { var ds = new DataContractSerializer(type); // BAD - return ds.ReadObject(s); + return ds.ReadObject(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/ResourceReaderBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/ResourceReaderBad.cs index 2da5dc1aa6a5..e39a87769900 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/ResourceReaderBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/ResourceReaderBad.cs @@ -6,11 +6,11 @@ class BadResourceReader { public static void Deserialize(Stream s) { - var ds = new ResourceReader(s); + var ds = new ResourceReader(s); // $ Alert[cs/unsafe-deserialization] // BAD var dict = ds.GetEnumerator(); while (dict.MoveNext()) - Console.WriteLine(" {0}: '{1}' (Type {2})", + Console.WriteLine(" {0}: '{1}' (Type {2})", dict.Key, dict.Value, dict.Value.GetType().Name); ds.Close(); } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserialization.qlref b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserialization.qlref index 78efa2399c0b..25a133ff8a71 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserialization.qlref +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserialization.qlref @@ -1 +1,4 @@ -Security Features/CWE-502/UnsafeDeserialization.ql \ No newline at end of file +query: Security Features/CWE-502/UnsafeDeserialization.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserializationBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserializationBad.cs index 385e700a0bf9..ce178961b9b6 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserializationBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/UnsafeDeserializationBad.cs @@ -6,6 +6,6 @@ public static object Deserialize(string s) { JavaScriptSerializer sr = new JavaScriptSerializer(new SimpleTypeResolver()); // BAD - return sr.DeserializeObject(s); + return sr.DeserializeObject(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlObjectSerializerBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlObjectSerializerBad.cs index 4096934da0ba..a8e1bc42e2fc 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlObjectSerializerBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlObjectSerializerBad.cs @@ -8,6 +8,6 @@ public static object Deserialize(Type type, Stream s) { XmlObjectSerializer ds = new DataContractSerializer(type); // BAD - return ds.ReadObject(s); + return ds.ReadObject(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlSerializerBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlSerializerBad.cs index 4d32bae9c082..a5f3287cd55d 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlSerializerBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserialization/XmlSerializerBad.cs @@ -8,6 +8,6 @@ public static object Deserialize(Type type, Stream s) { var ds = new XmlSerializer(type); // BAD - return ds.Deserialize(s); + return ds.Deserialize(s); // $ Alert[cs/unsafe-deserialization] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs index bb6c9b1de08d..8f19580b68a8 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/BinaryFormatterUntrustedInputBad.cs @@ -10,7 +10,7 @@ public static object Deserialize(TextBox textBox) { var ds = new BinaryFormatter(); // BAD - return ds.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(textBox.Text))); + return ds.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(textBox.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } @@ -20,6 +20,6 @@ public static object Deserialize(TextBox type, TextBox data) { var ds = new BinaryFormatter(); // BAD - return ds.Deserialize(new MemoryStream(Convert.FromBase64String(data.Text))); + return ds.Deserialize(new MemoryStream(Convert.FromBase64String(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractJsonSerializerUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractJsonSerializerUntrustedInputBad.cs index 2d3efe3ae269..e1e389c0a67f 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractJsonSerializerUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractJsonSerializerUntrustedInputBad.cs @@ -10,6 +10,6 @@ public static object Deserialize(TextBox type, TextBox data) { var ds = new DataContractJsonSerializer(Type.GetType(type.Text)); // BAD - return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); + return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractSerializerUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractSerializerUntrustedInputBad.cs index f4f266ed3e00..2e979b2387d6 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractSerializerUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/DataContractSerializerUntrustedInputBad.cs @@ -10,6 +10,6 @@ public static object Deserialize(TextBox type, TextBox data) { var ds = new DataContractSerializer(Type.GetType(type.Text)); // BAD - return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); + return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/ResourceReaderUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/ResourceReaderUntrustedInputBad.cs index cd5468afc2d2..33ca758ac9cf 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/ResourceReaderUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/ResourceReaderUntrustedInputBad.cs @@ -8,11 +8,11 @@ class BadResourceReader { public static void Deserialize(TextBox data) { - var ds = new ResourceReader(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); + var ds = new ResourceReader(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] // BAD var dict = ds.GetEnumerator(); while (dict.MoveNext()) - Console.WriteLine(" {0}: '{1}' (Type {2})", + Console.WriteLine(" {0}: '{1}' (Type {2})", dict.Key, dict.Value, dict.Value.GetType().Name); ds.Close(); } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.qlref b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.qlref index a1ffb72bf108..195452ad5675 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.qlref +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.qlref @@ -1,2 +1,4 @@ query: Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputBad.cs index db2b25097bac..6af634af09c5 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputBad.cs @@ -7,6 +7,6 @@ public static object Deserialize(TextBox textBox) { JavaScriptSerializer sr = new JavaScriptSerializer(new SimpleTypeResolver()); // BAD - return sr.DeserializeObject(textBox.Text); + return sr.DeserializeObject(textBox.Text); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlObjectSerializerUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlObjectSerializerUntrustedInputBad.cs index b525dd28692b..c7a0d94cb45b 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlObjectSerializerUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlObjectSerializerUntrustedInputBad.cs @@ -10,6 +10,6 @@ public static object Deserialize(TextBox type, TextBox data) { XmlObjectSerializer ds = new DataContractSerializer(Type.GetType(type.Text)); // BAD - return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); + return ds.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlSerializerUntrustedInputBad.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlSerializerUntrustedInputBad.cs index f658f2a9e1a7..b5299c01f3f4 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlSerializerUntrustedInputBad.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/XmlSerializerUntrustedInputBad.cs @@ -10,6 +10,6 @@ public static object Deserialize(TextBox type, TextBox data) { var ds = new XmlSerializer(Type.GetType(type.Text)); // BAD - return ds.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); + return ds.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(data.Text))); // $ Alert[cs/unsafe-deserialization-untrusted-input] } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/Test.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/Test.cs index c8c5cbb00988..90bdeef83368 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/Test.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/Test.cs @@ -14,9 +14,9 @@ public static object Deserialize1(TextBox data) public static object Deserialize2(TextBox data) { - return JsonConvert.DeserializeObject(data.Text, new JsonSerializerSettings + return JsonConvert.DeserializeObject(data.Text, new JsonSerializerSettings // $ Alert[cs/unsafe-deserialization-untrusted-input] { - TypeNameHandling = TypeNameHandling.Auto // BAD + TypeNameHandling = TypeNameHandling.Auto }); } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/UnsafeDeserializationUntrustedInput.qlref b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/UnsafeDeserializationUntrustedInput.qlref index a1ffb72bf108..195452ad5675 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/UnsafeDeserializationUntrustedInput.qlref +++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInputNewtonsoftJson/UnsafeDeserializationUntrustedInput.qlref @@ -1,2 +1,4 @@ query: Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql From a508089df8a961cc7031257611157958d0d0bdfd Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 16 Jul 2025 09:38:29 +0200 Subject: [PATCH 092/311] Rust: Improvements to tuple type inference based on PR feedback --- rust/ql/.generated.list | 1 - rust/ql/.gitattributes | 1 - .../rust/elements/internal/TuplePatImpl.qll | 16 +- rust/ql/lib/codeql/rust/internal/Type.qll | 41 ++-- .../codeql/rust/internal/TypeInference.qll | 33 ++- .../test/library-tests/type-inference/main.rs | 7 + .../type-inference/pattern_matching.rs | 4 +- .../type-inference/type-inference.expected | 214 ++++++++++-------- 8 files changed, 189 insertions(+), 128 deletions(-) diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index 1d2b69ce32ed..a87de2bc4682 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -417,7 +417,6 @@ lib/codeql/rust/elements/internal/TupleFieldConstructor.qll 89d3cf2540235044ed5a lib/codeql/rust/elements/internal/TupleFieldListConstructor.qll 4335ba2061b6e4968db9ec05c0b4d3e6a564db89a2df69e036f317672a7900b1 0b8dded875dbf696cf588e8c21acc27332a2ff66ced7bfabdfc1ad621991f888 lib/codeql/rust/elements/internal/TupleFieldListImpl.qll 74869e92a3cbdd7895adaaa418d29d5e97387daf46c17315f219ad967af15d76 5815e4b37db958663df1f6fedc9667a11b261c9c2133e3f983a3aedc452c01fc lib/codeql/rust/elements/internal/TuplePatConstructor.qll 2a5e83ad5b8713a732e610128aeddf14e9b344402d6cf30ff0b43aa39e838418 6d467f7141307523994f03ed7b8e8b1a5bcf860963c9934b90e54582ea38096a -lib/codeql/rust/elements/internal/TuplePatImpl.qll 4adb38f0f8dae4ff285b9f5843efb92af419719a7549e0ff62dc56969bd3c852 3f622130771d7731ed053175a83b289bab1d1f5931526c4854923dbcec7e43f1 lib/codeql/rust/elements/internal/TupleStructPatConstructor.qll 9d68f67a17a5cec0e78907a53eccfa7696be5b0571da4b486c8184274e56344a 3ffa29f546cd6c644be4fecc7415477a3a4dc00d69b8764be9119abe4c6d8b9e lib/codeql/rust/elements/internal/TupleTypeReprConstructor.qll 80c31c25fd27e330690fb500d757a4bbd33f226186d88ea73bfe4cf29a7db508 d572a72fa361990a3d0a3f9b81d1e966e2ba1ac0a60314ec824c1b8b2814c857 lib/codeql/rust/elements/internal/TupleTypeReprImpl.qll daf679e3cac0eaf1c20880b49b22bbe0822a27cc6ab2c241916b4bf6da995586 ebd87d7fce7d8acd7fa37c4107f8210e60412dd418104bd9fdbdbcde13c8b6a7 diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index 43819916ce08..a10f0277198c 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -419,7 +419,6 @@ /lib/codeql/rust/elements/internal/TupleFieldListConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/TupleFieldListImpl.qll linguist-generated /lib/codeql/rust/elements/internal/TuplePatConstructor.qll linguist-generated -/lib/codeql/rust/elements/internal/TuplePatImpl.qll linguist-generated /lib/codeql/rust/elements/internal/TupleStructPatConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/TupleTypeReprConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/TupleTypeReprImpl.qll linguist-generated diff --git a/rust/ql/lib/codeql/rust/elements/internal/TuplePatImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/TuplePatImpl.qll index 93f5b79c8208..ac9a723b6e13 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/TuplePatImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/TuplePatImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `TuplePat`. * @@ -12,6 +11,9 @@ private import codeql.rust.elements.internal.generated.TuplePat * be referenced directly. */ module Impl { + private import rust + + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * A tuple pattern. For example: * ```rust @@ -19,5 +21,15 @@ module Impl { * let (a, b, .., z) = (1, 2, 3, 4, 5); * ``` */ - class TuplePat extends Generated::TuplePat { } + class TuplePat extends Generated::TuplePat { + /** + * Gets the arity of the tuple matched by this pattern, if any. + * + * This is the number of fields in the tuple pattern if and only if the + * pattern does not contain a `..` pattern. + */ + int getTupleArity() { + result = this.getNumberOfFields() and not this.getAField() instanceof RestPat + } + } } diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index f9db78035348..79f2ad84b18a 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -10,7 +10,12 @@ private import codeql.rust.elements.internal.generated.Synth cached newtype TType = TTuple(int arity) { - arity = any(TupleTypeRepr t).getNumberOfFields() and + arity = + [ + any(TupleTypeRepr t).getNumberOfFields(), + any(TupleExpr e).getNumberOfFields(), + any(TuplePat p).getNumberOfFields() + ] and Stages::TypeInferenceStage::ref() } or TStruct(Struct s) or @@ -59,26 +64,11 @@ abstract class Type extends TType { abstract Location getLocation(); } -/** The unit type `()`. */ -class UnitType extends Type, TTuple { - UnitType() { this = TTuple(0) } - - override StructField getStructField(string name) { none() } - - override TupleField getTupleField(int i) { none() } - - override TypeParameter getTypeParameter(int i) { none() } - - override string toString() { result = "()" } - - override Location getLocation() { result instanceof EmptyLocation } -} - /** A tuple type `(T, ...)`. */ class TupleType extends Type, TTuple { private int arity; - TupleType() { this = TTuple(arity) and arity > 0 } + TupleType() { this = TTuple(arity) } override StructField getStructField(string name) { none() } @@ -86,6 +76,7 @@ class TupleType extends Type, TTuple { override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(arity, i) } + /** Gets the arity of this tuple type. */ int getArity() { result = arity } override string toString() { result = "(T_" + arity + ")" } @@ -93,6 +84,13 @@ class TupleType extends Type, TTuple { override Location getLocation() { result instanceof EmptyLocation } } +/** The unit type `()`. */ +class UnitType extends TupleType, TTuple { + UnitType() { this = TTuple(0) } + + override string toString() { result = "()" } +} + abstract private class StructOrEnumType extends Type { abstract ItemNode asItemNode(); } @@ -355,8 +353,9 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara /** * A tuple type parameter. For instance the `T` in `(T, U)`. * - * Since tuples are structural their parameters can be represented simply as - * their positional index. + * Since tuples are structural their type parameters can be represented as their + * positional index. The type inference library requires that type parameters + * belong to a single type, so we also include the arity of the tuple type. */ class TupleTypeParameter extends TypeParameter, TTupleTypeParameter { private int arity; @@ -371,8 +370,8 @@ class TupleTypeParameter extends TypeParameter, TTupleTypeParameter { /** Gets the index of this tuple type parameter. */ int getIndex() { result = index } - /** Gets the arity of this tuple type parameter. */ - int getArity() { result = arity } + /** Gets the tuple type that corresponds to this tuple type parameter. */ + TupleType getTupleType() { result = TTuple(arity) } } /** An implicit array type parameter. */ diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 8f2a2ca2ae1c..51e0f3a715ab 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -108,7 +108,7 @@ private module Input1 implements InputSig1 { maxArity = max(int i | i = any(TupleType tt).getArity()) and tp0 = ttp and kind = 2 and - id = ttp.getArity() * maxArity + ttp.getIndex() + id = ttp.getTupleType().getArity() * maxArity + ttp.getIndex() ) | tp0 order by kind, id @@ -335,7 +335,7 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat arity = n2.(TupleExpr).getNumberOfFields() and n1 = n2.(TupleExpr).getField(i) or - arity = n2.(TuplePat).getNumberOfFields() and + arity = n2.(TuplePat).getTupleArity() and n1 = n2.(TuplePat).getField(i) ) or @@ -553,9 +553,9 @@ private Type inferStructExprType(AstNode n, TypePath path) { } pragma[nomagic] -private Type inferTupleExprRootType(TupleExpr te) { - // `typeEquality` handles the non-root case - result = TTuple(te.getNumberOfFields()) +private Type inferTupleRootType(AstNode n) { + // `typeEquality` handles the non-root cases + result = TTuple([n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()]) } pragma[nomagic] @@ -1091,16 +1091,27 @@ private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) { /** Infers the type of `t` in `t.n` when `t` is a tuple. */ private Type inferTupleContainerExprType(Expr e, TypePath path) { - // NOTE: For a field expression `t.n` where `n` is a number `t` might both be - // a tuple struct or a tuple. It is only correct to let type information flow - // from `t.n` to tuple type parameters of `t` in the latter case. Hence we - // include the condition that the root type of `t` must be a tuple type. + // NOTE: For a field expression `t.n` where `n` is a number `t` might be a + // tuple as in: + // ```rust + // let t = (Default::default(), 2); + // let s: String = t.0; + // ``` + // But it could also be a tuple struct as in: + // ```rust + // struct T(String, u32); + // let t = T(Default::default(), 2); + // let s: String = t.0; + // ``` + // We need type information to flow from `t.n` to tuple type parameters of `t` + // in the former case but not the latter case. Hence we include the condition + // that the root type of `t` must be a tuple type. exists(int i, TypePath path0, FieldExpr fe, int arity | e = fe.getContainer() and fe.getIdentifier().getText() = i.toString() and arity = inferType(fe.getContainer()).(TupleType).getArity() and result = inferType(fe, path0) and - path = TypePath::cons(TTupleTypeParameter(arity, i), path0) // FIXME: + path = TypePath::cons(TTupleTypeParameter(arity, i), path0) ) } @@ -1992,7 +2003,7 @@ private module Cached { or result = inferStructExprType(n, path) or - result = inferTupleExprRootType(n) and + result = inferTupleRootType(n) and path.isEmpty() or result = inferPathExprType(n, path) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 03efbfc9b4ff..a8bb332a08f0 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2357,6 +2357,13 @@ mod tuples { let pair = (a, b); // $ type=pair:0(2).i64 type=pair:1(2).bool let i: i64 = pair.0; let j: bool = pair.1; + + let pair = [1, 1].into(); // $ type=pair:0(2).i32 MISSING: target=into + match pair { + (0,0) => print!("unexpected"), + _ => print!("expected"), + } + let x = pair.0; // $ type=x:i32 } } diff --git a/rust/ql/test/library-tests/type-inference/pattern_matching.rs b/rust/ql/test/library-tests/type-inference/pattern_matching.rs index 396428eedc0f..28da3e1ab580 100755 --- a/rust/ql/test/library-tests/type-inference/pattern_matching.rs +++ b/rust/ql/test/library-tests/type-inference/pattern_matching.rs @@ -704,7 +704,7 @@ pub fn complex_nested_patterns() { } // Catch-all with identifier pattern other => { - let other_complex = other; // $ MISSING: type=other_complex:? + let other_complex = other; // $ type=other_complex:0(2).Point type=other_complex:1(2).MyOption println!("Other complex data: {:?}", other_complex); } } @@ -766,7 +766,7 @@ pub fn patterns_in_function_parameters() { // Call the functions to use them let point = Point { x: 5, y: 10 }; - let extracted = extract_point(point); // $ target=extract_point MISSING: type=extracted:? + let extracted = extract_point(point); // $ target=extract_point type=extracted:0(2).i32 type=extracted:1(2).i32 let color = Color(200, 100, 50); let red = extract_color(color); // $ target=extract_color type=red:u8 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 b6f5e24244d6..e7c8467f0ae6 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -4172,96 +4172,130 @@ inferType | main.rs:2359:23:2359:26 | pair | 0(2) | {EXTERNAL LOCATION} | i64 | | main.rs:2359:23:2359:26 | pair | 1(2) | {EXTERNAL LOCATION} | bool | | main.rs:2359:23:2359:28 | pair.1 | | {EXTERNAL LOCATION} | bool | -| main.rs:2366:13:2366:23 | boxed_value | | {EXTERNAL LOCATION} | Box | -| main.rs:2366:13:2366:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | -| main.rs:2366:13:2366:23 | boxed_value | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2366:27:2366:42 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2366:27:2366:42 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2366:27:2366:42 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2366:36:2366:41 | 100i32 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2369:15:2369:25 | boxed_value | | {EXTERNAL LOCATION} | Box | -| main.rs:2369:15:2369:25 | boxed_value | A | {EXTERNAL LOCATION} | Global | -| main.rs:2369:15:2369:25 | boxed_value | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2370:13:2370:19 | box 100 | | {EXTERNAL LOCATION} | Box | -| main.rs:2370:13:2370:19 | box 100 | A | {EXTERNAL LOCATION} | Global | -| main.rs:2370:13:2370:19 | box 100 | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2370:17:2370:19 | 100 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2371:26:2371:36 | "Boxed 100\\n" | | file://:0:0:0:0 | & | -| main.rs:2371:26:2371:36 | "Boxed 100\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2371:26:2371:36 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2371:26:2371:36 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2373:13:2373:17 | box ... | | {EXTERNAL LOCATION} | Box | -| main.rs:2373:13:2373:17 | box ... | A | {EXTERNAL LOCATION} | Global | -| main.rs:2373:13:2373:17 | box ... | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2375:26:2375:42 | "Boxed value: {}\\n" | | file://:0:0:0:0 | & | -| main.rs:2375:26:2375:42 | "Boxed value: {}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2375:26:2375:51 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2375:26:2375:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2380:13:2380:22 | nested_box | | {EXTERNAL LOCATION} | Box | -| main.rs:2380:13:2380:22 | nested_box | A | {EXTERNAL LOCATION} | Global | -| main.rs:2380:13:2380:22 | nested_box | T | {EXTERNAL LOCATION} | Box | -| main.rs:2380:13:2380:22 | nested_box | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2380:13:2380:22 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2380:26:2380:50 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2380:26:2380:50 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2380:26:2380:50 | ...::new(...) | T | {EXTERNAL LOCATION} | Box | -| main.rs:2380:26:2380:50 | ...::new(...) | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2380:26:2380:50 | ...::new(...) | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2380:35:2380:49 | ...::new(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2380:35:2380:49 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2380:35:2380:49 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2380:44:2380:48 | 42i32 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2381:15:2381:24 | nested_box | | {EXTERNAL LOCATION} | Box | -| main.rs:2381:15:2381:24 | nested_box | A | {EXTERNAL LOCATION} | Global | -| main.rs:2381:15:2381:24 | nested_box | T | {EXTERNAL LOCATION} | Box | -| main.rs:2381:15:2381:24 | nested_box | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2381:15:2381:24 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2382:13:2382:21 | box ... | | {EXTERNAL LOCATION} | Box | -| main.rs:2382:13:2382:21 | box ... | A | {EXTERNAL LOCATION} | Global | -| main.rs:2382:13:2382:21 | box ... | T | {EXTERNAL LOCATION} | Box | -| main.rs:2382:13:2382:21 | box ... | T.A | {EXTERNAL LOCATION} | Global | -| main.rs:2382:13:2382:21 | box ... | T.T | {EXTERNAL LOCATION} | i32 | -| main.rs:2384:26:2384:43 | "Nested boxed: {}\\n" | | file://:0:0:0:0 | & | -| main.rs:2384:26:2384:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2384:26:2384:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2384:26:2384:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2396:16:2396:20 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:2396:16:2396:20 | SelfParam | &T | main.rs:2391:5:2393:5 | Row | -| main.rs:2396:30:2398:9 | { ... } | | {EXTERNAL LOCATION} | i64 | -| main.rs:2397:13:2397:16 | self | | file://:0:0:0:0 | & | -| main.rs:2397:13:2397:16 | self | &T | main.rs:2391:5:2393:5 | Row | -| main.rs:2397:13:2397:21 | self.data | | {EXTERNAL LOCATION} | i64 | -| main.rs:2406:26:2408:9 | { ... } | | main.rs:2401:5:2403:5 | Table | -| main.rs:2407:13:2407:38 | Table {...} | | main.rs:2401:5:2403:5 | Table | -| main.rs:2407:27:2407:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2407:27:2407:36 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2407:27:2407:36 | ...::new(...) | T | main.rs:2391:5:2393:5 | Row | -| main.rs:2410:23:2410:27 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:2410:23:2410:27 | SelfParam | &T | main.rs:2401:5:2403:5 | Table | -| main.rs:2410:30:2410:37 | property | | main.rs:2410:40:2410:59 | ImplTraitTypeRepr | -| main.rs:2410:69:2412:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2410:69:2412:9 | { ... } | | {EXTERNAL LOCATION} | i64 | -| main.rs:2411:13:2411:13 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2411:13:2411:13 | 0 | | {EXTERNAL LOCATION} | i64 | -| main.rs:2416:9:2416:15 | Some(...) | | {EXTERNAL LOCATION} | Option | -| main.rs:2416:9:2416:15 | Some(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2416:9:2419:10 | ... .map(...) | | {EXTERNAL LOCATION} | Option | -| main.rs:2416:14:2416:14 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2418:22:2418:26 | "{x}\\n" | | file://:0:0:0:0 | & | -| main.rs:2418:22:2418:26 | "{x}\\n" | &T | {EXTERNAL LOCATION} | str | -| main.rs:2418:22:2418:26 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2418:22:2418:26 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | -| main.rs:2421:13:2421:17 | table | | main.rs:2401:5:2403:5 | Table | -| main.rs:2421:21:2421:32 | ...::new(...) | | main.rs:2401:5:2403:5 | Table | -| main.rs:2422:13:2422:18 | result | | {EXTERNAL LOCATION} | i64 | -| main.rs:2422:22:2422:26 | table | | main.rs:2401:5:2403:5 | Table | -| main.rs:2422:22:2426:14 | table.count_with(...) | | {EXTERNAL LOCATION} | i64 | -| main.rs:2425:21:2425:21 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2432:5:2432:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2433:5:2433:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2433:20:2433:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2433:41:2433:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2449:5:2449:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | +| main.rs:2361:13:2361:16 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2361:13:2361:16 | pair | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:13:2361:16 | pair | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:20:2361:25 | [...] | | file://:0:0:0:0 | [] | +| main.rs:2361:20:2361:25 | [...] | [T;...] | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:20:2361:32 | ... .into() | | file://:0:0:0:0 | (T_2) | +| main.rs:2361:20:2361:32 | ... .into() | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:20:2361:32 | ... .into() | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:21:2361:21 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2361:24:2361:24 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2362:15:2362:18 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2362:15:2362:18 | pair | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2362:15:2362:18 | pair | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2363:13:2363:17 | TuplePat | | file://:0:0:0:0 | (T_2) | +| main.rs:2363:13:2363:17 | TuplePat | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2363:13:2363:17 | TuplePat | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2363:14:2363:14 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2363:16:2363:16 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2363:29:2363:40 | "unexpected" | | file://:0:0:0:0 | & | +| main.rs:2363:29:2363:40 | "unexpected" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2363:29:2363:40 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2363:29:2363:40 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2364:13:2364:13 | _ | | file://:0:0:0:0 | (T_2) | +| main.rs:2364:13:2364:13 | _ | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2364:13:2364:13 | _ | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2364:25:2364:34 | "expected" | | file://:0:0:0:0 | & | +| main.rs:2364:25:2364:34 | "expected" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2364:25:2364:34 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2364:25:2364:34 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2366:13:2366:13 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2366:17:2366:20 | pair | | file://:0:0:0:0 | (T_2) | +| main.rs:2366:17:2366:20 | pair | 0(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2366:17:2366:20 | pair | 1(2) | {EXTERNAL LOCATION} | i32 | +| main.rs:2366:17:2366:22 | pair.0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2373:13:2373:23 | boxed_value | | {EXTERNAL LOCATION} | Box | +| main.rs:2373:13:2373:23 | boxed_value | A | {EXTERNAL LOCATION} | Global | +| main.rs:2373:13:2373:23 | boxed_value | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2373:27:2373:42 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2373:27:2373:42 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2373:27:2373:42 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2373:36:2373:41 | 100i32 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2376:15:2376:25 | boxed_value | | {EXTERNAL LOCATION} | Box | +| main.rs:2376:15:2376:25 | boxed_value | A | {EXTERNAL LOCATION} | Global | +| main.rs:2376:15:2376:25 | boxed_value | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2377:13:2377:19 | box 100 | | {EXTERNAL LOCATION} | Box | +| main.rs:2377:13:2377:19 | box 100 | A | {EXTERNAL LOCATION} | Global | +| main.rs:2377:13:2377:19 | box 100 | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2377:17:2377:19 | 100 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2378:26:2378:36 | "Boxed 100\\n" | | file://:0:0:0:0 | & | +| main.rs:2378:26:2378:36 | "Boxed 100\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2378:26:2378:36 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2378:26:2378:36 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2380:13:2380:17 | box ... | | {EXTERNAL LOCATION} | Box | +| main.rs:2380:13:2380:17 | box ... | A | {EXTERNAL LOCATION} | Global | +| main.rs:2380:13:2380:17 | box ... | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2382:26:2382:42 | "Boxed value: {}\\n" | | file://:0:0:0:0 | & | +| main.rs:2382:26:2382:42 | "Boxed value: {}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2382:26:2382:51 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2382:26:2382:51 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2387:13:2387:22 | nested_box | | {EXTERNAL LOCATION} | Box | +| main.rs:2387:13:2387:22 | nested_box | A | {EXTERNAL LOCATION} | Global | +| main.rs:2387:13:2387:22 | nested_box | T | {EXTERNAL LOCATION} | Box | +| main.rs:2387:13:2387:22 | nested_box | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2387:13:2387:22 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2387:26:2387:50 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2387:26:2387:50 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2387:26:2387:50 | ...::new(...) | T | {EXTERNAL LOCATION} | Box | +| main.rs:2387:26:2387:50 | ...::new(...) | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2387:26:2387:50 | ...::new(...) | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2387:35:2387:49 | ...::new(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2387:35:2387:49 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2387:35:2387:49 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2387:44:2387:48 | 42i32 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2388:15:2388:24 | nested_box | | {EXTERNAL LOCATION} | Box | +| main.rs:2388:15:2388:24 | nested_box | A | {EXTERNAL LOCATION} | Global | +| main.rs:2388:15:2388:24 | nested_box | T | {EXTERNAL LOCATION} | Box | +| main.rs:2388:15:2388:24 | nested_box | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2388:15:2388:24 | nested_box | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2389:13:2389:21 | box ... | | {EXTERNAL LOCATION} | Box | +| main.rs:2389:13:2389:21 | box ... | A | {EXTERNAL LOCATION} | Global | +| main.rs:2389:13:2389:21 | box ... | T | {EXTERNAL LOCATION} | Box | +| main.rs:2389:13:2389:21 | box ... | T.A | {EXTERNAL LOCATION} | Global | +| main.rs:2389:13:2389:21 | box ... | T.T | {EXTERNAL LOCATION} | i32 | +| main.rs:2391:26:2391:43 | "Nested boxed: {}\\n" | | file://:0:0:0:0 | & | +| main.rs:2391:26:2391:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2391:26:2391:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2391:26:2391:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2403:16:2403:20 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:2403:16:2403:20 | SelfParam | &T | main.rs:2398:5:2400:5 | Row | +| main.rs:2403:30:2405:9 | { ... } | | {EXTERNAL LOCATION} | i64 | +| main.rs:2404:13:2404:16 | self | | file://:0:0:0:0 | & | +| main.rs:2404:13:2404:16 | self | &T | main.rs:2398:5:2400:5 | Row | +| main.rs:2404:13:2404:21 | self.data | | {EXTERNAL LOCATION} | i64 | +| main.rs:2413:26:2415:9 | { ... } | | main.rs:2408:5:2410:5 | Table | +| main.rs:2414:13:2414:38 | Table {...} | | main.rs:2408:5:2410:5 | Table | +| main.rs:2414:27:2414:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2414:27:2414:36 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2414:27:2414:36 | ...::new(...) | T | main.rs:2398:5:2400:5 | Row | +| main.rs:2417:23:2417:27 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:2417:23:2417:27 | SelfParam | &T | main.rs:2408:5:2410:5 | Table | +| main.rs:2417:30:2417:37 | property | | main.rs:2417:40:2417:59 | ImplTraitTypeRepr | +| main.rs:2417:69:2419:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2417:69:2419:9 | { ... } | | {EXTERNAL LOCATION} | i64 | +| main.rs:2418:13:2418:13 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2418:13:2418:13 | 0 | | {EXTERNAL LOCATION} | i64 | +| main.rs:2423:9:2423:15 | Some(...) | | {EXTERNAL LOCATION} | Option | +| main.rs:2423:9:2423:15 | Some(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2423:9:2426:10 | ... .map(...) | | {EXTERNAL LOCATION} | Option | +| main.rs:2423:14:2423:14 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2425:22:2425:26 | "{x}\\n" | | file://:0:0:0:0 | & | +| main.rs:2425:22:2425:26 | "{x}\\n" | &T | {EXTERNAL LOCATION} | str | +| main.rs:2425:22:2425:26 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2425:22:2425:26 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | +| main.rs:2428:13:2428:17 | table | | main.rs:2408:5:2410:5 | Table | +| main.rs:2428:21:2428:32 | ...::new(...) | | main.rs:2408:5:2410:5 | Table | +| main.rs:2429:13:2429:18 | result | | {EXTERNAL LOCATION} | i64 | +| main.rs:2429:22:2429:26 | table | | main.rs:2408:5:2410:5 | Table | +| main.rs:2429:22:2433:14 | table.count_with(...) | | {EXTERNAL LOCATION} | i64 | +| main.rs:2432:21:2432:21 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2439:5:2439:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2440:5:2440:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2440:20:2440:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2440:41:2440:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2456:5:2456:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () | | pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option | From a537c0091e5273a8a64123fbd10c43e0b245a581 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 16 Jul 2025 09:06:38 +0100 Subject: [PATCH 093/311] change note --- csharp/ql/src/change-notes/2025-07-16-web-config.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/src/change-notes/2025-07-16-web-config.md diff --git a/csharp/ql/src/change-notes/2025-07-16-web-config.md b/csharp/ql/src/change-notes/2025-07-16-web-config.md new file mode 100644 index 000000000000..238f64386633 --- /dev/null +++ b/csharp/ql/src/change-notes/2025-07-16-web-config.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* `web.config` and `web.release.config` files are now recognised regardless of case. This means queries `cs/web/debug-binary` and `cs/web/missing-x-frame-options` may produce more results than before. From e9fdca7d3991bd729aac9594a51550108dceef49 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 16 Jul 2025 11:12:25 +0200 Subject: [PATCH 094/311] C#: Address review comments. --- csharp/ql/lib/ext/System.Runtime.Serialization.model.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml b/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml index dc81e6f260fb..628d06b33b8d 100644 --- a/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml +++ b/csharp/ql/lib/ext/System.Runtime.Serialization.model.yml @@ -8,5 +8,6 @@ extensions: - ["System.Runtime.Serialization", "SerializationInfo", False, "GetEnumerator", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["System.Runtime.Serialization", "SerializationInfo", False, "GetString", "(System.String)", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["System.Runtime.Serialization", "SerializationInfo", False, "GetValue", "(System.String,System.Type)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + # Note that SerializationEntry hasn't been modeled yet, so the model below for get_Current will not in itself provide more flow. - ["System.Runtime.Serialization", "SerializationInfoEnumerator", False, "get_Current", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["System.Runtime.Serialization", "SerializationInfoEnumerator", False, "get_Value", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] From bbd7ed57ced01d2f60f000a634eb9c367c493c77 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 16 Jul 2025 12:32:35 +0200 Subject: [PATCH 095/311] Rust: Add inline expectation --- rust/ql/test/library-tests/type-inference/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index a8bb332a08f0..ae29e0515bdb 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2358,7 +2358,7 @@ mod tuples { let i: i64 = pair.0; let j: bool = pair.1; - let pair = [1, 1].into(); // $ type=pair:0(2).i32 MISSING: target=into + let pair = [1, 1].into(); // $ type=pair:0(2).i32 type=pair:1(2).i32 MISSING: target=into match pair { (0,0) => print!("unexpected"), _ => print!("expected"), From ca913b452c96ef82ace816014a85c15f838dbc6f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 15 Jul 2025 20:36:07 +0100 Subject: [PATCH 096/311] C++: Don't summarize calls through function pointers in FunctionWithWrappers. --- cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll index b7a7a95a4271..6d16d58c1ed1 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -37,7 +37,7 @@ private predicate wrapperFunctionStep( not target.isVirtual() and not source.isVirtual() and source.hasDefinition() and - exists(Call call, Expr arg, Parameter sourceParam | + exists(FunctionCall call, Expr arg, Parameter sourceParam | // there is a 'call' to 'target' with argument 'arg' at index 'targetParamIndex' target = resolveCall(call) and arg = call.getArgument(targetParamIndex) and @@ -154,7 +154,7 @@ abstract class FunctionWithWrappers extends Function { * Whether 'arg' is an argument in a call to an outermost wrapper function of 'this' function. */ predicate outermostWrapperFunctionCall(Expr arg, string callChain) { - exists(Function targetFunc, Call call, int argIndex | + exists(Function targetFunc, FunctionCall call, int argIndex | targetFunc = resolveCall(call) and this.wrapperFunction(targetFunc, argIndex, callChain) and ( From 7f8829ad8ea2ab5e700f45f0abec86cd77ac6c67 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 16 Jul 2025 14:00:27 +0200 Subject: [PATCH 097/311] Rust: Add additional inline expectation Co-authored-by: Arthur Baars --- rust/ql/test/library-tests/type-inference/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index ae29e0515bdb..f1a961522440 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2358,7 +2358,7 @@ mod tuples { let i: i64 = pair.0; let j: bool = pair.1; - let pair = [1, 1].into(); // $ type=pair:0(2).i32 type=pair:1(2).i32 MISSING: target=into + let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:0(2).i32 type=pair:1(2).i32 MISSING: target=into match pair { (0,0) => print!("unexpected"), _ => print!("expected"), From 24bea738c9a8eb8716800963105b6b92fb183971 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 14:35:36 +0200 Subject: [PATCH 098/311] Shared: Add missing QLDoc and change note --- .../change-notes/2025-07-16-initial-shared-concepts.md | 4 ++++ shared/concepts/codeql/concepts/ConceptsShared.qll | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 shared/concepts/change-notes/2025-07-16-initial-shared-concepts.md diff --git a/shared/concepts/change-notes/2025-07-16-initial-shared-concepts.md b/shared/concepts/change-notes/2025-07-16-initial-shared-concepts.md new file mode 100644 index 000000000000..bc80c6d6a0d3 --- /dev/null +++ b/shared/concepts/change-notes/2025-07-16-initial-shared-concepts.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Initial release. Moves the shared concepts library into its own qlpack. diff --git a/shared/concepts/codeql/concepts/ConceptsShared.qll b/shared/concepts/codeql/concepts/ConceptsShared.qll index fe3722eb3dde..2202110be05e 100644 --- a/shared/concepts/codeql/concepts/ConceptsShared.qll +++ b/shared/concepts/codeql/concepts/ConceptsShared.qll @@ -16,6 +16,9 @@ private import CryptoAlgorithms as CA private import codeql.dataflow.DataFlow as DF private import codeql.util.Location +/** + * Construct the shared concepts modules. + */ module ConceptsMake DataFlowLang> { final private class DataFlowNode = DataFlowLang::Node; From 1990438376f09dd850333e1a81e5d727332f3810 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 14:41:50 +0200 Subject: [PATCH 099/311] JS: Fix import The import should not have been private, because we want users to still be able to import this file and have access to the crypto algorithms. --- .../ql/lib/semmle/javascript/security/CryptoAlgorithms.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll index f13d72312fe2..13a03a3bd888 100644 --- a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll @@ -2,4 +2,4 @@ * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. */ -private import codeql.concepts.CryptoAlgorithms +import codeql.concepts.CryptoAlgorithms From df4b338c5d2a115db7a0653b81d3293dae773492 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Jul 2025 14:11:09 +0100 Subject: [PATCH 100/311] C++: Add change notes. --- cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md | 4 ++++ cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md create mode 100644 cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md diff --git a/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md b/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md new file mode 100644 index 000000000000..80b70a8c80fa --- /dev/null +++ b/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `FunctionWithWrappers` library (`semmle.code.cpp.security.FunctionWithWrappers`) no longer considers calls through function pointers as wrapper functions. \ No newline at end of file diff --git a/cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md b/cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md new file mode 100644 index 000000000000..0c3db774fa41 --- /dev/null +++ b/cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Due to changes in the `FunctionWithWrappers` library (`semmle.code.cpp.security.FunctionWithWrappers`) the primary alert location generated by the queries `cpp/path-injection`, `cpp/sql-injection`, `cpp/tainted-format-string`, and `cpp/command-line-injection` may have changed. \ No newline at end of file From 8b953e4f22bdb8adfbce6bae64702eaef5328443 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Jul 2025 14:28:04 +0100 Subject: [PATCH 101/311] C++: No need for 'resolveCall' anymore. --- cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll index 6d16d58c1ed1..b66731678475 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -17,7 +17,6 @@ import cpp import PrintfLike -private import semmle.code.cpp.ir.dataflow.ResolveCall bindingset[index] private string toCause(Function func, int index) { @@ -39,7 +38,7 @@ private predicate wrapperFunctionStep( source.hasDefinition() and exists(FunctionCall call, Expr arg, Parameter sourceParam | // there is a 'call' to 'target' with argument 'arg' at index 'targetParamIndex' - target = resolveCall(call) and + target = call.getTarget() and arg = call.getArgument(targetParamIndex) and // 'call' is enclosed in 'source' source = call.getEnclosingFunction() and @@ -155,7 +154,7 @@ abstract class FunctionWithWrappers extends Function { */ predicate outermostWrapperFunctionCall(Expr arg, string callChain) { exists(Function targetFunc, FunctionCall call, int argIndex | - targetFunc = resolveCall(call) and + targetFunc = call.getTarget() and this.wrapperFunction(targetFunc, argIndex, callChain) and ( exists(Function sourceFunc | sourceFunc = call.getEnclosingFunction() | From fdd1e3fefe4dc4d6781d11f5a689bfde5d7d3f35 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 16 Jul 2025 12:00:10 +0100 Subject: [PATCH 102/311] Use MaD models for unsafe deserialization sinks when possible Many of the unsafe deserialization sinks have to stay defined in QL because they have custom logic that cannot be expressed in MaD models. --- ...om.alibaba.com.caucho.hessian.io.model.yml | 7 + .../ql/lib/ext/com.caucho.burlap.io.model.yml | 6 + .../lib/ext/com.caucho.hessian.io.model.yml | 7 + .../ext/com.cedarsoftware.util.io.model.yml | 7 + .../com.esotericsoftware.yamlbeans.model.yml | 6 + java/ql/lib/ext/java.beans.model.yml | 5 + .../lib/ext/org.apache.commons.lang.model.yml | 5 + .../ext/org.apache.commons.lang3.model.yml | 1 + .../lib/ext/org.exolab.castor.xml.model.yml | 6 + java/ql/lib/ext/org.ho.yaml.model.yml | 13 + java/ql/lib/ext/org.jabsorb.model.yml | 6 + .../semmle/code/java/frameworks/Castor.qll | 16 +- .../code/java/frameworks/HessianBurlap.qll | 12 +- .../lib/semmle/code/java/frameworks/JYaml.qll | 12 +- .../semmle/code/java/frameworks/Jabsorb.qll | 8 +- .../semmle/code/java/frameworks/YamlBeans.qll | 8 +- .../code/java/frameworks/apache/Lang.qll | 4 +- .../security/UnsafeDeserializationQuery.qll | 47 ++-- .../CWE-502/UnsafeDeserialization.expected | 240 ++++++++++-------- 19 files changed, 260 insertions(+), 156 deletions(-) create mode 100644 java/ql/lib/ext/com.alibaba.com.caucho.hessian.io.model.yml create mode 100644 java/ql/lib/ext/com.caucho.burlap.io.model.yml create mode 100644 java/ql/lib/ext/com.caucho.hessian.io.model.yml create mode 100644 java/ql/lib/ext/com.cedarsoftware.util.io.model.yml create mode 100644 java/ql/lib/ext/com.esotericsoftware.yamlbeans.model.yml create mode 100644 java/ql/lib/ext/org.exolab.castor.xml.model.yml create mode 100644 java/ql/lib/ext/org.ho.yaml.model.yml create mode 100644 java/ql/lib/ext/org.jabsorb.model.yml diff --git a/java/ql/lib/ext/com.alibaba.com.caucho.hessian.io.model.yml b/java/ql/lib/ext/com.alibaba.com.caucho.hessian.io.model.yml new file mode 100644 index 000000000000..af8824aae0c1 --- /dev/null +++ b/java/ql/lib/ext/com.alibaba.com.caucho.hessian.io.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.alibaba.com.caucho.hessian.io", "AbstractHessianInput", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] + - ["com.alibaba.com.caucho.hessian.io", "Hessian2StreamingInput", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/com.caucho.burlap.io.model.yml b/java/ql/lib/ext/com.caucho.burlap.io.model.yml new file mode 100644 index 000000000000..862804438ca4 --- /dev/null +++ b/java/ql/lib/ext/com.caucho.burlap.io.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.caucho.burlap.io", "BurlapInput", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/com.caucho.hessian.io.model.yml b/java/ql/lib/ext/com.caucho.hessian.io.model.yml new file mode 100644 index 000000000000..73c3ddebf451 --- /dev/null +++ b/java/ql/lib/ext/com.caucho.hessian.io.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.caucho.hessian.io", "AbstractHessianInput", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] + - ["com.caucho.hessian.io", "Hessian2StreamingInput", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/com.cedarsoftware.util.io.model.yml b/java/ql/lib/ext/com.cedarsoftware.util.io.model.yml new file mode 100644 index 000000000000..926a86238114 --- /dev/null +++ b/java/ql/lib/ext/com.cedarsoftware.util.io.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.cedarsoftware.util.io", "JsonReader", False, "jsonToJava", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["com.cedarsoftware.util.io", "JsonReader", True, "readObject", "", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/com.esotericsoftware.yamlbeans.model.yml b/java/ql/lib/ext/com.esotericsoftware.yamlbeans.model.yml new file mode 100644 index 000000000000..944222c420b6 --- /dev/null +++ b/java/ql/lib/ext/com.esotericsoftware.yamlbeans.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.esotericsoftware.yamlbeans", "YamlReader", True, "read", "", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/java.beans.model.yml b/java/ql/lib/ext/java.beans.model.yml index 30667ec69615..07291296612d 100644 --- a/java/ql/lib/ext/java.beans.model.yml +++ b/java/ql/lib/ext/java.beans.model.yml @@ -13,3 +13,8 @@ extensions: - ["java.beans", "PropertyEditor", "getValue", "()", "summary", "df-manual"] # needs to be modeled by regular CodeQL matching the get and set keys to reduce FPs - ["java.beans", "PropertyEditor", "setAsText", "()", "summary", "df-manual"] # needs to be modeled by regular CodeQL matching the get and set keys to reduce FPs - ["java.beans", "PropertyEditor", "setValue", "()", "summary", "df-manual"] # needs to be modeled by regular CodeQL matching the get and set keys to reduce FPs + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["java.beans", "XMLDecoder", True, "readObject", "()", "", "Argument[this]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/org.apache.commons.lang.model.yml b/java/ql/lib/ext/org.apache.commons.lang.model.yml index 8dd3fd003f9d..0d38b845c9ca 100644 --- a/java/ql/lib/ext/org.apache.commons.lang.model.yml +++ b/java/ql/lib/ext/org.apache.commons.lang.model.yml @@ -5,3 +5,8 @@ extensions: data: - ["org.apache.commons.lang", "StringEscapeUtils", true, "escapeHtml", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["org.apache.commons.lang", "StringEscapeUtils", true, "escapeHtml", "(Writer,String)", "", "Argument[1]", "Argument[0]", "taint", "manual"] + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.apache.commons.lang", "SerializationUtils", False, "deserialize", "", "", "Argument[0]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/org.apache.commons.lang3.model.yml b/java/ql/lib/ext/org.apache.commons.lang3.model.yml index 541db005f0b6..7c455d780b13 100644 --- a/java/ql/lib/ext/org.apache.commons.lang3.model.yml +++ b/java/ql/lib/ext/org.apache.commons.lang3.model.yml @@ -3,6 +3,7 @@ extensions: pack: codeql/java-all extensible: sinkModel data: + - ["org.apache.commons.lang3", "SerializationUtils", False, "deserialize", "", "", "Argument[0]", "unsafe-deserialization", "manual"] # Note these sinks do not use the sink kind `regex-use[0]` because the regex injection query needs to select them separately from # other `regex-use[0]` sinks in order to avoid FPs. As a result, these sinks are currently not used in the polynomial ReDoS query. # TODO: refactor the `regex-use%` sink kind so that the polynomial ReDoS query can also use these sinks. diff --git a/java/ql/lib/ext/org.exolab.castor.xml.model.yml b/java/ql/lib/ext/org.exolab.castor.xml.model.yml new file mode 100644 index 000000000000..7113a9ab94a7 --- /dev/null +++ b/java/ql/lib/ext/org.exolab.castor.xml.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.exolab.castor.xml", "Unmarshaller", True, "unmarshal", "", "", "Argument[0..1]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/org.ho.yaml.model.yml b/java/ql/lib/ext/org.ho.yaml.model.yml new file mode 100644 index 000000000000..fd6e0e363563 --- /dev/null +++ b/java/ql/lib/ext/org.ho.yaml.model.yml @@ -0,0 +1,13 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.ho.yaml", "Yaml", False, "load", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "Yaml", False, "loadStream", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "Yaml", False, "loadStreamOfType", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "Yaml", False, "loadType", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "YamlConfig", False, "load", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "YamlConfig", False, "loadStream", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "YamlConfig", False, "loadStreamOfType", "", "", "Argument[0]", "unsafe-deserialization", "manual"] + - ["org.ho.yaml", "YamlConfig", False, "loadType", "", "", "Argument[0]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/ext/org.jabsorb.model.yml b/java/ql/lib/ext/org.jabsorb.model.yml new file mode 100644 index 000000000000..5c50178e9937 --- /dev/null +++ b/java/ql/lib/ext/org.jabsorb.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.jabsorb", "JSONSerializer", True, "fromJSON", "", "", "Argument[0]", "unsafe-deserialization", "manual"] diff --git a/java/ql/lib/semmle/code/java/frameworks/Castor.qll b/java/ql/lib/semmle/code/java/frameworks/Castor.qll index 2becb2fbf178..b49b3e43ebeb 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Castor.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Castor.qll @@ -1,20 +1,28 @@ /** + * DEPRECATED: Now modeled using data extensions instead. + * * Provides classes and predicates for working with the Castor framework. */ overlay[local?] -module; +deprecated module; import java /** + * DEPRECATED: Now modeled using data extensions instead. + * * The class `org.exolab.castor.xml.Unmarshaller`. */ -class CastorUnmarshaller extends RefType { +deprecated class CastorUnmarshaller extends RefType { CastorUnmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") } } -/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */ -class CastorUnmarshalMethod extends Method { +/** + * DEPRECATED: Now modeled using data extensions instead. + * + * A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. + */ +deprecated class CastorUnmarshalMethod extends Method { CastorUnmarshalMethod() { this.getDeclaringType() instanceof CastorUnmarshaller and this.getName() = "unmarshal" diff --git a/java/ql/lib/semmle/code/java/frameworks/HessianBurlap.qll b/java/ql/lib/semmle/code/java/frameworks/HessianBurlap.qll index 3a10b75a2a69..25449b351abd 100644 --- a/java/ql/lib/semmle/code/java/frameworks/HessianBurlap.qll +++ b/java/ql/lib/semmle/code/java/frameworks/HessianBurlap.qll @@ -17,10 +17,12 @@ class UnsafeHessianInput extends RefType { } /** + * DEPRECATED: Now modeled using data extensions instead. + * * A AbstractHessianInput or Hessian2StreamingInput subclass readObject method. * This is either `AbstractHessianInput.readObject` or `Hessian2StreamingInput.readObject`. */ -class UnsafeHessianInputReadObjectMethod extends Method { +deprecated class UnsafeHessianInputReadObjectMethod extends Method { UnsafeHessianInputReadObjectMethod() { this.getDeclaringType().getAnAncestor() instanceof UnsafeHessianInput and this.getName() = "readObject" @@ -34,8 +36,12 @@ class BurlapInput extends RefType { BurlapInput() { this.hasQualifiedName("com.caucho.burlap.io", "BurlapInput") } } -/** A method with the name `readObject` declared in `com.caucho.burlap.io.BurlapInput`. */ -class BurlapInputReadObjectMethod extends Method { +/** + * DEPRECATED: Now modeled using data extensions instead. + * + * A method with the name `readObject` declared in `com.caucho.burlap.io.BurlapInput`. + */ +deprecated class BurlapInputReadObjectMethod extends Method { BurlapInputReadObjectMethod() { this.getDeclaringType() instanceof BurlapInput and this.getName() = "readObject" diff --git a/java/ql/lib/semmle/code/java/frameworks/JYaml.qll b/java/ql/lib/semmle/code/java/frameworks/JYaml.qll index cd9414521c4e..c87d94baf8bf 100644 --- a/java/ql/lib/semmle/code/java/frameworks/JYaml.qll +++ b/java/ql/lib/semmle/code/java/frameworks/JYaml.qll @@ -1,22 +1,28 @@ /** + * DEPRECATED: Now modeled using data extensions instead. + * * Provides classes and predicates for working with the JYaml framework. */ overlay[local?] -module; +deprecated module; import java /** + * DEPRECATED: Now modeled using data extensions instead. + * * The class `org.ho.yaml.Yaml` or `org.ho.yaml.YamlConfig`. */ -class JYamlLoader extends RefType { +deprecated class JYamlLoader extends RefType { JYamlLoader() { this.hasQualifiedName("org.ho.yaml", ["Yaml", "YamlConfig"]) } } /** + * DEPRECATED: Now modeled using data extensions instead. + * * A JYaml unsafe load method, declared on either `Yaml` or `YamlConfig`. */ -class JYamlLoaderUnsafeLoadMethod extends Method { +deprecated class JYamlLoaderUnsafeLoadMethod extends Method { JYamlLoaderUnsafeLoadMethod() { this.getDeclaringType() instanceof JYamlLoader and this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"] diff --git a/java/ql/lib/semmle/code/java/frameworks/Jabsorb.qll b/java/ql/lib/semmle/code/java/frameworks/Jabsorb.qll index e8bb82f156fe..1997fd74f645 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Jabsorb.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Jabsorb.qll @@ -19,8 +19,12 @@ class JabsorbUnmarshallMethod extends Method { } } -/** The deserialization method `fromJSON`. */ -class JabsorbFromJsonMethod extends Method { +/** + * DEPRECATED: Now modeled using data extensions instead. + * + * The deserialization method `fromJSON`. + */ +deprecated class JabsorbFromJsonMethod extends Method { JabsorbFromJsonMethod() { this.getDeclaringType().getAnAncestor() instanceof JabsorbSerializer and this.getName() = "fromJSON" diff --git a/java/ql/lib/semmle/code/java/frameworks/YamlBeans.qll b/java/ql/lib/semmle/code/java/frameworks/YamlBeans.qll index 040ae60fc710..55ff862d3410 100644 --- a/java/ql/lib/semmle/code/java/frameworks/YamlBeans.qll +++ b/java/ql/lib/semmle/code/java/frameworks/YamlBeans.qll @@ -13,8 +13,12 @@ class YamlBeansReader extends RefType { YamlBeansReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") } } -/** A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. */ -class YamlBeansReaderReadMethod extends Method { +/** + * DEPRECATED: Now modeled using data extensions instead. + * + * A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. + */ +deprecated class YamlBeansReaderReadMethod extends Method { YamlBeansReaderReadMethod() { this.getDeclaringType() instanceof YamlBeansReader and this.getName() = "read" diff --git a/java/ql/lib/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/lib/semmle/code/java/frameworks/apache/Lang.qll index 27c7f9530ad1..a58500eb20df 100644 --- a/java/ql/lib/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/lib/semmle/code/java/frameworks/apache/Lang.qll @@ -16,10 +16,12 @@ class TypeApacheRandomStringUtils extends Class { } /** + * DEPRECATED: Now modeled using data extensions instead. + * * The method `deserialize` in either `org.apache.commons.lang.SerializationUtils` * or `org.apache.commons.lang3.SerializationUtils`. */ -class MethodApacheSerializationUtilsDeserialize extends Method { +deprecated class MethodApacheSerializationUtilsDeserialize extends Method { MethodApacheSerializationUtilsDeserialize() { this.getDeclaringType() .hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], diff --git a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll index 7489fbd00ef9..20dd433890d2 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll @@ -3,17 +3,16 @@ */ import semmle.code.java.dataflow.FlowSources +private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.FlowSinks private import semmle.code.java.dispatch.VirtualDispatch private import semmle.code.java.frameworks.Kryo private import semmle.code.java.frameworks.XStream private import semmle.code.java.frameworks.SnakeYaml private import semmle.code.java.frameworks.FastJson -private import semmle.code.java.frameworks.JYaml private import semmle.code.java.frameworks.JsonIo private import semmle.code.java.frameworks.YamlBeans private import semmle.code.java.frameworks.HessianBurlap -private import semmle.code.java.frameworks.Castor private import semmle.code.java.frameworks.Jackson private import semmle.code.java.frameworks.Jabsorb private import semmle.code.java.frameworks.Jms @@ -149,8 +148,15 @@ private module SafeKryoConfig implements DataFlow::ConfigSig { private module SafeKryoFlow = DataFlow::Global; +private class DefaultUnsafeDeserializationSink extends DataFlow::Node { + DefaultUnsafeDeserializationSink() { sinkNode(this, "unsafe-deserialization") } +} + /** * Holds if `ma` is a call that deserializes data from `sink`. + * + * Note that this does not include deserialization methods that have been + * specified using models-as-data. */ predicate unsafeDeserialization(MethodCall ma, Expr sink) { exists(Method m | m = ma.getMethod() | @@ -162,9 +168,6 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) { sink = ma.getQualifier() and not DataFlow::exprNode(sink).getTypeBound() instanceof SafeObjectInputStreamType or - m instanceof XmlDecoderReadObjectMethod and - sink = ma.getQualifier() - or m instanceof XStreamReadObjectMethod and sink = ma.getAnArgument() and not SafeXStreamFlow::flowToExpr(ma.getQualifier()) @@ -173,9 +176,6 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) { sink = ma.getAnArgument() and not SafeKryoFlow::flowToExpr(ma.getQualifier()) or - m instanceof MethodApacheSerializationUtilsDeserialize and - sink = ma.getArgument(0) - or ma instanceof UnsafeSnakeYamlParse and sink = ma.getArgument(0) or @@ -183,23 +183,6 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) { not fastJsonLooksSafe() and sink = ma.getArgument(0) or - ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and - sink = ma.getArgument(0) - or - ma.getMethod() instanceof JsonIoJsonToJavaMethod and - sink = ma.getArgument(0) - or - ma.getMethod() instanceof JsonIoReadObjectMethod and - sink = ma.getQualifier() - or - ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier() - or - ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier() - or - ma.getMethod() instanceof CastorUnmarshalMethod and sink = ma.getAnArgument() - or - ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier() - or ma.getMethod() instanceof ObjectMapperReadMethod and sink = ma.getArgument(0) and ( @@ -215,9 +198,6 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) { sink = ma.getArgument(2) and UnsafeTypeFlow::flowToExpr(ma.getArgument(1)) or - m instanceof JabsorbFromJsonMethod and - sink = ma.getArgument(0) - or m instanceof JoddJsonParseMethod and sink = ma.getArgument(0) and ( @@ -244,10 +224,17 @@ predicate unsafeDeserialization(MethodCall ma, Expr sink) { /** A sink for unsafe deserialization. */ class UnsafeDeserializationSink extends ApiSinkNode, DataFlow::ExprNode { - UnsafeDeserializationSink() { unsafeDeserialization(_, this.getExpr()) } + MethodCall mc; + + UnsafeDeserializationSink() { + unsafeDeserialization(mc, this.getExpr()) + or + this instanceof DefaultUnsafeDeserializationSink and + this.getExpr() = [mc.getQualifier(), mc.getAnArgument()] + } /** Gets a call that triggers unsafe deserialization. */ - MethodCall getMethodCall() { unsafeDeserialization(result, this.getExpr()) } + MethodCall getMethodCall() { result = mc } } /** Holds if `node` is a sanitizer for unsafe deserialization */ diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected index 89ddc0c1bf9e..027828f5bef6 100644 --- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected +++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected @@ -74,119 +74,121 @@ | ParcelableEntity.java:32:30:32:70 | fromJson(...) | GsonActivity.java:15:54:15:64 | getIntent(...) : Intent | ParcelableEntity.java:32:44:32:62 | readString(...) | Unsafe deserialization depends on a $@. | GsonActivity.java:15:54:15:64 | getIntent(...) | user-provided value | | TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization depends on a $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user-provided value | edges -| A.java:17:31:17:51 | getInputStream(...) : InputStream | A.java:18:50:18:60 | inputStream : InputStream | provenance | Src:MaD:1 | -| A.java:17:31:17:51 | getInputStream(...) : InputStream | A.java:19:12:19:13 | in | provenance | Src:MaD:1 inputStreamWrapper | +| A.java:17:31:17:51 | getInputStream(...) : InputStream | A.java:18:50:18:60 | inputStream : InputStream | provenance | Src:MaD:17 | +| A.java:17:31:17:51 | getInputStream(...) : InputStream | A.java:19:12:19:13 | in | provenance | Src:MaD:17 inputStreamWrapper | | A.java:18:28:18:61 | new ObjectInputStream(...) : ObjectInputStream | A.java:19:12:19:13 | in | provenance | | -| A.java:18:50:18:60 | inputStream : InputStream | A.java:18:28:18:61 | new ObjectInputStream(...) : ObjectInputStream | provenance | MaD:13 | -| A.java:23:31:23:55 | getTaintedObjectInput(...) : ObjectInput | A.java:24:12:24:22 | objectInput | provenance | Src:MaD:5 | -| A.java:28:33:28:59 | getTaintedMyObjectInput(...) : MyObjectInput | A.java:29:12:29:22 | objectInput | provenance | Src:MaD:4 | -| A.java:33:31:33:51 | getInputStream(...) : InputStream | A.java:34:50:34:60 | inputStream : InputStream | provenance | Src:MaD:1 | -| A.java:33:31:33:51 | getInputStream(...) : InputStream | A.java:35:12:35:13 | in | provenance | Src:MaD:1 inputStreamWrapper | +| A.java:18:50:18:60 | inputStream : InputStream | A.java:18:28:18:61 | new ObjectInputStream(...) : ObjectInputStream | provenance | MaD:29 | +| A.java:23:31:23:55 | getTaintedObjectInput(...) : ObjectInput | A.java:24:12:24:22 | objectInput | provenance | Src:MaD:21 | +| A.java:28:33:28:59 | getTaintedMyObjectInput(...) : MyObjectInput | A.java:29:12:29:22 | objectInput | provenance | Src:MaD:20 | +| A.java:33:31:33:51 | getInputStream(...) : InputStream | A.java:34:50:34:60 | inputStream : InputStream | provenance | Src:MaD:17 | +| A.java:33:31:33:51 | getInputStream(...) : InputStream | A.java:35:12:35:13 | in | provenance | Src:MaD:17 inputStreamWrapper | | A.java:34:28:34:61 | new ObjectInputStream(...) : ObjectInputStream | A.java:35:12:35:13 | in | provenance | | -| A.java:34:50:34:60 | inputStream : InputStream | A.java:34:28:34:61 | new ObjectInputStream(...) : ObjectInputStream | provenance | MaD:13 | -| A.java:45:31:45:51 | getInputStream(...) : InputStream | A.java:46:35:46:45 | inputStream : InputStream | provenance | Src:MaD:1 | -| A.java:46:20:46:46 | new XMLDecoder(...) : XMLDecoder | A.java:47:12:47:12 | d | provenance | | -| A.java:46:35:46:45 | inputStream : InputStream | A.java:46:20:46:46 | new XMLDecoder(...) : XMLDecoder | provenance | MaD:9 | -| A.java:52:31:52:51 | getInputStream(...) : InputStream | A.java:53:43:53:53 | inputStream : InputStream | provenance | Src:MaD:1 | +| A.java:34:50:34:60 | inputStream : InputStream | A.java:34:28:34:61 | new ObjectInputStream(...) : ObjectInputStream | provenance | MaD:29 | +| A.java:45:31:45:51 | getInputStream(...) : InputStream | A.java:46:35:46:45 | inputStream : InputStream | provenance | Src:MaD:17 | +| A.java:46:20:46:46 | new XMLDecoder(...) : XMLDecoder | A.java:47:12:47:12 | d | provenance | Sink:MaD:6 | +| A.java:46:35:46:45 | inputStream : InputStream | A.java:46:20:46:46 | new XMLDecoder(...) : XMLDecoder | provenance | MaD:25 | +| A.java:52:31:52:51 | getInputStream(...) : InputStream | A.java:53:43:53:53 | inputStream : InputStream | provenance | Src:MaD:17 | | A.java:53:21:53:54 | new InputStreamReader(...) : InputStreamReader | A.java:54:23:54:28 | reader | provenance | | -| A.java:53:43:53:53 | inputStream : InputStream | A.java:53:21:53:54 | new InputStreamReader(...) : InputStreamReader | provenance | MaD:12 | +| A.java:53:43:53:53 | inputStream : InputStream | A.java:53:21:53:54 | new InputStreamReader(...) : InputStreamReader | provenance | MaD:28 | | A.java:59:19:59:50 | new Input(...) : Input | A.java:60:28:60:32 | input | provenance | | | A.java:59:19:59:50 | new Input(...) : Input | A.java:61:34:61:38 | input | provenance | | | A.java:59:19:59:50 | new Input(...) : Input | A.java:62:40:62:44 | input | provenance | | -| A.java:59:29:59:49 | getInputStream(...) : InputStream | A.java:59:19:59:50 | new Input(...) : Input | provenance | Src:MaD:1 MaD:7 | -| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:81:26:81:30 | input | provenance | Src:MaD:1 | -| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:82:30:82:34 | input | provenance | Src:MaD:1 | -| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:83:50:83:54 | input : InputStream | provenance | Src:MaD:1 | -| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:84:24:84:28 | input | provenance | Src:MaD:1 | -| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:85:46:85:50 | input : InputStream | provenance | Src:MaD:1 | -| A.java:83:50:83:54 | input : InputStream | A.java:83:28:83:55 | new InputStreamReader(...) | provenance | MaD:12 | -| A.java:85:46:85:50 | input : InputStream | A.java:85:24:85:51 | new InputStreamReader(...) | provenance | MaD:12 | -| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input | provenance | Src:MaD:1 | -| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input | provenance | Src:MaD:1 | -| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:50:93:54 | input : InputStream | provenance | Src:MaD:1 | -| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input | provenance | Src:MaD:1 | -| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:46:95:50 | input : InputStream | provenance | Src:MaD:1 | -| A.java:93:50:93:54 | input : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) | provenance | MaD:12 | -| A.java:95:46:95:50 | input : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) | provenance | MaD:12 | -| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:111:26:111:30 | input | provenance | Src:MaD:1 | -| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:112:30:112:34 | input | provenance | Src:MaD:1 | -| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:113:50:113:54 | input : InputStream | provenance | Src:MaD:1 | -| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:114:24:114:28 | input | provenance | Src:MaD:1 | -| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:115:46:115:50 | input : InputStream | provenance | Src:MaD:1 | -| A.java:113:50:113:54 | input : InputStream | A.java:113:28:113:55 | new InputStreamReader(...) | provenance | MaD:12 | -| A.java:115:46:115:50 | input : InputStream | A.java:115:24:115:51 | new InputStreamReader(...) | provenance | MaD:12 | -| B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | provenance | Src:MaD:1 | -| B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:14:5:14:15 | inputStream : InputStream | provenance | Src:MaD:1 | -| B.java:14:5:14:15 | inputStream : InputStream | B.java:14:22:14:26 | bytes [post update] : byte[] | provenance | MaD:11 | +| A.java:59:29:59:49 | getInputStream(...) : InputStream | A.java:59:19:59:50 | new Input(...) : Input | provenance | Src:MaD:17 MaD:23 | +| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:81:26:81:30 | input | provenance | Src:MaD:17 | +| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:82:30:82:34 | input | provenance | Src:MaD:17 | +| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:83:50:83:54 | input : InputStream | provenance | Src:MaD:17 | +| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:84:24:84:28 | input | provenance | Src:MaD:17 | +| A.java:80:25:80:45 | getInputStream(...) : InputStream | A.java:85:46:85:50 | input : InputStream | provenance | Src:MaD:17 | +| A.java:83:50:83:54 | input : InputStream | A.java:83:28:83:55 | new InputStreamReader(...) | provenance | MaD:28 | +| A.java:85:46:85:50 | input : InputStream | A.java:85:24:85:51 | new InputStreamReader(...) | provenance | MaD:28 | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input | provenance | Src:MaD:17 | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input | provenance | Src:MaD:17 | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:50:93:54 | input : InputStream | provenance | Src:MaD:17 | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input | provenance | Src:MaD:17 | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:46:95:50 | input : InputStream | provenance | Src:MaD:17 | +| A.java:93:50:93:54 | input : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) | provenance | MaD:28 | +| A.java:95:46:95:50 | input : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) | provenance | MaD:28 | +| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:111:26:111:30 | input | provenance | Src:MaD:17 | +| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:112:30:112:34 | input | provenance | Src:MaD:17 | +| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:113:50:113:54 | input : InputStream | provenance | Src:MaD:17 | +| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:114:24:114:28 | input | provenance | Src:MaD:17 | +| A.java:110:25:110:45 | getInputStream(...) : InputStream | A.java:115:46:115:50 | input : InputStream | provenance | Src:MaD:17 | +| A.java:113:50:113:54 | input : InputStream | A.java:113:28:113:55 | new InputStreamReader(...) | provenance | MaD:28 | +| A.java:115:46:115:50 | input : InputStream | A.java:115:24:115:51 | new InputStreamReader(...) | provenance | MaD:28 | +| B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | provenance | Src:MaD:17 | +| B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:14:5:14:15 | inputStream : InputStream | provenance | Src:MaD:17 | +| B.java:14:5:14:15 | inputStream : InputStream | B.java:14:22:14:26 | bytes [post update] : byte[] | provenance | MaD:27 | | B.java:14:22:14:26 | bytes [post update] : byte[] | B.java:15:23:15:27 | bytes | provenance | | -| B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:21:5:21:15 | inputStream : InputStream | provenance | Src:MaD:1 | -| B.java:21:5:21:15 | inputStream : InputStream | B.java:21:22:21:26 | bytes [post update] : byte[] | provenance | MaD:11 | +| B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:21:5:21:15 | inputStream : InputStream | provenance | Src:MaD:17 | +| B.java:21:5:21:15 | inputStream : InputStream | B.java:21:22:21:26 | bytes [post update] : byte[] | provenance | MaD:27 | | B.java:21:22:21:26 | bytes [post update] : byte[] | B.java:22:27:22:31 | bytes : byte[] | provenance | | | B.java:22:16:22:32 | new String(...) : String | B.java:23:29:23:29 | s | provenance | | -| B.java:22:27:22:31 | bytes : byte[] | B.java:22:16:22:32 | new String(...) : String | provenance | MaD:15 | -| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:29:5:29:15 | inputStream : InputStream | provenance | Src:MaD:1 | -| B.java:29:5:29:15 | inputStream : InputStream | B.java:29:22:29:26 | bytes [post update] : byte[] | provenance | MaD:11 | +| B.java:22:27:22:31 | bytes : byte[] | B.java:22:16:22:32 | new String(...) : String | provenance | MaD:31 | +| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:29:5:29:15 | inputStream : InputStream | provenance | Src:MaD:17 | +| B.java:29:5:29:15 | inputStream : InputStream | B.java:29:22:29:26 | bytes [post update] : byte[] | provenance | MaD:27 | | B.java:29:22:29:26 | bytes [post update] : byte[] | B.java:30:27:30:31 | bytes : byte[] | provenance | | | B.java:30:16:30:32 | new String(...) : String | B.java:31:23:31:23 | s | provenance | | -| B.java:30:27:30:31 | bytes : byte[] | B.java:30:16:30:32 | new String(...) : String | provenance | MaD:15 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | provenance | Src:MaD:3 | -| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | provenance | Src:MaD:3 | -| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | provenance | Src:MaD:3 | -| C.java:38:17:38:44 | getParameter(...) : String | C.java:45:34:45:37 | data : String | provenance | Src:MaD:3 | -| C.java:45:19:45:44 | new JsonReader(...) : JsonReader | C.java:46:3:46:4 | jr | provenance | | +| B.java:30:27:30:31 | bytes : byte[] | B.java:30:16:30:32 | new String(...) : String | provenance | MaD:31 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data | provenance | Src:MaD:19 Sink:MaD:8 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data | provenance | Src:MaD:19 Sink:MaD:9 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data | provenance | Src:MaD:19 Sink:MaD:10 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data | provenance | Src:MaD:19 Sink:MaD:11 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data | provenance | Src:MaD:19 Sink:MaD:12 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data | provenance | Src:MaD:19 Sink:MaD:13 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | provenance | Src:MaD:19 Sink:MaD:14 | +| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | provenance | Src:MaD:19 Sink:MaD:15 | +| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | provenance | Src:MaD:19 Sink:MaD:3 | +| C.java:38:17:38:44 | getParameter(...) : String | C.java:45:34:45:37 | data : String | provenance | Src:MaD:19 | +| C.java:45:19:45:44 | new JsonReader(...) : JsonReader | C.java:46:3:46:4 | jr | provenance | Sink:MaD:4 | | C.java:45:34:45:37 | data : String | C.java:45:19:45:44 | new JsonReader(...) : JsonReader | provenance | Config | -| C.java:51:17:51:44 | getParameter(...) : String | C.java:52:33:52:36 | data : String | provenance | Src:MaD:3 | -| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:53:3:53:3 | r | provenance | | -| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:54:3:54:3 | r | provenance | | -| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:55:3:55:3 | r | provenance | | +| C.java:51:17:51:44 | getParameter(...) : String | C.java:52:33:52:36 | data : String | provenance | Src:MaD:19 | +| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:53:3:53:3 | r | provenance | Sink:MaD:5 | +| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:54:3:54:3 | r | provenance | Sink:MaD:5 | +| C.java:52:18:52:37 | new YamlReader(...) : YamlReader | C.java:55:3:55:3 | r | provenance | Sink:MaD:5 | | C.java:52:33:52:36 | data : String | C.java:52:18:52:37 | new YamlReader(...) : YamlReader | provenance | Config | -| C.java:60:18:60:45 | getParameter(...) : String | C.java:60:18:60:56 | getBytes(...) : byte[] | provenance | Src:MaD:3 MaD:16 | +| C.java:60:18:60:45 | getParameter(...) : String | C.java:60:18:60:56 | getBytes(...) : byte[] | provenance | Src:MaD:19 MaD:32 | | C.java:60:18:60:56 | getBytes(...) : byte[] | C.java:61:55:61:59 | bytes : byte[] | provenance | | | C.java:60:18:60:56 | getBytes(...) : byte[] | C.java:62:48:62:50 | bis : ByteArrayInputStream | provenance | inputStreamWrapper | | C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:62:48:62:50 | bis : ByteArrayInputStream | provenance | | -| C.java:61:55:61:59 | bytes : byte[] | C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:10 | -| C.java:62:31:62:51 | new HessianInput(...) : HessianInput | C.java:63:3:63:14 | hessianInput | provenance | | -| C.java:62:31:62:51 | new HessianInput(...) : HessianInput | C.java:64:3:64:14 | hessianInput | provenance | | +| C.java:61:55:61:59 | bytes : byte[] | C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:26 | +| C.java:62:31:62:51 | new HessianInput(...) : HessianInput | C.java:63:3:63:14 | hessianInput | provenance | Sink:MaD:2 | +| C.java:62:31:62:51 | new HessianInput(...) : HessianInput | C.java:64:3:64:14 | hessianInput | provenance | Sink:MaD:2 | | C.java:62:48:62:50 | bis : ByteArrayInputStream | C.java:62:31:62:51 | new HessianInput(...) : HessianInput | provenance | Config | -| C.java:69:18:69:45 | getParameter(...) : String | C.java:69:18:69:56 | getBytes(...) : byte[] | provenance | Src:MaD:3 MaD:16 | +| C.java:69:18:69:45 | getParameter(...) : String | C.java:69:18:69:56 | getBytes(...) : byte[] | provenance | Src:MaD:19 MaD:32 | | C.java:69:18:69:56 | getBytes(...) : byte[] | C.java:70:55:70:59 | bytes : byte[] | provenance | | | C.java:69:18:69:56 | getBytes(...) : byte[] | C.java:71:50:71:52 | bis : ByteArrayInputStream | provenance | inputStreamWrapper | | C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:71:50:71:52 | bis : ByteArrayInputStream | provenance | | -| C.java:70:55:70:59 | bytes : byte[] | C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:10 | -| C.java:71:32:71:53 | new Hessian2Input(...) : Hessian2Input | C.java:72:3:72:14 | hessianInput | provenance | | -| C.java:71:32:71:53 | new Hessian2Input(...) : Hessian2Input | C.java:73:3:73:14 | hessianInput | provenance | | +| C.java:70:55:70:59 | bytes : byte[] | C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:26 | +| C.java:71:32:71:53 | new Hessian2Input(...) : Hessian2Input | C.java:72:3:72:14 | hessianInput | provenance | Sink:MaD:2 | +| C.java:71:32:71:53 | new Hessian2Input(...) : Hessian2Input | C.java:73:3:73:14 | hessianInput | provenance | Sink:MaD:2 | | C.java:71:50:71:52 | bis : ByteArrayInputStream | C.java:71:32:71:53 | new Hessian2Input(...) : Hessian2Input | provenance | Config | -| C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) | provenance | Src:MaD:3 MaD:14 | -| C.java:84:27:84:54 | getParameter(...) : String | C.java:84:27:84:65 | getBytes(...) : byte[] | provenance | Src:MaD:3 MaD:16 | +| C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) | provenance | Src:MaD:19 MaD:30 Sink:MaD:7 | +| C.java:84:27:84:54 | getParameter(...) : String | C.java:84:27:84:65 | getBytes(...) : byte[] | provenance | Src:MaD:19 MaD:32 | | C.java:84:27:84:65 | getBytes(...) : byte[] | C.java:85:54:85:67 | serializedData : byte[] | provenance | | | C.java:84:27:84:65 | getBytes(...) : byte[] | C.java:86:45:86:46 | is : ByteArrayInputStream | provenance | inputStreamWrapper | | C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:86:45:86:46 | is : ByteArrayInputStream | provenance | | -| C.java:85:54:85:67 | serializedData : byte[] | C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:10 | -| C.java:86:29:86:47 | new BurlapInput(...) : BurlapInput | C.java:87:3:87:13 | burlapInput | provenance | | +| C.java:85:54:85:67 | serializedData : byte[] | C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | provenance | MaD:26 | +| C.java:86:29:86:47 | new BurlapInput(...) : BurlapInput | C.java:87:3:87:13 | burlapInput | provenance | Sink:MaD:1 | +| C.java:86:29:86:47 | new BurlapInput(...) : BurlapInput | C.java:87:3:87:13 | burlapInput | provenance | Sink:MaD:2 | | C.java:86:45:86:46 | is : ByteArrayInputStream | C.java:86:29:86:47 | new BurlapInput(...) : BurlapInput | provenance | Config | | C.java:86:45:86:46 | is : ByteArrayInputStream | C.java:90:21:90:22 | is : ByteArrayInputStream | provenance | | -| C.java:90:3:90:14 | burlapInput1 : BurlapInput | C.java:91:3:91:14 | burlapInput1 | provenance | | +| C.java:90:3:90:14 | burlapInput1 : BurlapInput | C.java:91:3:91:14 | burlapInput1 | provenance | Sink:MaD:1 | +| C.java:90:3:90:14 | burlapInput1 : BurlapInput | C.java:91:3:91:14 | burlapInput1 | provenance | Sink:MaD:2 | | C.java:90:21:90:22 | is : ByteArrayInputStream | C.java:90:3:90:14 | burlapInput1 : BurlapInput | provenance | Config | -| FlexjsonServlet.java:67:23:67:46 | getParameter(...) : String | FlexjsonServlet.java:68:127:68:130 | json | provenance | Src:MaD:3 | -| FlexjsonServlet.java:79:23:79:46 | getParameter(...) : String | FlexjsonServlet.java:80:93:80:96 | json | provenance | Src:MaD:3 | -| FlexjsonServlet.java:119:23:119:46 | getParameter(...) : String | FlexjsonServlet.java:124:50:124:53 | json | provenance | Src:MaD:3 | +| FlexjsonServlet.java:67:23:67:46 | getParameter(...) : String | FlexjsonServlet.java:68:127:68:130 | json | provenance | Src:MaD:19 | +| FlexjsonServlet.java:79:23:79:46 | getParameter(...) : String | FlexjsonServlet.java:80:93:80:96 | json | provenance | Src:MaD:19 | +| FlexjsonServlet.java:119:23:119:46 | getParameter(...) : String | FlexjsonServlet.java:124:50:124:53 | json | provenance | Src:MaD:19 | | GsonActivity.java:15:54:15:64 | getIntent(...) : Intent | ParcelableEntity.java:29:50:29:62 | parcel : Parcel | provenance | Config | -| GsonServlet.java:39:23:39:46 | getParameter(...) : String | GsonServlet.java:44:40:44:43 | json | provenance | Src:MaD:3 | -| GsonServlet.java:53:23:53:46 | getParameter(...) : String | GsonServlet.java:60:40:60:43 | json | provenance | Src:MaD:3 | -| JabsorbServlet.java:89:23:89:46 | getParameter(...) : String | JabsorbServlet.java:93:48:93:51 | json : String | provenance | Src:MaD:3 | +| GsonServlet.java:39:23:39:46 | getParameter(...) : String | GsonServlet.java:44:40:44:43 | json | provenance | Src:MaD:19 | +| GsonServlet.java:53:23:53:46 | getParameter(...) : String | GsonServlet.java:60:40:60:43 | json | provenance | Src:MaD:19 | +| JabsorbServlet.java:89:23:89:46 | getParameter(...) : String | JabsorbServlet.java:93:48:93:51 | json : String | provenance | Src:MaD:19 | | JabsorbServlet.java:93:33:93:52 | new JSONObject(...) : JSONObject | JabsorbServlet.java:102:83:102:92 | jsonObject | provenance | | -| JabsorbServlet.java:93:48:93:51 | json : String | JabsorbServlet.java:93:33:93:52 | new JSONObject(...) : JSONObject | provenance | MaD:18 | -| JabsorbServlet.java:110:23:110:46 | getParameter(...) : String | JabsorbServlet.java:116:52:116:55 | json | provenance | Src:MaD:3 | -| JacksonTest.java:20:25:20:47 | getInputStream(...) : InputStream | JacksonTest.java:20:54:20:58 | bytes [post update] : byte[] | provenance | Src:MaD:1 MaD:11 | +| JabsorbServlet.java:93:48:93:51 | json : String | JabsorbServlet.java:93:33:93:52 | new JSONObject(...) : JSONObject | provenance | MaD:34 | +| JabsorbServlet.java:110:23:110:46 | getParameter(...) : String | JabsorbServlet.java:116:52:116:55 | json | provenance | Src:MaD:19 Sink:MaD:16 | +| JacksonTest.java:20:25:20:47 | getInputStream(...) : InputStream | JacksonTest.java:20:54:20:58 | bytes [post update] : byte[] | provenance | Src:MaD:17 MaD:27 | | JacksonTest.java:20:54:20:58 | bytes [post update] : byte[] | JacksonTest.java:21:46:21:50 | bytes : byte[] | provenance | | | JacksonTest.java:21:35:21:57 | new String(...) : String | JacksonTest.java:22:28:22:35 | jexlExpr : String | provenance | | -| JacksonTest.java:21:46:21:50 | bytes : byte[] | JacksonTest.java:21:35:21:57 | new String(...) : String | provenance | MaD:15 | +| JacksonTest.java:21:46:21:50 | bytes : byte[] | JacksonTest.java:21:35:21:57 | new String(...) : String | provenance | MaD:31 | | JacksonTest.java:22:28:22:35 | jexlExpr : String | JacksonTest.java:74:32:74:37 | string : String | provenance | | | JacksonTest.java:22:28:22:35 | jexlExpr : String | JacksonTest.java:83:32:83:37 | string : String | provenance | | | JacksonTest.java:22:28:22:35 | jexlExpr : String | JacksonTest.java:92:32:92:37 | string : String | provenance | | @@ -201,45 +203,61 @@ edges | JacksonTest.java:139:32:139:37 | string : String | JacksonTest.java:142:30:142:35 | string | provenance | | | JacksonTest.java:148:32:148:37 | string : String | JacksonTest.java:151:62:151:67 | string : String | provenance | | | JacksonTest.java:151:62:151:67 | string : String | JacksonTest.java:151:31:151:68 | createParser(...) | provenance | Config | -| JacksonTest.java:151:62:151:67 | string : String | JacksonTest.java:151:31:151:68 | createParser(...) | provenance | MaD:8 | +| JacksonTest.java:151:62:151:67 | string : String | JacksonTest.java:151:31:151:68 | createParser(...) | provenance | MaD:24 | | JacksonTest.java:157:32:157:37 | string : String | JacksonTest.java:160:48:160:53 | string : String | provenance | | | JacksonTest.java:160:48:160:53 | string : String | JacksonTest.java:160:32:160:54 | readTree(...) | provenance | Config | | JacksonTest.java:166:32:166:36 | input : String | JacksonTest.java:167:30:167:34 | input : String | provenance | | -| JacksonTest.java:167:30:167:34 | input : String | JacksonTest.java:167:30:167:45 | split(...) : String[] | provenance | MaD:17 | +| JacksonTest.java:167:30:167:34 | input : String | JacksonTest.java:167:30:167:45 | split(...) : String[] | provenance | MaD:33 | | JacksonTest.java:167:30:167:45 | split(...) : String[] | JacksonTest.java:172:30:172:33 | data | provenance | | | JacksonTest.java:178:32:178:36 | input : String | JacksonTest.java:179:30:179:34 | input : String | provenance | | -| JacksonTest.java:179:30:179:34 | input : String | JacksonTest.java:179:30:179:45 | split(...) : String[] | provenance | MaD:17 | +| JacksonTest.java:179:30:179:34 | input : String | JacksonTest.java:179:30:179:45 | split(...) : String[] | provenance | MaD:33 | | JacksonTest.java:179:30:179:45 | split(...) : String[] | JacksonTest.java:183:30:183:33 | data | provenance | | -| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:45:37:45:40 | json | provenance | Src:MaD:3 | -| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:47:56:47:59 | json | provenance | Src:MaD:3 | -| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:49:67:49:70 | json | provenance | Src:MaD:3 | -| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:51:61:51:64 | json | provenance | Src:MaD:3 | -| JoddJsonServlet.java:58:23:58:46 | getParameter(...) : String | JoddJsonServlet.java:63:39:63:42 | json | provenance | Src:MaD:3 | -| ObjectMessageTest.java:6:27:6:41 | message : Message | ObjectMessageTest.java:7:26:7:32 | message | provenance | Src:MaD:2 | +| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:45:37:45:40 | json | provenance | Src:MaD:19 | +| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:47:56:47:59 | json | provenance | Src:MaD:19 | +| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:49:67:49:70 | json | provenance | Src:MaD:19 | +| JoddJsonServlet.java:32:23:32:46 | getParameter(...) : String | JoddJsonServlet.java:51:61:51:64 | json | provenance | Src:MaD:19 | +| JoddJsonServlet.java:58:23:58:46 | getParameter(...) : String | JoddJsonServlet.java:63:39:63:42 | json | provenance | Src:MaD:19 | +| ObjectMessageTest.java:6:27:6:41 | message : Message | ObjectMessageTest.java:7:26:7:32 | message | provenance | Src:MaD:18 | | ParcelableEntity.java:29:50:29:62 | parcel : Parcel | ParcelableEntity.java:32:44:32:49 | parcel : Parcel | provenance | | -| ParcelableEntity.java:32:44:32:49 | parcel : Parcel | ParcelableEntity.java:32:44:32:62 | readString(...) | provenance | MaD:6 | +| ParcelableEntity.java:32:44:32:49 | parcel : Parcel | ParcelableEntity.java:32:44:32:62 | readString(...) | provenance | MaD:22 | | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | provenance | inputStreamWrapper | | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | provenance | | -| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | provenance | MaD:13 | +| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | provenance | MaD:29 | models -| 1 | Source: java.net; Socket; false; getInputStream; (); ; ReturnValue; remote; manual | -| 2 | Source: javax.jms; MessageListener; true; onMessage; (Message); ; Parameter[0]; remote; manual | -| 3 | Source: javax.servlet; ServletRequest; false; getParameter; (String); ; ReturnValue; remote; manual | -| 4 | Source: unsafedeserialization; A; false; getTaintedMyObjectInput; (); ; ReturnValue; remote; manual | -| 5 | Source: unsafedeserialization; A; false; getTaintedObjectInput; (); ; ReturnValue; remote; manual | -| 6 | Summary: android.os; Parcel; false; readString; ; ; Argument[this]; ReturnValue; taint; manual | -| 7 | Summary: com.esotericsoftware.kryo.io; Input; false; Input; ; ; Argument[0]; Argument[this]; taint; manual | -| 8 | Summary: com.fasterxml.jackson.core; JsonFactory; false; createParser; ; ; Argument[0]; ReturnValue; taint; manual | -| 9 | Summary: java.beans; XMLDecoder; false; XMLDecoder; ; ; Argument[0]; Argument[this]; taint; manual | -| 10 | Summary: java.io; ByteArrayInputStream; false; ByteArrayInputStream; ; ; Argument[0]; Argument[this]; taint; manual | -| 11 | Summary: java.io; InputStream; true; read; (byte[]); ; Argument[this]; Argument[0]; taint; manual | -| 12 | Summary: java.io; InputStreamReader; false; InputStreamReader; ; ; Argument[0]; Argument[this]; taint; manual | -| 13 | Summary: java.io; ObjectInputStream; false; ObjectInputStream; ; ; Argument[0]; Argument[this]; taint; manual | -| 14 | Summary: java.io; StringReader; false; StringReader; ; ; Argument[0]; Argument[this]; taint; manual | -| 15 | Summary: java.lang; String; false; String; ; ; Argument[0]; Argument[this]; taint; manual | -| 16 | Summary: java.lang; String; false; getBytes; ; ; Argument[this]; ReturnValue; taint; manual | -| 17 | Summary: java.lang; String; false; split; ; ; Argument[this]; ReturnValue; taint; manual | -| 18 | Summary: org.json; JSONObject; false; JSONObject; (String); ; Argument[0]; Argument[this]; taint; manual | +| 1 | Sink: com.caucho.burlap.io; BurlapInput; true; readObject; ; ; Argument[this]; unsafe-deserialization; manual | +| 2 | Sink: com.caucho.hessian.io; AbstractHessianInput; true; readObject; ; ; Argument[this]; unsafe-deserialization; manual | +| 3 | Sink: com.cedarsoftware.util.io; JsonReader; false; jsonToJava; ; ; Argument[0]; unsafe-deserialization; manual | +| 4 | Sink: com.cedarsoftware.util.io; JsonReader; true; readObject; ; ; Argument[this]; unsafe-deserialization; manual | +| 5 | Sink: com.esotericsoftware.yamlbeans; YamlReader; true; read; ; ; Argument[this]; unsafe-deserialization; manual | +| 6 | Sink: java.beans; XMLDecoder; true; readObject; (); ; Argument[this]; unsafe-deserialization; manual | +| 7 | Sink: org.exolab.castor.xml; Unmarshaller; true; unmarshal; ; ; Argument[0..1]; unsafe-deserialization; manual | +| 8 | Sink: org.ho.yaml; Yaml; false; load; ; ; Argument[0]; unsafe-deserialization; manual | +| 9 | Sink: org.ho.yaml; Yaml; false; loadStream; ; ; Argument[0]; unsafe-deserialization; manual | +| 10 | Sink: org.ho.yaml; Yaml; false; loadStreamOfType; ; ; Argument[0]; unsafe-deserialization; manual | +| 11 | Sink: org.ho.yaml; Yaml; false; loadType; ; ; Argument[0]; unsafe-deserialization; manual | +| 12 | Sink: org.ho.yaml; YamlConfig; false; load; ; ; Argument[0]; unsafe-deserialization; manual | +| 13 | Sink: org.ho.yaml; YamlConfig; false; loadStream; ; ; Argument[0]; unsafe-deserialization; manual | +| 14 | Sink: org.ho.yaml; YamlConfig; false; loadStreamOfType; ; ; Argument[0]; unsafe-deserialization; manual | +| 15 | Sink: org.ho.yaml; YamlConfig; false; loadType; ; ; Argument[0]; unsafe-deserialization; manual | +| 16 | Sink: org.jabsorb; JSONSerializer; true; fromJSON; ; ; Argument[0]; unsafe-deserialization; manual | +| 17 | Source: java.net; Socket; false; getInputStream; (); ; ReturnValue; remote; manual | +| 18 | Source: javax.jms; MessageListener; true; onMessage; (Message); ; Parameter[0]; remote; manual | +| 19 | Source: javax.servlet; ServletRequest; false; getParameter; (String); ; ReturnValue; remote; manual | +| 20 | Source: unsafedeserialization; A; false; getTaintedMyObjectInput; (); ; ReturnValue; remote; manual | +| 21 | Source: unsafedeserialization; A; false; getTaintedObjectInput; (); ; ReturnValue; remote; manual | +| 22 | Summary: android.os; Parcel; false; readString; ; ; Argument[this]; ReturnValue; taint; manual | +| 23 | Summary: com.esotericsoftware.kryo.io; Input; false; Input; ; ; Argument[0]; Argument[this]; taint; manual | +| 24 | Summary: com.fasterxml.jackson.core; JsonFactory; false; createParser; ; ; Argument[0]; ReturnValue; taint; manual | +| 25 | Summary: java.beans; XMLDecoder; false; XMLDecoder; ; ; Argument[0]; Argument[this]; taint; manual | +| 26 | Summary: java.io; ByteArrayInputStream; false; ByteArrayInputStream; ; ; Argument[0]; Argument[this]; taint; manual | +| 27 | Summary: java.io; InputStream; true; read; (byte[]); ; Argument[this]; Argument[0]; taint; manual | +| 28 | Summary: java.io; InputStreamReader; false; InputStreamReader; ; ; Argument[0]; Argument[this]; taint; manual | +| 29 | Summary: java.io; ObjectInputStream; false; ObjectInputStream; ; ; Argument[0]; Argument[this]; taint; manual | +| 30 | Summary: java.io; StringReader; false; StringReader; ; ; Argument[0]; Argument[this]; taint; manual | +| 31 | Summary: java.lang; String; false; String; ; ; Argument[0]; Argument[this]; taint; manual | +| 32 | Summary: java.lang; String; false; getBytes; ; ; Argument[this]; ReturnValue; taint; manual | +| 33 | Summary: java.lang; String; false; split; ; ; Argument[this]; ReturnValue; taint; manual | +| 34 | Summary: org.json; JSONObject; false; JSONObject; (String); ; Argument[0]; Argument[this]; taint; manual | nodes | A.java:17:31:17:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:18:28:18:61 | new ObjectInputStream(...) : ObjectInputStream | semmle.label | new ObjectInputStream(...) : ObjectInputStream | From ad60aff860faa3e97422a73f2e07b9f4cee31d82 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 11 Jul 2025 11:35:14 +0100 Subject: [PATCH 103/311] Update which sink kinds are shared between languages --- shared/mad/codeql/mad/ModelValidation.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll index 98b2a212c316..018c1797ddcd 100644 --- a/shared/mad/codeql/mad/ModelValidation.qll +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -29,8 +29,9 @@ module KindValidation { [ // shared "code-injection", "command-injection", "environment-injection", "file-content-store", - "html-injection", "js-injection", "ldap-injection", "log-injection", "path-injection", - "request-forgery", "sql-injection", "url-redirection", "xpath-injection", + "html-injection", "js-injection", "ldap-injection", "log-injection", "nosql-injection", + "path-injection", "request-forgery", "sql-injection", "url-redirection", + "xpath-injection", "unsafe-deserialization", // Java-only currently, but may be shared in the future "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", @@ -38,7 +39,7 @@ module KindValidation { "response-splitting", "trust-boundary-violation", "template-injection", "url-forward", "xslt-injection", // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", + "mongodb.sink", // Swift-only currently, but may be shared in the future "database-store", "format-string", "hash-iteration-count", "predicate-injection", "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe", From 7d4a70cc1d5969ffe321b11c747e2db79304abab Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 16 Jul 2025 12:21:36 +0100 Subject: [PATCH 104/311] Add change notes --- ...5-07-16-models-as-data-unsafe-deserialization-sinks.md | 4 ++++ ...2025-07-16-unsafe-deserialization-sinks-deprecation.md | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 java/ql/lib/change-notes/2025-07-16-models-as-data-unsafe-deserialization-sinks.md create mode 100644 java/ql/lib/change-notes/2025-07-16-unsafe-deserialization-sinks-deprecation.md diff --git a/java/ql/lib/change-notes/2025-07-16-models-as-data-unsafe-deserialization-sinks.md b/java/ql/lib/change-notes/2025-07-16-models-as-data-unsafe-deserialization-sinks.md new file mode 100644 index 000000000000..914856159620 --- /dev/null +++ b/java/ql/lib/change-notes/2025-07-16-models-as-data-unsafe-deserialization-sinks.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* You can now add sinks for the query "Deserialization of user-controlled data" (`java/unsafe-deserialization`) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/#extensible-predicates-used-to-create-custom-models-in-java-and-kotlin) by extending `sinkModel` and using the kind "unsafe-deserialization". The existing sinks which do not require extra logic to determine if they are unsafe are now defined in this way. diff --git a/java/ql/lib/change-notes/2025-07-16-unsafe-deserialization-sinks-deprecation.md b/java/ql/lib/change-notes/2025-07-16-unsafe-deserialization-sinks-deprecation.md new file mode 100644 index 000000000000..5fc92247a642 --- /dev/null +++ b/java/ql/lib/change-notes/2025-07-16-unsafe-deserialization-sinks-deprecation.md @@ -0,0 +1,8 @@ +--- +category: deprecated +--- +* The module `semmle.code.java.frameworks.Castor` has been deprecated and will be removed in a future release, including its two classes `CastorUnmarshaller` and `CastorUnmarshalMethod`. +* The module `semmle.code.java.frameworks.JYaml` has been deprecated and will be removed in a future release, including its two classes `JYamlLoader` and `JYamlLoaderUnsafeLoadMethod`. +* The classes `UnsafeHessianInputReadObjectMethod` and `BurlapInputReadObjectMethod` in the module `semmle.code.java.frameworks.HessianBurlap` have been deprecated and will be removed in a future release. +* The class `YamlBeansReaderReadMethod` in the module `semmle.code.java.frameworks.YamlBeans` has been deprecated and will be removed in a future release. +* The class `MethodApacheSerializationUtilsDeserialize` in the module `semmle.code.java.frameworks.apache.Lang` has been deprecated and will be removed in a future release. From 2709bf06154ef0387f3d7213219cdf2b28f5436e Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 15:54:18 +0200 Subject: [PATCH 105/311] C++: Add test that shows that IR generation for `<=>` is broken --- .../library-tests/ir/ir/PrintAST.expected | 101 ++++++++++++++++ .../library-tests/ir/ir/aliased_ir.expected | 84 ++++++++++++++ .../ir/ir/aliased_ssa_consistency.expected | 2 + .../aliased_ssa_consistency_unsound.expected | 2 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 29 +++++ .../ir/ir/raw_consistency.expected | 8 ++ .../test/library-tests/ir/ir/raw_ir.expected | 108 ++++++++++++++++++ 7 files changed, 334 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 346ace60e2fe..a3ee6b46bd53 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24436,6 +24436,107 @@ ir.cpp: # 2742| Type = [IntType] int # 2742| ValueCategory = prvalue # 2743| getStmt(14): [ReturnStmt] return ... +# 2747| [CopyAssignmentOperator] std::strong_ordering& std::strong_ordering::operator=(std::strong_ordering const&) +# 2747| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const strong_ordering & +# 2747| [MoveAssignmentOperator] std::strong_ordering& std::strong_ordering::operator=(std::strong_ordering&&) +# 2747| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] strong_ordering && +# 2747| [CopyConstructor] void std::strong_ordering::strong_ordering(std::strong_ordering const&) +# 2747| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const strong_ordering & +# 2747| [MoveConstructor] void std::strong_ordering::strong_ordering(std::strong_ordering&&) +# 2747| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] strong_ordering && +# 2747| : +# 2747| getEntryPoint(): [BlockStmt] { ... } +# 2747| getStmt(0): [ReturnStmt] return ... +# 2748| [Constructor] void std::strong_ordering::strong_ordering(std::_Order) +# 2748| : +# 2748| getParameter(0): [Parameter] v +# 2748| Type = [ScopedEnum] _Order +# 2748| : +# 2748| getEntryPoint(): [BlockStmt] { ... } +# 2748| getStmt(0): [ReturnStmt] return ... +# 2763| [CopyAssignmentOperator] ThreeWay& ThreeWay::operator=(ThreeWay const&) +# 2763| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const ThreeWay & +# 2763| [MoveAssignmentOperator] ThreeWay& ThreeWay::operator=(ThreeWay&&) +# 2763| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] ThreeWay && +# 2763| [Constructor] void ThreeWay::ThreeWay() +# 2763| : +# 2766| [MemberFunction] std::strong_ordering ThreeWay::operator<=>(ThreeWay&) +# 2766| : +# 2766| getParameter(0): [Parameter] y +# 2766| Type = [LValueReferenceType] ThreeWay & +# 2766| getEntryPoint(): [BlockStmt] { ... } +# 2766| getStmt(0): [ReturnStmt] return ... +# 2766| getExpr(): [SpaceshipExpr] ... <=> ... +# 2766| Type = [Class] strong_ordering +# 2766| ValueCategory = prvalue +# 2766| getChild(0): [PointerFieldAccess] x +# 2766| Type = [IntType] int +# 2766| ValueCategory = prvalue(load) +# 2766| getQualifier(): [ThisExpr] this +# 2766| Type = [PointerType] ThreeWay * +# 2766| ValueCategory = prvalue(load) +# 2766| getChild(1): [ReferenceFieldAccess] x +# 2766| Type = [IntType] int +# 2766| ValueCategory = prvalue(load) +# 2766| getQualifier(): [VariableAccess] y +# 2766| Type = [LValueReferenceType] ThreeWay & +# 2766| ValueCategory = prvalue(load) +# 2766| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference) +# 2766| Type = [Class] ThreeWay +# 2766| ValueCategory = lvalue +# 2769| [TopLevelFunction] void test_three_way(int, int, ThreeWay, ThreeWay) +# 2769| : +# 2769| getParameter(0): [Parameter] a +# 2769| Type = [IntType] int +# 2769| getParameter(1): [Parameter] b +# 2769| Type = [IntType] int +# 2769| getParameter(2): [Parameter] c +# 2769| Type = [Class] ThreeWay +# 2769| getParameter(3): [Parameter] d +# 2769| Type = [Class] ThreeWay +# 2769| getEntryPoint(): [BlockStmt] { ... } +# 2770| getStmt(0): [DeclStmt] declaration +# 2770| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2770| Type = [Class] strong_ordering +# 2770| getVariable().getInitializer(): [Initializer] initializer for x +# 2770| getExpr(): [SpaceshipExpr] ... <=> ... +# 2770| Type = [Class] strong_ordering +# 2770| ValueCategory = prvalue +# 2770| getChild(0): [VariableAccess] a +# 2770| Type = [IntType] int +# 2770| ValueCategory = prvalue(load) +# 2770| getChild(1): [VariableAccess] b +# 2770| Type = [IntType] int +# 2770| ValueCategory = prvalue(load) +# 2771| getStmt(1): [DeclStmt] declaration +# 2771| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 2771| Type = [Class] strong_ordering +# 2771| getVariable().getInitializer(): [Initializer] initializer for y +# 2771| getExpr(): [FunctionCall] call to operator<=> +# 2771| Type = [Class] strong_ordering +# 2771| ValueCategory = prvalue +# 2771| getQualifier(): [VariableAccess] c +# 2771| Type = [Class] ThreeWay +# 2771| ValueCategory = lvalue +# 2771| getArgument(0): [VariableAccess] d +# 2771| Type = [Class] ThreeWay +# 2771| ValueCategory = lvalue +# 2771| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to) +# 2771| Type = [LValueReferenceType] ThreeWay & +# 2771| ValueCategory = prvalue +# 2772| getStmt(2): [ReturnStmt] return ... ir23.cpp: # 1| [TopLevelFunction] bool consteval_1() # 1| : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 78f0bbd1e0c8..51baf8a73f28 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20273,6 +20273,90 @@ ir.cpp: # 2728| v2728_14(void) = AliasedUse : ~m2728_9 # 2728| v2728_15(void) = ExitFunction : +# 2747| void std::strong_ordering::strong_ordering(std::strong_ordering&&) +# 2747| Block 0 +# 2747| v2747_1(void) = EnterFunction : +# 2747| m2747_2(unknown) = AliasedDefinition : +# 2747| m2747_3(unknown) = InitializeNonLocal : +# 2747| m2747_4(unknown) = Chi : total:m2747_2, partial:m2747_3 +# 2747| r2747_5(glval) = VariableAddress[#this] : +# 2747| m2747_6(glval) = InitializeParameter[#this] : &:r2747_5 +# 2747| r2747_7(glval) = Load[#this] : &:r2747_5, m2747_6 +# 2747| m2747_8(strong_ordering) = InitializeIndirection[#this] : &:r2747_7 +#-----| r0_1(glval) = VariableAddress[(unnamed parameter 0)] : +#-----| m0_2(strong_ordering &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1 +#-----| r0_3(strong_ordering &&) = Load[(unnamed parameter 0)] : &:r0_1, m0_2 +#-----| m0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3 +# 2747| v2747_9(void) = NoOp : +# 2747| v2747_10(void) = ReturnIndirection[#this] : &:r2747_7, m2747_8 +#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, m0_4 +# 2747| v2747_11(void) = ReturnVoid : +# 2747| v2747_12(void) = AliasedUse : m2747_3 +# 2747| v2747_13(void) = ExitFunction : + +# 2748| void std::strong_ordering::strong_ordering(std::_Order) +# 2748| Block 0 +# 2748| v2748_1(void) = EnterFunction : +# 2748| m2748_2(unknown) = AliasedDefinition : +# 2748| m2748_3(unknown) = InitializeNonLocal : +# 2748| m2748_4(unknown) = Chi : total:m2748_2, partial:m2748_3 +# 2748| r2748_5(glval) = VariableAddress[#this] : +# 2748| m2748_6(glval) = InitializeParameter[#this] : &:r2748_5 +# 2748| r2748_7(glval) = Load[#this] : &:r2748_5, m2748_6 +# 2748| m2748_8(strong_ordering) = InitializeIndirection[#this] : &:r2748_7 +# 2748| r2748_9(glval<_Order>) = VariableAddress[v] : +# 2748| m2748_10(_Order) = InitializeParameter[v] : &:r2748_9 +# 2748| v2748_11(void) = NoOp : +# 2748| v2748_12(void) = ReturnIndirection[#this] : &:r2748_7, m2748_8 +# 2748| v2748_13(void) = ReturnVoid : +# 2748| v2748_14(void) = AliasedUse : m2748_3 +# 2748| v2748_15(void) = ExitFunction : + +# 2766| std::strong_ordering ThreeWay::operator<=>(ThreeWay&) +# 2766| Block 0 +# 2766| v2766_1(void) = EnterFunction : +# 2766| m2766_2(unknown) = AliasedDefinition : +# 2766| m2766_3(unknown) = InitializeNonLocal : +# 2766| m2766_4(unknown) = Chi : total:m2766_2, partial:m2766_3 +# 2766| r2766_5(glval) = VariableAddress[#this] : +# 2766| m2766_6(glval) = InitializeParameter[#this] : &:r2766_5 +# 2766| r2766_7(glval) = Load[#this] : &:r2766_5, m2766_6 +# 2766| m2766_8(ThreeWay) = InitializeIndirection[#this] : &:r2766_7 +# 2766| r2766_9(glval) = VariableAddress[y] : +# 2766| m2766_10(ThreeWay &) = InitializeParameter[y] : &:r2766_9 +# 2766| r2766_11(ThreeWay &) = Load[y] : &:r2766_9, m2766_10 +# 2766| m2766_12(unknown) = InitializeIndirection[y] : &:r2766_11 +# 2766| r2766_13(glval) = VariableAddress[#return] : +# 2766| r2766_14(glval) = VariableAddress[#this] : +# 2766| r2766_15(ThreeWay *) = Load[#this] : &:r2766_14, m2766_6 +# 2766| r2766_16(glval) = FieldAddress[x] : r2766_15 +# 2766| r2766_17(int) = Load[?] : &:r2766_16, ~m2766_8 +# 2766| r2766_18(glval) = VariableAddress[y] : +# 2766| r2766_19(ThreeWay &) = Load[y] : &:r2766_18, m2766_10 +# 2766| r2766_20(glval) = CopyValue : r2766_19 +# 2766| r2766_21(glval) = FieldAddress[x] : r2766_20 +# 2766| r2766_22(int) = Load[?] : &:r2766_21, ~m2766_12 + +# 2769| void test_three_way(int, int, ThreeWay, ThreeWay) +# 2769| Block 0 +# 2769| v2769_1(void) = EnterFunction : +# 2769| m2769_2(unknown) = AliasedDefinition : +# 2769| m2769_3(unknown) = InitializeNonLocal : +# 2769| m2769_4(unknown) = Chi : total:m2769_2, partial:m2769_3 +# 2769| r2769_5(glval) = VariableAddress[a] : +# 2769| m2769_6(int) = InitializeParameter[a] : &:r2769_5 +# 2769| r2769_7(glval) = VariableAddress[b] : +# 2769| m2769_8(int) = InitializeParameter[b] : &:r2769_7 +# 2769| r2769_9(glval) = VariableAddress[c] : +# 2769| m2769_10(ThreeWay) = InitializeParameter[c] : &:r2769_9 +# 2769| r2769_11(glval) = VariableAddress[d] : +# 2769| m2769_12(ThreeWay) = InitializeParameter[d] : &:r2769_11 +# 2770| r2770_1(glval) = VariableAddress[x] : +# 2770| r2770_2(glval) = VariableAddress[a] : +# 2770| r2770_3(int) = Load[a] : &:r2770_2, m2769_6 +# 2770| r2770_4(glval) = VariableAddress[b] : +# 2770| r2770_5(int) = Load[b] : &:r2770_4, m2769_8 + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index b83d9ea47e38..d8abe2017336 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -6,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index b83d9ea47e38..d8abe2017336 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -6,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 92566968e6ea..74c41c7e916b 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2742,4 +2742,33 @@ void test_postfix_crement(int *p, int q) { int q2 = (int)(q++); } +namespace std { + enum class _Order : signed char { __less = -1, __equiv = 0, __greater = 1 }; + class strong_ordering { + explicit constexpr strong_ordering(_Order v) {} + + public: + static const strong_ordering less; + static const strong_ordering equal; + static const strong_ordering equivalent; + static const strong_ordering greater; + }; + + inline constexpr strong_ordering strong_ordering::less(_Order::__less); + inline constexpr strong_ordering strong_ordering::equal(_Order::__equiv); + inline constexpr strong_ordering strong_ordering::equivalent(_Order::__equiv); + inline constexpr strong_ordering strong_ordering::greater(_Order::__greater); +} + +class ThreeWay { + int x; +public: + std::strong_ordering operator<=>(ThreeWay &y) { return this->x <=> y.x; } +}; + +void test_three_way(int a, int b, ThreeWay c, ThreeWay d) { + auto x = a <=> b; + auto y = c <=> d; +} + // semmle-extractor-options: -std=c++20 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index e30106d35204..949580140850 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,4 +1,6 @@ missingOperand +| ir.cpp:2766:58:2766:72 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:12:2770:18 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | unexpectedOperand duplicateOperand missingPhiOperand @@ -6,6 +8,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -21,6 +25,10 @@ lostReachability backEdgeCountMismatch useNotDominatedByDefinition | ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | +| ir.cpp:2766:24:2766:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2766:46:2766:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2766:51:2766:73 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:8:2770:8 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 68c2f3602983..436c59a32005 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18432,6 +18432,114 @@ ir.cpp: # 2728| v2728_12(void) = AliasedUse : ~m? # 2728| v2728_13(void) = ExitFunction : +# 2747| void std::strong_ordering::strong_ordering(std::strong_ordering&&) +# 2747| Block 0 +# 2747| v2747_1(void) = EnterFunction : +# 2747| mu2747_2(unknown) = AliasedDefinition : +# 2747| mu2747_3(unknown) = InitializeNonLocal : +# 2747| r2747_4(glval) = VariableAddress[#this] : +# 2747| mu2747_5(glval) = InitializeParameter[#this] : &:r2747_4 +# 2747| r2747_6(glval) = Load[#this] : &:r2747_4, ~m? +# 2747| mu2747_7(strong_ordering) = InitializeIndirection[#this] : &:r2747_6 +#-----| r0_1(glval) = VariableAddress[(unnamed parameter 0)] : +#-----| mu0_2(strong_ordering &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1 +#-----| r0_3(strong_ordering &&) = Load[(unnamed parameter 0)] : &:r0_1, ~m? +#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3 +# 2747| v2747_8(void) = NoOp : +# 2747| v2747_9(void) = ReturnIndirection[#this] : &:r2747_6, ~m? +#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m? +# 2747| v2747_10(void) = ReturnVoid : +# 2747| v2747_11(void) = AliasedUse : ~m? +# 2747| v2747_12(void) = ExitFunction : + +# 2748| void std::strong_ordering::strong_ordering(std::_Order) +# 2748| Block 0 +# 2748| v2748_1(void) = EnterFunction : +# 2748| mu2748_2(unknown) = AliasedDefinition : +# 2748| mu2748_3(unknown) = InitializeNonLocal : +# 2748| r2748_4(glval) = VariableAddress[#this] : +# 2748| mu2748_5(glval) = InitializeParameter[#this] : &:r2748_4 +# 2748| r2748_6(glval) = Load[#this] : &:r2748_4, ~m? +# 2748| mu2748_7(strong_ordering) = InitializeIndirection[#this] : &:r2748_6 +# 2748| r2748_8(glval<_Order>) = VariableAddress[v] : +# 2748| mu2748_9(_Order) = InitializeParameter[v] : &:r2748_8 +# 2748| v2748_10(void) = NoOp : +# 2748| v2748_11(void) = ReturnIndirection[#this] : &:r2748_6, ~m? +# 2748| v2748_12(void) = ReturnVoid : +# 2748| v2748_13(void) = AliasedUse : ~m? +# 2748| v2748_14(void) = ExitFunction : + +# 2766| std::strong_ordering ThreeWay::operator<=>(ThreeWay&) +# 2766| Block 0 +# 2766| v2766_1(void) = EnterFunction : +# 2766| mu2766_2(unknown) = AliasedDefinition : +# 2766| mu2766_3(unknown) = InitializeNonLocal : +# 2766| r2766_4(glval) = VariableAddress[#this] : +# 2766| mu2766_5(glval) = InitializeParameter[#this] : &:r2766_4 +# 2766| r2766_6(glval) = Load[#this] : &:r2766_4, ~m? +# 2766| mu2766_7(ThreeWay) = InitializeIndirection[#this] : &:r2766_6 +# 2766| r2766_8(glval) = VariableAddress[y] : +# 2766| mu2766_9(ThreeWay &) = InitializeParameter[y] : &:r2766_8 +# 2766| r2766_10(ThreeWay &) = Load[y] : &:r2766_8, ~m? +# 2766| mu2766_11(unknown) = InitializeIndirection[y] : &:r2766_10 +# 2766| r2766_12(glval) = VariableAddress[#return] : +# 2766| r2766_13(glval) = VariableAddress[#this] : +# 2766| r2766_14(ThreeWay *) = Load[#this] : &:r2766_13, ~m? +# 2766| r2766_15(glval) = FieldAddress[x] : r2766_14 +# 2766| r2766_16(int) = Load[?] : &:r2766_15, ~m? +# 2766| r2766_17(glval) = VariableAddress[y] : +# 2766| r2766_18(ThreeWay &) = Load[y] : &:r2766_17, ~m? +# 2766| r2766_19(glval) = CopyValue : r2766_18 +# 2766| r2766_20(glval) = FieldAddress[x] : r2766_19 +# 2766| r2766_21(int) = Load[?] : &:r2766_20, ~m? + +# 2766| Block 1 +# 2766| mu2766_22(strong_ordering) = Store[#return] : &:r2766_12 +# 2766| v2766_23(void) = ReturnIndirection[#this] : &:r2766_6, ~m? +# 2766| v2766_24(void) = ReturnIndirection[y] : &:r2766_10, ~m? +# 2766| r2766_25(glval) = VariableAddress[#return] : +# 2766| v2766_26(void) = ReturnValue : &:r2766_25, ~m? +# 2766| v2766_27(void) = AliasedUse : ~m? +# 2766| v2766_28(void) = ExitFunction : + +# 2769| void test_three_way(int, int, ThreeWay, ThreeWay) +# 2769| Block 0 +# 2769| v2769_1(void) = EnterFunction : +# 2769| mu2769_2(unknown) = AliasedDefinition : +# 2769| mu2769_3(unknown) = InitializeNonLocal : +# 2769| r2769_4(glval) = VariableAddress[a] : +# 2769| mu2769_5(int) = InitializeParameter[a] : &:r2769_4 +# 2769| r2769_6(glval) = VariableAddress[b] : +# 2769| mu2769_7(int) = InitializeParameter[b] : &:r2769_6 +# 2769| r2769_8(glval) = VariableAddress[c] : +# 2769| mu2769_9(ThreeWay) = InitializeParameter[c] : &:r2769_8 +# 2769| r2769_10(glval) = VariableAddress[d] : +# 2769| mu2769_11(ThreeWay) = InitializeParameter[d] : &:r2769_10 +# 2770| r2770_1(glval) = VariableAddress[x] : +# 2770| r2770_2(glval) = VariableAddress[a] : +# 2770| r2770_3(int) = Load[a] : &:r2770_2, ~m? +# 2770| r2770_4(glval) = VariableAddress[b] : +# 2770| r2770_5(int) = Load[b] : &:r2770_4, ~m? + +# 2770| Block 1 +# 2770| mu2770_6(strong_ordering) = Store[x] : &:r2770_1 +# 2771| r2771_1(glval) = VariableAddress[y] : +# 2771| r2771_2(glval) = VariableAddress[c] : +# 2771| r2771_3(glval) = FunctionAddress[operator<=>] : +# 2771| r2771_4(glval) = VariableAddress[d] : +# 2771| r2771_5(ThreeWay &) = CopyValue : r2771_4 +# 2771| r2771_6(strong_ordering) = Call[operator<=>] : func:r2771_3, this:r2771_2, 0:r2771_5 +# 2771| mu2771_7(unknown) = ^CallSideEffect : ~m? +# 2771| v2771_8(void) = ^IndirectReadSideEffect[-1] : &:r2771_2, ~m? +# 2771| v2771_9(void) = ^BufferReadSideEffect[0] : &:r2771_5, ~m? +# 2771| mu2771_10(ThreeWay) = ^IndirectMayWriteSideEffect[-1] : &:r2771_2 +# 2771| mu2771_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r2771_5 +# 2771| mu2771_12(strong_ordering) = Store[y] : &:r2771_1, r2771_6 +# 2772| v2772_1(void) = NoOp : +# 2769| v2769_12(void) = ReturnVoid : +# 2769| v2769_13(void) = AliasedUse : ~m? +# 2769| v2769_14(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 From 807ab986f4f831ba9504195fdd533fa5c346b2d0 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 16:19:40 +0200 Subject: [PATCH 106/311] C++: Update more exoected test results --- .../test/library-tests/ir/ir/unaliased_ssa_consistency.expected | 2 ++ .../ir/ir/unaliased_ssa_consistency_unsound.expected | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index b83d9ea47e38..d8abe2017336 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -6,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index b83d9ea47e38..d8abe2017336 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -6,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | +| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 805e31fdb98ab6e4eb8e9919692c2645c832c302 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 16 Jul 2025 15:25:45 +0100 Subject: [PATCH 107/311] Update test expectations --- .../query-tests/security/CWE-611/XXE.expected | 187 +++++++++--------- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-611/XXE.expected b/java/ql/test/query-tests/security/CWE-611/XXE.expected index 463ea4ec8728..a1d0725321d9 100644 --- a/java/ql/test/query-tests/security/CWE-611/XXE.expected +++ b/java/ql/test/query-tests/security/CWE-611/XXE.expected @@ -113,117 +113,118 @@ | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XML parsing depends on a $@ without guarding against external entity expansion. | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | user-provided value | | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XML parsing depends on a $@ without guarding against external entity expansion. | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | user-provided value | edges -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:11:66:11:67 | is : InputStream | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:12:22:12:23 | is | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:14:22:14:23 | is | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:15:22:15:23 | is | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:16:34:16:35 | is | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:20:24:20:25 | is | provenance | Src:MaD:1 | -| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:21:24:21:25 | is | provenance | Src:MaD:1 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:11:66:11:67 | is : InputStream | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:12:22:12:23 | is | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:14:22:14:23 | is | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:15:22:15:23 | is | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:16:34:16:35 | is | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:20:24:20:25 | is | provenance | Src:MaD:2 | +| CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | CdaUtilTests.java:21:24:21:25 | is | provenance | Src:MaD:2 | | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | CdaUtilTests.java:13:22:13:25 | iSrc | provenance | | | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | CdaUtilTests.java:17:22:17:25 | iSrc | provenance | | | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | CdaUtilTests.java:18:22:18:25 | iSrc | provenance | | | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | CdaUtilTests.java:19:34:19:37 | iSrc | provenance | | -| CdaUtilTests.java:11:44:11:68 | new InputStreamReader(...) : InputStreamReader | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | provenance | MaD:13 | -| CdaUtilTests.java:11:66:11:67 | is : InputStream | CdaUtilTests.java:11:44:11:68 | new InputStreamReader(...) : InputStreamReader | provenance | MaD:5 | -| DigesterTests.java:14:49:14:72 | getInputStream(...) : ServletInputStream | DigesterTests.java:16:24:16:41 | servletInputStream | provenance | Src:MaD:2 | +| CdaUtilTests.java:11:44:11:68 | new InputStreamReader(...) : InputStreamReader | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | provenance | MaD:14 | +| CdaUtilTests.java:11:66:11:67 | is : InputStream | CdaUtilTests.java:11:44:11:68 | new InputStreamReader(...) : InputStreamReader | provenance | MaD:6 | +| DigesterTests.java:14:49:14:72 | getInputStream(...) : ServletInputStream | DigesterTests.java:16:24:16:41 | servletInputStream | provenance | Src:MaD:3 | | DocumentBuilderTests.java:95:24:95:76 | new SAXSource(...) : SAXSource | DocumentBuilderTests.java:96:19:96:24 | source : SAXSource | provenance | | -| DocumentBuilderTests.java:95:38:95:75 | new InputSource(...) : InputSource | DocumentBuilderTests.java:95:24:95:76 | new SAXSource(...) : SAXSource | provenance | MaD:7 | -| DocumentBuilderTests.java:95:54:95:74 | getInputStream(...) : InputStream | DocumentBuilderTests.java:95:38:95:75 | new InputSource(...) : InputSource | provenance | Src:MaD:1 MaD:13 | -| DocumentBuilderTests.java:96:19:96:24 | source : SAXSource | DocumentBuilderTests.java:96:19:96:41 | getInputSource(...) | provenance | MaD:9 | +| DocumentBuilderTests.java:95:38:95:75 | new InputSource(...) : InputSource | DocumentBuilderTests.java:95:24:95:76 | new SAXSource(...) : SAXSource | provenance | MaD:8 | +| DocumentBuilderTests.java:95:54:95:74 | getInputStream(...) : InputStream | DocumentBuilderTests.java:95:38:95:75 | new InputSource(...) : InputSource | provenance | Src:MaD:2 MaD:14 | +| DocumentBuilderTests.java:96:19:96:24 | source : SAXSource | DocumentBuilderTests.java:96:19:96:41 | getInputSource(...) | provenance | MaD:10 | | DocumentBuilderTests.java:102:27:102:65 | new StreamSource(...) : StreamSource | DocumentBuilderTests.java:103:49:103:54 | source : StreamSource | provenance | | | DocumentBuilderTests.java:102:27:102:65 | new StreamSource(...) : StreamSource | DocumentBuilderTests.java:104:19:104:24 | source : StreamSource | provenance | | -| DocumentBuilderTests.java:102:44:102:64 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:27:102:65 | new StreamSource(...) : StreamSource | provenance | Src:MaD:1 MaD:11 | -| DocumentBuilderTests.java:103:49:103:54 | source : StreamSource | DocumentBuilderTests.java:103:19:103:55 | sourceToInputSource(...) | provenance | MaD:10 | -| DocumentBuilderTests.java:104:19:104:24 | source : StreamSource | DocumentBuilderTests.java:104:19:104:41 | getInputStream(...) | provenance | MaD:12 | +| DocumentBuilderTests.java:102:44:102:64 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:27:102:65 | new StreamSource(...) : StreamSource | provenance | Src:MaD:2 MaD:12 | +| DocumentBuilderTests.java:103:49:103:54 | source : StreamSource | DocumentBuilderTests.java:103:19:103:55 | sourceToInputSource(...) | provenance | MaD:11 | +| DocumentBuilderTests.java:104:19:104:24 | source : StreamSource | DocumentBuilderTests.java:104:19:104:41 | getInputStream(...) | provenance | MaD:13 | | SAXSourceTests.java:17:24:17:84 | new SAXSource(...) : SAXSource | SAXSourceTests.java:20:18:20:23 | source | provenance | | -| SAXSourceTests.java:17:46:17:83 | new InputSource(...) : InputSource | SAXSourceTests.java:17:24:17:84 | new SAXSource(...) : SAXSource | provenance | MaD:8 | -| SAXSourceTests.java:17:62:17:82 | getInputStream(...) : InputStream | SAXSourceTests.java:17:46:17:83 | new InputSource(...) : InputSource | provenance | Src:MaD:1 MaD:13 | -| SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:30:32:30:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SAXSourceTests.java:17:46:17:83 | new InputSource(...) : InputSource | SAXSourceTests.java:17:24:17:84 | new SAXSource(...) : SAXSource | provenance | MaD:9 | +| SAXSourceTests.java:17:62:17:82 | getInputStream(...) : InputStream | SAXSourceTests.java:17:46:17:83 | new InputSource(...) : InputSource | provenance | Src:MaD:2 MaD:14 | +| SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:30:32:30:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:30:32:30:32 | b [post update] : byte[] | SimpleXMLTests.java:31:52:31:52 | b : byte[] | provenance | | -| SimpleXMLTests.java:31:52:31:52 | b : byte[] | SimpleXMLTests.java:31:41:31:53 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:37:32:37:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:31:52:31:52 | b : byte[] | SimpleXMLTests.java:31:41:31:53 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:37:32:37:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:37:32:37:32 | b [post update] : byte[] | SimpleXMLTests.java:38:52:38:52 | b : byte[] | provenance | | -| SimpleXMLTests.java:38:52:38:52 | b : byte[] | SimpleXMLTests.java:38:41:38:53 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:89:32:89:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:38:52:38:52 | b : byte[] | SimpleXMLTests.java:38:41:38:53 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:89:32:89:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:89:32:89:32 | b [post update] : byte[] | SimpleXMLTests.java:90:48:90:48 | b : byte[] | provenance | | -| SimpleXMLTests.java:90:48:90:48 | b : byte[] | SimpleXMLTests.java:90:37:90:49 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:96:32:96:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:90:48:90:48 | b : byte[] | SimpleXMLTests.java:90:37:90:49 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:96:32:96:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:96:32:96:32 | b [post update] : byte[] | SimpleXMLTests.java:97:48:97:48 | b : byte[] | provenance | | -| SimpleXMLTests.java:97:48:97:48 | b : byte[] | SimpleXMLTests.java:97:37:97:49 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:103:32:103:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:97:48:97:48 | b : byte[] | SimpleXMLTests.java:97:37:97:49 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:103:32:103:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:103:32:103:32 | b [post update] : byte[] | SimpleXMLTests.java:104:37:104:37 | b : byte[] | provenance | | -| SimpleXMLTests.java:104:37:104:37 | b : byte[] | SimpleXMLTests.java:104:26:104:38 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:110:32:110:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:104:37:104:37 | b : byte[] | SimpleXMLTests.java:104:26:104:38 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:110:32:110:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:110:32:110:32 | b [post update] : byte[] | SimpleXMLTests.java:111:37:111:37 | b : byte[] | provenance | | -| SimpleXMLTests.java:111:37:111:37 | b : byte[] | SimpleXMLTests.java:111:26:111:38 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | provenance | Src:MaD:1 MaD:5 | -| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:145:32:145:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:111:37:111:37 | b : byte[] | SimpleXMLTests.java:111:26:111:38 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | provenance | Src:MaD:2 MaD:6 | +| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:145:32:145:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:145:32:145:32 | b [post update] : byte[] | SimpleXMLTests.java:146:33:146:33 | b : byte[] | provenance | | -| SimpleXMLTests.java:146:33:146:33 | b : byte[] | SimpleXMLTests.java:146:22:146:34 | new String(...) | provenance | MaD:6 | -| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:152:32:152:32 | b [post update] : byte[] | provenance | Src:MaD:1 MaD:4 | +| SimpleXMLTests.java:146:33:146:33 | b : byte[] | SimpleXMLTests.java:146:22:146:34 | new String(...) | provenance | MaD:7 | +| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:152:32:152:32 | b [post update] : byte[] | provenance | Src:MaD:2 MaD:5 | | SimpleXMLTests.java:152:32:152:32 | b [post update] : byte[] | SimpleXMLTests.java:153:33:153:33 | b : byte[] | provenance | | -| SimpleXMLTests.java:153:33:153:33 | b : byte[] | SimpleXMLTests.java:153:22:153:34 | new String(...) | provenance | MaD:6 | -| TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | provenance | Src:MaD:1 MaD:11 | -| TransformerTests.java:141:35:141:72 | new InputSource(...) : InputSource | TransformerTests.java:141:21:141:73 | new SAXSource(...) | provenance | MaD:7 | -| TransformerTests.java:141:51:141:71 | getInputStream(...) : InputStream | TransformerTests.java:141:35:141:72 | new InputSource(...) : InputSource | provenance | Src:MaD:1 MaD:13 | -| ValidatorTests.java:17:49:17:72 | getInputStream(...) : ServletInputStream | ValidatorTests.java:21:48:21:65 | servletInputStream : ServletInputStream | provenance | Src:MaD:2 | +| SimpleXMLTests.java:153:33:153:33 | b : byte[] | SimpleXMLTests.java:153:22:153:34 | new String(...) | provenance | MaD:7 | +| TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | provenance | Src:MaD:2 MaD:12 | +| TransformerTests.java:141:35:141:72 | new InputSource(...) : InputSource | TransformerTests.java:141:21:141:73 | new SAXSource(...) | provenance | MaD:8 | +| TransformerTests.java:141:51:141:71 | getInputStream(...) : InputStream | TransformerTests.java:141:35:141:72 | new InputSource(...) : InputSource | provenance | Src:MaD:2 MaD:14 | +| ValidatorTests.java:17:49:17:72 | getInputStream(...) : ServletInputStream | ValidatorTests.java:21:48:21:65 | servletInputStream : ServletInputStream | provenance | Src:MaD:3 | | ValidatorTests.java:21:31:21:66 | new StreamSource(...) : StreamSource | ValidatorTests.java:22:28:22:33 | source | provenance | | -| ValidatorTests.java:21:48:21:65 | servletInputStream : ServletInputStream | ValidatorTests.java:21:31:21:66 | new StreamSource(...) : StreamSource | provenance | MaD:11 | -| XMLDecoderTests.java:16:49:16:72 | getInputStream(...) : ServletInputStream | XMLDecoderTests.java:17:48:17:65 | servletInputStream : ServletInputStream | provenance | Src:MaD:2 | -| XMLDecoderTests.java:17:33:17:66 | new XMLDecoder(...) : XMLDecoder | XMLDecoderTests.java:18:9:18:18 | xmlDecoder | provenance | | -| XMLDecoderTests.java:17:48:17:65 | servletInputStream : ServletInputStream | XMLDecoderTests.java:17:33:17:66 | new XMLDecoder(...) : XMLDecoder | provenance | MaD:3 | -| XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XPathExpressionTests.java:27:35:27:55 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:19:27:56 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | -| XPathExpressionTests.java:42:39:42:59 | getInputStream(...) : InputStream | XPathExpressionTests.java:42:23:42:60 | new InputSource(...) | provenance | Src:MaD:1 MaD:13 | +| ValidatorTests.java:21:48:21:65 | servletInputStream : ServletInputStream | ValidatorTests.java:21:31:21:66 | new StreamSource(...) : StreamSource | provenance | MaD:12 | +| XMLDecoderTests.java:16:49:16:72 | getInputStream(...) : ServletInputStream | XMLDecoderTests.java:17:48:17:65 | servletInputStream : ServletInputStream | provenance | Src:MaD:3 | +| XMLDecoderTests.java:17:33:17:66 | new XMLDecoder(...) : XMLDecoder | XMLDecoderTests.java:18:9:18:18 | xmlDecoder | provenance | Sink:MaD:1 | +| XMLDecoderTests.java:17:48:17:65 | servletInputStream : ServletInputStream | XMLDecoderTests.java:17:33:17:66 | new XMLDecoder(...) : XMLDecoder | provenance | MaD:4 | +| XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XPathExpressionTests.java:27:35:27:55 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:19:27:56 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | +| XPathExpressionTests.java:42:39:42:59 | getInputStream(...) : InputStream | XPathExpressionTests.java:42:23:42:60 | new InputSource(...) | provenance | Src:MaD:2 MaD:14 | models -| 1 | Source: java.net; Socket; false; getInputStream; (); ; ReturnValue; remote; manual | -| 2 | Source: javax.servlet; ServletRequest; false; getInputStream; (); ; ReturnValue; remote; manual | -| 3 | Summary: java.beans; XMLDecoder; false; XMLDecoder; ; ; Argument[0]; Argument[this]; taint; manual | -| 4 | Summary: java.io; InputStream; true; read; (byte[]); ; Argument[this]; Argument[0]; taint; manual | -| 5 | Summary: java.io; InputStreamReader; false; InputStreamReader; ; ; Argument[0]; Argument[this]; taint; manual | -| 6 | Summary: java.lang; String; false; String; ; ; Argument[0]; Argument[this]; taint; manual | -| 7 | Summary: javax.xml.transform.sax; SAXSource; false; SAXSource; (InputSource); ; Argument[0]; Argument[this]; taint; manual | -| 8 | Summary: javax.xml.transform.sax; SAXSource; false; SAXSource; (XMLReader,InputSource); ; Argument[1]; Argument[this]; taint; manual | -| 9 | Summary: javax.xml.transform.sax; SAXSource; false; getInputSource; ; ; Argument[this]; ReturnValue; taint; manual | -| 10 | Summary: javax.xml.transform.sax; SAXSource; false; sourceToInputSource; ; ; Argument[0]; ReturnValue; taint; manual | -| 11 | Summary: javax.xml.transform.stream; StreamSource; false; StreamSource; ; ; Argument[0]; Argument[this]; taint; manual | -| 12 | Summary: javax.xml.transform.stream; StreamSource; false; getInputStream; ; ; Argument[this]; ReturnValue; taint; manual | -| 13 | Summary: org.xml.sax; InputSource; false; InputSource; ; ; Argument[0]; Argument[this]; taint; manual | +| 1 | Sink: java.beans; XMLDecoder; true; readObject; (); ; Argument[this]; unsafe-deserialization; manual | +| 2 | Source: java.net; Socket; false; getInputStream; (); ; ReturnValue; remote; manual | +| 3 | Source: javax.servlet; ServletRequest; false; getInputStream; (); ; ReturnValue; remote; manual | +| 4 | Summary: java.beans; XMLDecoder; false; XMLDecoder; ; ; Argument[0]; Argument[this]; taint; manual | +| 5 | Summary: java.io; InputStream; true; read; (byte[]); ; Argument[this]; Argument[0]; taint; manual | +| 6 | Summary: java.io; InputStreamReader; false; InputStreamReader; ; ; Argument[0]; Argument[this]; taint; manual | +| 7 | Summary: java.lang; String; false; String; ; ; Argument[0]; Argument[this]; taint; manual | +| 8 | Summary: javax.xml.transform.sax; SAXSource; false; SAXSource; (InputSource); ; Argument[0]; Argument[this]; taint; manual | +| 9 | Summary: javax.xml.transform.sax; SAXSource; false; SAXSource; (XMLReader,InputSource); ; Argument[1]; Argument[this]; taint; manual | +| 10 | Summary: javax.xml.transform.sax; SAXSource; false; getInputSource; ; ; Argument[this]; ReturnValue; taint; manual | +| 11 | Summary: javax.xml.transform.sax; SAXSource; false; sourceToInputSource; ; ; Argument[0]; ReturnValue; taint; manual | +| 12 | Summary: javax.xml.transform.stream; StreamSource; false; StreamSource; ; ; Argument[0]; Argument[this]; taint; manual | +| 13 | Summary: javax.xml.transform.stream; StreamSource; false; getInputStream; ; ; Argument[this]; ReturnValue; taint; manual | +| 14 | Summary: org.xml.sax; InputSource; false; InputSource; ; ; Argument[0]; Argument[this]; taint; manual | nodes | CdaUtilTests.java:10:26:10:46 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | CdaUtilTests.java:11:28:11:69 | new InputSource(...) : InputSource | semmle.label | new InputSource(...) : InputSource | From 87deab861fc6c6f09a1b8af1cdac3b8dd9d51ce7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:23:50 +0100 Subject: [PATCH 108/311] Rust: Remove Sqlx.qll. --- rust/ql/lib/codeql/rust/Frameworks.qll | 1 - rust/ql/lib/codeql/rust/frameworks/Sqlx.qll | 44 --------- .../security/CWE-089/SqlInjection.expected | 90 ++----------------- .../security/CWE-089/SqlSinks.expected | 39 ++++++++ 4 files changed, 45 insertions(+), 129 deletions(-) delete mode 100644 rust/ql/lib/codeql/rust/frameworks/Sqlx.qll diff --git a/rust/ql/lib/codeql/rust/Frameworks.qll b/rust/ql/lib/codeql/rust/Frameworks.qll index 0e91ed427ba4..317746f2d186 100644 --- a/rust/ql/lib/codeql/rust/Frameworks.qll +++ b/rust/ql/lib/codeql/rust/Frameworks.qll @@ -4,6 +4,5 @@ private import codeql.rust.frameworks.rustcrypto.RustCrypto private import codeql.rust.frameworks.Poem -private import codeql.rust.frameworks.Sqlx private import codeql.rust.frameworks.stdlib.Clone private import codeql.rust.frameworks.stdlib.Stdlib diff --git a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll deleted file mode 100644 index 5b33f72fdf68..000000000000 --- a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Provides modeling for the `SQLx` library. - */ - -private import rust -private import codeql.rust.Concepts -private import codeql.rust.dataflow.DataFlow -private import codeql.rust.internal.TypeInference -private import codeql.rust.internal.Type - -/** - * A call to `sqlx::query` and variations. - */ -private class SqlxQuery extends SqlConstruction::Range { - CallExpr call; - - SqlxQuery() { - this.asExpr().getExpr() = call and - call.getStaticTarget().(Addressable).getCanonicalPath() = - [ - "sqlx_core::query::query", "sqlx_core::query_as::query_as", - "sqlx_core::query_with::query_with", "sqlx_core::query_as_with::query_as_with", - "sqlx_core::query_scalar::query_scalar", "sqlx_core::query_scalar_with::query_scalar_with", - "sqlx_core::raw_sql::raw_sql" - ] - } - - override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } -} - -/** - * A call to `sqlx::Executor::execute`. - */ -private class SqlxExecute extends SqlExecution::Range { - MethodCallExpr call; - - SqlxExecute() { - this.asExpr().getExpr() = call and - call.getStaticTarget().(Addressable).getCanonicalPath() = - "sqlx_core::executor::Executor::execute" - } - - override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } -} diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index eea48df8d5b0..1570cd211c8f 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,88 +1,10 @@ #select -| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | -| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | edges -| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | | -| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:2 | -| sqlx.rs:47:22:47:37 | ...::args(...) [element] | sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | provenance | MaD:3 | -| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | provenance | MaD:5 | -| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | sqlx.rs:47:9:47:18 | arg_string | provenance | | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:9 | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:9 | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | | -| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:1 | -| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:6 | -| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:10 | -| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:7 | -| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | | -| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | -| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:7 | -| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:4 | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | -| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | -| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | -| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:11 | -| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:12 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:8 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:4 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:8 | -| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | -| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:8 | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:4 | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:8 | -| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | -| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:4 | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -models -| 1 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 2 | Source: std::env::args; ReturnValue.Element; commandargs | -| 3 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | -| 4 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 5 | Summary: ::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | -| 6 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 7 | Summary: ::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 8 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 9 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 10 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 11 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | -| 12 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | nodes -| sqlx.rs:47:9:47:18 | arg_string | semmle.label | arg_string | -| sqlx.rs:47:22:47:35 | ...::args | semmle.label | ...::args | -| sqlx.rs:47:22:47:37 | ...::args(...) [element] | semmle.label | ...::args(...) [element] | -| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] | -| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:48:9:48:21 | remote_string | semmle.label | remote_string | -| sqlx.rs:48:25:48:46 | ...::get | semmle.label | ...::get | -| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | semmle.label | ...::get(...) [Ok] | -| sqlx.rs:48:25:48:78 | ... .unwrap() | semmle.label | ... .unwrap() | -| sqlx.rs:48:25:48:85 | ... .text() [Ok] | semmle.label | ... .text() [Ok] | -| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number | -| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | semmle.label | remote_string.parse() [Ok] | -| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 | -| sqlx.rs:52:24:52:88 | res | semmle.label | res | -| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) | -| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr | -| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | semmle.label | unsafe_query_1 [&ref] | -| sqlx.rs:53:26:53:36 | &arg_string [&ref] | semmle.label | &arg_string [&ref] | -| sqlx.rs:53:27:53:36 | arg_string | semmle.label | arg_string | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] | -| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] | -| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string | -| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 | -| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | -| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | -| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | subpaths +testFailures +| sqlx.rs:47:80:47:96 | //... | Missing result: Source=args1 | +| sqlx.rs:48:121:48:139 | //... | Missing result: Source=remote1 | +| sqlx.rs:77:71:77:129 | //... | Fixed spurious result: Alert[rust/sql-injection]=remote1 | +| sqlx.rs:78:73:78:117 | //... | Missing result: Alert[rust/sql-injection]=args1 | +| sqlx.rs:80:77:80:123 | //... | Missing result: Alert[rust/sql-injection]=remote1 | diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected index e69de29bb2d1..9c3ebb3fe83a 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected @@ -0,0 +1,39 @@ +| sqlx.rs:75:71:75:83 | //... | Missing result: sql-sink | +| sqlx.rs:76:71:76:83 | //... | Missing result: sql-sink | +| sqlx.rs:77:71:77:129 | //... | Missing result: sql-sink | +| sqlx.rs:78:73:78:117 | //... | Missing result: sql-sink | +| sqlx.rs:80:77:80:123 | //... | Missing result: sql-sink | +| sqlx.rs:81:77:81:132 | //... | Missing result: sql-sink | +| sqlx.rs:82:77:82:132 | //... | Missing result: sql-sink | +| sqlx.rs:84:94:84:106 | //... | Missing result: sql-sink | +| sqlx.rs:85:92:85:104 | //... | Missing result: sql-sink | +| sqlx.rs:87:99:87:111 | //... | Missing result: sql-sink | +| sqlx.rs:88:99:88:111 | //... | Missing result: sql-sink | +| sqlx.rs:111:77:111:89 | //... | Missing result: sql-sink | +| sqlx.rs:113:83:113:138 | //... | Missing result: sql-sink | +| sqlx.rs:117:75:117:87 | //... | Missing result: sql-sink | +| sqlx.rs:118:99:118:111 | //... | Missing result: sql-sink | +| sqlx.rs:120:81:120:136 | //... | Missing result: sql-sink | +| sqlx.rs:121:104:121:116 | //... | Missing result: sql-sink | +| sqlx.rs:124:66:124:78 | //... | Missing result: sql-sink | +| sqlx.rs:125:90:125:102 | //... | Missing result: sql-sink | +| sqlx.rs:127:72:127:127 | //... | Missing result: sql-sink | +| sqlx.rs:128:95:128:107 | //... | Missing result: sql-sink | +| sqlx.rs:131:106:131:118 | //... | Missing result: sql-sink | +| sqlx.rs:133:130:133:142 | //... | Missing result: sql-sink | +| sqlx.rs:136:109:136:164 | //... | Missing result: sql-sink | +| sqlx.rs:137:132:137:144 | //... | Missing result: sql-sink | +| sqlx.rs:140:129:140:141 | //... | Missing result: sql-sink | +| sqlx.rs:142:153:142:165 | //... | Missing result: sql-sink | +| sqlx.rs:145:132:145:189 | //... | Missing result: sql-sink | +| sqlx.rs:146:155:146:167 | //... | Missing result: sql-sink | +| sqlx.rs:149:77:149:89 | //... | Missing result: sql-sink | +| sqlx.rs:150:101:150:113 | //... | Missing result: sql-sink | +| sqlx.rs:151:116:151:128 | //... | Missing result: sql-sink | +| sqlx.rs:153:83:153:138 | //... | Missing result: sql-sink | +| sqlx.rs:154:106:154:118 | //... | Missing result: sql-sink | +| sqlx.rs:155:121:155:133 | //... | Missing result: sql-sink | +| sqlx.rs:185:71:185:83 | //... | Missing result: sql-sink | +| sqlx.rs:186:95:186:107 | //... | Missing result: sql-sink | +| sqlx.rs:188:77:188:132 | //... | Missing result: sql-sink | +| sqlx.rs:189:100:189:112 | //... | Missing result: sql-sink | From 62b7d84638056b101dac70534d0da8211c1cea37 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:36:42 +0100 Subject: [PATCH 109/311] Rust: Add Sqlx as MaD sinks instead. --- .../lib/codeql/rust/frameworks/sqlx.model.yml | 13 +++ .../security/CWE-089/SqlInjection.expected | 99 +++++++++++++++++-- .../security/CWE-089/SqlSinks.expected | 39 -------- 3 files changed, 106 insertions(+), 45 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml diff --git a/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml new file mode 100644 index 000000000000..b3ca9d89299e --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml @@ -0,0 +1,13 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: sinkModel + data: + - ["sqlx_core::query::query", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_as::query_as", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_with::query_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_as_with::query_as_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_scalar::query_scalar", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_scalar_with::query_scalar_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::raw_sql::raw_sql", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::executor::Executor::execute", "Argument[0]", "sql-injection", "manual"] diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index 1570cd211c8f..cc00a44d9fc4 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,10 +1,97 @@ #select +| sqlx.rs:77:13:77:23 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:13:77:23 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | +| sqlx.rs:78:13:78:23 | ...::query | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:13:78:23 | ...::query | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | +| sqlx.rs:80:17:80:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:17:80:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | edges +| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | | +| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:3 | +| sqlx.rs:47:22:47:37 | ...::args(...) [element] | sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | provenance | MaD:4 | +| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | provenance | MaD:6 | +| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | sqlx.rs:47:9:47:18 | arg_string | provenance | | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | | +| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:2 | +| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:7 | +| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:11 | +| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:8 | +| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | | +| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | +| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:8 | +| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:9 | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:5 | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:9 | +| sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | +| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | +| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | +| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:12 | +| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:13 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | +| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | +| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:1 Sink:MaD:1 | +models +| 1 | Sink: sqlx_core::query::query; Argument[0]; sql-injection | +| 2 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 3 | Source: std::env::args; ReturnValue.Element; commandargs | +| 4 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | +| 5 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 6 | Summary: ::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | +| 7 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 8 | Summary: ::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 9 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 10 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 11 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 12 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 13 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | nodes +| sqlx.rs:47:9:47:18 | arg_string | semmle.label | arg_string | +| sqlx.rs:47:22:47:35 | ...::args | semmle.label | ...::args | +| sqlx.rs:47:22:47:37 | ...::args(...) [element] | semmle.label | ...::args(...) [element] | +| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] | +| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:48:9:48:21 | remote_string | semmle.label | remote_string | +| sqlx.rs:48:25:48:46 | ...::get | semmle.label | ...::get | +| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | semmle.label | ...::get(...) [Ok] | +| sqlx.rs:48:25:48:78 | ... .unwrap() | semmle.label | ... .unwrap() | +| sqlx.rs:48:25:48:85 | ... .text() [Ok] | semmle.label | ... .text() [Ok] | +| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number | +| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | semmle.label | remote_string.parse() [Ok] | +| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 | +| sqlx.rs:52:24:52:88 | res | semmle.label | res | +| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) | +| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr | +| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | semmle.label | unsafe_query_1 [&ref] | +| sqlx.rs:53:26:53:36 | &arg_string [&ref] | semmle.label | &arg_string [&ref] | +| sqlx.rs:53:27:53:36 | arg_string | semmle.label | arg_string | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] | +| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] | +| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string | +| sqlx.rs:77:13:77:23 | ...::query | semmle.label | ...::query | +| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | semmle.label | safe_query_3.as_str() [&ref] | +| sqlx.rs:78:13:78:23 | ...::query | semmle.label | ...::query | +| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | semmle.label | unsafe_query_1.as_str() [&ref] | +| sqlx.rs:80:17:80:27 | ...::query | semmle.label | ...::query | +| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | semmle.label | unsafe_query_2.as_str() [&ref] | subpaths -testFailures -| sqlx.rs:47:80:47:96 | //... | Missing result: Source=args1 | -| sqlx.rs:48:121:48:139 | //... | Missing result: Source=remote1 | -| sqlx.rs:77:71:77:129 | //... | Fixed spurious result: Alert[rust/sql-injection]=remote1 | -| sqlx.rs:78:73:78:117 | //... | Missing result: Alert[rust/sql-injection]=args1 | -| sqlx.rs:80:77:80:123 | //... | Missing result: Alert[rust/sql-injection]=remote1 | diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected index 9c3ebb3fe83a..e69de29bb2d1 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected @@ -1,39 +0,0 @@ -| sqlx.rs:75:71:75:83 | //... | Missing result: sql-sink | -| sqlx.rs:76:71:76:83 | //... | Missing result: sql-sink | -| sqlx.rs:77:71:77:129 | //... | Missing result: sql-sink | -| sqlx.rs:78:73:78:117 | //... | Missing result: sql-sink | -| sqlx.rs:80:77:80:123 | //... | Missing result: sql-sink | -| sqlx.rs:81:77:81:132 | //... | Missing result: sql-sink | -| sqlx.rs:82:77:82:132 | //... | Missing result: sql-sink | -| sqlx.rs:84:94:84:106 | //... | Missing result: sql-sink | -| sqlx.rs:85:92:85:104 | //... | Missing result: sql-sink | -| sqlx.rs:87:99:87:111 | //... | Missing result: sql-sink | -| sqlx.rs:88:99:88:111 | //... | Missing result: sql-sink | -| sqlx.rs:111:77:111:89 | //... | Missing result: sql-sink | -| sqlx.rs:113:83:113:138 | //... | Missing result: sql-sink | -| sqlx.rs:117:75:117:87 | //... | Missing result: sql-sink | -| sqlx.rs:118:99:118:111 | //... | Missing result: sql-sink | -| sqlx.rs:120:81:120:136 | //... | Missing result: sql-sink | -| sqlx.rs:121:104:121:116 | //... | Missing result: sql-sink | -| sqlx.rs:124:66:124:78 | //... | Missing result: sql-sink | -| sqlx.rs:125:90:125:102 | //... | Missing result: sql-sink | -| sqlx.rs:127:72:127:127 | //... | Missing result: sql-sink | -| sqlx.rs:128:95:128:107 | //... | Missing result: sql-sink | -| sqlx.rs:131:106:131:118 | //... | Missing result: sql-sink | -| sqlx.rs:133:130:133:142 | //... | Missing result: sql-sink | -| sqlx.rs:136:109:136:164 | //... | Missing result: sql-sink | -| sqlx.rs:137:132:137:144 | //... | Missing result: sql-sink | -| sqlx.rs:140:129:140:141 | //... | Missing result: sql-sink | -| sqlx.rs:142:153:142:165 | //... | Missing result: sql-sink | -| sqlx.rs:145:132:145:189 | //... | Missing result: sql-sink | -| sqlx.rs:146:155:146:167 | //... | Missing result: sql-sink | -| sqlx.rs:149:77:149:89 | //... | Missing result: sql-sink | -| sqlx.rs:150:101:150:113 | //... | Missing result: sql-sink | -| sqlx.rs:151:116:151:128 | //... | Missing result: sql-sink | -| sqlx.rs:153:83:153:138 | //... | Missing result: sql-sink | -| sqlx.rs:154:106:154:118 | //... | Missing result: sql-sink | -| sqlx.rs:155:121:155:133 | //... | Missing result: sql-sink | -| sqlx.rs:185:71:185:83 | //... | Missing result: sql-sink | -| sqlx.rs:186:95:186:107 | //... | Missing result: sql-sink | -| sqlx.rs:188:77:188:132 | //... | Missing result: sql-sink | -| sqlx.rs:189:100:189:112 | //... | Missing result: sql-sink | From f319381f277cd3469298f0e66077cde55fef47b7 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 17:53:55 +0200 Subject: [PATCH 110/311] C++: Support the spaceship operator in the IR --- .../code/cpp/ir/implementation/Opcode.qll | 10 +++ .../aliased_ssa/Instruction.qll | 7 +++ .../cpp/ir/implementation/raw/Instruction.qll | 7 +++ .../raw/internal/TranslatedExpr.qll | 8 ++- .../unaliased_ssa/Instruction.qll | 7 +++ .../library-tests/ir/ir/aliased_ir.expected | 63 ++++++++++++++----- .../ir/ir/aliased_ssa_consistency.expected | 2 - .../aliased_ssa_consistency_unsound.expected | 2 - .../ir/ir/raw_consistency.expected | 8 --- .../test/library-tests/ir/ir/raw_ir.expected | 54 ++++++++-------- .../ir/ir/unaliased_ssa_consistency.expected | 2 - ...unaliased_ssa_consistency_unsound.expected | 2 - 12 files changed, 110 insertions(+), 62 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index 90afabca30de..d8c1c6115c80 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -42,6 +42,7 @@ private newtype TOpcode = TCompareGT() or TCompareLE() or TCompareGE() or + TSpaceship() or TPointerAdd() or TPointerSub() or TPointerDiff() or @@ -765,6 +766,15 @@ module Opcode { final override string toString() { result = "CompareGE" } } + /** + * The `Opcode` for a `SpaceshipInstruction`. + * + * See the `SpaceshipInstruction` documentation for more details. + */ + class Spaceship extends BinaryOpcode, TSpaceship { + final override string toString() { result = "Spaceship" } + } + /** * The `Opcode` for a `PointerAddInstruction`. * diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index d5332cecf85a..f766185db86a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that represents a three-way comparison operator. + */ +class CompareThreeWayInstruction extends BinaryInstruction { + CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +} + /** * An instruction that branches to one of multiple successor instructions based on the value of an * integer operand. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index d5332cecf85a..f766185db86a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that represents a three-way comparison operator. + */ +class CompareThreeWayInstruction extends BinaryInstruction { + CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +} + /** * An instruction that branches to one of multiple successor instructions based on the value of an * integer operand. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 2aa5eeebb6b7..a7e85fe9b1a5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1808,6 +1808,11 @@ private Opcode comparisonOpcode(ComparisonOperation expr) { expr instanceof GEExpr and result instanceof Opcode::CompareGE } +private Opcode spaceShipOpcode(SpaceshipExpr expr) { + exists(expr) and + result instanceof Opcode::Spaceship +} + /** * IR translation of a simple binary operation. */ @@ -1867,7 +1872,8 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { override Opcode getOpcode() { result = binaryArithmeticOpcode(expr) or result = binaryBitwiseOpcode(expr) or - result = comparisonOpcode(expr) + result = comparisonOpcode(expr) or + result = spaceShipOpcode(expr) } override Type getExprType() { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index d5332cecf85a..f766185db86a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1604,6 +1604,13 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that represents a three-way comparison operator. + */ +class CompareThreeWayInstruction extends BinaryInstruction { + CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +} + /** * An instruction that branches to one of multiple successor instructions based on the value of an * integer operand. diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 51baf8a73f28..6d58656b55ff 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20336,26 +20336,55 @@ ir.cpp: # 2766| r2766_20(glval) = CopyValue : r2766_19 # 2766| r2766_21(glval) = FieldAddress[x] : r2766_20 # 2766| r2766_22(int) = Load[?] : &:r2766_21, ~m2766_12 +# 2766| r2766_23(strong_ordering) = Spaceship : r2766_17, r2766_22 +# 2766| m2766_24(strong_ordering) = Store[#return] : &:r2766_13, r2766_23 +# 2766| v2766_25(void) = ReturnIndirection[#this] : &:r2766_7, m2766_8 +# 2766| v2766_26(void) = ReturnIndirection[y] : &:r2766_11, m2766_12 +# 2766| r2766_27(glval) = VariableAddress[#return] : +# 2766| v2766_28(void) = ReturnValue : &:r2766_27, m2766_24 +# 2766| v2766_29(void) = AliasedUse : m2766_3 +# 2766| v2766_30(void) = ExitFunction : # 2769| void test_three_way(int, int, ThreeWay, ThreeWay) # 2769| Block 0 -# 2769| v2769_1(void) = EnterFunction : -# 2769| m2769_2(unknown) = AliasedDefinition : -# 2769| m2769_3(unknown) = InitializeNonLocal : -# 2769| m2769_4(unknown) = Chi : total:m2769_2, partial:m2769_3 -# 2769| r2769_5(glval) = VariableAddress[a] : -# 2769| m2769_6(int) = InitializeParameter[a] : &:r2769_5 -# 2769| r2769_7(glval) = VariableAddress[b] : -# 2769| m2769_8(int) = InitializeParameter[b] : &:r2769_7 -# 2769| r2769_9(glval) = VariableAddress[c] : -# 2769| m2769_10(ThreeWay) = InitializeParameter[c] : &:r2769_9 -# 2769| r2769_11(glval) = VariableAddress[d] : -# 2769| m2769_12(ThreeWay) = InitializeParameter[d] : &:r2769_11 -# 2770| r2770_1(glval) = VariableAddress[x] : -# 2770| r2770_2(glval) = VariableAddress[a] : -# 2770| r2770_3(int) = Load[a] : &:r2770_2, m2769_6 -# 2770| r2770_4(glval) = VariableAddress[b] : -# 2770| r2770_5(int) = Load[b] : &:r2770_4, m2769_8 +# 2769| v2769_1(void) = EnterFunction : +# 2769| m2769_2(unknown) = AliasedDefinition : +# 2769| m2769_3(unknown) = InitializeNonLocal : +# 2769| m2769_4(unknown) = Chi : total:m2769_2, partial:m2769_3 +# 2769| r2769_5(glval) = VariableAddress[a] : +# 2769| m2769_6(int) = InitializeParameter[a] : &:r2769_5 +# 2769| r2769_7(glval) = VariableAddress[b] : +# 2769| m2769_8(int) = InitializeParameter[b] : &:r2769_7 +# 2769| r2769_9(glval) = VariableAddress[c] : +# 2769| m2769_10(ThreeWay) = InitializeParameter[c] : &:r2769_9 +# 2769| r2769_11(glval) = VariableAddress[d] : +# 2769| m2769_12(ThreeWay) = InitializeParameter[d] : &:r2769_11 +# 2770| r2770_1(glval) = VariableAddress[x] : +# 2770| r2770_2(glval) = VariableAddress[a] : +# 2770| r2770_3(int) = Load[a] : &:r2770_2, m2769_6 +# 2770| r2770_4(glval) = VariableAddress[b] : +# 2770| r2770_5(int) = Load[b] : &:r2770_4, m2769_8 +# 2770| r2770_6(strong_ordering) = Spaceship : r2770_3, r2770_5 +# 2770| m2770_7(strong_ordering) = Store[x] : &:r2770_1, r2770_6 +# 2771| r2771_1(glval) = VariableAddress[y] : +# 2771| r2771_2(glval) = VariableAddress[c] : +# 2771| r2771_3(glval) = FunctionAddress[operator<=>] : +# 2771| r2771_4(glval) = VariableAddress[d] : +# 2771| r2771_5(ThreeWay &) = CopyValue : r2771_4 +# 2771| r2771_6(strong_ordering) = Call[operator<=>] : func:r2771_3, this:r2771_2, 0:r2771_5 +# 2771| m2771_7(unknown) = ^CallSideEffect : ~m2769_4 +# 2771| m2771_8(unknown) = Chi : total:m2769_4, partial:m2771_7 +# 2771| v2771_9(void) = ^IndirectReadSideEffect[-1] : &:r2771_2, m2769_10 +# 2771| v2771_10(void) = ^BufferReadSideEffect[0] : &:r2771_5, ~m2769_12 +# 2771| m2771_11(ThreeWay) = ^IndirectMayWriteSideEffect[-1] : &:r2771_2 +# 2771| m2771_12(ThreeWay) = Chi : total:m2769_10, partial:m2771_11 +# 2771| m2771_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r2771_5 +# 2771| m2771_14(ThreeWay) = Chi : total:m2769_12, partial:m2771_13 +# 2771| m2771_15(strong_ordering) = Store[y] : &:r2771_1, r2771_6 +# 2772| v2772_1(void) = NoOp : +# 2769| v2769_13(void) = ReturnVoid : +# 2769| v2769_14(void) = AliasedUse : ~m2771_8 +# 2769| v2769_15(void) = ExitFunction : ir23.cpp: # 1| bool consteval_1() diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index d8abe2017336..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -6,8 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index d8abe2017336..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -6,8 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 949580140850..e30106d35204 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,6 +1,4 @@ missingOperand -| ir.cpp:2766:58:2766:72 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:12:2770:18 | Store: ... <=> ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | unexpectedOperand duplicateOperand missingPhiOperand @@ -8,8 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -25,10 +21,6 @@ lostReachability backEdgeCountMismatch useNotDominatedByDefinition | ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | -| ir.cpp:2766:24:2766:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2766:46:2766:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2766:51:2766:73 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:8:2770:8 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 436c59a32005..8cdb5e8c351f 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18492,37 +18492,35 @@ ir.cpp: # 2766| r2766_19(glval) = CopyValue : r2766_18 # 2766| r2766_20(glval) = FieldAddress[x] : r2766_19 # 2766| r2766_21(int) = Load[?] : &:r2766_20, ~m? - -# 2766| Block 1 -# 2766| mu2766_22(strong_ordering) = Store[#return] : &:r2766_12 -# 2766| v2766_23(void) = ReturnIndirection[#this] : &:r2766_6, ~m? -# 2766| v2766_24(void) = ReturnIndirection[y] : &:r2766_10, ~m? -# 2766| r2766_25(glval) = VariableAddress[#return] : -# 2766| v2766_26(void) = ReturnValue : &:r2766_25, ~m? -# 2766| v2766_27(void) = AliasedUse : ~m? -# 2766| v2766_28(void) = ExitFunction : +# 2766| r2766_22(strong_ordering) = Spaceship : r2766_16, r2766_21 +# 2766| mu2766_23(strong_ordering) = Store[#return] : &:r2766_12, r2766_22 +# 2766| v2766_24(void) = ReturnIndirection[#this] : &:r2766_6, ~m? +# 2766| v2766_25(void) = ReturnIndirection[y] : &:r2766_10, ~m? +# 2766| r2766_26(glval) = VariableAddress[#return] : +# 2766| v2766_27(void) = ReturnValue : &:r2766_26, ~m? +# 2766| v2766_28(void) = AliasedUse : ~m? +# 2766| v2766_29(void) = ExitFunction : # 2769| void test_three_way(int, int, ThreeWay, ThreeWay) # 2769| Block 0 -# 2769| v2769_1(void) = EnterFunction : -# 2769| mu2769_2(unknown) = AliasedDefinition : -# 2769| mu2769_3(unknown) = InitializeNonLocal : -# 2769| r2769_4(glval) = VariableAddress[a] : -# 2769| mu2769_5(int) = InitializeParameter[a] : &:r2769_4 -# 2769| r2769_6(glval) = VariableAddress[b] : -# 2769| mu2769_7(int) = InitializeParameter[b] : &:r2769_6 -# 2769| r2769_8(glval) = VariableAddress[c] : -# 2769| mu2769_9(ThreeWay) = InitializeParameter[c] : &:r2769_8 -# 2769| r2769_10(glval) = VariableAddress[d] : -# 2769| mu2769_11(ThreeWay) = InitializeParameter[d] : &:r2769_10 -# 2770| r2770_1(glval) = VariableAddress[x] : -# 2770| r2770_2(glval) = VariableAddress[a] : -# 2770| r2770_3(int) = Load[a] : &:r2770_2, ~m? -# 2770| r2770_4(glval) = VariableAddress[b] : -# 2770| r2770_5(int) = Load[b] : &:r2770_4, ~m? - -# 2770| Block 1 -# 2770| mu2770_6(strong_ordering) = Store[x] : &:r2770_1 +# 2769| v2769_1(void) = EnterFunction : +# 2769| mu2769_2(unknown) = AliasedDefinition : +# 2769| mu2769_3(unknown) = InitializeNonLocal : +# 2769| r2769_4(glval) = VariableAddress[a] : +# 2769| mu2769_5(int) = InitializeParameter[a] : &:r2769_4 +# 2769| r2769_6(glval) = VariableAddress[b] : +# 2769| mu2769_7(int) = InitializeParameter[b] : &:r2769_6 +# 2769| r2769_8(glval) = VariableAddress[c] : +# 2769| mu2769_9(ThreeWay) = InitializeParameter[c] : &:r2769_8 +# 2769| r2769_10(glval) = VariableAddress[d] : +# 2769| mu2769_11(ThreeWay) = InitializeParameter[d] : &:r2769_10 +# 2770| r2770_1(glval) = VariableAddress[x] : +# 2770| r2770_2(glval) = VariableAddress[a] : +# 2770| r2770_3(int) = Load[a] : &:r2770_2, ~m? +# 2770| r2770_4(glval) = VariableAddress[b] : +# 2770| r2770_5(int) = Load[b] : &:r2770_4, ~m? +# 2770| r2770_6(strong_ordering) = Spaceship : r2770_3, r2770_5 +# 2770| mu2770_7(strong_ordering) = Store[x] : &:r2770_1, r2770_6 # 2771| r2771_1(glval) = VariableAddress[y] : # 2771| r2771_2(glval) = VariableAddress[c] : # 2771| r2771_3(glval) = FunctionAddress[operator<=>] : diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index d8abe2017336..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -6,8 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index d8abe2017336..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -6,8 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2766:72:2766:72 | Load: x | Instruction 'Load: x' has no successors in function '$@'. | ir.cpp:2766:24:2766:34 | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | std::strong_ordering ThreeWay::operator<=>(ThreeWay&) | -| ir.cpp:2770:18:2770:18 | Load: b | Instruction 'Load: b' has no successors in function '$@'. | ir.cpp:2769:6:2769:19 | void test_three_way(int, int, ThreeWay, ThreeWay) | void test_three_way(int, int, ThreeWay, ThreeWay) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 29a6af4efd18763a24b795b0ae1598814402a061 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Jul 2025 18:11:17 +0200 Subject: [PATCH 111/311] C++: Fix instruction class name --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 4 ++-- .../lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index f766185db86a..a564508e16b4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1607,8 +1607,8 @@ class CompareGEInstruction extends RelationalInstruction { /** * An instruction that represents a three-way comparison operator. */ -class CompareThreeWayInstruction extends BinaryInstruction { - CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +class SpaceshipInstruction extends BinaryInstruction { + SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index f766185db86a..a564508e16b4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1607,8 +1607,8 @@ class CompareGEInstruction extends RelationalInstruction { /** * An instruction that represents a three-way comparison operator. */ -class CompareThreeWayInstruction extends BinaryInstruction { - CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +class SpaceshipInstruction extends BinaryInstruction { + SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index f766185db86a..a564508e16b4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1607,8 +1607,8 @@ class CompareGEInstruction extends RelationalInstruction { /** * An instruction that represents a three-way comparison operator. */ -class CompareThreeWayInstruction extends BinaryInstruction { - CompareThreeWayInstruction() { this.getOpcode() instanceof Opcode::Spaceship } +class SpaceshipInstruction extends BinaryInstruction { + SpaceshipInstruction() { this.getOpcode() instanceof Opcode::Spaceship } } /** From 680e31dc48f1486f1e32a840f98128309fa3b377 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Thu, 17 Jul 2025 10:02:00 +0100 Subject: [PATCH 112/311] Modernize raise-not-implemented --- python/ql/src/Exceptions/NotImplemented.qll | 2 ++ .../NotImplementedIsNotAnException.qhelp | 19 ++++++++++--------- .../NotImplementedIsNotAnException.ql | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/python/ql/src/Exceptions/NotImplemented.qll b/python/ql/src/Exceptions/NotImplemented.qll index 2186a7b5f30b..184b7429a9f5 100644 --- a/python/ql/src/Exceptions/NotImplemented.qll +++ b/python/ql/src/Exceptions/NotImplemented.qll @@ -1,3 +1,5 @@ +deprecated module; + import python /** Holds if `notimpl` refers to `NotImplemented` or `NotImplemented()` in the `raise` statement */ diff --git a/python/ql/src/Exceptions/NotImplementedIsNotAnException.qhelp b/python/ql/src/Exceptions/NotImplementedIsNotAnException.qhelp index 3bf09bbfab07..c89a8806dea6 100644 --- a/python/ql/src/Exceptions/NotImplementedIsNotAnException.qhelp +++ b/python/ql/src/Exceptions/NotImplementedIsNotAnException.qhelp @@ -4,25 +4,25 @@ -

    NotImplemented is not an Exception, but is often mistakenly used in place of NotImplementedError. -Executing raise NotImplemented or raise NotImplemented() will raise a TypeError. -When raise NotImplemented is used to mark code that is genuinely never called, this mistake is benign. - -However, should it be called, then a TypeError will be raised rather than the expected NotImplemented, -which might make debugging the issue difficult. +

    +The constant NotImplemented is not an Exception, but is often confused for NotImplementedError. +If it is used as an exception, such as in raise NotImplemented or raise NotImplemented("message"), +a TypeError will be raised rather than the expected NotImplemented. This may make debugging more difficult.

    -

    The correct use of NotImplemented is to implement binary operators. +

    NotImplemented should only be used as a special return value for implementing special methods such as __lt__. Code that is not intended to be called should raise NotImplementedError.

    -

    Replace uses of NotImplemented with NotImplementedError.

    +

    If a NotImplementedError is intended to be raised, replace the use of NotImplemented +with that. If NotImplemented is intended to be returned rather than raised, replace the raise with return NotImplemented +

    -In the example below, the method wrong will incorrectly raise a TypeError when called. +In the following example, the method wrong will incorrectly raise a TypeError when called. The method right will raise a NotImplementedError.

    @@ -34,6 +34,7 @@ The method right will raise a NotImplementedError.
  • Python Language Reference: The NotImplementedError exception.
  • +
  • Python Language Reference: The NotImplemented constant.
  • Python Language Reference: Emulating numeric types.
  • diff --git a/python/ql/src/Exceptions/NotImplementedIsNotAnException.ql b/python/ql/src/Exceptions/NotImplementedIsNotAnException.ql index 80dcd6f0dbea..36bf992b51a7 100644 --- a/python/ql/src/Exceptions/NotImplementedIsNotAnException.ql +++ b/python/ql/src/Exceptions/NotImplementedIsNotAnException.ql @@ -1,6 +1,6 @@ /** - * @name NotImplemented is not an Exception - * @description Using 'NotImplemented' as an exception will result in a type error. + * @name Raising `NotImplemented` + * @description Using `NotImplemented` as an exception will result in a type error. * @kind problem * @problem.severity warning * @sub-severity high @@ -12,8 +12,17 @@ */ import python -import Exceptions.NotImplemented +import semmle.python.ApiGraphs + +predicate raiseNotImplemented(Raise raise, Expr notImpl) { + exists(API::Node n | n = API::builtin("NotImplemented") | + notImpl = n.getACall().asExpr() + or + n.asSource().flowsTo(DataFlow::exprNode(notImpl)) + ) and + notImpl = raise.getException() +} from Expr notimpl -where use_of_not_implemented_in_raise(_, notimpl) +where raiseNotImplemented(_, notimpl) select notimpl, "NotImplemented is not an Exception. Did you mean NotImplementedError?" From fbe79e8a52c86f538e9d1c0f22df24f9cff93617 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 19 Jun 2025 11:05:03 +0200 Subject: [PATCH 113/311] Java: Add AnnotatedExitNodes to the CFG. --- .../lib/semmle/code/java/ControlFlowGraph.qll | 44 ++++++++++++++++++- .../code/java/security/PathSanitizer.qll | 14 +----- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index 33b7a6c0a9fc..7188e1e6e212 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -82,6 +82,7 @@ module; */ import java +private import codeql.util.Boolean private import Completion private import controlflow.internal.Preconditions private import controlflow.internal.SwitchCases @@ -102,6 +103,7 @@ module ControlFlow { private newtype TNode = TExprNode(Expr e) { hasControlFlow(e) } or TStmtNode(Stmt s) or + TAnnotatedExitNode(Callable c, Boolean normal) { exists(c.getBody()) } or TExitNode(Callable c) { exists(c.getBody()) } or TAssertThrowNode(AssertStmt s) @@ -191,6 +193,38 @@ module ControlFlow { override Location getLocation() { result = s.getLocation() } } + /** A control flow node indicating the normal or exceptional termination of a callable. */ + class AnnotatedExitNode extends Node, TAnnotatedExitNode { + Callable c; + boolean normal; + + AnnotatedExitNode() { this = TAnnotatedExitNode(c, normal) } + + override Callable getEnclosingCallable() { result = c } + + override ExprParent getAstNode() { result = c } + + /** Gets a textual representation of this element. */ + override string toString() { + normal = true and result = "Normal Exit" + or + normal = false and result = "Exceptional Exit" + } + + /** Gets the source location for this element. */ + override Location getLocation() { result = c.getLocation() } + } + + /** A control flow node indicating normal termination of a callable. */ + class NormalExitNode extends AnnotatedExitNode { + NormalExitNode() { this = TAnnotatedExitNode(_, true) } + } + + /** A control flow node indicating exceptional termination of a callable. */ + class ExceptionalExitNode extends AnnotatedExitNode { + ExceptionalExitNode() { this = TAnnotatedExitNode(_, false) } + } + /** A control flow node indicating the termination of a callable. */ class ExitNode extends Node, TExitNode { Callable c; @@ -1266,11 +1300,17 @@ private module ControlFlowGraphImpl { */ cached Node succ(Node n, Completion completion) { - // After executing the callable body, the final node is the exit node. + // After executing the callable body, the final nodes are first the + // annotated exit node and then the final exit node. exists(Callable c | last(c.getBody(), n, completion) | - result.(ExitNode).getEnclosingCallable() = c + if completion instanceof ThrowCompletion + then result.(ExceptionalExitNode).getEnclosingCallable() = c + else result.(NormalExitNode).getEnclosingCallable() = c ) or + completion = NormalCompletion() and + n.(AnnotatedExitNode).getEnclosingCallable() = result.(ExitNode).getEnclosingCallable() + or // Logic expressions and conditional expressions execute in AST pre-order. completion = NormalCompletion() and ( diff --git a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll index ed0761f6869e..e789d3c47785 100644 --- a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll +++ b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll @@ -31,20 +31,10 @@ private module ValidationMethod { * Holds if `m` validates its `arg`th parameter by using `validationGuard`. */ private predicate validationMethod(Method m, int arg) { - exists( - Guard g, SsaImplicitInit var, ControlFlow::ExitNode exit, ControlFlowNode normexit, - boolean branch - | + exists(Guard g, SsaImplicitInit var, ControlFlow::NormalExitNode normexit, boolean branch | validationGuard(g, var.getAUse(), branch) and var.isParameterDefinition(m.getParameter(arg)) and - exit.getEnclosingCallable() = m and - normexit.getANormalSuccessor() = exit and - 1 = strictcount(ControlFlowNode n | n.getANormalSuccessor() = exit) - | - exists(ConditionNode conditionNode | - g = conditionNode.getCondition() and conditionNode.getABranchSuccessor(branch) = exit - ) - or + normexit.getEnclosingCallable() = m and g.controls(normexit.getBasicBlock(), branch) ) } From e7a6259bd768e8c304250969c20a0a9d1356bc02 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 15 Jul 2025 14:17:34 +0200 Subject: [PATCH 114/311] Java: Accept test changes. --- .../controlflow/basic/bbStmts.expected | 16 ++++++- .../basic/bbStrictDominance.expected | 14 ++++++ .../controlflow/basic/bbSuccessor.expected | 43 +++++++++++------ .../controlflow/basic/getASuccessor.expected | 48 ++++++++++++------- .../controlflow/dominance/dominator.expected | 4 +- .../controlflow/basic/bbStmts.expected | 6 ++- .../basic/bbStrictDominance.expected | 4 ++ .../controlflow/basic/bbSuccessor.expected | 8 +++- .../controlflow/dominance/dominator.expected | 4 +- .../test/library-tests/guards/guards.expected | 2 + .../library-tests/guards/guardslogic.expected | 10 ++++ .../guards/guardspreconditions.expected | 24 ++++++++++ .../MultiCatch/MultiCatchControlFlow.expected | 10 ++-- .../pattern-instanceof/cfg.expected | 26 +++++++--- .../pattern-switch/cfg/test.expected | 42 +++++++++++----- .../CloseReaderTest/TestSucc.expected | 10 ++-- .../LoopVarReadTest/TestSucc.expected | 8 +++- .../successors/SaveFileTest/TestSucc.expected | 12 +++-- .../successors/SchackTest/TestSucc.expected | 23 ++++++--- .../successors/TestBreak/TestSucc.expected | 12 +++-- .../TestContinue/FalseSuccessors.expected | 2 +- .../successors/TestContinue/TestSucc.expected | 10 ++-- .../TestDeclarations/TestSucc.expected | 10 ++-- .../successors/TestFinally/TestSucc.expected | 16 +++++-- .../TestSucc.expected | 11 +++-- .../TestLoopBranch/TestSucc.expected | 26 +++++++--- .../successors/TestThrow/TestSucc.expected | 24 ++++++---- .../successors/TestThrow2/TestSucc.expected | 10 ++-- .../successors/TestTryCatch/TestSucc.expected | 11 +++-- .../TestTryWithResources/TestSucc.expected | 9 +++- .../UnreachableBlocks.expected | 4 ++ 31 files changed, 339 insertions(+), 120 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected index 8fe0abd91c0e..116bde45f980 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected @@ -1,8 +1,12 @@ +| Test.kt:3:8:80:1 | Exceptional Exit | 0 | Test.kt:3:8:80:1 | Exceptional Exit | +| Test.kt:3:8:80:1 | Exit | 0 | Test.kt:3:8:80:1 | Exit | | Test.kt:3:8:80:1 | { ... } | 0 | Test.kt:3:8:80:1 | { ... } | | Test.kt:3:8:80:1 | { ... } | 1 | Test.kt:3:1:80:1 | super(...) | | Test.kt:3:8:80:1 | { ... } | 2 | Test.kt:3:8:80:1 | { ... } | -| Test.kt:3:8:80:1 | { ... } | 3 | Test.kt:3:8:80:1 | Exit | +| Test.kt:3:8:80:1 | { ... } | 3 | Test.kt:3:8:80:1 | Normal Exit | +| Test.kt:4:2:79:2 | Exceptional Exit | 0 | Test.kt:4:2:79:2 | Exceptional Exit | | Test.kt:4:2:79:2 | Exit | 0 | Test.kt:4:2:79:2 | Exit | +| Test.kt:4:2:79:2 | Normal Exit | 0 | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:4:13:79:2 | { ... } | 0 | Test.kt:4:13:79:2 | { ... } | | Test.kt:4:13:79:2 | { ... } | 1 | Test.kt:5:7:5:7 | var ...; | | Test.kt:4:13:79:2 | { ... } | 2 | Test.kt:5:16:5:16 | 0 | @@ -102,7 +106,9 @@ | Test.kt:43:3:43:3 | ; | 8 | Test.kt:77:3:77:8 | ...=... | | Test.kt:43:3:43:3 | ; | 9 | Test.kt:78:3:78:8 | INSTANCE | | Test.kt:43:3:43:3 | ; | 10 | Test.kt:78:3:78:8 | return ... | +| Test.kt:82:1:89:1 | Exceptional Exit | 0 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:82:1:89:1 | Exit | 0 | Test.kt:82:1:89:1 | Exit | +| Test.kt:82:1:89:1 | Normal Exit | 0 | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | 0 | Test.kt:82:21:89:1 | { ... } | | Test.kt:82:21:89:1 | { ... } | 1 | Test.kt:83:2:88:2 | try ... | | Test.kt:82:21:89:1 | { ... } | 2 | Test.kt:83:6:86:2 | { ... } | @@ -117,7 +123,9 @@ | Test.kt:86:4:88:2 | catch (...) | 2 | Test.kt:86:34:88:2 | { ... } | | Test.kt:86:4:88:2 | catch (...) | 3 | Test.kt:87:10:87:10 | 2 | | Test.kt:86:4:88:2 | catch (...) | 4 | Test.kt:87:3:87:10 | return ... | +| Test.kt:91:1:98:1 | Exceptional Exit | 0 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:91:1:98:1 | Exit | 0 | Test.kt:91:1:98:1 | Exit | +| Test.kt:91:1:98:1 | Normal Exit | 0 | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | 0 | Test.kt:91:22:98:1 | { ... } | | Test.kt:91:22:98:1 | { ... } | 1 | Test.kt:92:2:97:2 | try ... | | Test.kt:91:22:98:1 | { ... } | 2 | Test.kt:92:6:95:2 | { ... } | @@ -133,6 +141,7 @@ | Test.kt:95:4:97:2 | catch (...) | 3 | Test.kt:96:10:96:10 | 2 | | Test.kt:95:4:97:2 | catch (...) | 4 | Test.kt:96:3:96:10 | return ... | | Test.kt:100:1:110:1 | Exit | 0 | Test.kt:100:1:110:1 | Exit | +| Test.kt:100:1:110:1 | Normal Exit | 0 | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | 0 | Test.kt:100:25:110:1 | { ... } | | Test.kt:100:25:110:1 | { ... } | 1 | Test.kt:101:5:103:5 | ; | | Test.kt:100:25:110:1 | { ... } | 2 | Test.kt:101:5:103:5 | when ... | @@ -147,6 +156,7 @@ | Test.kt:101:33:103:5 | { ... } | 0 | Test.kt:101:33:103:5 | { ... } | | Test.kt:101:33:103:5 | { ... } | 1 | Test.kt:102:15:102:25 | new Exception(...) | | Test.kt:101:33:103:5 | { ... } | 2 | Test.kt:102:9:102:25 | throw ... | +| Test.kt:101:33:103:5 | { ... } | 3 | Test.kt:100:1:110:1 | Exceptional Exit | | Test.kt:105:5:109:5 | ; | 0 | Test.kt:105:5:109:5 | ; | | Test.kt:105:5:109:5 | ; | 1 | Test.kt:105:5:109:5 | when ... | | Test.kt:105:5:109:5 | ; | 2 | Test.kt:105:9:107:5 | ... -> ... | @@ -165,7 +175,9 @@ | Test.kt:107:27:109:5 | { ... } | 1 | Test.kt:108:9:108:29 | ; | | Test.kt:107:27:109:5 | { ... } | 2 | Test.kt:108:17:108:28 | "y not null" | | Test.kt:107:27:109:5 | { ... } | 3 | Test.kt:108:9:108:29 | println(...) | +| Test.kt:112:1:116:1 | Exceptional Exit | 0 | Test.kt:112:1:116:1 | Exceptional Exit | | Test.kt:112:1:116:1 | Exit | 0 | Test.kt:112:1:116:1 | Exit | +| Test.kt:112:1:116:1 | Normal Exit | 0 | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:112:32:116:1 | { ... } | 0 | Test.kt:112:32:116:1 | { ... } | | Test.kt:112:32:116:1 | { ... } | 1 | Test.kt:113:5:115:5 | ; | | Test.kt:112:32:116:1 | { ... } | 2 | Test.kt:113:5:115:5 | when ... | @@ -174,7 +186,9 @@ | Test.kt:112:32:116:1 | { ... } | 5 | Test.kt:113:9:113:9 | x | | Test.kt:113:14:113:14 | y | 0 | Test.kt:113:14:113:14 | y | | Test.kt:113:17:115:5 | { ... } | 0 | Test.kt:113:17:115:5 | { ... } | +| Test.kt:118:1:124:1 | Exceptional Exit | 0 | Test.kt:118:1:124:1 | Exceptional Exit | | Test.kt:118:1:124:1 | Exit | 0 | Test.kt:118:1:124:1 | Exit | +| Test.kt:118:1:124:1 | Normal Exit | 0 | Test.kt:118:1:124:1 | Normal Exit | | Test.kt:118:37:124:1 | { ... } | 0 | Test.kt:118:37:124:1 | { ... } | | Test.kt:118:37:124:1 | { ... } | 1 | Test.kt:119:2:123:12 | ; | | Test.kt:118:37:124:1 | { ... } | 2 | Test.kt:119:2:123:12 | when ... | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected index fa358b39a35e..6d0cb2bab712 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected @@ -1,4 +1,7 @@ +| Test.kt:3:8:80:1 | { ... } | Test.kt:3:8:80:1 | Exit | +| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Exit | +| Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:18:3:18:3 | ; | @@ -10,6 +13,7 @@ | Test.kt:4:13:79:2 | { ... } | Test.kt:38:16:41:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:43:3:43:3 | ; | | Test.kt:18:3:18:3 | ; | Test.kt:4:2:79:2 | Exit | +| Test.kt:18:3:18:3 | ; | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:9 | ... -> ... | | Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | | Test.kt:18:3:18:3 | ; | Test.kt:30:15:33:3 | { ... } | @@ -27,13 +31,18 @@ | Test.kt:35:3:35:3 | ; | Test.kt:43:3:43:3 | ; | | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | | Test.kt:38:9:38:9 | x | Test.kt:43:3:43:3 | ; | +| Test.kt:82:1:89:1 | Normal Exit | Test.kt:82:1:89:1 | Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Exit | +| Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:7:84:7 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | +| Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exit | +| Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Exit | +| Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:33:103:5 | { ... } | | Test.kt:100:25:110:1 | { ... } | Test.kt:105:5:109:5 | ; | @@ -41,15 +50,20 @@ | Test.kt:100:25:110:1 | { ... } | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:100:25:110:1 | { ... } | Test.kt:107:27:109:5 | { ... } | | Test.kt:101:22:101:22 | y | Test.kt:101:33:103:5 | { ... } | +| Test.kt:105:5:109:5 | ; | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:105:5:109:5 | ; | Test.kt:105:20:107:5 | { ... } | | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:105:5:109:5 | ; | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | +| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Exit | +| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:17:115:5 | { ... } | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | +| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Exit | +| Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Normal Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | | Test.kt:118:37:124:1 | { ... } | Test.kt:123:8:123:10 | { ... } | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected index 3768db75d7e8..cf5da7c83b77 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected @@ -1,10 +1,14 @@ +| Test.kt:3:8:80:1 | Exceptional Exit | Test.kt:3:8:80:1 | Exit | +| Test.kt:3:8:80:1 | { ... } | Test.kt:3:8:80:1 | Exit | +| Test.kt:4:2:79:2 | Exceptional Exit | Test.kt:4:2:79:2 | Exit | +| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:11:3:16:3 | ... -> ... | Test.kt:18:3:18:3 | ; | | Test.kt:11:14:14:3 | { ... } | Test.kt:18:3:18:3 | ; | | Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:9 | ... -> ... | | Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | -| Test.kt:21:3:24:9 | ... -> ... | Test.kt:4:2:79:2 | Exit | +| Test.kt:21:3:24:9 | ... -> ... | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:22:4:22:4 | ; | Test.kt:30:15:33:3 | { ... } | | Test.kt:22:4:22:4 | ; | Test.kt:35:3:35:3 | ; | | Test.kt:30:15:33:3 | { ... } | Test.kt:35:3:35:3 | ; | @@ -12,15 +16,20 @@ | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | | Test.kt:38:9:38:9 | x | Test.kt:43:3:43:3 | ; | | Test.kt:38:16:41:3 | { ... } | Test.kt:38:9:38:9 | x | -| Test.kt:43:3:43:3 | ; | Test.kt:4:2:79:2 | Exit | +| Test.kt:43:3:43:3 | ; | Test.kt:4:2:79:2 | Normal Exit | +| Test.kt:82:1:89:1 | Exceptional Exit | Test.kt:82:1:89:1 | Exit | +| Test.kt:82:1:89:1 | Normal Exit | Test.kt:82:1:89:1 | Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:7:84:7 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:84:7:84:7 | x | Test.kt:82:1:89:1 | Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exit | +| Test.kt:84:7:84:7 | x | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:91:1:98:1 | Exceptional Exit | Test.kt:91:1:98:1 | Exit | +| Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | -| Test.kt:93:7:93:7 | x | Test.kt:91:1:98:1 | Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exit | +| Test.kt:93:7:93:7 | x | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:100:1:110:1 | Normal Exit | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | | Test.kt:100:25:110:1 | { ... } | Test.kt:105:5:109:5 | ; | | Test.kt:101:22:101:22 | y | Test.kt:101:33:103:5 | { ... } | @@ -28,18 +37,22 @@ | Test.kt:101:33:103:5 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:105:5:109:5 | ; | Test.kt:105:20:107:5 | { ... } | | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | -| Test.kt:105:20:107:5 | { ... } | Test.kt:100:1:110:1 | Exit | -| Test.kt:107:16:109:5 | ... -> ... | Test.kt:100:1:110:1 | Exit | +| Test.kt:105:20:107:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:107:16:109:5 | ... -> ... | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | -| Test.kt:107:27:109:5 | { ... } | Test.kt:100:1:110:1 | Exit | -| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Exit | +| Test.kt:107:27:109:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:112:1:116:1 | Exceptional Exit | Test.kt:112:1:116:1 | Exit | +| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | +| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | -| Test.kt:113:14:113:14 | y | Test.kt:112:1:116:1 | Exit | +| Test.kt:113:14:113:14 | y | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | -| Test.kt:113:17:115:5 | { ... } | Test.kt:112:1:116:1 | Exit | +| Test.kt:113:17:115:5 | { ... } | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:118:1:124:1 | Exceptional Exit | Test.kt:118:1:124:1 | Exit | +| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | -| Test.kt:121:9:121:9 | ; | Test.kt:118:1:124:1 | Exit | +| Test.kt:121:9:121:9 | ; | Test.kt:118:1:124:1 | Normal Exit | | Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | -| Test.kt:122:12:122:16 | ... -> ... | Test.kt:118:1:124:1 | Exit | -| Test.kt:123:8:123:10 | { ... } | Test.kt:118:1:124:1 | Exit | +| Test.kt:122:12:122:16 | ... -> ... | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:123:8:123:10 | { ... } | Test.kt:118:1:124:1 | Normal Exit | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected index 81142abc1df8..1d07b13c9d75 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected @@ -1,9 +1,13 @@ #select | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | Test.kt:3:8:80:1 | { ... } | BlockStmt | +| Test.kt:3:8:80:1 | Exceptional Exit | Constructor | Test.kt:3:8:80:1 | Exit | Constructor | | Test.kt:3:8:80:1 | Exit | Constructor | file://:0:0:0:0 | | | +| Test.kt:3:8:80:1 | Normal Exit | Constructor | Test.kt:3:8:80:1 | Exit | Constructor | | Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | -| Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:8:80:1 | Exit | Constructor | +| Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:8:80:1 | Normal Exit | Constructor | +| Test.kt:4:2:79:2 | Exceptional Exit | Method | Test.kt:4:2:79:2 | Exit | Method | | Test.kt:4:2:79:2 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:4:2:79:2 | Normal Exit | Method | Test.kt:4:2:79:2 | Exit | Method | | Test.kt:4:13:79:2 | { ... } | BlockStmt | Test.kt:5:7:5:7 | var ...; | LocalVariableDeclStmt | | Test.kt:5:7:5:7 | var ...; | LocalVariableDeclStmt | Test.kt:5:16:5:16 | 0 | IntegerLiteral | | Test.kt:5:7:5:7 | x | LocalVariableDeclExpr | Test.kt:6:7:6:7 | var ...; | LocalVariableDeclStmt | @@ -53,7 +57,7 @@ | Test.kt:22:4:22:9 | ...=... | AssignExpr | Test.kt:27:3:27:3 | ; | ExprStmt | | Test.kt:22:8:22:9 | 40 | LongLiteral | Test.kt:22:4:22:9 | ...=... | AssignExpr | | Test.kt:24:4:24:9 | INSTANCE | VarAccess | Test.kt:24:4:24:9 | return ... | ReturnStmt | -| Test.kt:24:4:24:9 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Exit | Method | +| Test.kt:24:4:24:9 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | | Test.kt:27:3:27:3 | ; | ExprStmt | Test.kt:27:7:27:8 | 10 | IntegerLiteral | | Test.kt:27:3:27:8 | ...=... | AssignExpr | Test.kt:30:3:33:3 | ; | ExprStmt | | Test.kt:27:7:27:8 | 10 | IntegerLiteral | Test.kt:27:3:27:8 | ...=... | AssignExpr | @@ -106,8 +110,10 @@ | Test.kt:77:3:77:8 | ...=... | AssignExpr | Test.kt:78:3:78:8 | INSTANCE | VarAccess | | Test.kt:77:7:77:8 | 40 | IntegerLiteral | Test.kt:77:3:77:8 | ...=... | AssignExpr | | Test.kt:78:3:78:8 | INSTANCE | VarAccess | Test.kt:78:3:78:8 | return ... | ReturnStmt | -| Test.kt:78:3:78:8 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Exit | Method | +| Test.kt:78:3:78:8 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | +| Test.kt:82:1:89:1 | Exceptional Exit | Method | Test.kt:82:1:89:1 | Exit | Method | | Test.kt:82:1:89:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:82:1:89:1 | Normal Exit | Method | Test.kt:82:1:89:1 | Exit | Method | | Test.kt:82:21:89:1 | { ... } | BlockStmt | Test.kt:83:2:88:2 | try ... | TryStmt | | Test.kt:83:2:88:2 | try ... | TryStmt | Test.kt:83:6:86:2 | { ... } | BlockStmt | | Test.kt:83:6:86:2 | { ... } | BlockStmt | Test.kt:84:7:84:7 | var ...; | LocalVariableDeclStmt | @@ -116,14 +122,16 @@ | Test.kt:84:11:84:11 | o | VarAccess | Test.kt:84:11:84:18 | (...)... | CastExpr | | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:84:7:84:7 | x | LocalVariableDeclExpr | | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:86:4:88:2 | catch (...) | CatchClause | -| Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Exit | Method | +| Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:85:10:85:10 | 1 | IntegerLiteral | Test.kt:85:3:85:10 | return ... | ReturnStmt | | Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:86:34:88:2 | { ... } | BlockStmt | | Test.kt:86:34:88:2 | { ... } | BlockStmt | Test.kt:87:10:87:10 | 2 | IntegerLiteral | -| Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Exit | Method | +| Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:87:10:87:10 | 2 | IntegerLiteral | Test.kt:87:3:87:10 | return ... | ReturnStmt | +| Test.kt:91:1:98:1 | Exceptional Exit | Method | Test.kt:91:1:98:1 | Exit | Method | | Test.kt:91:1:98:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:91:1:98:1 | Normal Exit | Method | Test.kt:91:1:98:1 | Exit | Method | | Test.kt:91:22:98:1 | { ... } | BlockStmt | Test.kt:92:2:97:2 | try ... | TryStmt | | Test.kt:92:2:97:2 | try ... | TryStmt | Test.kt:92:6:95:2 | { ... } | BlockStmt | | Test.kt:92:6:95:2 | { ... } | BlockStmt | Test.kt:93:7:93:7 | var ...; | LocalVariableDeclStmt | @@ -132,14 +140,16 @@ | Test.kt:93:11:93:11 | o | VarAccess | Test.kt:93:12:93:13 | ...!! | NotNullExpr | | Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:93:7:93:7 | x | LocalVariableDeclExpr | | Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause | -| Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Exit | Method | +| Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt | | Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:95:36:97:2 | { ... } | BlockStmt | | Test.kt:95:36:97:2 | { ... } | BlockStmt | Test.kt:96:10:96:10 | 2 | IntegerLiteral | -| Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Exit | Method | +| Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:96:10:96:10 | 2 | IntegerLiteral | Test.kt:96:3:96:10 | return ... | ReturnStmt | +| Test.kt:100:1:110:1 | Exceptional Exit | Method | Test.kt:100:1:110:1 | Exit | Method | | Test.kt:100:1:110:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:100:1:110:1 | Normal Exit | Method | Test.kt:100:1:110:1 | Exit | Method | | Test.kt:100:25:110:1 | { ... } | BlockStmt | Test.kt:101:5:103:5 | ; | ExprStmt | | Test.kt:101:5:103:5 | ... -> ... | WhenBranch | Test.kt:101:9:101:30 | ... && ... | AndLogicalExpr | | Test.kt:101:5:103:5 | ; | ExprStmt | Test.kt:101:5:103:5 | when ... | WhenExpr | @@ -154,7 +164,7 @@ | Test.kt:101:22:101:30 | ... (value equals) ... | ValueEQExpr | Test.kt:105:5:109:5 | ; | ExprStmt | | Test.kt:101:27:101:30 | null | NullLiteral | Test.kt:101:22:101:30 | ... (value equals) ... | ValueEQExpr | | Test.kt:101:33:103:5 | { ... } | BlockStmt | Test.kt:102:15:102:25 | new Exception(...) | ClassInstanceExpr | -| Test.kt:102:9:102:25 | throw ... | ThrowStmt | Test.kt:100:1:110:1 | Exit | Method | +| Test.kt:102:9:102:25 | throw ... | ThrowStmt | Test.kt:100:1:110:1 | Exceptional Exit | Method | | Test.kt:102:15:102:25 | new Exception(...) | ClassInstanceExpr | Test.kt:102:9:102:25 | throw ... | ThrowStmt | | Test.kt:105:5:109:5 | ; | ExprStmt | Test.kt:105:5:109:5 | when ... | WhenExpr | | Test.kt:105:5:109:5 | when ... | WhenExpr | Test.kt:105:9:107:5 | ... -> ... | WhenBranch | @@ -165,29 +175,33 @@ | Test.kt:105:14:105:17 | null | NullLiteral | Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr | | Test.kt:105:20:107:5 | { ... } | BlockStmt | Test.kt:106:9:106:29 | ; | ExprStmt | | Test.kt:106:9:106:29 | ; | ExprStmt | Test.kt:106:17:106:28 | "x not null" | StringLiteral | -| Test.kt:106:9:106:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Exit | Method | +| Test.kt:106:9:106:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Normal Exit | Method | | Test.kt:106:17:106:28 | "x not null" | StringLiteral | Test.kt:106:9:106:29 | println(...) | MethodCall | | Test.kt:107:16:107:16 | y | VarAccess | Test.kt:107:21:107:24 | null | NullLiteral | -| Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:100:1:110:1 | Exit | Method | +| Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:100:1:110:1 | Normal Exit | Method | | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:107:27:109:5 | { ... } | BlockStmt | | Test.kt:107:16:109:5 | ... -> ... | WhenBranch | Test.kt:107:16:107:16 | y | VarAccess | | Test.kt:107:21:107:24 | null | NullLiteral | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | | Test.kt:107:27:109:5 | { ... } | BlockStmt | Test.kt:108:9:108:29 | ; | ExprStmt | | Test.kt:108:9:108:29 | ; | ExprStmt | Test.kt:108:17:108:28 | "y not null" | StringLiteral | -| Test.kt:108:9:108:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Exit | Method | +| Test.kt:108:9:108:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Normal Exit | Method | | Test.kt:108:17:108:28 | "y not null" | StringLiteral | Test.kt:108:9:108:29 | println(...) | MethodCall | +| Test.kt:112:1:116:1 | Exceptional Exit | Method | Test.kt:112:1:116:1 | Exit | Method | | Test.kt:112:1:116:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:112:1:116:1 | Normal Exit | Method | Test.kt:112:1:116:1 | Exit | Method | | Test.kt:112:32:116:1 | { ... } | BlockStmt | Test.kt:113:5:115:5 | ; | ExprStmt | | Test.kt:113:5:115:5 | ... -> ... | WhenBranch | Test.kt:113:9:113:14 | ... && ... | AndLogicalExpr | | Test.kt:113:5:115:5 | ; | ExprStmt | Test.kt:113:5:115:5 | when ... | WhenExpr | | Test.kt:113:5:115:5 | when ... | WhenExpr | Test.kt:113:5:115:5 | ... -> ... | WhenBranch | -| Test.kt:113:9:113:9 | x | VarAccess | Test.kt:112:1:116:1 | Exit | Method | +| Test.kt:113:9:113:9 | x | VarAccess | Test.kt:112:1:116:1 | Normal Exit | Method | | Test.kt:113:9:113:9 | x | VarAccess | Test.kt:113:14:113:14 | y | VarAccess | | Test.kt:113:9:113:14 | ... && ... | AndLogicalExpr | Test.kt:113:9:113:9 | x | VarAccess | -| Test.kt:113:14:113:14 | y | VarAccess | Test.kt:112:1:116:1 | Exit | Method | +| Test.kt:113:14:113:14 | y | VarAccess | Test.kt:112:1:116:1 | Normal Exit | Method | | Test.kt:113:14:113:14 | y | VarAccess | Test.kt:113:17:115:5 | { ... } | BlockStmt | -| Test.kt:113:17:115:5 | { ... } | BlockStmt | Test.kt:112:1:116:1 | Exit | Method | +| Test.kt:113:17:115:5 | { ... } | BlockStmt | Test.kt:112:1:116:1 | Normal Exit | Method | +| Test.kt:118:1:124:1 | Exceptional Exit | Method | Test.kt:118:1:124:1 | Exit | Method | | Test.kt:118:1:124:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:118:1:124:1 | Normal Exit | Method | Test.kt:118:1:124:1 | Exit | Method | | Test.kt:118:37:124:1 | { ... } | BlockStmt | Test.kt:119:2:123:12 | ; | ExprStmt | | Test.kt:119:2:123:12 | ; | ExprStmt | Test.kt:119:2:123:12 | when ... | WhenExpr | | Test.kt:119:2:123:12 | when ... | WhenExpr | Test.kt:120:3:123:10 | ... -> ... | WhenBranch | @@ -197,11 +211,11 @@ | Test.kt:121:4:121:4 | x | VarAccess | Test.kt:122:12:122:16 | ... -> ... | WhenBranch | | Test.kt:121:4:121:9 | ... -> ... | WhenBranch | Test.kt:121:4:121:4 | x | VarAccess | | Test.kt:121:9:121:9 | ; | ExprStmt | Test.kt:121:9:121:9 | y | VarAccess | -| Test.kt:121:9:121:9 | y | VarAccess | Test.kt:118:1:124:1 | Exit | Method | +| Test.kt:121:9:121:9 | y | VarAccess | Test.kt:118:1:124:1 | Normal Exit | Method | | Test.kt:121:9:121:9 | y | VarAccess | Test.kt:123:8:123:10 | { ... } | BlockStmt | | Test.kt:122:12:122:16 | ... -> ... | WhenBranch | Test.kt:122:12:122:16 | true | BooleanLiteral | | Test.kt:122:12:122:16 | ; | ExprStmt | Test.kt:122:12:122:16 | false | BooleanLiteral | -| Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:118:1:124:1 | Exit | Method | +| Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:118:1:124:1 | Normal Exit | Method | | Test.kt:122:12:122:16 | true | BooleanLiteral | Test.kt:122:12:122:16 | ; | ExprStmt | -| Test.kt:123:8:123:10 | { ... } | BlockStmt | Test.kt:118:1:124:1 | Exit | Method | +| Test.kt:123:8:123:10 | { ... } | BlockStmt | Test.kt:118:1:124:1 | Normal Exit | Method | missingSuccessor diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected index 3eae23451868..31da586d6307 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected @@ -44,7 +44,7 @@ | Test.kt:21:3:24:11 | true | Test.kt:24:11:24:11 | z | | Test.kt:21:3:24:11 | when ... | Test.kt:21:3:24:11 | ... -> ... | | Test.kt:21:7:21:7 | x | Test.kt:21:11:21:11 | 0 | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:2:2:79:2 | Exit | +| Test.kt:21:7:21:11 | ... < ... | Test.kt:2:2:79:2 | Normal Exit | | Test.kt:21:7:21:11 | ... < ... | Test.kt:21:3:24:11 | ... -> ... | | Test.kt:21:7:21:11 | ... < ... | Test.kt:22:4:22:4 | ; | | Test.kt:21:11:21:11 | 0 | Test.kt:21:7:21:11 | ... < ... | @@ -142,7 +142,7 @@ | Test.kt:92:4:93:9 | ; | Test.kt:92:4:93:9 | when ... | | Test.kt:92:4:93:9 | when ... | Test.kt:92:4:93:9 | ... -> ... | | Test.kt:92:8:92:8 | a | Test.kt:92:13:92:14 | 10 | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:81:2:98:2 | Exit | +| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:81:2:98:2 | Normal Exit | | Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:93:5:93:9 | break | | Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:94:4:95:12 | ; | | Test.kt:92:13:92:14 | 10 | Test.kt:92:8:92:14 | ... (value equals) ... | diff --git a/java/ql/test/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test/library-tests/controlflow/basic/bbStmts.expected index 0fbf3623f089..df336ce90a22 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbStmts.expected @@ -1,7 +1,11 @@ +| Test.java:3:14:3:17 | Exceptional Exit | 0 | Test.java:3:14:3:17 | Exceptional Exit | +| Test.java:3:14:3:17 | Exit | 0 | Test.java:3:14:3:17 | Exit | | Test.java:3:14:3:17 | { ... } | 0 | Test.java:3:14:3:17 | { ... } | | Test.java:3:14:3:17 | { ... } | 1 | Test.java:3:14:3:17 | super(...) | -| Test.java:3:14:3:17 | { ... } | 2 | Test.java:3:14:3:17 | Exit | +| Test.java:3:14:3:17 | { ... } | 2 | Test.java:3:14:3:17 | Normal Exit | +| Test.java:4:14:4:17 | Exceptional Exit | 0 | Test.java:4:14:4:17 | Exceptional Exit | | Test.java:4:14:4:17 | Exit | 0 | Test.java:4:14:4:17 | Exit | +| Test.java:4:14:4:17 | Normal Exit | 0 | Test.java:4:14:4:17 | Normal Exit | | Test.java:4:21:76:2 | { ... } | 0 | Test.java:4:21:76:2 | { ... } | | Test.java:4:21:76:2 | { ... } | 1 | Test.java:5:3:5:12 | var ...; | | Test.java:4:21:76:2 | { ... } | 2 | Test.java:5:11:5:11 | 0 | diff --git a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected index 8440209d0a45..be658fb29158 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected @@ -1,4 +1,7 @@ +| Test.java:3:14:3:17 | { ... } | Test.java:3:14:3:17 | Exit | +| Test.java:4:14:4:17 | Normal Exit | Test.java:4:14:4:17 | Exit | | Test.java:4:21:76:2 | { ... } | Test.java:4:14:4:17 | Exit | +| Test.java:4:21:76:2 | { ... } | Test.java:4:14:4:17 | Normal Exit | | Test.java:4:21:76:2 | { ... } | Test.java:11:14:14:3 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:14:10:16:3 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:18:3:18:8 | ; | @@ -21,6 +24,7 @@ | Test.java:4:21:76:2 | { ... } | Test.java:63:9:66:4 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:70:3:70:9 | ; | | Test.java:18:3:18:8 | ; | Test.java:4:14:4:17 | Exit | +| Test.java:18:3:18:8 | ; | Test.java:4:14:4:17 | Normal Exit | | Test.java:18:3:18:8 | ; | Test.java:22:4:22:10 | ; | | Test.java:18:3:18:8 | ; | Test.java:24:4:24:10 | return ... | | Test.java:18:3:18:8 | ; | Test.java:30:15:33:3 | { ... } | diff --git a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected index 0886f784fd9a..a6e5d8430c12 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected @@ -1,3 +1,7 @@ +| Test.java:3:14:3:17 | Exceptional Exit | Test.java:3:14:3:17 | Exit | +| Test.java:3:14:3:17 | { ... } | Test.java:3:14:3:17 | Exit | +| Test.java:4:14:4:17 | Exceptional Exit | Test.java:4:14:4:17 | Exit | +| Test.java:4:14:4:17 | Normal Exit | Test.java:4:14:4:17 | Exit | | Test.java:4:21:76:2 | { ... } | Test.java:11:14:14:3 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:14:10:16:3 | { ... } | | Test.java:11:14:14:3 | { ... } | Test.java:18:3:18:8 | ; | @@ -6,7 +10,7 @@ | Test.java:18:3:18:8 | ; | Test.java:24:4:24:10 | return ... | | Test.java:22:4:22:10 | ; | Test.java:30:15:33:3 | { ... } | | Test.java:22:4:22:10 | ; | Test.java:35:3:35:9 | ; | -| Test.java:24:4:24:10 | return ... | Test.java:4:14:4:17 | Exit | +| Test.java:24:4:24:10 | return ... | Test.java:4:14:4:17 | Normal Exit | | Test.java:30:15:33:3 | { ... } | Test.java:35:3:35:9 | ; | | Test.java:35:3:35:9 | ; | Test.java:38:9:38:9 | x | | Test.java:38:9:38:9 | x | Test.java:38:16:41:3 | { ... } | @@ -27,4 +31,4 @@ | Test.java:57:15:60:5 | { ... } | Test.java:70:3:70:9 | ; | | Test.java:60:12:62:5 | { ... } | Test.java:54:26:54:26 | j | | Test.java:63:9:66:4 | { ... } | Test.java:54:26:54:26 | j | -| Test.java:70:3:70:9 | ; | Test.java:4:14:4:17 | Exit | +| Test.java:70:3:70:9 | ; | Test.java:4:14:4:17 | Normal Exit | diff --git a/java/ql/test/library-tests/controlflow/dominance/dominator.expected b/java/ql/test/library-tests/controlflow/dominance/dominator.expected index de43e6721e64..1e385c4fd62f 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test/library-tests/controlflow/dominance/dominator.expected @@ -27,7 +27,7 @@ | Test.java:14:18:14:18 | y | Test.java:14:14:14:18 | ... + ... | | Test.java:17:3:17:12 | if (...) | Test.java:17:7:17:7 | x | | Test.java:17:7:17:7 | x | Test.java:17:11:17:11 | 0 | -| Test.java:17:7:17:11 | ... < ... | Test.java:2:6:2:9 | Exit | +| Test.java:17:7:17:11 | ... < ... | Test.java:2:6:2:9 | Normal Exit | | Test.java:17:7:17:11 | ... < ... | Test.java:18:4:18:10 | ; | | Test.java:17:7:17:11 | ... < ... | Test.java:20:11:20:11 | z | | Test.java:17:11:17:11 | 0 | Test.java:17:7:17:11 | ... < ... | @@ -163,7 +163,7 @@ | Test.java:83:9:83:9 | c | Test.java:83:5:83:9 | ...=... | | Test.java:85:4:85:15 | if (...) | Test.java:85:8:85:8 | a | | Test.java:85:8:85:8 | a | Test.java:85:13:85:14 | 10 | -| Test.java:85:8:85:14 | ... == ... | Test.java:74:6:74:10 | Exit | +| Test.java:85:8:85:14 | ... == ... | Test.java:74:6:74:10 | Normal Exit | | Test.java:85:8:85:14 | ... == ... | Test.java:86:5:86:10 | break | | Test.java:85:8:85:14 | ... == ... | Test.java:87:4:87:15 | if (...) | | Test.java:85:13:85:14 | 10 | Test.java:85:8:85:14 | ... == ... | diff --git a/java/ql/test/library-tests/guards/guards.expected b/java/ql/test/library-tests/guards/guards.expected index 2c5bff6233ad..ffe67bc3a323 100644 --- a/java/ql/test/library-tests/guards/guards.expected +++ b/java/ql/test/library-tests/guards/guards.expected @@ -1,3 +1,4 @@ +| Test.java:5:7:5:11 | ... < ... | false | Test.java:3:7:3:10 | Normal Exit | | Test.java:5:7:5:11 | ... < ... | false | Test.java:8:3:8:12 | var ...; | | Test.java:5:7:5:11 | ... < ... | false | Test.java:9:9:9:9 | x | | Test.java:5:7:5:11 | ... < ... | false | Test.java:9:17:22:3 | { ... } | @@ -10,6 +11,7 @@ | Test.java:5:7:5:11 | ... < ... | false | Test.java:18:24:20:4 | { ... } | | Test.java:5:7:5:11 | ... < ... | false | Test.java:21:4:21:7 | ; | | Test.java:5:7:5:11 | ... < ... | true | Test.java:5:14:7:3 | { ... } | +| Test.java:9:9:9:14 | ... >= ... | false | Test.java:3:7:3:10 | Normal Exit | | Test.java:9:9:9:14 | ... >= ... | true | Test.java:9:17:22:3 | { ... } | | Test.java:9:9:9:14 | ... >= ... | true | Test.java:11:5:11:8 | ; | | Test.java:9:9:9:14 | ... >= ... | true | Test.java:12:4:12:14 | if (...) | diff --git a/java/ql/test/library-tests/guards/guardslogic.expected b/java/ql/test/library-tests/guards/guardslogic.expected index 29c11ccd153d..6bf536d3ce1c 100644 --- a/java/ql/test/library-tests/guards/guardslogic.expected +++ b/java/ql/test/library-tests/guards/guardslogic.expected @@ -46,6 +46,11 @@ | Logic.java:36:16:36:21 | g(...) | false | Logic.java:40:5:40:18 | var ...; | | Logic.java:37:9:37:14 | ... > ... | true | Logic.java:37:17:39:5 | { ... } | | Logic.java:44:10:44:10 | b | false | Logic.java:44:33:44:35 | msg | +| Logic.java:44:10:44:10 | b | true | Logic.java:43:23:43:31 | Normal Exit | +| Logic.java:48:5:48:22 | checkTrue(...) | exception | Logic.java:47:23:47:32 | Exceptional Exit | +| Logic.java:48:5:48:22 | checkTrue(...) | no exception | Logic.java:47:23:47:32 | Normal Exit | +| Logic.java:48:15:48:16 | !... | true | Logic.java:47:23:47:32 | Normal Exit | +| Logic.java:48:16:48:16 | b | false | Logic.java:47:23:47:32 | Normal Exit | | Logic.java:52:5:52:29 | checkTrue(...) | no exception | Logic.java:53:5:53:28 | ; | | Logic.java:52:5:52:29 | checkTrue(...) | no exception | Logic.java:54:5:54:15 | if (...) | | Logic.java:52:5:52:29 | checkTrue(...) | no exception | Logic.java:54:17:56:5 | { ... } | @@ -62,3 +67,8 @@ | Logic.java:53:21:53:26 | g(...) | false | Logic.java:57:5:57:18 | var ...; | | Logic.java:54:9:54:14 | ... > ... | true | Logic.java:54:17:56:5 | { ... } | | Logic.java:61:10:61:10 | b | false | Logic.java:61:33:61:35 | msg | +| Logic.java:61:10:61:10 | b | true | Logic.java:60:23:60:31 | Normal Exit | +| Logic.java:65:5:65:22 | checkTrue(...) | exception | Logic.java:64:23:64:32 | Exceptional Exit | +| Logic.java:65:5:65:22 | checkTrue(...) | no exception | Logic.java:64:23:64:32 | Normal Exit | +| Logic.java:65:15:65:16 | !... | true | Logic.java:64:23:64:32 | Normal Exit | +| Logic.java:65:16:65:16 | b | false | Logic.java:64:23:64:32 | Normal Exit | diff --git a/java/ql/test/library-tests/guards/guardspreconditions.expected b/java/ql/test/library-tests/guards/guardspreconditions.expected index 41080a5dab6e..2d4597f0282b 100644 --- a/java/ql/test/library-tests/guards/guardspreconditions.expected +++ b/java/ql/test/library-tests/guards/guardspreconditions.expected @@ -1,20 +1,44 @@ +| Preconditions.java:8:9:8:31 | assertTrue(...) | exception | Preconditions.java:7:10:7:14 | Exceptional Exit | | Preconditions.java:8:9:8:31 | assertTrue(...) | no exception | Preconditions.java:9:9:9:18 | ; | +| Preconditions.java:13:9:13:32 | assertTrue(...) | exception | Preconditions.java:12:10:12:14 | Exceptional Exit | | Preconditions.java:13:9:13:32 | assertTrue(...) | no exception | Preconditions.java:14:9:14:18 | ; | +| Preconditions.java:18:9:18:33 | assertFalse(...) | exception | Preconditions.java:17:10:17:14 | Exceptional Exit | | Preconditions.java:18:9:18:33 | assertFalse(...) | no exception | Preconditions.java:19:9:19:18 | ; | +| Preconditions.java:23:9:23:32 | assertFalse(...) | exception | Preconditions.java:22:10:22:14 | Exceptional Exit | | Preconditions.java:23:9:23:32 | assertFalse(...) | no exception | Preconditions.java:24:9:24:18 | ; | +| Preconditions.java:28:9:28:41 | assertTrue(...) | exception | Preconditions.java:27:10:27:14 | Exceptional Exit | | Preconditions.java:28:9:28:41 | assertTrue(...) | no exception | Preconditions.java:29:9:29:18 | ; | +| Preconditions.java:33:9:33:42 | assertTrue(...) | exception | Preconditions.java:32:10:32:14 | Exceptional Exit | | Preconditions.java:33:9:33:42 | assertTrue(...) | no exception | Preconditions.java:34:9:34:18 | ; | +| Preconditions.java:38:9:38:43 | assertFalse(...) | exception | Preconditions.java:37:10:37:14 | Exceptional Exit | | Preconditions.java:38:9:38:43 | assertFalse(...) | no exception | Preconditions.java:39:9:39:18 | ; | +| Preconditions.java:43:9:43:42 | assertFalse(...) | exception | Preconditions.java:42:10:42:14 | Exceptional Exit | | Preconditions.java:43:9:43:42 | assertFalse(...) | no exception | Preconditions.java:44:9:44:18 | ; | +| Preconditions.java:48:9:48:35 | assertTrue(...) | exception | Preconditions.java:47:10:47:14 | Exceptional Exit | | Preconditions.java:48:9:48:35 | assertTrue(...) | no exception | Preconditions.java:49:9:49:18 | ; | +| Preconditions.java:53:9:53:36 | assertTrue(...) | exception | Preconditions.java:52:10:52:15 | Exceptional Exit | | Preconditions.java:53:9:53:36 | assertTrue(...) | no exception | Preconditions.java:54:9:54:18 | ; | +| Preconditions.java:58:9:58:37 | assertFalse(...) | exception | Preconditions.java:57:10:57:15 | Exceptional Exit | | Preconditions.java:58:9:58:37 | assertFalse(...) | no exception | Preconditions.java:59:9:59:18 | ; | +| Preconditions.java:63:9:63:36 | assertFalse(...) | exception | Preconditions.java:62:10:62:15 | Exceptional Exit | | Preconditions.java:63:9:63:36 | assertFalse(...) | no exception | Preconditions.java:64:9:64:18 | ; | +| Preconditions.java:68:9:68:45 | assertTrue(...) | exception | Preconditions.java:67:10:67:15 | Exceptional Exit | | Preconditions.java:68:9:68:45 | assertTrue(...) | no exception | Preconditions.java:69:9:69:18 | ; | +| Preconditions.java:73:9:73:46 | assertTrue(...) | exception | Preconditions.java:72:10:72:15 | Exceptional Exit | | Preconditions.java:73:9:73:46 | assertTrue(...) | no exception | Preconditions.java:74:9:74:18 | ; | +| Preconditions.java:78:9:78:47 | assertFalse(...) | exception | Preconditions.java:77:10:77:15 | Exceptional Exit | | Preconditions.java:78:9:78:47 | assertFalse(...) | no exception | Preconditions.java:79:9:79:18 | ; | +| Preconditions.java:83:9:83:46 | assertFalse(...) | exception | Preconditions.java:82:10:82:15 | Exceptional Exit | | Preconditions.java:83:9:83:46 | assertFalse(...) | no exception | Preconditions.java:84:9:84:18 | ; | +| Preconditions.java:88:9:88:15 | t(...) | exception | Preconditions.java:87:10:87:15 | Exceptional Exit | | Preconditions.java:88:9:88:15 | t(...) | no exception | Preconditions.java:89:9:89:18 | ; | +| Preconditions.java:93:9:93:16 | t(...) | exception | Preconditions.java:92:10:92:15 | Exceptional Exit | | Preconditions.java:93:9:93:16 | t(...) | no exception | Preconditions.java:94:9:94:18 | ; | +| Preconditions.java:98:9:98:16 | f(...) | exception | Preconditions.java:97:10:97:15 | Exceptional Exit | | Preconditions.java:98:9:98:16 | f(...) | no exception | Preconditions.java:99:9:99:18 | ; | +| Preconditions.java:103:9:103:15 | f(...) | exception | Preconditions.java:102:10:102:15 | Exceptional Exit | | Preconditions.java:103:9:103:15 | f(...) | no exception | Preconditions.java:104:9:104:18 | ; | +| Preconditions.java:108:9:108:46 | assertTrue(...) | exception | Preconditions.java:107:17:107:17 | Exceptional Exit | +| Preconditions.java:108:9:108:46 | assertTrue(...) | no exception | Preconditions.java:107:17:107:17 | Normal Exit | +| Preconditions.java:112:9:112:47 | assertFalse(...) | exception | Preconditions.java:111:17:111:17 | Exceptional Exit | +| Preconditions.java:112:9:112:47 | assertFalse(...) | no exception | Preconditions.java:111:17:111:17 | Normal Exit | diff --git a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected index a849ab5392d5..d389eb658f5e 100644 --- a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected +++ b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected @@ -1,4 +1,4 @@ -| MultiCatch.java:6:14:6:23 | super(...) | MultiCatch.java:6:14:6:23 | Exit | +| MultiCatch.java:6:14:6:23 | super(...) | MultiCatch.java:6:14:6:23 | Normal Exit | | MultiCatch.java:6:14:6:23 | { ... } | MultiCatch.java:6:14:6:23 | super(...) | | MultiCatch.java:8:2:20:2 | { ... } | MultiCatch.java:9:3:19:3 | try ... | | MultiCatch.java:9:3:19:3 | try ... | MultiCatch.java:10:3:15:3 | { ... } | @@ -16,7 +16,7 @@ | MultiCatch.java:17:4:17:4 | e | MultiCatch.java:17:4:17:22 | printStackTrace(...) | | MultiCatch.java:17:4:17:22 | printStackTrace(...) | MultiCatch.java:18:10:18:10 | e | | MultiCatch.java:17:4:17:23 | ; | MultiCatch.java:17:4:17:4 | e | -| MultiCatch.java:18:4:18:11 | throw ... | MultiCatch.java:7:14:7:23 | Exit | +| MultiCatch.java:18:4:18:11 | throw ... | MultiCatch.java:7:14:7:23 | Exceptional Exit | | MultiCatch.java:18:10:18:10 | e | MultiCatch.java:18:4:18:11 | throw ... | | MultiCatch.java:23:2:33:2 | { ... } | MultiCatch.java:24:3:32:4 | try ... | | MultiCatch.java:24:3:32:4 | try ... | MultiCatch.java:25:3:31:3 | { ... } | @@ -31,12 +31,12 @@ | MultiCatch.java:28:12:28:12 | c | MultiCatch.java:30:10:30:24 | new Exception(...) | | MultiCatch.java:29:5:29:29 | throw ... | MultiCatch.java:31:5:31:37 | catch (...) | | MultiCatch.java:29:11:29:28 | new SQLException(...) | MultiCatch.java:29:5:29:29 | throw ... | -| MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:22:14:22:24 | Exit | +| MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:22:14:22:24 | Exceptional Exit | | MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:31:5:31:37 | catch (...) | | MultiCatch.java:30:10:30:24 | new Exception(...) | MultiCatch.java:30:4:30:25 | throw ... | | MultiCatch.java:31:5:31:37 | catch (...) | MultiCatch.java:31:36:31:36 | e | | MultiCatch.java:31:36:31:36 | e | MultiCatch.java:32:3:32:4 | { ... } | -| MultiCatch.java:32:3:32:4 | { ... } | MultiCatch.java:22:14:22:24 | Exit | +| MultiCatch.java:32:3:32:4 | { ... } | MultiCatch.java:22:14:22:24 | Normal Exit | | MultiCatch.java:36:2:42:2 | { ... } | MultiCatch.java:37:3:41:4 | try ... | | MultiCatch.java:37:3:41:4 | try ... | MultiCatch.java:38:3:40:3 | { ... } | | MultiCatch.java:38:3:40:3 | { ... } | MultiCatch.java:39:10:39:26 | new IOException(...) | @@ -45,4 +45,4 @@ | MultiCatch.java:39:10:39:26 | new IOException(...) | MultiCatch.java:40:5:40:22 | catch (...) | | MultiCatch.java:40:5:40:22 | catch (...) | MultiCatch.java:40:21:40:21 | e | | MultiCatch.java:40:21:40:21 | e | MultiCatch.java:41:3:41:4 | { ... } | -| MultiCatch.java:41:3:41:4 | { ... } | MultiCatch.java:35:14:35:26 | Exit | +| MultiCatch.java:41:3:41:4 | { ... } | MultiCatch.java:35:14:35:26 | Normal Exit | diff --git a/java/ql/test/library-tests/pattern-instanceof/cfg.expected b/java/ql/test/library-tests/pattern-instanceof/cfg.expected index b6caebd532a6..5ef73c8ac78d 100644 --- a/java/ql/test/library-tests/pattern-instanceof/cfg.expected +++ b/java/ql/test/library-tests/pattern-instanceof/cfg.expected @@ -1,5 +1,9 @@ -| Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | Exceptional Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | Normal Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Normal Exit | | Test.java:1:14:1:17 | { ... } | Test.java:1:14:1:17 | super(...) | +| Test.java:3:22:3:25 | Exceptional Exit | Test.java:3:22:3:25 | Exit | +| Test.java:3:22:3:25 | Normal Exit | Test.java:3:22:3:25 | Exit | | Test.java:3:40:20:3 | { ... } | Test.java:5:5:5:34 | var ...; | | Test.java:5:5:5:34 | var ...; | Test.java:5:26:5:33 | source(...) | | Test.java:5:12:5:33 | directTaint | Test.java:6:5:6:36 | var ...; | @@ -29,7 +33,7 @@ | Test.java:11:12:11:12 | s | Test.java:11:7:11:13 | sink(...) | | Test.java:14:5:14:92 | if (...) | Test.java:14:9:14:9 | o | | Test.java:14:9:14:9 | o | Test.java:14:9:14:91 | ...instanceof... | -| Test.java:14:9:14:91 | ...instanceof... | Test.java:3:22:3:25 | Exit | +| Test.java:14:9:14:91 | ...instanceof... | Test.java:3:22:3:25 | Normal Exit | | Test.java:14:9:14:91 | ...instanceof... | Test.java:14:41:14:47 | tainted | | Test.java:14:22:14:91 | Outer(...) | Test.java:14:94:18:5 | { ... } | | Test.java:14:28:14:67 | Inner(...) | Test.java:14:77:14:90 | alsoNotTainted | @@ -43,17 +47,23 @@ | Test.java:16:7:16:22 | sink(...) | Test.java:17:7:17:27 | ; | | Test.java:16:7:16:23 | ; | Test.java:16:12:16:21 | notTainted | | Test.java:16:12:16:21 | notTainted | Test.java:16:7:16:22 | sink(...) | -| Test.java:17:7:17:26 | sink(...) | Test.java:3:22:3:25 | Exit | +| Test.java:17:7:17:26 | sink(...) | Test.java:3:22:3:25 | Normal Exit | | Test.java:17:7:17:27 | ; | Test.java:17:12:17:25 | alsoNotTainted | | Test.java:17:12:17:25 | alsoNotTainted | Test.java:17:7:17:26 | sink(...) | +| Test.java:22:24:22:29 | Exceptional Exit | Test.java:22:24:22:29 | Exit | +| Test.java:22:24:22:29 | Normal Exit | Test.java:22:24:22:29 | Exit | | Test.java:22:33:22:53 | { ... } | Test.java:22:42:22:50 | "tainted" | -| Test.java:22:35:22:51 | return ... | Test.java:22:24:22:29 | Exit | +| Test.java:22:35:22:51 | return ... | Test.java:22:24:22:29 | Normal Exit | | Test.java:22:42:22:50 | "tainted" | Test.java:22:35:22:51 | return ... | -| Test.java:23:40:23:42 | { ... } | Test.java:23:22:23:25 | Exit | +| Test.java:23:22:23:25 | Exceptional Exit | Test.java:23:22:23:25 | Exit | +| Test.java:23:22:23:25 | Normal Exit | Test.java:23:22:23:25 | Exit | +| Test.java:23:40:23:42 | { ... } | Test.java:23:22:23:25 | Normal Exit | | Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | ; | -| Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | Exit | +| Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | Normal Exit | | Test.java:27:8:27:12 | ; | Test.java:27:8:27:12 | this | | Test.java:27:8:27:12 | ; | Test.java:27:8:27:12 | this | +| Test.java:27:8:27:12 | Exceptional Exit | Test.java:27:8:27:12 | Exit | +| Test.java:27:8:27:12 | Normal Exit | Test.java:27:8:27:12 | Exit | | Test.java:27:8:27:12 | i | Test.java:27:8:27:12 | ...=... | | Test.java:27:8:27:12 | otherField | Test.java:27:8:27:12 | ...=... | | Test.java:27:8:27:12 | super(...) | Test.java:27:8:27:12 | ; | @@ -61,9 +71,11 @@ | Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | otherField | | Test.java:27:8:27:12 | { ... } | Test.java:27:8:27:12 | super(...) | | Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | ; | -| Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | Exit | +| Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | Normal Exit | | Test.java:28:8:28:12 | ; | Test.java:28:8:28:12 | this | | Test.java:28:8:28:12 | ; | Test.java:28:8:28:12 | this | +| Test.java:28:8:28:12 | Exceptional Exit | Test.java:28:8:28:12 | Exit | +| Test.java:28:8:28:12 | Normal Exit | Test.java:28:8:28:12 | Exit | | Test.java:28:8:28:12 | nonTaintedField | Test.java:28:8:28:12 | ...=... | | Test.java:28:8:28:12 | super(...) | Test.java:28:8:28:12 | ; | | Test.java:28:8:28:12 | taintedField | Test.java:28:8:28:12 | ...=... | diff --git a/java/ql/test/library-tests/pattern-switch/cfg/test.expected b/java/ql/test/library-tests/pattern-switch/cfg/test.expected index c29059faf33e..f9058bd8f4c2 100644 --- a/java/ql/test/library-tests/pattern-switch/cfg/test.expected +++ b/java/ql/test/library-tests/pattern-switch/cfg/test.expected @@ -1,6 +1,12 @@ -| Exhaustive.java:1:14:1:23 | super(...) | Exhaustive.java:1:14:1:23 | Exit | +| Exhaustive.java:1:14:1:23 | Exceptional Exit | Exhaustive.java:1:14:1:23 | Exit | +| Exhaustive.java:1:14:1:23 | Normal Exit | Exhaustive.java:1:14:1:23 | Exit | +| Exhaustive.java:1:14:1:23 | super(...) | Exhaustive.java:1:14:1:23 | Normal Exit | | Exhaustive.java:1:14:1:23 | { ... } | Exhaustive.java:1:14:1:23 | super(...) | -| Exhaustive.java:3:8:3:8 | super(...) | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | Exceptional Exit | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | Exceptional Exit | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | Normal Exit | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | Normal Exit | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | super(...) | Exhaustive.java:3:8:3:8 | Normal Exit | | Exhaustive.java:3:8:3:8 | { ... } | Exhaustive.java:3:8:3:8 | super(...) | | Exhaustive.java:3:8:3:8 | { ... } | Exhaustive.java:3:12:3:12 | ; | | Exhaustive.java:3:12:3:12 | ...=... | Exhaustive.java:3:15:3:15 | ; | @@ -9,13 +15,19 @@ | Exhaustive.java:3:15:3:15 | ...=... | Exhaustive.java:3:18:3:18 | ; | | Exhaustive.java:3:15:3:15 | ; | Exhaustive.java:3:15:3:15 | new E(...) | | Exhaustive.java:3:15:3:15 | new E(...) | Exhaustive.java:3:15:3:15 | ...=... | -| Exhaustive.java:3:18:3:18 | ...=... | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:18:3:18 | ...=... | Exhaustive.java:3:8:3:8 | Normal Exit | | Exhaustive.java:3:18:3:18 | ; | Exhaustive.java:3:18:3:18 | new E(...) | | Exhaustive.java:3:18:3:18 | new E(...) | Exhaustive.java:3:18:3:18 | ...=... | -| Exhaustive.java:5:15:5:15 | super(...) | Exhaustive.java:5:15:5:15 | Exit | +| Exhaustive.java:5:15:5:15 | Exceptional Exit | Exhaustive.java:5:15:5:15 | Exit | +| Exhaustive.java:5:15:5:15 | Normal Exit | Exhaustive.java:5:15:5:15 | Exit | +| Exhaustive.java:5:15:5:15 | super(...) | Exhaustive.java:5:15:5:15 | Normal Exit | | Exhaustive.java:5:15:5:15 | { ... } | Exhaustive.java:5:15:5:15 | super(...) | -| Exhaustive.java:6:15:6:15 | super(...) | Exhaustive.java:6:15:6:15 | Exit | +| Exhaustive.java:6:15:6:15 | Exceptional Exit | Exhaustive.java:6:15:6:15 | Exit | +| Exhaustive.java:6:15:6:15 | Normal Exit | Exhaustive.java:6:15:6:15 | Exit | +| Exhaustive.java:6:15:6:15 | super(...) | Exhaustive.java:6:15:6:15 | Normal Exit | | Exhaustive.java:6:15:6:15 | { ... } | Exhaustive.java:6:15:6:15 | super(...) | +| Exhaustive.java:8:22:8:25 | Exceptional Exit | Exhaustive.java:8:22:8:25 | Exit | +| Exhaustive.java:8:22:8:25 | Normal Exit | Exhaustive.java:8:22:8:25 | Exit | | Exhaustive.java:8:47:35:3 | { ... } | Exhaustive.java:11:5:11:14 | switch (...) | | Exhaustive.java:11:5:11:14 | switch (...) | Exhaustive.java:11:13:11:13 | o | | Exhaustive.java:11:13:11:13 | o | Exhaustive.java:12:7:12:22 | case | @@ -50,11 +62,15 @@ | Exhaustive.java:30:13:30:13 | i | Exhaustive.java:31:7:31:15 | case | | Exhaustive.java:31:7:31:15 | case | Exhaustive.java:31:14:31:14 | | | Exhaustive.java:31:7:31:15 | case | Exhaustive.java:32:7:32:15 | case | -| Exhaustive.java:31:14:31:14 | | Exhaustive.java:8:22:8:25 | Exit | +| Exhaustive.java:31:14:31:14 | | Exhaustive.java:8:22:8:25 | Normal Exit | | Exhaustive.java:32:7:32:15 | case | Exhaustive.java:32:14:32:14 | | -| Exhaustive.java:32:14:32:14 | | Exhaustive.java:8:22:8:25 | Exit | -| Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Exit | +| Exhaustive.java:32:14:32:14 | | Exhaustive.java:8:22:8:25 | Normal Exit | +| Test.java:1:14:1:17 | Exceptional Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | Normal Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Normal Exit | | Test.java:1:14:1:17 | { ... } | Test.java:1:14:1:17 | super(...) | +| Test.java:3:22:3:25 | Exceptional Exit | Test.java:3:22:3:25 | Exit | +| Test.java:3:22:3:25 | Normal Exit | Test.java:3:22:3:25 | Exit | | Test.java:3:41:134:3 | { ... } | Test.java:5:6:5:19 | switch (...) | | Test.java:5:6:5:19 | switch (...) | Test.java:5:14:5:18 | thing | | Test.java:5:14:5:18 | thing | Test.java:6:8:6:23 | case | @@ -380,11 +396,13 @@ | Test.java:130:8:130:21 | case | Test.java:130:20:130:20 | | | Test.java:130:8:130:21 | case | Test.java:131:8:131:15 | default | | Test.java:130:20:130:20 | | Test.java:131:8:131:15 | default | -| Test.java:131:8:131:15 | default | Test.java:3:22:3:25 | Exit | +| Test.java:131:8:131:15 | default | Test.java:3:22:3:25 | Normal Exit | | Test.java:138:8:138:8 | ...=... | Test.java:138:8:138:8 | ; | -| Test.java:138:8:138:8 | ...=... | Test.java:138:8:138:8 | Exit | +| Test.java:138:8:138:8 | ...=... | Test.java:138:8:138:8 | Normal Exit | | Test.java:138:8:138:8 | ; | Test.java:138:8:138:8 | this | | Test.java:138:8:138:8 | ; | Test.java:138:8:138:8 | this | +| Test.java:138:8:138:8 | Exceptional Exit | Test.java:138:8:138:8 | Exit | +| Test.java:138:8:138:8 | Normal Exit | Test.java:138:8:138:8 | Exit | | Test.java:138:8:138:8 | b | Test.java:138:8:138:8 | ...=... | | Test.java:138:8:138:8 | field3 | Test.java:138:8:138:8 | ...=... | | Test.java:138:8:138:8 | super(...) | Test.java:138:8:138:8 | ; | @@ -392,9 +410,11 @@ | Test.java:138:8:138:8 | this | Test.java:138:8:138:8 | field3 | | Test.java:138:8:138:8 | { ... } | Test.java:138:8:138:8 | super(...) | | Test.java:139:8:139:8 | ...=... | Test.java:139:8:139:8 | ; | -| Test.java:139:8:139:8 | ...=... | Test.java:139:8:139:8 | Exit | +| Test.java:139:8:139:8 | ...=... | Test.java:139:8:139:8 | Normal Exit | | Test.java:139:8:139:8 | ; | Test.java:139:8:139:8 | this | | Test.java:139:8:139:8 | ; | Test.java:139:8:139:8 | this | +| Test.java:139:8:139:8 | Exceptional Exit | Test.java:139:8:139:8 | Exit | +| Test.java:139:8:139:8 | Normal Exit | Test.java:139:8:139:8 | Exit | | Test.java:139:8:139:8 | field1 | Test.java:139:8:139:8 | ...=... | | Test.java:139:8:139:8 | field2 | Test.java:139:8:139:8 | ...=... | | Test.java:139:8:139:8 | super(...) | Test.java:139:8:139:8 | ; | diff --git a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected index a6f3820334af..fc529feba134 100644 --- a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected @@ -1,5 +1,9 @@ -| CloseReaderTest.java:8:14:8:28 | super(...) | CloseReaderTest.java:8:14:8:28 | Exit | +| CloseReaderTest.java:8:14:8:28 | Exceptional Exit | CloseReaderTest.java:8:14:8:28 | Exit | +| CloseReaderTest.java:8:14:8:28 | Normal Exit | CloseReaderTest.java:8:14:8:28 | Exit | +| CloseReaderTest.java:8:14:8:28 | super(...) | CloseReaderTest.java:8:14:8:28 | Normal Exit | | CloseReaderTest.java:8:14:8:28 | { ... } | CloseReaderTest.java:8:14:8:28 | super(...) | +| CloseReaderTest.java:9:23:9:34 | Exceptional Exit | CloseReaderTest.java:9:23:9:34 | Exit | +| CloseReaderTest.java:9:23:9:34 | Normal Exit | CloseReaderTest.java:9:23:9:34 | Exit | | CloseReaderTest.java:10:2:24:2 | { ... } | CloseReaderTest.java:12:3:13:42 | ; | | CloseReaderTest.java:12:3:12:12 | System.out | CloseReaderTest.java:12:20:12:40 | "Enter password for " | | CloseReaderTest.java:12:3:13:41 | print(...) | CloseReaderTest.java:14:3:14:21 | ; | @@ -19,12 +23,12 @@ | CloseReaderTest.java:16:5:16:13 | System.in | CloseReaderTest.java:15:45:16:14 | new InputStreamReader(...) | | CloseReaderTest.java:17:3:23:3 | try ... | CloseReaderTest.java:18:3:20:3 | { ... } | | CloseReaderTest.java:18:3:20:3 | { ... } | CloseReaderTest.java:19:11:19:15 | stdin | -| CloseReaderTest.java:19:4:19:27 | return ... | CloseReaderTest.java:9:23:9:34 | Exit | +| CloseReaderTest.java:19:4:19:27 | return ... | CloseReaderTest.java:9:23:9:34 | Normal Exit | | CloseReaderTest.java:19:11:19:15 | stdin | CloseReaderTest.java:19:11:19:26 | readLine(...) | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:19:4:19:27 | return ... | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:20:5:20:26 | catch (...) | | CloseReaderTest.java:20:5:20:26 | catch (...) | CloseReaderTest.java:20:24:20:25 | ex | | CloseReaderTest.java:20:24:20:25 | ex | CloseReaderTest.java:21:3:23:3 | { ... } | | CloseReaderTest.java:21:3:23:3 | { ... } | CloseReaderTest.java:22:11:22:14 | null | -| CloseReaderTest.java:22:4:22:15 | return ... | CloseReaderTest.java:9:23:9:34 | Exit | +| CloseReaderTest.java:22:4:22:15 | return ... | CloseReaderTest.java:9:23:9:34 | Normal Exit | | CloseReaderTest.java:22:11:22:14 | null | CloseReaderTest.java:22:4:22:15 | return ... | diff --git a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected index dcf2dac3cca1..3566cc8753f2 100644 --- a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected @@ -1,5 +1,9 @@ -| LoopVarReadTest.java:3:14:3:28 | super(...) | LoopVarReadTest.java:3:14:3:28 | Exit | +| LoopVarReadTest.java:3:14:3:28 | Exceptional Exit | LoopVarReadTest.java:3:14:3:28 | Exit | +| LoopVarReadTest.java:3:14:3:28 | Normal Exit | LoopVarReadTest.java:3:14:3:28 | Exit | +| LoopVarReadTest.java:3:14:3:28 | super(...) | LoopVarReadTest.java:3:14:3:28 | Normal Exit | | LoopVarReadTest.java:3:14:3:28 | { ... } | LoopVarReadTest.java:3:14:3:28 | super(...) | +| LoopVarReadTest.java:4:21:4:28 | Exceptional Exit | LoopVarReadTest.java:4:21:4:28 | Exit | +| LoopVarReadTest.java:4:21:4:28 | Normal Exit | LoopVarReadTest.java:4:21:4:28 | Exit | | LoopVarReadTest.java:5:2:15:2 | { ... } | LoopVarReadTest.java:6:3:6:12 | var ...; | | LoopVarReadTest.java:6:3:6:12 | var ...; | LoopVarReadTest.java:6:11:6:11 | 2 | | LoopVarReadTest.java:6:7:6:11 | x | LoopVarReadTest.java:7:3:7:33 | for (...;...;...) | @@ -23,6 +27,6 @@ | LoopVarReadTest.java:12:7:12:12 | q | LoopVarReadTest.java:14:3:14:28 | ; | | LoopVarReadTest.java:12:11:12:12 | 10 | LoopVarReadTest.java:12:7:12:12 | q | | LoopVarReadTest.java:14:3:14:12 | System.out | LoopVarReadTest.java:14:22:14:26 | "foo" | -| LoopVarReadTest.java:14:3:14:27 | println(...) | LoopVarReadTest.java:4:21:4:28 | Exit | +| LoopVarReadTest.java:14:3:14:27 | println(...) | LoopVarReadTest.java:4:21:4:28 | Normal Exit | | LoopVarReadTest.java:14:3:14:28 | ; | LoopVarReadTest.java:14:3:14:12 | System.out | | LoopVarReadTest.java:14:22:14:26 | "foo" | LoopVarReadTest.java:14:3:14:27 | println(...) | diff --git a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected index 3c261f67ee15..640e731147f9 100644 --- a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected @@ -1,5 +1,9 @@ -| SaveFileTest.java:11:14:11:25 | super(...) | SaveFileTest.java:11:14:11:25 | Exit | +| SaveFileTest.java:11:14:11:25 | Exceptional Exit | SaveFileTest.java:11:14:11:25 | Exit | +| SaveFileTest.java:11:14:11:25 | Normal Exit | SaveFileTest.java:11:14:11:25 | Exit | +| SaveFileTest.java:11:14:11:25 | super(...) | SaveFileTest.java:11:14:11:25 | Normal Exit | | SaveFileTest.java:11:14:11:25 | { ... } | SaveFileTest.java:11:14:11:25 | super(...) | +| SaveFileTest.java:12:14:12:21 | Exceptional Exit | SaveFileTest.java:12:14:12:21 | Exit | +| SaveFileTest.java:12:14:12:21 | Normal Exit | SaveFileTest.java:12:14:12:21 | Exit | | SaveFileTest.java:15:2:55:2 | { ... } | SaveFileTest.java:17:3:17:25 | var ...; | | SaveFileTest.java:17:3:17:25 | var ...; | SaveFileTest.java:17:21:17:24 | path | | SaveFileTest.java:17:10:17:24 | savePath | SaveFileTest.java:18:3:18:27 | if (...) | @@ -95,9 +99,11 @@ | SaveFileTest.java:48:5:48:15 | flush(...) | SaveFileTest.java:50:6:50:30 | catch (...) | | SaveFileTest.java:48:5:48:16 | ; | SaveFileTest.java:48:5:48:7 | bos | | SaveFileTest.java:49:5:49:7 | bos | SaveFileTest.java:49:5:49:15 | close(...) | -| SaveFileTest.java:49:5:49:15 | close(...) | SaveFileTest.java:12:14:12:21 | Exit | +| SaveFileTest.java:49:5:49:15 | close(...) | SaveFileTest.java:12:14:12:21 | Exceptional Exit | +| SaveFileTest.java:49:5:49:15 | close(...) | SaveFileTest.java:12:14:12:21 | Normal Exit | | SaveFileTest.java:49:5:49:15 | close(...) | SaveFileTest.java:50:6:50:30 | catch (...) | | SaveFileTest.java:49:5:49:16 | ; | SaveFileTest.java:49:5:49:7 | bos | | SaveFileTest.java:50:6:50:30 | catch (...) | SaveFileTest.java:50:23:50:29 | ignored | | SaveFileTest.java:50:23:50:29 | ignored | SaveFileTest.java:51:4:52:4 | { ... } | -| SaveFileTest.java:51:4:52:4 | { ... } | SaveFileTest.java:12:14:12:21 | Exit | +| SaveFileTest.java:51:4:52:4 | { ... } | SaveFileTest.java:12:14:12:21 | Exceptional Exit | +| SaveFileTest.java:51:4:52:4 | { ... } | SaveFileTest.java:12:14:12:21 | Normal Exit | diff --git a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected index c645abe35072..a23f6a2bc54e 100644 --- a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected @@ -1,9 +1,17 @@ -| SchackTest.java:1:14:1:23 | super(...) | SchackTest.java:1:14:1:23 | Exit | +| SchackTest.java:1:14:1:23 | Exceptional Exit | SchackTest.java:1:14:1:23 | Exit | +| SchackTest.java:1:14:1:23 | Normal Exit | SchackTest.java:1:14:1:23 | Exit | +| SchackTest.java:1:14:1:23 | super(...) | SchackTest.java:1:14:1:23 | Normal Exit | | SchackTest.java:1:14:1:23 | { ... } | SchackTest.java:1:14:1:23 | super(...) | -| SchackTest.java:2:8:2:10 | super(...) | SchackTest.java:2:8:2:10 | Exit | +| SchackTest.java:2:8:2:10 | Exceptional Exit | SchackTest.java:2:8:2:10 | Exit | +| SchackTest.java:2:8:2:10 | Normal Exit | SchackTest.java:2:8:2:10 | Exit | +| SchackTest.java:2:8:2:10 | super(...) | SchackTest.java:2:8:2:10 | Normal Exit | | SchackTest.java:2:8:2:10 | { ... } | SchackTest.java:2:8:2:10 | super(...) | -| SchackTest.java:3:8:3:10 | super(...) | SchackTest.java:3:8:3:10 | Exit | +| SchackTest.java:3:8:3:10 | Exceptional Exit | SchackTest.java:3:8:3:10 | Exit | +| SchackTest.java:3:8:3:10 | Normal Exit | SchackTest.java:3:8:3:10 | Exit | +| SchackTest.java:3:8:3:10 | super(...) | SchackTest.java:3:8:3:10 | Normal Exit | | SchackTest.java:3:8:3:10 | { ... } | SchackTest.java:3:8:3:10 | super(...) | +| SchackTest.java:5:7:5:9 | Exceptional Exit | SchackTest.java:5:7:5:9 | Exit | +| SchackTest.java:5:7:5:9 | Normal Exit | SchackTest.java:5:7:5:9 | Exit | | SchackTest.java:5:18:24:2 | { ... } | SchackTest.java:6:3:23:3 | try ... | | SchackTest.java:6:3:23:3 | try ... | SchackTest.java:6:7:17:3 | { ... } | | SchackTest.java:6:7:17:3 | { ... } | SchackTest.java:7:4:15:4 | try ... | @@ -56,18 +64,21 @@ | SchackTest.java:20:23:20:72 | "successor (but neither true nor false successor)" | SchackTest.java:20:4:20:73 | println(...) | | SchackTest.java:21:13:23:3 | { ... } | SchackTest.java:22:4:22:41 | ; | | SchackTest.java:22:4:22:13 | System.out | SchackTest.java:22:23:22:39 | "false successor" | -| SchackTest.java:22:4:22:40 | println(...) | SchackTest.java:5:7:5:9 | Exit | +| SchackTest.java:22:4:22:40 | println(...) | SchackTest.java:5:7:5:9 | Exceptional Exit | +| SchackTest.java:22:4:22:40 | println(...) | SchackTest.java:5:7:5:9 | Normal Exit | | SchackTest.java:22:4:22:41 | ; | SchackTest.java:22:4:22:13 | System.out | | SchackTest.java:22:23:22:39 | "false successor" | SchackTest.java:22:4:22:40 | println(...) | +| SchackTest.java:26:18:26:20 | Exceptional Exit | SchackTest.java:26:18:26:20 | Exit | +| SchackTest.java:26:18:26:20 | Normal Exit | SchackTest.java:26:18:26:20 | Exit | | SchackTest.java:26:35:30:2 | { ... } | SchackTest.java:27:3:27:25 | if (...) | | SchackTest.java:27:3:27:25 | if (...) | SchackTest.java:27:7:27:19 | random(...) | | SchackTest.java:27:7:27:19 | random(...) | SchackTest.java:27:23:27:24 | .5 | | SchackTest.java:27:7:27:24 | ... > ... | SchackTest.java:28:10:28:18 | new ExB(...) | | SchackTest.java:27:7:27:24 | ... > ... | SchackTest.java:29:10:29:22 | random(...) | | SchackTest.java:27:23:27:24 | .5 | SchackTest.java:27:7:27:24 | ... > ... | -| SchackTest.java:28:4:28:19 | throw ... | SchackTest.java:26:18:26:20 | Exit | +| SchackTest.java:28:4:28:19 | throw ... | SchackTest.java:26:18:26:20 | Exceptional Exit | | SchackTest.java:28:10:28:18 | new ExB(...) | SchackTest.java:28:4:28:19 | throw ... | -| SchackTest.java:29:3:29:28 | return ... | SchackTest.java:26:18:26:20 | Exit | +| SchackTest.java:29:3:29:28 | return ... | SchackTest.java:26:18:26:20 | Normal Exit | | SchackTest.java:29:10:29:22 | random(...) | SchackTest.java:29:26:29:27 | .3 | | SchackTest.java:29:10:29:27 | ... > ... | SchackTest.java:29:3:29:28 | return ... | | SchackTest.java:29:26:29:27 | .3 | SchackTest.java:29:10:29:27 | ... > ... | diff --git a/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected b/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected index 8dac71ffd45d..3fc266a0928c 100644 --- a/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected +++ b/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected @@ -1,5 +1,9 @@ -| TestBreak.java:3:14:3:22 | super(...) | TestBreak.java:3:14:3:22 | Exit | +| TestBreak.java:3:14:3:22 | Exceptional Exit | TestBreak.java:3:14:3:22 | Exit | +| TestBreak.java:3:14:3:22 | Normal Exit | TestBreak.java:3:14:3:22 | Exit | +| TestBreak.java:3:14:3:22 | super(...) | TestBreak.java:3:14:3:22 | Normal Exit | | TestBreak.java:3:14:3:22 | { ... } | TestBreak.java:3:14:3:22 | super(...) | +| TestBreak.java:4:14:4:14 | Exceptional Exit | TestBreak.java:4:14:4:14 | Exit | +| TestBreak.java:4:14:4:14 | Normal Exit | TestBreak.java:4:14:4:14 | Exit | | TestBreak.java:5:2:85:2 | { ... } | TestBreak.java:7:3:8:11 |