chore(pumpkin-nbt): add fuzzing & benches
This commit is contained in:
parent
60ad62bbf1
commit
35b91efd38
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2951,6 +2951,7 @@ version = "0.1.0-dev+26.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cesu8",
|
"cesu8",
|
||||||
|
"criterion",
|
||||||
"flate2",
|
"flate2",
|
||||||
"pumpkin-codecs",
|
"pumpkin-codecs",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@ -17,6 +17,12 @@ tracing.workspace = true
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
criterion.workspace = true
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "nbt"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
114
pumpkin-nbt/benches/nbt.rs
Normal file
114
pumpkin-nbt/benches/nbt.rs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
use criterion::{Criterion, criterion_group, criterion_main};
|
||||||
|
use pumpkin_nbt::{Nbt, NbtCompound, deserializer, serializer, tag::NbtTag};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
struct LargeTest {
|
||||||
|
byte: i8,
|
||||||
|
short: i16,
|
||||||
|
int: i32,
|
||||||
|
long: i64,
|
||||||
|
float: f32,
|
||||||
|
double: f64,
|
||||||
|
string: String,
|
||||||
|
byte_array: Vec<u8>,
|
||||||
|
int_array: Vec<i32>,
|
||||||
|
long_array: Vec<i64>,
|
||||||
|
list_string: Vec<String>,
|
||||||
|
nested: Option<Box<Self>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_large_test_data(depth: usize) -> LargeTest {
|
||||||
|
LargeTest {
|
||||||
|
byte: 123,
|
||||||
|
short: 1342,
|
||||||
|
int: 4313,
|
||||||
|
long: 34,
|
||||||
|
float: 1.00,
|
||||||
|
double: 69.42,
|
||||||
|
string: "Hello test benchmark data".to_string(),
|
||||||
|
byte_array: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
int_array: vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
||||||
|
long_array: vec![20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
|
||||||
|
list_string: vec!["one".to_string(), "two".to_string(), "three".to_string()],
|
||||||
|
nested: (depth > 0).then(|| Box::new(create_large_test_data(depth - 1))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_large_compound(depth: usize) -> NbtCompound {
|
||||||
|
let mut compound = NbtCompound::new();
|
||||||
|
compound.put_byte("byte", 123);
|
||||||
|
compound.put_short("short", 1342);
|
||||||
|
compound.put_int("int", 4313);
|
||||||
|
compound.put_long("long", 34);
|
||||||
|
compound.put_float("float", 1.00);
|
||||||
|
compound.put_double("double", 69.42);
|
||||||
|
compound.put_string("string", "Hello test benchmark data".to_string());
|
||||||
|
compound.put(
|
||||||
|
"byte_array",
|
||||||
|
NbtTag::ByteArray(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
||||||
|
);
|
||||||
|
compound.put(
|
||||||
|
"int_array",
|
||||||
|
NbtTag::IntArray(vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
||||||
|
);
|
||||||
|
compound.put(
|
||||||
|
"long_array",
|
||||||
|
NbtTag::LongArray(vec![20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let list = vec![
|
||||||
|
NbtTag::String("one".to_string()),
|
||||||
|
NbtTag::String("two".to_string()),
|
||||||
|
NbtTag::String("three".to_string()),
|
||||||
|
];
|
||||||
|
compound.put_list("list_string", list);
|
||||||
|
|
||||||
|
if depth > 0 {
|
||||||
|
compound.put_compound("nested", create_large_compound(depth - 1));
|
||||||
|
}
|
||||||
|
compound
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bench_nbt(c: &mut Criterion) {
|
||||||
|
let test_data = create_large_test_data(5);
|
||||||
|
let mut ser_bytes = Vec::new();
|
||||||
|
serializer::to_bytes(&test_data, &mut ser_bytes).unwrap();
|
||||||
|
|
||||||
|
let compound_data = create_large_compound(5);
|
||||||
|
let nbt_wrapper = Nbt::new(String::new(), compound_data.clone());
|
||||||
|
let wrapper_bytes = nbt_wrapper.write();
|
||||||
|
|
||||||
|
c.bench_function("nbt/serialize/serde", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
serializer::to_bytes(&test_data, &mut out).unwrap();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("nbt/deserialize/serde", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let cursor = Cursor::new(&ser_bytes);
|
||||||
|
let _: LargeTest = deserializer::from_bytes(cursor).unwrap();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("nbt/serialize/raw", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let nbt = Nbt::new(String::new(), compound_data.clone());
|
||||||
|
let _ = nbt.write();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("nbt/deserialize/raw", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut cursor = Cursor::new(&wrapper_bytes);
|
||||||
|
let mut reader = deserializer::NbtReadHelper::new(&mut cursor);
|
||||||
|
Nbt::read(&mut reader).unwrap();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, bench_nbt);
|
||||||
|
criterion_main!(benches);
|
||||||
3
pumpkin-nbt/fuzz/.gitignore
vendored
Normal file
3
pumpkin-nbt/fuzz/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target
|
||||||
|
corpus
|
||||||
|
artifacts
|
||||||
362
pumpkin-nbt/fuzz/Cargo.lock
generated
Normal file
362
pumpkin-nbt/fuzz/Cargo.lock
generated
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler2"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.62"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
|
||||||
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cesu8"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.186"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libfuzzer-sys"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pumpkin-codecs"
|
||||||
|
version = "0.1.0-dev+26.1"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pumpkin-nbt"
|
||||||
|
version = "0.1.0-dev+26.1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"cesu8",
|
||||||
|
"flate2",
|
||||||
|
"pumpkin-codecs",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pumpkin-nbt-fuzz"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"libfuzzer-sys",
|
||||||
|
"pumpkin-nbt",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.3+wasi-0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.57.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
46
pumpkin-nbt/fuzz/Cargo.toml
Normal file
46
pumpkin-nbt/fuzz/Cargo.toml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
[package]
|
||||||
|
name = "pumpkin-nbt-fuzz"
|
||||||
|
version = "0.0.0"
|
||||||
|
publish = false
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libfuzzer-sys = "0.4"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
arbitrary = { version = "1.3", features = ["derive"] }
|
||||||
|
|
||||||
|
[dependencies.pumpkin-nbt]
|
||||||
|
path = ".."
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "deserialize"
|
||||||
|
path = "fuzz_targets/deserialize.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "deserialize_serde"
|
||||||
|
path = "fuzz_targets/deserialize_serde.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "decompress_gzip"
|
||||||
|
path = "fuzz_targets/decompress_gzip.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "roundtrip"
|
||||||
|
path = "fuzz_targets/roundtrip.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
bench = false
|
||||||
9
pumpkin-nbt/fuzz/fuzz_targets/decompress_gzip.rs
Normal file
9
pumpkin-nbt/fuzz/fuzz_targets/decompress_gzip.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use pumpkin_nbt::nbt_compress::read_gzip_compound_tag;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
let cursor = Cursor::new(data);
|
||||||
|
let _ = read_gzip_compound_tag(cursor);
|
||||||
|
});
|
||||||
15
pumpkin-nbt/fuzz/fuzz_targets/deserialize.rs
Normal file
15
pumpkin-nbt/fuzz/fuzz_targets/deserialize.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use pumpkin_nbt::Nbt;
|
||||||
|
use pumpkin_nbt::deserializer::NbtReadHelper;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
let mut cursor = Cursor::new(data);
|
||||||
|
let mut reader = NbtReadHelper::new(&mut cursor);
|
||||||
|
let _ = Nbt::read(&mut reader);
|
||||||
|
|
||||||
|
let mut cursor_unnamed = Cursor::new(data);
|
||||||
|
let mut reader_unnamed = NbtReadHelper::new(&mut cursor_unnamed);
|
||||||
|
let _ = Nbt::read_unnamed(&mut reader_unnamed);
|
||||||
|
});
|
||||||
29
pumpkin-nbt/fuzz/fuzz_targets/deserialize_serde.rs
Normal file
29
pumpkin-nbt/fuzz/fuzz_targets/deserialize_serde.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use pumpkin_nbt::deserializer::{from_bytes, from_bytes_unnamed};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
struct FuzzStruct {
|
||||||
|
byte: i8,
|
||||||
|
short: i16,
|
||||||
|
int: i32,
|
||||||
|
long: i64,
|
||||||
|
float: f32,
|
||||||
|
double: f64,
|
||||||
|
string: String,
|
||||||
|
byte_array: Vec<u8>,
|
||||||
|
int_array: Vec<i32>,
|
||||||
|
long_array: Vec<i64>,
|
||||||
|
list_string: Vec<String>,
|
||||||
|
nested: Option<Box<FuzzStruct>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzz_target!(|data: &[u8]| {
|
||||||
|
let cursor = Cursor::new(data);
|
||||||
|
let _: Result<FuzzStruct, _> = from_bytes(cursor);
|
||||||
|
|
||||||
|
let cursor_unnamed = Cursor::new(data);
|
||||||
|
let _: Result<FuzzStruct, _> = from_bytes_unnamed(cursor_unnamed);
|
||||||
|
});
|
||||||
33
pumpkin-nbt/fuzz/fuzz_targets/roundtrip.rs
Normal file
33
pumpkin-nbt/fuzz/fuzz_targets/roundtrip.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#![no_main]
|
||||||
|
use arbitrary::Arbitrary;
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use pumpkin_nbt::deserializer::from_bytes;
|
||||||
|
use pumpkin_nbt::serializer::to_bytes;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
struct RoundtripStruct {
|
||||||
|
byte: i8,
|
||||||
|
short: i16,
|
||||||
|
int: i32,
|
||||||
|
long: i64,
|
||||||
|
float: f32,
|
||||||
|
double: f64,
|
||||||
|
string: String,
|
||||||
|
byte_array: Vec<u8>,
|
||||||
|
int_array: Vec<i32>,
|
||||||
|
long_array: Vec<i64>,
|
||||||
|
list_string: Vec<String>,
|
||||||
|
// Nested struct to test recursion
|
||||||
|
nested: Option<Box<RoundtripStruct>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzz_target!(|data: RoundtripStruct| {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
if to_bytes(&data, &mut bytes).is_ok() {
|
||||||
|
let cursor = Cursor::new(bytes);
|
||||||
|
let reconstructed: RoundtripStruct = from_bytes(cursor).expect("Failed to deserialize valid NBT");
|
||||||
|
assert_eq!(data, reconstructed);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -3,7 +3,7 @@ use std::io::{Seek, SeekFrom};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, END_ID, Error, INT_ARRAY_ID, INT_ID, LIST_ID,
|
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, END_ID, Error, INT_ARRAY_ID, INT_ID, LIST_ID,
|
||||||
LONG_ARRAY_ID, LONG_ID, NbtTag, get_nbt_string, io,
|
LONG_ARRAY_ID, LONG_ID, MAX_ARRAY_LENGTH, NbtTag, get_nbt_string, io,
|
||||||
};
|
};
|
||||||
use io::Read;
|
use io::Read;
|
||||||
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
|
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
|
||||||
@ -150,13 +150,18 @@ impl<'de, R: Read + Seek> de::Deserializer<'de> for &mut Deserializer<R> {
|
|||||||
return Err(Error::NegativeLength(remaining_values));
|
return Err(Error::NegativeLength(remaining_values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let remaining_values = remaining_values as usize;
|
||||||
|
if remaining_values > MAX_ARRAY_LENGTH {
|
||||||
|
return Err(Error::LargeLength(remaining_values));
|
||||||
|
}
|
||||||
|
|
||||||
//TODO this is a bit hacky but I couldn't think of a better way
|
//TODO this is a bit hacky but I couldn't think of a better way
|
||||||
// This flag gets auto cleared in visit_seq
|
// This flag gets auto cleared in visit_seq
|
||||||
set_curr_visitor_seq_list_id(Some(list_type));
|
set_curr_visitor_seq_list_id(Some(list_type));
|
||||||
let result = visitor.visit_seq(ListAccess {
|
let result = visitor.visit_seq(ListAccess {
|
||||||
de: self,
|
de: self,
|
||||||
list_type,
|
list_type,
|
||||||
remaining_values: remaining_values as usize,
|
remaining_values,
|
||||||
})?;
|
})?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use compound::NbtCompound;
|
|
||||||
use deserializer::NbtReadHelper;
|
use deserializer::NbtReadHelper;
|
||||||
use serde::{de, ser};
|
use serde::{de, ser};
|
||||||
use serializer::WriteAdaptor;
|
use serializer::WriteAdaptor;
|
||||||
@ -19,6 +18,7 @@ pub mod nbt_ops;
|
|||||||
pub mod serializer;
|
pub mod serializer;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
|
|
||||||
|
pub use compound::NbtCompound;
|
||||||
pub use deserializer::{from_bytes, from_bytes_unnamed};
|
pub use deserializer::{from_bytes, from_bytes_unnamed};
|
||||||
pub use serializer::{to_bytes, to_bytes_named, to_bytes_unnamed};
|
pub use serializer::{to_bytes, to_bytes_named, to_bytes_unnamed};
|
||||||
|
|
||||||
@ -38,6 +38,8 @@ pub const COMPOUND_ID: u8 = 0x0A;
|
|||||||
pub const INT_ARRAY_ID: u8 = 0x0B;
|
pub const INT_ARRAY_ID: u8 = 0x0B;
|
||||||
pub const LONG_ARRAY_ID: u8 = 0x0C;
|
pub const LONG_ARRAY_ID: u8 = 0x0C;
|
||||||
|
|
||||||
|
pub const MAX_ARRAY_LENGTH: usize = 2_000_000;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("The root tag of the NBT file is not a compound tag. Received tag id: {0}")]
|
#[error("The root tag of the NBT file is not a compound tag. Received tag id: {0}")]
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use std::io::{Cursor, Read, Seek, Write};
|
|||||||
/// A Result containing either the parsed `NbtCompound` or an Error
|
/// A Result containing either the parsed `NbtCompound` or an Error
|
||||||
pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> {
|
pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> {
|
||||||
// Create a GZip decoder and directly chain it to the NBT reader
|
// Create a GZip decoder and directly chain it to the NBT reader
|
||||||
let mut decoder = GzDecoder::new(input);
|
let mut decoder = GzDecoder::new(input).take(64 * 1024 * 1024); // 64 MB limit
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
decoder.read_to_end(&mut buf).map_err(Error::Incomplete)?;
|
decoder.read_to_end(&mut buf).map_err(Error::Incomplete)?;
|
||||||
let mut reader = NbtReadHelper::new(Cursor::new(buf));
|
let mut reader = NbtReadHelper::new(Cursor::new(buf));
|
||||||
@ -69,7 +69,7 @@ pub fn write_gzip_compound_tag_to_bytes(compound: NbtCompound) -> Result<Vec<u8>
|
|||||||
/// A Result containing either the deserialized type or an Error
|
/// A Result containing either the deserialized type or an Error
|
||||||
pub fn from_gzip_bytes<'a, T: serde::Deserialize<'a>, R: Read>(input: R) -> Result<T, Error> {
|
pub fn from_gzip_bytes<'a, T: serde::Deserialize<'a>, R: Read>(input: R) -> Result<T, Error> {
|
||||||
// Create a GZip decoder and directly use it for deserialization
|
// Create a GZip decoder and directly use it for deserialization
|
||||||
let mut decoder = GzDecoder::new(input);
|
let mut decoder = GzDecoder::new(input).take(64 * 1024 * 1024); // 64 MB limit
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
decoder.read_to_end(&mut buf).map_err(Error::Incomplete)?;
|
decoder.read_to_end(&mut buf).map_err(Error::Incomplete)?;
|
||||||
deserializer::from_bytes(Cursor::new(buf))
|
deserializer::from_bytes(Cursor::new(buf))
|
||||||
|
|||||||
@ -6,8 +6,8 @@ use serializer::WriteAdaptor;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, Error, FLOAT_ID, INT_ARRAY_ID, INT_ID,
|
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, Error, FLOAT_ID, INT_ARRAY_ID, INT_ID,
|
||||||
LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID, Seek, Write, compound, deserializer,
|
LIST_ID, LONG_ARRAY_ID, LONG_ID, MAX_ARRAY_LENGTH, SHORT_ID, STRING_ID, Seek, Write, compound,
|
||||||
get_nbt_string, io, nbt_byte_array, nbt_int_array, nbt_long_array, serializer,
|
deserializer, get_nbt_string, io, nbt_byte_array, nbt_int_array, nbt_long_array, serializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -286,6 +286,9 @@ impl NbtTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
|
if len > MAX_ARRAY_LENGTH {
|
||||||
|
return Err(Error::LargeLength(len));
|
||||||
|
}
|
||||||
let mut byte_array = Vec::with_capacity(len);
|
let mut byte_array = Vec::with_capacity(len);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let byte = reader.get_i8_be()?;
|
let byte = reader.get_i8_be()?;
|
||||||
@ -301,7 +304,12 @@ impl NbtTag {
|
|||||||
return Err(Error::NegativeLength(len));
|
return Err(Error::NegativeLength(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut list = Vec::with_capacity(len as usize);
|
let len = len as usize;
|
||||||
|
if len > MAX_ARRAY_LENGTH {
|
||||||
|
return Err(Error::LargeLength(len));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut list = Vec::with_capacity(len);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let tag = Self::deserialize_data(reader, tag_type_id)?;
|
let tag = Self::deserialize_data(reader, tag_type_id)?;
|
||||||
assert_eq!(tag.get_type_id(), tag_type_id);
|
assert_eq!(tag.get_type_id(), tag_type_id);
|
||||||
@ -318,6 +326,9 @@ impl NbtTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
|
if len > MAX_ARRAY_LENGTH {
|
||||||
|
return Err(Error::LargeLength(len));
|
||||||
|
}
|
||||||
let mut int_array = Vec::with_capacity(len);
|
let mut int_array = Vec::with_capacity(len);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let int = reader.get_i32_be()?;
|
let int = reader.get_i32_be()?;
|
||||||
@ -332,6 +343,9 @@ impl NbtTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
|
if len > MAX_ARRAY_LENGTH {
|
||||||
|
return Err(Error::LargeLength(len));
|
||||||
|
}
|
||||||
let mut long_array = Vec::with_capacity(len);
|
let mut long_array = Vec::with_capacity(len);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let long = reader.get_i64_be()?;
|
let long = reader.get_i64_be()?;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user