diff --git a/src/options.rs b/src/options.rs index 677b0e7..50b3d92 100644 --- a/src/options.rs +++ b/src/options.rs @@ -165,6 +165,20 @@ pub struct BuildOptions { /// and the fuzzer can store an input to the corpus at each condition that it passes; /// giving it a better chance of producing an input that reaches `res = 2;`. pub disable_branch_folding: Option, + + #[arg(long)] + /// Disable the inclusion of the `/include:main` MSVC linker argument + /// + /// The purpose of `/include:main` is to force the MSVC linker to include an + /// external reference to the symbol `main`, such that fuzzing targets built + /// on Windows are able to find LibFuzzer's `main` function. + /// + /// In certain corner cases, users may prefer to *not* build with this + /// argument. One such example: if a user is intending to build and fuzz a + /// Windows DLL, they would likely choose to enable this flag, to prevent + /// the DLL from having an extern `main` reference added to it. (DLLs/shared + /// libraries should not have any reference to `main`.) + pub no_include_main_msvc: bool, } impl stdfmt::Display for BuildOptions { @@ -265,6 +279,7 @@ mod test { no_cfg_fuzzing: false, no_trace_compares: false, disable_branch_folding: None, + no_include_main_msvc: false, }; let opts = vec![ diff --git a/src/project.rs b/src/project.rs index c62bfe9..1017d63 100644 --- a/src/project.rs +++ b/src/project.rs @@ -233,8 +233,23 @@ impl FuzzProject { if !build.release || build.debug_assertions || build.careful_mode { rustflags.push_str(" -Cdebug-assertions"); } - if build.triple.contains("-msvc") { - // The entrypoint is in the bundled libfuzzer rlib, this gets the linker to find it. + if build.triple.contains("-msvc") && !build.no_include_main_msvc { + // This forces the MSVC linker (which runs on Windows systems) to + // find the entry point (i.e. the `main` function) within the + // LibFuzzer `.rlib` file produced during the build. + // + // The `--no-include-main-msvc` argument disables the addition of + // this linker argument. In certain situations, a user may not want + // this argument included as part of the MSVC invocation. + // + // For example, if the user is attempting to build and fuzz a + // Windows DLL (shared library), adding `/include:main` will force + // the DLL to compile with an external reference to `main`. + // DLLs/shared libraries are designed to be built as a separate + // object file, intentionally left *without* knowledge of the entry + // point. So, forcing a DLL to include `main` will cause linking to + // fail. Using `--no-include-main-msvc` will allow the DLL to be + // built without issue. rustflags.push_str(" -Clink-arg=/include:main"); }