1 use alloc::string::{String, ToString}; 2 3 use regex_automata::meta; 4 5 /// An error that occurred during parsing or compiling a regular expression. 6 #[non_exhaustive] 7 #[derive(Clone, PartialEq)] 8 pub enum Error { 9 /// A syntax error. 10 Syntax(String), 11 /// The compiled program exceeded the set size 12 /// limit. The argument is the size limit imposed by 13 /// [`RegexBuilder::size_limit`](crate::RegexBuilder::size_limit). Even 14 /// when not configured explicitly, it defaults to a reasonable limit. 15 /// 16 /// If you're getting this error, it occurred because your regex has been 17 /// compiled to an intermediate state that is too big. It is important to 18 /// note that exceeding this limit does _not_ mean the regex is too big to 19 /// _work_, but rather, the regex is big enough that it may wind up being 20 /// surprisingly slow when used in a search. In other words, this error is 21 /// meant to be a practical heuristic for avoiding a performance footgun, 22 /// and especially so for the case where the regex pattern is coming from 23 /// an untrusted source. 24 /// 25 /// There are generally two ways to move forward if you hit this error. 26 /// The first is to find some way to use a smaller regex. The second is to 27 /// increase the size limit via `RegexBuilder::size_limit`. However, if 28 /// your regex pattern is not from a trusted source, then neither of these 29 /// approaches may be appropriate. Instead, you'll have to determine just 30 /// how big of a regex you want to allow. 31 CompiledTooBig(usize), 32 } 33 34 impl Error { from_meta_build_error(err: meta::BuildError) -> Error35 pub(crate) fn from_meta_build_error(err: meta::BuildError) -> Error { 36 if let Some(size_limit) = err.size_limit() { 37 Error::CompiledTooBig(size_limit) 38 } else if let Some(ref err) = err.syntax_error() { 39 Error::Syntax(err.to_string()) 40 } else { 41 // This is a little suspect. Technically there are more ways for 42 // a meta regex to fail to build other than "exceeded size limit" 43 // and "syntax error." For example, if there are too many states 44 // or even too many patterns. But in practice this is probably 45 // good enough. The worst thing that happens is that Error::Syntax 46 // represents an error that isn't technically a syntax error, but 47 // the actual message will still be shown. So... it's not too bad. 48 // 49 // We really should have made the Error type in the regex crate 50 // completely opaque. Rookie mistake. 51 Error::Syntax(err.to_string()) 52 } 53 } 54 } 55 56 #[cfg(feature = "std")] 57 impl std::error::Error for Error { 58 // TODO: Remove this method entirely on the next breaking semver release. 59 #[allow(deprecated)] description(&self) -> &str60 fn description(&self) -> &str { 61 match *self { 62 Error::Syntax(ref err) => err, 63 Error::CompiledTooBig(_) => "compiled program too big", 64 } 65 } 66 } 67 68 impl core::fmt::Display for Error { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result69 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 70 match *self { 71 Error::Syntax(ref err) => err.fmt(f), 72 Error::CompiledTooBig(limit) => write!( 73 f, 74 "Compiled regex exceeds size limit of {} bytes.", 75 limit 76 ), 77 } 78 } 79 } 80 81 // We implement our own Debug implementation so that we show nicer syntax 82 // errors when people use `Regex::new(...).unwrap()`. It's a little weird, 83 // but the `Syntax` variant is already storing a `String` anyway, so we might 84 // as well format it nicely. 85 impl core::fmt::Debug for Error { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result86 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 87 match *self { 88 Error::Syntax(ref err) => { 89 let hr: String = core::iter::repeat('~').take(79).collect(); 90 writeln!(f, "Syntax(")?; 91 writeln!(f, "{}", hr)?; 92 writeln!(f, "{}", err)?; 93 writeln!(f, "{}", hr)?; 94 write!(f, ")")?; 95 Ok(()) 96 } 97 Error::CompiledTooBig(limit) => { 98 f.debug_tuple("CompiledTooBig").field(&limit).finish() 99 } 100 } 101 } 102 } 103