From 3c1a7176cbae67ebda31c4ee5400bd5e551c4003 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Sun, 29 Jun 2025 21:17:39 +0300 Subject: [PATCH] feat(snix/eval): proper error handling for invalid regexes We don't want to crash the evaluator when an invalid regex is passed, but instead display a user-facing error message. This CL does that. Change-Id: I81fd8e342fc877344f8d2a3704ef53caf5190aa3 Reviewed-on: https://cl.snix.dev/c/snix/+/30588 Reviewed-by: Vova Kryachko Tested-by: besadii Reviewed-by: Bence Nemes --- snix/eval/src/builtins/mod.rs | 8 +++++--- snix/eval/src/errors.rs | 6 ++++++ .../tests/snix_tests/eval-fail-match-invalid-regex.nix | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 snix/eval/src/tests/snix_tests/eval-fail-match-invalid-regex.nix diff --git a/snix/eval/src/builtins/mod.rs b/snix/eval/src/builtins/mod.rs index 96a2734f2..127368565 100644 --- a/snix/eval/src/builtins/mod.rs +++ b/snix/eval/src/builtins/mod.rs @@ -991,8 +991,9 @@ mod pure_builtins { return Ok(re); } let re = re.to_str()?; - let re: Regex = - cached_regex(&format!("^{}$", re.to_str()?)).expect("TODO(tazjin): propagate error"); + let re = re.to_str()?; + let re: Regex = cached_regex(&format!("^{}$", re)) + .map_err(|_| ErrorKind::InvalidRegex(re.to_string()))?; match re.captures(s.to_str()?) { Some(caps) => Ok(Value::List( @@ -1213,7 +1214,8 @@ mod pure_builtins { let s = str.to_contextful_str()?; let text = s.to_str()?; let re = regex.to_str()?; - let re = cached_regex(re.to_str()?).unwrap(); + let re = re.to_str()?; + let re = cached_regex(re).map_err(|_| ErrorKind::InvalidRegex(re.to_string()))?; let mut capture_locations = re.capture_locations(); let num_captures = capture_locations.len(); let mut ret = Vec::new(); diff --git a/snix/eval/src/errors.rs b/snix/eval/src/errors.rs index 2e09a0881..36d4a92d7 100644 --- a/snix/eval/src/errors.rs +++ b/snix/eval/src/errors.rs @@ -294,6 +294,10 @@ to a missing value in the attribute set(s) included via `with`."# /// or "sha512" #[error("unknown hash type '{0}'")] UnknownHashType(String), + + /// An invalid regular expression was passed. + #[error("invalid regular expression '{0}'")] + InvalidRegex(String), } impl error::Error for Error { @@ -688,6 +692,7 @@ impl Error { | ErrorKind::WithContext { .. } | ErrorKind::UnknownHashType(_) | ErrorKind::InvalidHash(_) + | ErrorKind::InvalidRegex(_) | ErrorKind::CatchableError(_) => return None, }; @@ -735,6 +740,7 @@ impl Error { ErrorKind::UnknownHashType(_) => "E039", ErrorKind::UnexpectedArgumentBuiltin { .. } => "E040", ErrorKind::InvalidHash(_) => "E041", + ErrorKind::InvalidRegex(_) => "E042", // Special error code for errors from other Snix // components. We may want to introduce a code namespacing diff --git a/snix/eval/src/tests/snix_tests/eval-fail-match-invalid-regex.nix b/snix/eval/src/tests/snix_tests/eval-fail-match-invalid-regex.nix new file mode 100644 index 000000000..3c12e5bda --- /dev/null +++ b/snix/eval/src/tests/snix_tests/eval-fail-match-invalid-regex.nix @@ -0,0 +1 @@ +builtins.match "a(b))c" "abc"