diff --git a/Cargo.lock b/Cargo.lock index 20b6f4933..2970388c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1208,6 +1208,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "ecdsa" version = "0.16.9" @@ -5308,6 +5314,7 @@ name = "yara-x-cli" version = "1.13.0" dependencies = [ "anyhow", + "ascii_tree", "assert_cmd", "assert_fs", "chardetng", @@ -5315,6 +5322,7 @@ dependencies = [ "clap_complete", "crossbeam", "crossterm 0.29.0", + "dunce", "enable-ansi-support", "encoding_rs", "env_logger", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fb32d3513..226c126ec 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -46,6 +46,7 @@ rules-profiling = ["yara-x/rules-profiling"] [dependencies] anyhow = { workspace = true } +ascii_tree = { workspace = true } clap = { workspace = true, features = ["cargo", "derive"] } clap_complete = { workspace = true } figment = { workspace = true, features = ["toml"] } @@ -71,6 +72,7 @@ yara-x-fmt = { workspace = true } chardetng = "0.1.17" crossbeam = "0.8.4" crossterm = "0.29.0" +dunce = "1.0.5" encoding_rs = "0.8.35" superconsole = "0.2.0" unicode-width = "0.2.2" diff --git a/cli/src/commands/deps.rs b/cli/src/commands/deps.rs new file mode 100644 index 000000000..4059f6b6e --- /dev/null +++ b/cli/src/commands/deps.rs @@ -0,0 +1,219 @@ +use std::collections::{BTreeMap, HashSet}; +use std::fs; +use std::path::PathBuf; + +use ::ascii_tree::write_tree; +use ::ascii_tree::Tree; +use ::ascii_tree::Tree::Node; +use anyhow::{bail, Context}; +use clap::{arg, value_parser, ArgAction, ArgMatches, Command}; + +use yara_x_parser::ast::dfs::{DFSContext, DFSEvent, DFSIter}; +use yara_x_parser::ast::{Expr, AST}; +use yara_x_parser::Parser; + +#[derive(Debug, Default)] +struct Deps<'a> { + rules: HashSet<&'a str>, + modules: HashSet<&'a str>, +} + +pub fn deps() -> Command { + super::command("deps") + .about("Show rule dependencies and modules") + // The `deps` command is not ready yet. + .hide(true) + .arg( + arg!() + .help("Path to YARA source file") + .value_parser(value_parser!(PathBuf)), + ) + .arg( + arg!(-r - -"rule") + .required(false) + .help("Rules to display dependency information for") + .action(ArgAction::Append), + ) +} + +pub fn exec_deps(args: &ArgMatches) -> anyhow::Result<()> { + let rules_path = args.get_one::("RULES_PATH").unwrap(); + let requested_rules = args.get_many::("rule"); + + let requested_rules: Vec<_> = requested_rules + .map_or(Vec::new(), |v| v.collect()) + .into_iter() + .map(|v| v.as_str()) + .collect(); + + let src = fs::read(rules_path) + .with_context(|| format!("can not read `{}`", rules_path.display()))?; + + let parser = Parser::new(src.as_slice()); + let ast: AST = parser.into(); + + if !ast.errors().is_empty() { + for err in ast.errors().iter() { + println!("{err:?}"); + } + bail!("{} syntax error(s) found", ast.errors().len()); + } + + // Map of rules to dependencies and modules they use. + // + // Given these rules: + // + // rule a { condition: pe.is_dll() } + // rule b { condition: a or x } + // + // Deps would look like: + // + // { + // "a": Deps { rules: {}, modules: {"pe"} }, + // "b": Deps { rules: {"a"}, modules: {} } + // } + // + // The unknown identifier "x" is silently ignored. + let mut dep_map: BTreeMap<&str, Deps> = BTreeMap::new(); + + for rule in ast.rules() { + if dep_map.insert(rule.identifier.name, Deps::default()).is_some() { + bail!("Duplicate rule \"{}\" found", rule.identifier.name); + }; + find_dependencies(&rule.condition, rule.identifier.name, &mut dep_map); + } + + let dep_tree = generate_dep_tree(&dep_map, &requested_rules); + + for dep in dep_tree.iter() { + let mut output = String::new(); + write_tree(&mut output, &dep)?; + println!("{output}"); + } + + Ok(()) +} + +fn generate_dep_tree( + dep_map: &BTreeMap<&str, Deps>, + requested_rules: &Vec<&str>, +) -> Vec { + let mut nodes: Vec = Vec::new(); + + for (rule, deps) in dep_map.iter() { + if requested_rules.is_empty() || requested_rules.contains(rule) { + nodes.push(tree_for_rule(rule, &deps, &dep_map)); + } + } + + nodes +} + +fn tree_for_rule( + rule: &str, + deps: &Deps, + dep_map: &BTreeMap<&str, Deps>, +) -> Tree { + let mut nodes: Vec = Vec::new(); + + for module in deps.modules.iter() { + nodes.push(Node(format!("mod: {module}"), vec![])); + } + + for dep in deps.rules.iter() { + match dep_map.get(dep) { + Some(new_deps) => { + nodes.push(tree_for_rule(dep, new_deps, dep_map)); + } + None => { + nodes.push(Node(dep.to_string(), vec![])); + } + } + } + + Node(rule.to_string(), nodes) +} + +fn find_dependencies<'a>( + expr: &'a Expr<'a>, + rule_name: &'a str, + dep_map: &mut BTreeMap<&'a str, Deps<'a>>, +) { + // Contains the variables that are currently defined. This acts + // as a stack where the variables defined by the innermost `for` + // or `with` statements are at top of the array. + let mut variables = Vec::new(); + // The `scopes` array contains the indexes within the `variables` + // array where a scope start. For instance, if we have two nested + // `with` statements where the outermost one defines variables `a` + // and `b`, while the innermost defines variables `c` and `d`, the + // `variables` vector will contain [`a`, `b`, `c`, `d`] and the + // `scopes` vector will contain: [2], which indicates that index + // within `variables` where the innermost scope starts. + let mut scopes = Vec::new(); + + let mut dfs = DFSIter::new(expr); + while let Some(event) = dfs.next() { + match event { + DFSEvent::Enter(expr) => { + match dfs.contexts().next() { + Some(DFSContext::Body(Expr::ForIn(for_in))) => { + scopes.push(variables.len()); + variables + .extend(for_in.variables.iter().map(|v| v.name)); + } + Some(DFSContext::Body(Expr::With(with))) => { + scopes.push(variables.len()); + variables.extend( + with.declarations + .iter() + .map(|d| d.identifier.name), + ); + } + _ => {} + } + if let Expr::Ident(ident) = expr { + // If this is a known variable, ignore it. + if variables.contains(&ident.name) { + continue; + } + if dep_map.contains_key(ident.name) { + // This is an identifier that matches a previously + // seen rule. + dep_map.entry(rule_name).and_modify(|v| { + v.rules.insert(ident.name); + }); + } else if yara_x::mods::module_names() + .any(|module| module == ident.name) + { + // This is a known module or is not in the list of + // variable identifier to be ignored. + dep_map.entry(rule_name).and_modify(|v| { + v.modules.insert(ident.name); + }); + } + } + } + DFSEvent::Leave(expr) => { + // When leaving a `for` or `with` statement, remove all the + // variables they defined. + if matches!(expr, Expr::ForIn(_) | Expr::With(_)) { + variables.drain(scopes.pop().unwrap()..); + } + // When leaving the operand of a FieldAccess expression we prune + // the DFS tree, which prevents the siblings of this node from + // being traversed. This implies that only the first operand of the + // FieldAccess node is visited. The rest of the operands of a + // field access expression can contain identifiers, but those + // identifiers will correspond to some field in a structure, not + // to a variable or module name. + if matches!( + dfs.contexts().next(), + Some(DFSContext::Operand(Expr::FieldAccess(_))) + ) { + dfs.prune(); + } + } + } + } +} diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index a129fde70..bf5f163a9 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -2,6 +2,7 @@ mod check; mod compile; mod completion; mod debug; +mod deps; mod dump; mod fix; mod fmt; @@ -12,6 +13,7 @@ pub use compile::*; pub use completion::*; #[cfg(feature = "debug-cmd")] pub use debug::*; +pub use deps::*; pub use dump::*; pub use fix::*; pub use fmt::*; @@ -70,6 +72,7 @@ pub fn cli() -> Command { commands::fmt(), commands::fix(), commands::completion(), + commands::deps(), ]) } diff --git a/cli/src/commands/scan.rs b/cli/src/commands/scan.rs index 97ace168d..4d549b79e 100644 --- a/cli/src/commands/scan.rs +++ b/cli/src/commands/scan.rs @@ -11,6 +11,7 @@ use clap::{ arg, value_parser, Arg, ArgAction, ArgMatches, Command, ValueEnum, }; use crossbeam::channel::Sender; +use dunce; use itertools::Itertools; use superconsole::style::Stylize; use superconsole::{Component, Line, Lines, Span}; @@ -1069,8 +1070,7 @@ mod output_handler { scan_results: &mut dyn ExactSizeIterator, _output: &Sender, ) -> bool { - let path = file_path - .canonicalize() + let path = dunce::canonicalize(&file_path) .ok() .as_ref() .and_then(|absolute| absolute.to_str()) diff --git a/cli/src/main.rs b/cli/src/main.rs index f95c4fa4d..040c172ea 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -91,6 +91,7 @@ fn main() -> anyhow::Result<()> { Some(("dump", args)) => commands::exec_dump(args), Some(("compile", args)) => commands::exec_compile(args, &config), Some(("completion", args)) => commands::exec_completion(args), + Some(("deps", args)) => commands::exec_deps(args), _ => unreachable!(), }; diff --git a/cli/src/tests/deps.rs b/cli/src/tests/deps.rs new file mode 100644 index 000000000..80642f265 --- /dev/null +++ b/cli/src/tests/deps.rs @@ -0,0 +1,428 @@ +use assert_cmd::{cargo_bin, Command}; +use assert_fs::prelude::*; +use assert_fs::TempDir; + +#[test] +fn basic_rule() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file.write_str("rule a { condition: true }").unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn duplicate_rule() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: true } rule a { condition: true }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .failure() + .code(1) + .stderr("error: Duplicate rule \"a\" found\n"); +} + +#[test] +fn specific_rule_only() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: true } rule b { condition: true }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg("-r") + .arg("b") + .arg(input_file.path()) + .assert() + .stdout( + r#" b + +"#, + ) + .success(); +} + +#[test] +fn rule_does_not_exist() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file.write_str("rule a { condition: true }").unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg("-r") + .arg("does_not_exist") + .arg(input_file.path()) + .assert() + .stdout(r#""#) + .success(); +} + +#[test] +fn unknown_identifier() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file.write_str("rule a { condition: x }").unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn module_identifier() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file.write_str("rule a { condition: pe.is_dll() }").unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn dependency_and_module() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + r#"rule a { condition: pe.is_dll() } rule b { condition: a } "#, + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + + b + └─ a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn for_in_variable_module_name() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: for 1 pe in (1): (pe > 0) }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn nested_variables() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + r#"rule a { + condition: + for 1 pe in (1): ( + for 1 elf in (2): ( + pe + elf > 0 + ) + ) + }"#, + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn with_variables() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + r#"rule a { + condition: + with pe = 1, elf = 2: ( + pe + elf > 0 + ) + }"#, + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn with_variables_and_unknown() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + r#"rule a { + condition: + with pe = 1, elf = 2: ( + pe + elf + x > 0 + ) + }"#, + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + +"#, + ) + .success(); +} + +#[test] +fn with_variables_and_previous_rule() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: true } rule b { condition: with a = 1: (a > 0) }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg("-r") + .arg("b") + .arg(input_file.path()) + .assert() + .stdout( + r#" b + +"#, + ) + .success(); +} +#[test] +fn with_module_in_expression() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + "rule a { condition: with a = pe: ( a.number_of_signatures > 0) }", + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn for_in_variable_module_name_other_module() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: for 1 pe in (1): (pe + elf.number_of_sections > 0) }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg("-r") + .arg("a") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: elf + +"#, + ) + .success(); +} + +#[test] +fn field_access() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: pe.number_of_sections > 0 }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn field_access_with_unknown_lookup() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: pe.signatures[i].issuer == \"foo\" }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn field_access_with_variable() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str("rule a { condition: for any i in (1..pe.number_of_signatures): (pe.signatures[i].issuer == \"foo\") }") + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + └─ mod: pe + +"#, + ) + .success(); +} + +#[test] +fn field_access_hiding_ident() { + let temp_dir = TempDir::new().unwrap(); + let input_file = temp_dir.child("rule.yar"); + + input_file + .write_str( + r#" + import "pe" + + rule a { + condition: + true + } + + rule b { + condition: + pe.a + } + "#, + ) + .unwrap(); + + Command::new(cargo_bin!("yr")) + .arg("deps") + .arg(input_file.path()) + .assert() + .stdout( + r#" a + + b + └─ mod: pe + +"#, + ) + .success(); +} diff --git a/cli/src/tests/mod.rs b/cli/src/tests/mod.rs index 7c4457260..ce96b93ff 100644 --- a/cli/src/tests/mod.rs +++ b/cli/src/tests/mod.rs @@ -1,6 +1,7 @@ mod check; #[cfg(feature = "debug-cmd")] mod debug; +mod deps; mod fix; mod fmt; mod scan; diff --git a/lib/fuzz/Cargo.lock b/lib/fuzz/Cargo.lock index dbbbeae16..c72494bd0 100644 --- a/lib/fuzz/Cargo.lock +++ b/lib/fuzz/Cargo.lock @@ -62,9 +62,9 @@ checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arbitrary" @@ -306,36 +306,36 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cdfa673abeaf2aa0634988468a751fbf5b3de612bd48c1bb36a3dc7e42fe44" +checksum = "d6abf69c884fde2d9d4cc232a585fb18f16af3ae04c634315c84ebe158ded92d" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744d5b84c226fe5dd5cc522552d2c69a55e1ea9f98e650b9075493d263698fca" +checksum = "263d31fcdf83a10267e8c38b53bc8f7688dfbc331267fd8fdf5b22e0dc47a55b" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9850ce67c4bdc5708204a24f3f571e1e933be2852ec785c778ad76e1f91a5e" +checksum = "d459d5377c01c4472b71029caa2df41afaf47711676aa9b12d7414f15104637b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa84e3a1dba026781d0a24761b072e03bbb404b8015f621d332457f627b3a19" +checksum = "8283088d5823ba7856ab8d531b7c3654b24984748f9fd99dcf3210701fd1d065" dependencies = [ "serde", "serde_derive", @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cabfe32111207a68ddd237d184300789c6d650d47db0ff7c9c53ef48e347902" +checksum = "7d3138316d8dd341d725d6ab1598750545c76ad32892837fde558edd68a01b43" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -370,9 +370,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc5479395bb325f96e2e5e714e8c276b061c0eaa020525332bf16c6046a825" +checksum = "505cead19304a8dc8689e31b29038775c3f73f9d5ea7a5e33864437a1f46c6b6" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -383,24 +383,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678aea3a48ca54a38e1b057c253daf2ff4c2869b1e70af6545bee1475434b20d" +checksum = "ce62ba94f570644ce7de6ed05bd39ca28936665dec10a2a1f6f2c531d6add45c" [[package]] name = "cranelift-control" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5210a53058d2b2504269d168fb075f80f3921126dd27e593e726b6387413be" +checksum = "db6cfe339689c3926412a7060ab00ef3b2b43d936b537e7a3f696121be9d0eaa" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb138631be4325459938ea0507fb6001a9bbfe6022ee130423acbd8583c47244" +checksum = "625518090e912bdfe3c41464bf97ae421f6044d4ca0f5c3267dcacdb352b033d" dependencies = [ "cranelift-bitset", "serde", @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c087396f79a0cdcdd38c7adc1e9955ba3022d026afb9f08769f0c13795d1b6b" +checksum = "17f652d40ddf3afb55be64d8979d312b52b384a8cebbcde1dd1c2e32ebcd4466" dependencies = [ "cranelift-codegen", "log", @@ -421,15 +421,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52eaa7b30b2a2d85f177790227f8f7a9b76d35da96302ef28fb394e588e3530b" +checksum = "9f512767e83015f4baf6e732cabca93cea82907e3ab237f826ef64f7ece75eb6" [[package]] name = "cranelift-native" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c68cefa46cc4e37728d0789a11744dc619a5bd96cabbe44cb9d8dcacc20134" +checksum = "cb1ca6e4dca568ff988d367e4707be2362cee9782265b0a501eaf467ffd550a8" dependencies = [ "cranelift-codegen", "libc", @@ -438,9 +438,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.127.3" +version = "0.127.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9092860471c4562c18ea1e47f446072795ad344a4a01f7d0f8cee445390d545" +checksum = "97400ad8fbd3a434092fc0b486fa7784150b53187941d818b1087f3ac0a547f0" [[package]] name = "crc" @@ -1540,9 +1540,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.184" +version = "2.1.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dc6a90669f481b41cae3005c68efa36bef275b95aa9123a7af7f1c68c6e5b2" +checksum = "4bd5cbe0eeb605e2029aa8bd29e17ae797c156705dc515e4db22c3d69f7126d9" dependencies = [ "psl-types", ] @@ -1555,9 +1555,9 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "pulley-interpreter" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63350fc565d2b7ab7f610d0655b28f5f80348658c2cf33d05d7ec43356c4be3c" +checksum = "5de307c194cf6310d486dd5595ffc329c53b4acafd54e214752c1eb2e68be3a9" dependencies = [ "cranelift-bitset", "log", @@ -1567,9 +1567,9 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d46b2339b894fed7983d91e5723c40e4bc593cb78cd86ffac0798d29f21372e0" +checksum = "99dca2747e910d10bafe911e172a1b35860268421c3ee5ddb7e16c35e0288b4a" dependencies = [ "proc-macro2", "quote", @@ -1642,9 +1642,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1665,9 +1665,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rfc6979" @@ -2326,9 +2326,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f033059744520d5943887511a83731856a78a00f0dac943dc9e9d2292289cad" +checksum = "0702b64d4c3fe43ae4ce229e06af06a27783e48c519e68586d180717cdd24314" dependencies = [ "addr2line", "anyhow", @@ -2367,9 +2367,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c6de1f26b145fbe9e6980b0495e1c855920091d31c0d1e32e7e49318211103" +checksum = "3ffeb777a21965a85e4b1ce7b308c63ba130df91912096b49b95523bf3bdd2c7" dependencies = [ "anyhow", "cranelift-bitset", @@ -2390,9 +2390,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-cranelift" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1fbd0cae8d129883a7bad7f2272e6662dcebf4e0f6b38539603359235959a" +checksum = "85da1ba5fee01a3ee21c4d0c8052cc9035388639fa091a969b534d4c6f8449d4" dependencies = [ "anyhow", "cfg-if", @@ -2418,9 +2418,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-fiber" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a2a724a50b8ace66a6089002cbe99eec0f611a15c78262739b6aeb590ab252" +checksum = "a4c7de5a0872764c1ca640886af10a70cf7f8526386906245b43cdb345ece0e6" dependencies = [ "anyhow", "cc", @@ -2433,9 +2433,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3ea5e264b8f6a3a91444ffee58449288e239c9d60c2483bf78c631f3269fa7" +checksum = "160acd973d770d62bef1b2697d7fac83a8fe63ef966215e624382b2a9532bd58" dependencies = [ "cc", "wasmtime-internal-versioned-export-macros", @@ -2443,9 +2443,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c161f4e0636998a68f2c2159260a0d8bbb2d2d2b762938f7be62b2ac0535ed4" +checksum = "cc57f590ba7ea967ea9e8c8560175c6926e5b15d11c29bbde3ad0013a29470eb" dependencies = [ "anyhow", "cfg-if", @@ -2455,24 +2455,24 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55d246d16cad85ab49f6e76026d934df2f45974d97eb2ab837a6312dda4c76a" +checksum = "07612904518d47b677e8db67ca47c16d8c8cefb0099020729f886776950cb58b" dependencies = [ "libm", ] [[package]] name = "wasmtime-internal-slab" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6e7127a10a3d38939c54fa3e1701512bd78340ec112ffc628c36516e38bd3a" +checksum = "bc83ff16531e1e1537e0de2b630af56a0a9e1fab864130c5b7e213da71783a0f" [[package]] name = "wasmtime-internal-unwinder" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a899f4006b6332a9312060c9216beaf58447da5939af8f19144138f59d6e366" +checksum = "47371d697244785e4bbb371229f9a2daa8628d1e03368ec895cf658370e1bf38" dependencies = [ "anyhow", "cfg-if", @@ -2483,9 +2483,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "40.0.3" +version = "40.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426e1088960ab200c49b8e5812667a442c705df018b5c57bd9b3cf80c12b0bdb" +checksum = "ad3cd4aff8f2e7ec658c7a0424b74ad88a6940505303fb0616323592a1c400a6" dependencies = [ "proc-macro2", "quote",