()
| 309 | |
| 310 | #[mz_ore::test] |
| 311 | fn zero_width_record_array_bounded() { |
| 312 | // Regression for an OOM found by the reader_decode fuzz target: an |
| 313 | // `array<record{null}>` element is zero-width on the wire (the byte-floor |
| 314 | // check below can't bound it) yet each element still allocates a |
| 315 | // `Value::Record`, so a multi-million-element block claimed from a |
| 316 | // handful of bytes amplified into gigabytes. The cumulative node cap must |
| 317 | // reject it rather than allocate. |
| 318 | use std::str::FromStr; |
| 319 | |
| 320 | use super::{AvroDeserializer, GeneralDeserializer}; |
| 321 | use crate::util::zig_i64; |
| 322 | use crate::{Schema, ValueDecoder}; |
| 323 | |
| 324 | let schema = Schema::from_str( |
| 325 | r#"{"type": "array", "items": |
| 326 | {"type": "record", "name": "R", "fields": [{"name": "g0", "type": "null"}]}}"#, |
| 327 | ) |
| 328 | .unwrap(); |
| 329 | // A single block claiming far more zero-width records than the node cap, |
| 330 | // followed by no element bytes at all. |
| 331 | let mut body = Vec::new(); |
| 332 | zig_i64(100_000_000, &mut body); |
| 333 | let dsr = GeneralDeserializer { |
| 334 | schema: schema.top_node(), |
| 335 | }; |
| 336 | let mut reader: &[u8] = &body; |
| 337 | let res = dsr.deserialize(&mut reader, ValueDecoder); |
| 338 | assert!( |
| 339 | res.is_err(), |
| 340 | "an array of zero-width records longer than the node cap must be rejected, not allocated" |
| 341 | ); |
| 342 | } |
| 343 | |
| 344 | #[mz_ore::test] |
| 345 | fn small_zero_width_record_array_decodes() { |
nothing calls this directly
no test coverage detected