From 47620bc0f59e6b4c8f63a308e791f670fa64e535 Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Tue, 9 May 2023 16:52:59 +0200 Subject: [PATCH 1/4] Make it possible to link to custom libfuzzer in another dep --- Cargo.toml | 2 ++ build.rs | 66 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1552302..1325336 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ once_cell = "1" cc = { version = "1.0", features = ["parallel"] } [features] +default = ["link"] +link = [] arbitrary-derive = ["arbitrary/derive"] [workspace] diff --git a/build.rs b/build.rs index ab1bbc5..a31586c 100644 --- a/build.rs +++ b/build.rs @@ -1,40 +1,42 @@ fn main() { - println!("cargo:rerun-if-env-changed=CUSTOM_LIBFUZZER_PATH"); - if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") { - println!("cargo:rerun-if-changed={custom}"); + if cfg!(feature = "link") { + println!("cargo:rerun-if-env-changed=CUSTOM_LIBFUZZER_PATH"); + if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") { + println!("cargo:rerun-if-changed={custom}"); - let custom_lib_path = ::std::path::PathBuf::from(&custom); - let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy(); + let custom_lib_path = ::std::path::PathBuf::from(&custom); + let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy(); - let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy(); - let custom_lib_name = custom_lib_name - .strip_prefix("lib") - .unwrap_or(custom_lib_name.as_ref()); + let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy(); + let custom_lib_name = custom_lib_name + .strip_prefix("lib") + .unwrap_or(custom_lib_name.as_ref()); - println!("cargo:rustc-link-search=native={}", custom_lib_dir); - println!("cargo:rustc-link-lib=static={}", custom_lib_name); + println!("cargo:rustc-link-search=native={}", custom_lib_dir); + println!("cargo:rustc-link-lib=static={}", custom_lib_name); - match std::env::var("CUSTOM_LIBFUZZER_STD_CXX") { - // Default behavior for backwards compat. - Err(_) => println!("cargo:rustc-link-lib=stdc++"), - Ok(s) if s == "none" => (), - Ok(s) => println!("cargo:rustc-link-lib={}", s), + match std::env::var("CUSTOM_LIBFUZZER_STD_CXX") { + // Default behavior for backwards compat. + Err(_) => println!("cargo:rustc-link-lib=stdc++"), + Ok(s) if s == "none" => (), + Ok(s) => println!("cargo:rustc-link-lib={}", s), + } + } else { + let mut build = cc::Build::new(); + let sources = ::std::fs::read_dir("libfuzzer") + .expect("listable source directory") + .map(|de| de.expect("file in directory").path()) + .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true)) + .collect::>(); + for source in sources.iter() { + println!("cargo:rerun-if-changed={}", source.display()); + build.file(source.to_str().unwrap()); + } + build.flag("-std=c++17"); + build.flag("-fno-omit-frame-pointer"); + build.flag("-w"); + build.cpp(true); + build.compile("libfuzzer.a"); } - } else { - let mut build = cc::Build::new(); - let sources = ::std::fs::read_dir("libfuzzer") - .expect("listable source directory") - .map(|de| de.expect("file in directory").path()) - .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true)) - .collect::>(); - for source in sources.iter() { - println!("cargo:rerun-if-changed={}", source.display()); - build.file(source.to_str().unwrap()); - } - build.flag("-std=c++17"); - build.flag("-fno-omit-frame-pointer"); - build.flag("-w"); - build.cpp(true); - build.compile("libfuzzer.a"); } } From eaac2d695e557c33ebc1853ab3771c394115f36b Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Wed, 10 May 2023 13:47:56 +0200 Subject: [PATCH 2/4] sequester build and link into a separate function --- Cargo.toml | 4 +-- build.rs | 74 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1325336..a129872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,8 @@ once_cell = "1" cc = { version = "1.0", features = ["parallel"] } [features] -default = ["link"] -link = [] +default = ["link_libfuzzer"] +link_libfuzzer = [] arbitrary-derive = ["arbitrary/derive"] [workspace] diff --git a/build.rs b/build.rs index a31586c..e549e3f 100644 --- a/build.rs +++ b/build.rs @@ -1,42 +1,46 @@ -fn main() { - if cfg!(feature = "link") { - println!("cargo:rerun-if-env-changed=CUSTOM_LIBFUZZER_PATH"); - if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") { - println!("cargo:rerun-if-changed={custom}"); +fn build_and_link_libfuzzer() { + println!("cargo:rerun-if-env-changed=CUSTOM_LIBFUZZER_PATH"); + if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") { + println!("cargo:rerun-if-changed={custom}"); - let custom_lib_path = ::std::path::PathBuf::from(&custom); - let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy(); + let custom_lib_path = ::std::path::PathBuf::from(&custom); + let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy(); - let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy(); - let custom_lib_name = custom_lib_name - .strip_prefix("lib") - .unwrap_or(custom_lib_name.as_ref()); + let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy(); + let custom_lib_name = custom_lib_name + .strip_prefix("lib") + .unwrap_or(custom_lib_name.as_ref()); - println!("cargo:rustc-link-search=native={}", custom_lib_dir); - println!("cargo:rustc-link-lib=static={}", custom_lib_name); + println!("cargo:rustc-link-search=native={}", custom_lib_dir); + println!("cargo:rustc-link-lib=static={}", custom_lib_name); - match std::env::var("CUSTOM_LIBFUZZER_STD_CXX") { - // Default behavior for backwards compat. - Err(_) => println!("cargo:rustc-link-lib=stdc++"), - Ok(s) if s == "none" => (), - Ok(s) => println!("cargo:rustc-link-lib={}", s), - } - } else { - let mut build = cc::Build::new(); - let sources = ::std::fs::read_dir("libfuzzer") - .expect("listable source directory") - .map(|de| de.expect("file in directory").path()) - .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true)) - .collect::>(); - for source in sources.iter() { - println!("cargo:rerun-if-changed={}", source.display()); - build.file(source.to_str().unwrap()); - } - build.flag("-std=c++17"); - build.flag("-fno-omit-frame-pointer"); - build.flag("-w"); - build.cpp(true); - build.compile("libfuzzer.a"); + match std::env::var("CUSTOM_LIBFUZZER_STD_CXX") { + // Default behavior for backwards compat. + Err(_) => println!("cargo:rustc-link-lib=stdc++"), + Ok(s) if s == "none" => (), + Ok(s) => println!("cargo:rustc-link-lib={}", s), + } + } else { + let mut build = cc::Build::new(); + let sources = ::std::fs::read_dir("libfuzzer") + .expect("listable source directory") + .map(|de| de.expect("file in directory").path()) + .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true)) + .collect::>(); + for source in sources.iter() { + println!("cargo:rerun-if-changed={}", source.display()); + build.file(source.to_str().unwrap()); } + build.flag("-std=c++17"); + build.flag("-fno-omit-frame-pointer"); + build.flag("-w"); + build.cpp(true); + build.compile("libfuzzer.a"); + } +} + +fn main() { + if cfg!(feature = "link_libfuzzer") { + build_and_link_libfuzzer(); } } From aeb3fda9c4a947a069f16ed6129b0768daa91d08 Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Wed, 10 May 2023 14:27:12 +0200 Subject: [PATCH 3/4] add details for usage in README --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 8bdba6e..3f1daca 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,29 @@ And finally, run the fuzzer: $ ./target/debug/fuzzed ``` +### Linking to a local libfuzzer + +When using `libfuzzer-sys`, you can provide your own `libfuzzer` runtime in two ways. + +If you are developing a fuzzer, you can set the `CUSTOM_LIBFUZZER_PATH` environment variable to the path of your local +libfuzzer runtime, which will then be linked instead of building libfuzzer as part of the build stage of `libfuzzer-sys`. +For an example, to link to a prebuilt LLVM 16 libfuzzer, you could use: + +```bash +$ export CUSTOM_LIBFUZZER_PATH=/usr/lib64/clang/16/lib/libclang_rt.fuzzer-x86_64.a +$ cargo fuzz run ... +``` + +Alternatively, you may also disable the default `link_libfuzzer` feature: + +In `Cargo.toml`: +```toml +[dependencies] +libfuzzer-sys = { path = "../../libfuzzer", default-features = false } +``` + +Then link to your own runtime in your `build.rs`. + ## Updating libfuzzer from upstream ``` From 606e928ad80bfdf8473f0ae1fb95694aa177446b Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Wed, 10 May 2023 14:28:14 +0200 Subject: [PATCH 4/4] formatting --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f1daca..db6f7f5 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ $ ./target/debug/fuzzed When using `libfuzzer-sys`, you can provide your own `libfuzzer` runtime in two ways. If you are developing a fuzzer, you can set the `CUSTOM_LIBFUZZER_PATH` environment variable to the path of your local -libfuzzer runtime, which will then be linked instead of building libfuzzer as part of the build stage of `libfuzzer-sys`. -For an example, to link to a prebuilt LLVM 16 libfuzzer, you could use: +`libfuzzer` runtime, which will then be linked instead of building libfuzzer as part of the build stage of `libfuzzer-sys`. +For an example, to link to a prebuilt LLVM 16 `libfuzzer`, you could use: ```bash $ export CUSTOM_LIBFUZZER_PATH=/usr/lib64/clang/16/lib/libclang_rt.fuzzer-x86_64.a