Rust: Verifier::reset() does not reset apparent_size (duplicated num_tables assignment)
- Dominant language
- C++
- Stars
- 26.5k
- Forks
- 3.7k
- PR merge metrics
- No merged PRs in 30d
Description
### Summary
`Verifier::reset()` assigns `self.num_tables = 0` twice and never resets `self.apparent_size`. A `Verifier` reused via `reset()` therefore keeps accumulating `apparent_size` across uses, and once the running total exceeds `max_apparent_size` it rejects **every** subsequent buffer with `ApparentSizeTooLarge`, regardless of whether that buffer is valid.
https://github.com/google/flatbuffers/blob/81edeb17d9118143f2c81caf27edfb0df401279e/rust/flatbuffers/src/verifier.rs#L276-L282
```rust
/// Resets verifier internal state.
#[inline]
pub fn reset(&mut self) {
self.depth = 0;
self.num_tables = 0;
self.num_tables = 0; // <-- duplicated; `self.apparent_size = 0;` appears to be intended
}
```
`apparent_size` is initialized in `new()` and incremented in `range_in_buffer()`, but is never cleared anywhere:
```
274: Self { opts, buffer, depth: 0, num_tables: 0, apparent_size: 0 }
311: self.apparent_size += size;
312: if self.apparent_size > self.opts.max_apparent_size {
```
### Reproduction
Executed against the crate at `master` (`81edeb17`), version 25.12.19:
```rust
// rust/flatbuffers/tests/reset_apparent_size.rs
use flatbuffers::{InvalidFlatbuffer, Verifier, VerifierOptions};
#[test]
fn reset_should_clear_apparent_size() {
let opts = VerifierOptions { max_apparent_size: 100, ..Default::default() };
let buf = [0u8; 64];
let mut v = Verifier::new(&opts, &buf);
v.range_in_buffer(0, 60).expect("first range must fit");
v.reset();
match v.range_in_buffer(0, 60) {
Ok(()) => println!("reset() cleared apparent_size"),
Err(InvalidFlatbuffer::ApparentSizeTooLarge) => {
panic!("after reset(), apparent_size still held 60")
}
Err(e) => panic!("unexpected error: {e:?}"),
}
}
```
```
$ cargo test --test reset_apparent_size
thread 'reset_should_clear_apparent_size' panicked at:
after reset(), apparent_size still held 60
test result: FAILED. 0 passed; 1 failed
```
The second call is identical to the first and should succeed after a documented state reset; instead the running total reaches 120 against the 100-byte limit and is rejected.
### Impact
Correctness / availability, not a verification bypass — the effect is over-rejection of valid buffers, so it cannot cause malicious buffers to be accepted. Applications that reuse one `Verifier` across messages (which is what `reset()` exists for) will begin failing all verification once cumulative size passes `max_apparent_size` (default `1 << 31`).
### Suggested fix
```rust
pub fn reset(&mut self) {
self.depth = 0;
self.num_tables = 0;
self.apparent_size = 0;
}
```
Happy to send a PR if useful.
Contributor guide
Research direction
Start in rust/flatbuffers/src/verifier.rs at Verifier::reset() and the apparent_size accounting in range_in_buffer(). Run the reproduction in rust/flatbuffers/tests/reset_apparent_size.rs; done means reset allows the identical range to pass again without triggering ApparentSizeTooLarge.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 90/100