Windows Support for LibAFL-LibFuzzer (#3130)

* Add windows build script and additional changes to support windows for libafl-libfuzzer

* Update build scripts and harness wrapping directives

* Resolve issue with corpus edge count calculation

* Add help message and make fork do nothing on Windows

* Format harness_wrap.cpp

* Clippy happiness pass

* Clippy happiness pass

* Clippy happiness pass

* Correct logic

* Correct logic

* Update help output and make runs argument work

* Add test for libafl_libfuzzer on windows

* Add workflow for libafl_libfuzzer test

* Fix copy without dependent task

* Add libafl_libfuzzer_windows to preflight list

* Format harness

* Explicitly ignore windows fuzzer

* Remove windows-specific copy from unix instructions

* Ensure using nightly

* Fix job name

* Update build to use libFuzzer.lib on Windows to keep consistent with Linux

* Remove nightly requirement

---------

Co-authored-by: Rowan Hart <rowanhart@microsoft.com>
This commit is contained in:
Rowan Hart 2025-05-20 16:35:48 -07:00 committed by GitHub
parent db1d38eeb6
commit 0b25d723c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 351 additions and 70 deletions

View File

@ -329,6 +329,7 @@ jobs:
- ./fuzzers/inprocess/libfuzzer_stb_image
# - ./fuzzers/structure_aware/libfuzzer_stb_image_concolic
# - ./fuzzers/inprocess/sqlite_centralized_multi_machine
# - ./fuzzers/inprocess/libafl_libfuzzer_windows
# Fuzz Anything
- ./fuzzers/fuzz_anything/push_harness
@ -569,6 +570,16 @@ jobs:
- name: Build fuzzers/binary_only/frida_libpng
run: cd fuzzers/binary_only/frida_libpng/ && just test
windows-libafl-libfuzzer:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions/checkout@v4
- uses: ./.github/workflows/windows-tester-prepare
- name: Build fuzzers/inprocess/libafl_libfuzzer_windows
run: cd fuzzers/inprocess/libafl_libfuzzer_windows && just test
windows-libfuzzer-stb-image:
runs-on: windows-latest
needs:

View File

@ -47,7 +47,7 @@ lib2: libpng
[windows]
harness: lib lib2
copy libpng-1.6.37\Release\libpng16.lib . && copy libpng-1.6.37\Release\libpng16.dll . && copy zlib\Release\zlib.lib . && copy zlib\Release\zlib.dll . && copy target\release\frida_fuzzer.exe .
copy libpng-1.6.37\Release\libpng16.lib . && copy libpng-1.6.37\Release\libpng16.dll . && copy zlib\Release\zlib.lib . && copy zlib\Release\zlib.dll .
cl /O2 /c /I .\libpng-1.6.37 harness.cc /Fo:harness.obj && link /DLL /OUT:libpng-harness.dll harness.obj libpng16.lib zlib.lib
[unix]

View File

@ -0,0 +1,30 @@
import "../../../just/libafl.just"
FUZZER_NAME := "libafl_libfuzzer_windows"
FUZZER_NAME_WIN := "libafl_libfuzzer_windows.exe"
set windows-shell := ['cmd.exe', '/c']
set unstable
[windows]
libafl_libfuzzer:
powershell -File ..\..\..\libafl_libfuzzer_runtime\build.ps1
[windows]
harness: libafl_libfuzzer
copy ..\..\..\libafl_libfuzzer_runtime\libFuzzer.lib .
cl /c /O2 /EHsc /std:c++17 /MDd /fsanitize-coverage=inline-8bit-counters /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div /Fo:harness.obj harness.cc
link harness.obj libFuzzer.lib sancov.lib /OUT:libafl_libfuzzer_windows.exe
[windows]
run: harness
if not exist corpus mkdir corpus
{{FUZZER_NAME_WIN}} -use_value_profile=1 corpus
[windows]
[script("cmd.exe", "/c")]
test: harness
if exist corpus rd /s /q corpus
mkdir corpus
{{FUZZER_NAME_WIN}} -use_value_profile=1 -runs=30000 corpus
dir /a-d corpus && (echo Files exist) || (exit /b 1337)

View File

@ -0,0 +1,4 @@
# LibAFL-LibFuzzer Windows
A simple example demonstrating how to build LibFuzzer harnesses with LibAFL-LibFuzzer
as an alternative runtime on Windows.

View File

@ -0,0 +1,33 @@
// Simple decoder function with an off by one error that is triggered under
// certain conditions.
#include <cstddef>
#include <cstdint>
int DecodeInput(const uint8_t *data, size_t size) {
if (size < 5) {
return -1; // Error: not enough data
}
if (data[0] != 'F' || data[1] != 'U' || data[2] != 'Z' || data[3] == 'Z') {
return -1; // Error: invalid header
}
if (data[4] <= 0) {
return -1; // Error: invalid size
}
int csum = 0;
for (size_t i = 5; i < size; ++i) {
csum += data[i];
}
return csum; // Error: checksum mismatch
}
extern "C" __declspec(dllexport) int LLVMFuzzerTestOneInput(const uint8_t *data,
size_t size) {
DecodeInput(data, size);
return 0;
}

View File

@ -86,22 +86,35 @@ To do so, [ensure a recent nightly version of Rust is installed](https://rustup.
[`libafl_libfuzzer_runtime`](../libafl_libfuzzer_runtime) folder and build the runtime with the following command:
```bash
./build.sh
just build
```
The static library will be available at `libFuzzer.a` in the [`libafl_libfuzzer_runtime`](../libafl_libfuzzer_runtime)
directory.
If you encounter build failures without clear error outputs that help you resolve the issue, please [submit an issue].
Or you can call `build.sh` (Unix) or `build.ps1` (Windows).
This library may now be used in place of libFuzzer.
To do so, change your CFLAGS/CXXFLAGS from `-fsanitize=fuzzer` to:
The static library will be available at `libFuzzer.a` (`libFuzzer.lib` for Windows) in
the [`libafl_libfuzzer_runtime`](../libafl_libfuzzer_runtime) directory. If you
encounter build failures without clear error outputs that help you resolve the issue,
please [submit an issue].
```
-fsanitize=fuzzer-no-link -L/path/to/libafl_libfuzzer_runtime -lFuzzer
```
#### Unix
Alternatively, you may directly overwrite the system libFuzzer library and use `-fsanitize=fuzzer` as normal.
This changes per system, but on my machine is located at `/usr/lib64/clang/16/lib/linux/libclang_rt.fuzzer-x86_64.a`.
This library may now be used in place of libFuzzer. To do so, change your
CFLAGS/CXXFLAGS from `-fsanitize=fuzzer` to:
``` -fsanitize=fuzzer-no-link -L/path/to/libafl_libfuzzer_runtime -lFuzzer ```
Alternatively, you may directly overwrite the system libFuzzer library and use
`-fsanitize=fuzzer` as normal. This changes per system, but on my machine is located at
`/usr/lib64/clang/16/lib/linux/libclang_rt.fuzzer-x86_64.a`.
#### Windows
For Windows, change your CFLAGS/CXXFLAGS from `-fsanitize=fuzzer` to:
```/fsanitize-coverage=inline-8bit-counters /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div```
And then ensure you link with `sancov.lib` when producing your final executable. See
`fuzzers\inprocess\libafl_libfuzzer_windows` for an example.
#### Caveats

View File

@ -4,16 +4,19 @@ version = "0.15.2"
edition = "2024"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["fork"]
default = []
## Enables forking mode for the LibAFL launcher (instead of starting new processes)
fork = ["libafl/fork"]
track_hit_feedbacks = [
"libafl/track_hit_feedbacks",
"libafl_targets/track_hit_feedbacks",
]
tui_monitor = ["libafl/tui_monitor"]
[target.'cfg(not(windows))'.features]
## Enable the `fork` feature on non-windows platforms
default = ["fork", "tui_monitor"]
[profile.release]
lto = true
@ -40,7 +43,6 @@ libafl = { path = "../libafl", default-features = false, features = [
"regex",
"errors_backtrace",
"serdeany_autoreg",
"tui_monitor",
"unicode",
] }
libafl_bolts = { path = "../libafl_bolts", default-features = false, features = [

View File

@ -154,7 +154,7 @@ where
}
#[inline]
fn count_all(&self) -> usize {
self.count_disabled().saturating_add(self.count_disabled())
self.count().saturating_add(self.count_disabled())
}
#[expect(clippy::used_underscore_items)]

View File

@ -1,20 +1,31 @@
use core::ffi::c_int;
#[cfg(unix)]
use std::io::{Write, stderr, stdout};
use std::{fmt::Debug, fs::File, net::TcpListener, os::fd::AsRawFd, str::FromStr};
use std::{
fmt::Debug,
fs::File,
io::{Write, stderr, stdout},
net::TcpListener,
os::fd::AsRawFd,
str::FromStr,
};
#[cfg(feature = "tui_monitor")]
use libafl::monitors::tui::TuiMonitor;
use libafl::{
Error, Fuzzer, HasMetadata,
corpus::Corpus,
events::{
EventConfig, EventReceiver, ProgressReporter, SimpleEventManager,
SimpleRestartingEventManager, launcher::Launcher,
},
events::{EventReceiver, ProgressReporter, SimpleEventManager},
executors::ExitKind,
monitors::{Monitor, MultiMonitor, tui::TuiMonitor},
monitors::MultiMonitor,
stages::StagesTuple,
state::{HasCurrentStageId, HasExecutions, HasLastReportTime, HasSolutions, Stoppable},
};
#[cfg(unix)]
use libafl::{
events::{EventConfig, SimpleRestartingEventManager, launcher::Launcher},
monitors::Monitor,
};
#[cfg(unix)]
use libafl_bolts::{
core_affinity::Cores,
shmem::{ShMemProvider, StdShMemProvider},
@ -22,25 +33,27 @@ use libafl_bolts::{
use crate::{feedbacks::LibfuzzerCrashCauseMetadata, fuzz_with, options::LibfuzzerOptions};
#[cfg(unix)]
fn destroy_output_fds(options: &LibfuzzerOptions) {
#[cfg(unix)]
{
use libafl_bolts::os::{dup2, null_fd};
use libafl_bolts::os::{dup2, null_fd};
let null_fd = null_fd().unwrap();
let stdout_fd = stdout().as_raw_fd();
let stderr_fd = stderr().as_raw_fd();
let null_fd = null_fd().unwrap();
let stdout_fd = stdout().as_raw_fd();
let stderr_fd = stderr().as_raw_fd();
if options.tui() {
#[cfg(feature = "tui_monitor")]
if options.tui() {
dup2(null_fd, stdout_fd).unwrap();
dup2(null_fd, stderr_fd).unwrap();
return;
}
if options.close_fd_mask() != 0 {
if options.close_fd_mask() & u8::try_from(stderr_fd).unwrap() != 0 {
dup2(null_fd, stdout_fd).unwrap();
}
if options.close_fd_mask() & u8::try_from(stderr_fd).unwrap() != 0 {
dup2(null_fd, stderr_fd).unwrap();
} else if options.close_fd_mask() != 0 {
if options.close_fd_mask() & u8::try_from(stderr_fd).unwrap() != 0 {
dup2(null_fd, stdout_fd).unwrap();
}
if options.close_fd_mask() & u8::try_from(stderr_fd).unwrap() != 0 {
dup2(null_fd, stderr_fd).unwrap();
}
}
}
}
@ -87,10 +100,17 @@ where
return Err(Error::shutting_down());
}
}
fuzzer.fuzz_loop(stages, executor, state, mgr)?;
if options.runs() == 0 {
fuzzer.fuzz_loop(stages, executor, state, mgr)?;
} else {
for _ in 0..options.runs() {
fuzzer.fuzz_one(stages, executor, state, mgr)?;
}
}
Ok(())
}
#[cfg(unix)]
fn fuzz_single_forking<M>(
options: &LibfuzzerOptions,
harness: &extern "C" fn(*const u8, usize) -> c_int,
@ -121,9 +141,7 @@ where
})
}
/// Communicate the selected port to subprocesses
const PORT_PROVIDER_VAR: &str = "_LIBAFL_LIBFUZZER_FORK_PORT";
#[cfg(unix)]
fn fuzz_many_forking<M>(
options: &LibfuzzerOptions,
harness: &extern "C" fn(*const u8, usize) -> c_int,
@ -134,6 +152,9 @@ fn fuzz_many_forking<M>(
where
M: Monitor + Clone + Debug + 'static,
{
// Communicate the selected port to subprocesses
const PORT_PROVIDER_VAR: &str = "_LIBAFL_LIBFUZZER_FORK_PORT";
destroy_output_fds(options);
let broker_port = std::env::var(PORT_PROVIDER_VAR)
.map_err(Error::from)
@ -194,22 +215,31 @@ pub fn fuzz(
options: &LibfuzzerOptions,
harness: &extern "C" fn(*const u8, usize) -> c_int,
) -> Result<(), Error> {
#[cfg(unix)]
if let Some(forks) = options.forks() {
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
#[cfg(feature = "tui_monitor")]
if options.tui() {
let monitor = TuiMonitor::builder()
.title(options.fuzzer_name())
.enhanced_graphics(true)
.build();
fuzz_many_forking(options, harness, shmem_provider, forks, monitor)
} else if forks == 1 {
let monitor = MultiMonitor::new(create_monitor_closure());
fuzz_single_forking(options, harness, shmem_provider, monitor)
} else {
let monitor = MultiMonitor::new(create_monitor_closure());
fuzz_many_forking(options, harness, shmem_provider, forks, monitor)
return fuzz_many_forking(options, harness, shmem_provider, forks, monitor);
}
} else if options.tui() {
// Non-TUI path or when tui_monitor feature is disabled
let monitor = MultiMonitor::new(create_monitor_closure());
if forks == 1 {
return fuzz_single_forking(options, harness, shmem_provider, monitor);
}
return fuzz_many_forking(options, harness, shmem_provider, forks, monitor);
}
#[cfg(feature = "tui_monitor")]
if options.tui() {
// if the user specifies TUI, we assume they want to fork; it would not be possible to use
// TUI safely otherwise
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
@ -217,12 +247,15 @@ pub fn fuzz(
.title(options.fuzzer_name())
.enhanced_graphics(true)
.build();
fuzz_many_forking(options, harness, shmem_provider, 1, monitor)
} else {
destroy_output_fds(options);
fuzz_with!(options, harness, do_fuzz, |fuzz_single| {
let mgr = SimpleEventManager::new(MultiMonitor::new(create_monitor_closure()));
crate::start_fuzzing_single(fuzz_single, None, mgr)
})
return fuzz_many_forking(options, harness, shmem_provider, 1, monitor);
}
// Default path when no forks or TUI are specified, or when tui_monitor feature is disabled
#[cfg(unix)]
destroy_output_fds(options);
fuzz_with!(options, harness, do_fuzz, |fuzz_single| {
let mgr = SimpleEventManager::new(MultiMonitor::new(create_monitor_closure()));
crate::start_fuzzing_single(fuzz_single, None, mgr)
})
}

View File

@ -8,3 +8,23 @@ extern "C" int libafl_libfuzzer_test_one_input(
return -2; // custom code for "we died!"
}
}
#ifdef _WIN32
// For Windows API functions used by MiMalloc
#pragma comment(lib, "advapi32.lib")
// For Windows networking functionality used by LibAFL
#pragma comment(lib, "ws2_32.lib")
// For Windows API functions to retrieve user home directory used by Rust STD
#pragma comment(lib, "userenv.lib")
// For base Windows API functions like file reads and writes
#pragma comment(lib, "ntdll.lib")
// For crypto functions called by LibAFL's random utilities
#pragma comment(lib, "bcrypt.lib")
// Required by windows_core
#pragma comment(lib, "ole32.lib")
// For debug facilities used in debug builds
#pragma comment(lib, "dbghelp.lib")
#pragma comment(linker, "/export:LLVMFuzzerRunDriver")
#pragma comment(linker, "/export:__sanitizer_cov_8bit_counters_init")
#endif // _WIN32

View File

@ -67,8 +67,13 @@
#![allow(clippy::borrow_deref_ref)]
use core::ffi::{CStr, c_char, c_int};
use std::{fs::File, io::stderr, os::fd::RawFd};
#[cfg(unix)]
use std::{
os::fd::RawFd,
{fs::File, io::stderr},
};
#[cfg(unix)]
use env_logger::Target;
use libafl::{
Error,
@ -328,11 +333,20 @@ macro_rules! fuzz_with {
// Attempt to use tokens from libfuzzer dicts
if !state.has_metadata::<Tokens>() {
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
let mut toks = if let Some(tokens) = $options.dict() {
tokens.clone()
} else {
Tokens::default()
};
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
let toks = if let Some(tokens) = $options.dict() {
tokens.clone()
} else {
Tokens::default()
};
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
{
toks += libafl_targets::autotokens()?;

View File

@ -1,7 +1,7 @@
use std::{env::temp_dir, ffi::c_int, fs::rename};
#[cfg(unix)]
use std::{
env::temp_dir,
ffi::c_int,
fs::{File, rename},
fs::File,
io::Write,
os::fd::{AsRawFd, FromRawFd},
};

View File

@ -102,6 +102,7 @@ impl Default for ArtifactPrefix {
#[derive(Debug, Clone)]
#[expect(clippy::struct_excessive_bools)]
pub struct LibfuzzerOptions {
#[allow(unused)]
fuzzer_name: String,
mode: LibfuzzerMode,
artifact_prefix: ArtifactPrefix,
@ -122,6 +123,7 @@ pub struct LibfuzzerOptions {
skip_tracing: bool,
tui: bool,
runs: usize,
#[allow(unused)]
close_fd_mask: u8,
unknown: Vec<String>,
}
@ -144,6 +146,7 @@ impl LibfuzzerOptions {
.map(|builder| builder.build(name))
}
#[cfg(unix)]
pub fn fuzzer_name(&self) -> &str {
&self.fuzzer_name
}
@ -224,6 +227,7 @@ impl LibfuzzerOptions {
self.runs
}
#[cfg(unix)]
pub fn close_fd_mask(&self) -> u8 {
self.close_fd_mask
}
@ -318,6 +322,7 @@ impl<'a> LibfuzzerOptionsBuilder<'a> {
})?);
}
"dict" => self.dict = Some(value),
#[cfg(not(windows))]
"fork" | "jobs" => {
self.forks = Some(parse_or_bail!(name, value, usize));
}
@ -358,6 +363,47 @@ impl<'a> LibfuzzerOptionsBuilder<'a> {
}
"runs" => self.runs = parse_or_bail!(name, value, usize),
"close_fd_mask" => self.close_fd_mask = parse_or_bail!(name, value, u8),
"help" => {
println!(
"Usage:\n\
\n\
To run fuzzing pass 0 or more directories.\n\
{name} [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n\
\n\
To run individual tests without fuzzing pass 1 or more files:\n\
{name} [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n\
\n\
Flags: (strictly in form -flag=value)\n\
artifact_prefix 0 Write fuzzing artifacts (crash, timeout, or slow inputs) as $(artifact_prefix)file\n\
timeout 1200 Timeout in seconds. If one unit runs more than this number of seconds the process will abort.\n\
grimoire 0 If 1, enable the Grimoire mutator that is structure-aware.\n\
use_value_profile 0 Use value profile to guide fuzzing.\n\
unicode 1 If 1, generate Unicode inputs.\n\
dict 0 Use the dictionary file.\n\
fork 0 Number of forks to use (>1 requires Unix-like OS).\n\
jobs 0 Same as fork. Number of jobs to run with stdout/stderr redirected.\n\
ignore_crashes 0 If 1, ignore crashes in fork mode.\n\
ignore_timeouts 0 If 1, ignore timeouts in fork mode.\n\
ignore_ooms 0 If 1, ignore out-of-memory errors in fork mode.\n\
rss_limit_mb 2048 If non-zero, the fuzzer will exit upon reaching this limit of RSS memory usage (in Mb).\n\
malloc_limit_mb 2048 If non-zero, the fuzzer will exit if the target tries to allocate this number of Mb with one malloc call.\n\
ignore_remaining_args 0 If 1, ignore all arguments passed after this one.\n\
dedup 0 If 1, deduplicate corpus elements.\n\
shrink 0 If 1, try to shrink corpus elements.\n\
skip_tracing 0 If 1, skip coverage tracing for faster execution.\n\
tui 0 If 1, use the terminal UI interface.\n\
runs 0 Number of individual test runs (0 for infinite runs).\n\
close_fd_mask 0 If 1, close stdout; if 2, close stderr; if 3, close both.\n\
merge 0 If 1, merge multiple corpora into a single one.\n\
minimize_crash 0 If 1, minimize crashes to their smallest reproducing input.\n\
report 0 If 1, report statistics without actually fuzzing.\n\
help 0 Print this help message.\n\
\n\
Flags starting with '--' will be ignored and will be passed verbatim to subprocesses.\n\
"
);
std::process::exit(0);
}
_ => {
self.unknown.push(arg);
}

View File

@ -3,11 +3,15 @@ use std::{
fs::{read, write},
};
#[cfg(windows)]
use libafl::executors::inprocess::InProcessExecutor;
#[cfg(unix)]
use libafl::executors::inprocess_fork::InProcessForkExecutor;
use libafl::{
Error, ExecutesInput, Fuzzer, StdFuzzer,
corpus::{Corpus, HasTestcase, InMemoryCorpus, Testcase},
events::SimpleEventManager,
executors::{ExitKind, inprocess_fork::InProcessForkExecutor},
executors::ExitKind,
feedbacks::{CrashFeedback, TimeoutFeedback},
inputs::{BytesInput, HasMutatorBytes, HasTargetBytes},
mutators::{HavocScheduledMutator, Mutator, havoc_mutations_no_crossover},
@ -15,10 +19,11 @@ use libafl::{
stages::StdTMinMutationalStage,
state::{HasCorpus, StdState},
};
#[cfg(unix)]
use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider};
use libafl_bolts::{
AsSlice, HasLen,
rands::{RomuDuoJrRand, StdRand},
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
};
use libafl_targets::LLVMCustomMutator;
@ -60,15 +65,28 @@ fn minimize_crash_with_mutator<M: Mutator<BytesInput, TMinState>>(
let mut fuzzer = StdFuzzer::new(QueueScheduler::new(), (), ());
let shmem_provider = StdShMemProvider::new()?;
let mut executor = InProcessForkExecutor::new(
#[cfg(unix)]
let mut executor = {
let shmem_provider = StdShMemProvider::new()?;
InProcessForkExecutor::new(
&mut harness,
(),
&mut fuzzer,
&mut state,
&mut mgr,
options.timeout(),
shmem_provider,
)?
};
#[cfg(windows)]
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
(),
&mut fuzzer,
&mut state,
&mut mgr,
options.timeout(),
shmem_provider,
)?;
let exit_kind = fuzzer.execute_input(&mut state, &mut executor, &mut mgr, &input)?;

View File

@ -0,0 +1,10 @@
set windows-shell := ['cmd.exe', '/c']
set unstable
[unix]
build:
./build.sh
[windows]
build:
powershell -File build.ps1

View File

@ -0,0 +1,46 @@
#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $SCRIPT_DIR
if ($args.Count -eq 0) {
$profile = "release"
} else {
$profile = $args[0]
}
Write-Host "Building libafl_libfuzzer runtime with profile '$profile'" -ForegroundColor Green
Invoke-Expression "cargo build --profile $profile"
$tmpdir = Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tmpdir | Out-Null
function Cleanup {
if (Test-Path $tmpdir) {
Remove-Item -Recurse -Force $tmpdir
}
}
try {
if ($profile -eq "dev") {
# Set the profile to debug for dev builds, because the path isn't the same
# as the profile name
$profile = "debug"
}
$targetPath = Join-Path $SCRIPT_DIR "target\$profile\afl_libfuzzer_runtime.lib"
$outputPath = Join-Path $SCRIPT_DIR "libFuzzer.lib"
Copy-Item -Path $targetPath -Destination $outputPath -Force | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to copy final library"
}
Write-Host "Done! Wrote the runtime to '$outputPath'" -ForegroundColor Green
} finally {
Cleanup
}

View File

@ -17,8 +17,9 @@ fn main() {
.write_to_file(Path::new(&out_dir).join("harness_wrap.rs"))
.expect("Couldn't write the harness wrapper!");
cc::Build::new()
.cpp(true)
.file("src/harness_wrap.cpp")
.compile("harness_wrap");
let mut harness_wrap = cc::Build::new();
harness_wrap.cpp(true).file("src/harness_wrap.cpp");
harness_wrap.compile("harness_wrap");
}