@@ -2344,10 +2344,17 @@ impl<'a> DFA<&'a [u32]> {
2344
2344
// table, match states and accelerators below. If any validation fails,
2345
2345
// then we return an error.
2346
2346
let ( dfa, nread) = unsafe { DFA :: from_bytes_unchecked ( slice) ? } ;
2347
+ // Note that validation order is important here:
2348
+ //
2349
+ // * `MatchState::validate` can be called with an untrusted DFA.
2350
+ // * `TransistionTable::validate` uses `dfa.ms` through `match_len`.
2351
+ // * `StartTable::validate` needs a valid transition table.
2352
+ //
2353
+ // So... validate the match states first.
2354
+ dfa. accels . validate ( ) ?;
2355
+ dfa. ms . validate ( & dfa) ?;
2347
2356
dfa. tt . validate ( & dfa) ?;
2348
2357
dfa. st . validate ( & dfa) ?;
2349
- dfa. ms . validate ( & dfa) ?;
2350
- dfa. accels . validate ( ) ?;
2351
2358
// N.B. dfa.special doesn't have a way to do unchecked deserialization,
2352
2359
// so it has already been validated.
2353
2360
for state in dfa. states ( ) {
@@ -5235,7 +5242,10 @@ mod tests {
5235
5242
assert_eq ! ( Err ( expected) , got) ;
5236
5243
}
5237
5244
5238
- // This panics in TransitionTable::validate if the match states are not validated first.
5245
+ // This panics in `TransitionTable::validate` if the match states are not
5246
+ // validated first.
5247
+ //
5248
+ // See: https://github.com/rust-lang/regex/pull/1295
5239
5249
#[ test]
5240
5250
fn regression_validation_order ( ) {
5241
5251
let mut dfa = DFA :: new ( "abc" ) . unwrap ( ) ;
0 commit comments