mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Add simple fuzz testing (#2581)
This commit is contained in:
parent
0ebce56b36
commit
9aadb18186
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -35,3 +35,15 @@ jobs:
|
|||||||
- uses: dtolnay/rust-toolchain@1.70.0
|
- uses: dtolnay/rust-toolchain@1.70.0
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- run: cargo check --workspace
|
- run: cargo check --workspace
|
||||||
|
|
||||||
|
fuzz:
|
||||||
|
name: Check fuzzers
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: nightly-2023-09-13
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
- run: cargo install cargo-fuzz
|
||||||
|
- run: cd tests/fuzz && cargo fuzz build --dev
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,10 @@ tests/png
|
|||||||
tests/pdf
|
tests/pdf
|
||||||
tests/svg
|
tests/svg
|
||||||
tests/target
|
tests/target
|
||||||
|
tests/fuzz/target
|
||||||
|
tests/fuzz/corpus
|
||||||
|
tests/fuzz/artifacts
|
||||||
|
tests/fuzz/coverage
|
||||||
tarpaulin-report.html
|
tarpaulin-report.html
|
||||||
|
|
||||||
# Rust
|
# Rust
|
||||||
|
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -102,6 +102,12 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@ -220,6 +226,7 @@ version = "1.0.83"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1178,6 +1185,15 @@ version = "1.0.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -1252,6 +1268,17 @@ dependencies = [
|
|||||||
"libdeflate-sys",
|
"libdeflate-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libfuzzer-sys"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"cc",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -2730,6 +2757,17 @@ dependencies = [
|
|||||||
"yaml-front-matter",
|
"yaml-front-matter",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typst-fuzz"
|
||||||
|
version = "0.10.0"
|
||||||
|
dependencies = [
|
||||||
|
"comemo",
|
||||||
|
"libfuzzer-sys",
|
||||||
|
"typst",
|
||||||
|
"typst-render",
|
||||||
|
"typst-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-ide"
|
name = "typst-ide"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["crates/*", "tests"]
|
members = ["crates/*", "tests", "tests/fuzz"]
|
||||||
default-members = ["crates/typst-cli"]
|
default-members = ["crates/typst-cli"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ include_dir = "0.7"
|
|||||||
indexmap = { version = "2", features = ["serde"] }
|
indexmap = { version = "2", features = ["serde"] }
|
||||||
inferno = "0.11.15"
|
inferno = "0.11.15"
|
||||||
kurbo = "0.9"
|
kurbo = "0.9"
|
||||||
|
libfuzzer-sys = "0.4"
|
||||||
lipsum = "0.9"
|
lipsum = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
miniz_oxide = "0.7"
|
miniz_oxide = "0.7"
|
||||||
|
27
tests/fuzz/Cargo.toml
Normal file
27
tests/fuzz/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "typst-fuzz"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
typst = { workspace = true }
|
||||||
|
typst-render = { workspace = true }
|
||||||
|
typst-syntax = { workspace = true }
|
||||||
|
comemo = { workspace = true }
|
||||||
|
libfuzzer-sys = { workspace = true }
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "parse"
|
||||||
|
path = "src/parse.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "compile"
|
||||||
|
path = "src/compile.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
74
tests/fuzz/src/compile.rs
Normal file
74
tests/fuzz/src/compile.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use comemo::Prehashed;
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use typst::diag::{FileError, FileResult};
|
||||||
|
use typst::eval::Tracer;
|
||||||
|
use typst::foundations::{Bytes, Datetime};
|
||||||
|
use typst::syntax::{FileId, Source};
|
||||||
|
use typst::text::{Font, FontBook};
|
||||||
|
use typst::visualize::Color;
|
||||||
|
use typst::{Library, World};
|
||||||
|
|
||||||
|
const FONT: &[u8] = include_bytes!("../../../assets/fonts/LinLibertine_R.ttf");
|
||||||
|
|
||||||
|
struct FuzzWorld {
|
||||||
|
library: Prehashed<Library>,
|
||||||
|
book: Prehashed<FontBook>,
|
||||||
|
font: Font,
|
||||||
|
source: Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FuzzWorld {
|
||||||
|
fn new(text: &str) -> Self {
|
||||||
|
let font = Font::new(FONT.into(), 0).unwrap();
|
||||||
|
let book = FontBook::from_fonts([&font]);
|
||||||
|
Self {
|
||||||
|
library: Prehashed::new(Library::build()),
|
||||||
|
book: Prehashed::new(book),
|
||||||
|
font,
|
||||||
|
source: Source::detached(text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl World for FuzzWorld {
|
||||||
|
fn library(&self) -> &Prehashed<Library> {
|
||||||
|
&self.library
|
||||||
|
}
|
||||||
|
|
||||||
|
fn book(&self) -> &Prehashed<FontBook> {
|
||||||
|
&self.book
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(&self) -> Source {
|
||||||
|
self.source.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self, src: FileId) -> FileResult<Source> {
|
||||||
|
Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file(&self, src: FileId) -> FileResult<Bytes> {
|
||||||
|
Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn font(&self, _: usize) -> Option<Font> {
|
||||||
|
Some(self.font.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn today(&self, _: Option<i64>) -> Option<Datetime> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzz_target!(|text: &str| {
|
||||||
|
let world = FuzzWorld::new(text);
|
||||||
|
let mut tracer = Tracer::new();
|
||||||
|
if let Ok(document) = typst::compile(&world, &mut tracer) {
|
||||||
|
if let Some(page) = document.pages.first() {
|
||||||
|
std::hint::black_box(typst_render::render(page, 1.0, Color::WHITE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comemo::evict(10);
|
||||||
|
});
|
8
tests/fuzz/src/parse.rs
Normal file
8
tests/fuzz/src/parse.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use typst_syntax::parse;
|
||||||
|
|
||||||
|
fuzz_target!(|text: &str| {
|
||||||
|
std::hint::black_box(parse(text));
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user