mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Compare commits
11 Commits
bun-v1.3.4
...
u/markovej
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6ad32c38f | ||
|
|
ed17aaf19c | ||
|
|
d3302a9e8f | ||
|
|
e0f0ec4ec0 | ||
|
|
860d67e2c7 | ||
|
|
b9643d21e9 | ||
|
|
3adc9ef81a | ||
|
|
98b5b58e10 | ||
|
|
34123e3143 | ||
|
|
2f4008f80b | ||
|
|
bb1b93c6fb |
23
build.zig
23
build.zig
@@ -18,6 +18,22 @@ const OperatingSystem = @import("src/env.zig").OperatingSystem;
|
||||
|
||||
const pathRel = fs.path.relative;
|
||||
|
||||
/// When updating this, make sure to adjust SetupZig.cmake
|
||||
const recommended_zig_version = "0.14.0";
|
||||
|
||||
// comptime {
|
||||
// if (!std.mem.eql(u8, builtin.zig_version_string, recommended_zig_version)) {
|
||||
// @compileError(
|
||||
// "" ++
|
||||
// "Bun requires Zig version " ++ recommended_zig_version ++ ", but you have " ++
|
||||
// builtin.zig_version_string ++ ". This is automatically configured via Bun's " ++
|
||||
// "CMake setup. You likely meant to run `bun run build`. If you are trying to " ++
|
||||
// "upgrade the Zig compiler, edit ZIG_COMMIT in cmake/tools/SetupZig.cmake or " ++
|
||||
// "comment this error out.",
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
const zero_sha = "0000000000000000000000000000000000000000";
|
||||
|
||||
const BunBuildOptions = struct {
|
||||
@@ -33,6 +49,7 @@ const BunBuildOptions = struct {
|
||||
enable_logs: bool = false,
|
||||
enable_asan: bool,
|
||||
enable_valgrind: bool,
|
||||
enable_fuzzilli: bool,
|
||||
use_mimalloc: bool,
|
||||
tracy_callstack_depth: u16,
|
||||
reported_nodejs_version: Version,
|
||||
@@ -82,6 +99,7 @@ const BunBuildOptions = struct {
|
||||
opts.addOption(bool, "enable_logs", this.enable_logs);
|
||||
opts.addOption(bool, "enable_asan", this.enable_asan);
|
||||
opts.addOption(bool, "enable_valgrind", this.enable_valgrind);
|
||||
opts.addOption(bool, "enable_fuzzilli", this.enable_fuzzilli);
|
||||
opts.addOption(bool, "use_mimalloc", this.use_mimalloc);
|
||||
opts.addOption([]const u8, "reported_nodejs_version", b.fmt("{f}", .{this.reported_nodejs_version}));
|
||||
opts.addOption(bool, "zig_self_hosted_backend", this.no_llvm);
|
||||
@@ -255,6 +273,7 @@ pub fn build(b: *Build) !void {
|
||||
.tracy_callstack_depth = b.option(u16, "tracy_callstack_depth", "") orelse 10,
|
||||
.enable_logs = b.option(bool, "enable_logs", "Enable logs in release") orelse false,
|
||||
.enable_asan = b.option(bool, "enable_asan", "Enable asan") orelse false,
|
||||
.enable_fuzzilli = b.option(bool, "enable_fuzzilli", "Enable fuzzilli instrumentation") orelse false,
|
||||
.enable_valgrind = b.option(bool, "enable_valgrind", "Enable valgrind") orelse false,
|
||||
.use_mimalloc = b.option(bool, "use_mimalloc", "Use mimalloc as default allocator") orelse false,
|
||||
.llvm_codegen_threads = b.option(u32, "llvm_codegen_threads", "Number of threads to use for LLVM codegen") orelse 1,
|
||||
@@ -489,6 +508,7 @@ fn addMultiCheck(
|
||||
.codegen_path = root_build_options.codegen_path,
|
||||
.no_llvm = root_build_options.no_llvm,
|
||||
.enable_asan = root_build_options.enable_asan,
|
||||
.enable_fuzzilli = root_build_options.enable_fuzzilli,
|
||||
.enable_valgrind = root_build_options.enable_valgrind,
|
||||
.use_mimalloc = root_build_options.use_mimalloc,
|
||||
.override_no_export_cpp_apis = root_build_options.override_no_export_cpp_apis,
|
||||
@@ -613,6 +633,9 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
obj.step.dependOn(&fail_step.step);
|
||||
}
|
||||
}
|
||||
if (opts.enable_fuzzilli) {
|
||||
obj.sanitize_coverage_trace_pc_guard = true;
|
||||
}
|
||||
obj.bundle_compiler_rt = false;
|
||||
obj.bundle_ubsan_rt = false;
|
||||
|
||||
|
||||
@@ -51,6 +51,19 @@ if(ENABLE_ASAN)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_FUZZILLI)
|
||||
# Enable coverage instrumentation for fuzzing with Fuzzilli
|
||||
register_compiler_flags(
|
||||
DESCRIPTION "Enable coverage instrumentation for fuzzing"
|
||||
-fsanitize-coverage=trace-pc-guard
|
||||
)
|
||||
|
||||
register_linker_flags(
|
||||
DESCRIPTION "Link coverage instrumentation"
|
||||
-fsanitize-coverage=trace-pc-guard
|
||||
)
|
||||
endif()
|
||||
|
||||
# --- Optimization level ---
|
||||
if(DEBUG)
|
||||
register_compiler_flags(
|
||||
|
||||
@@ -202,4 +202,6 @@ optionx(ERROR_LIMIT STRING "Maximum number of errors to show when compiling C++
|
||||
# bun.zig, and enables C++ code to also be aware of the option.
|
||||
set(USE_MIMALLOC_AS_DEFAULT_ALLOCATOR ON)
|
||||
|
||||
optionx(ENABLE_FUZZILLI BOOL "If Fuzzilli support should be enabled" DEFAULT OFF)
|
||||
|
||||
list(APPEND CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON)
|
||||
|
||||
@@ -915,6 +915,16 @@ if(USE_MIMALLOC_AS_DEFAULT_ALLOCATOR)
|
||||
target_compile_definitions(${bun} PRIVATE USE_MIMALLOC=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_FUZZILLI)
|
||||
target_compile_definitions(${bun} PRIVATE BUN_FUZZILLI_ENABLED=1)
|
||||
target_sources(${bun} PRIVATE
|
||||
${CWD}/src/fuzzilli/client.cpp
|
||||
${CWD}/src/fuzzilli/session.cpp
|
||||
${CWD}/src/fuzzilli/log.cpp
|
||||
${CWD}/src/fuzzilli/reprl.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${bun} PRIVATE
|
||||
_HAS_EXCEPTIONS=0
|
||||
LIBUS_USE_OPENSSL=1
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"bd:v": "(bun run --silent build:debug &> /tmp/bun.debug.build.log || (cat /tmp/bun.debug.build.log && rm -rf /tmp/bun.debug.build.log && exit 1)) && rm -f /tmp/bun.debug.build.log && ./build/debug/bun-debug",
|
||||
"bd": "BUN_DEBUG_QUIET_LOGS=1 bun --silent bd:v",
|
||||
"build:debug": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -B build/debug --log-level=NOTICE",
|
||||
"build:debug:fuzzilli": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_FUZZILLI=ON -B build/debug --log-level=NOTICE",
|
||||
"build:debug:noasan": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=OFF -B build/debug --log-level=NOTICE",
|
||||
"build:release": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Release -B build/release",
|
||||
"build:ci": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=ON -DCI=true -B build/release-ci --verbose --fresh",
|
||||
|
||||
@@ -36,7 +36,6 @@ MessagePortChannelProviderImpl::MessagePortChannelProviderImpl() = default;
|
||||
|
||||
MessagePortChannelProviderImpl::~MessagePortChannelProviderImpl()
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void MessagePortChannelProviderImpl::createNewMessagePortChannel(const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
#include "Path.h"
|
||||
|
||||
#include "DOMURL.h"
|
||||
|
||||
#include "headers-cpp.h"
|
||||
|
||||
#include <JavaScriptCore/CallFrame.h>
|
||||
#include <JavaScriptCore/JSArrayBufferViewInlines.h>
|
||||
|
||||
int main() {
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
char buf[80];
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buf, 80, "%Y-%m-%d %H:%M:%s", timeinfo);
|
||||
|
||||
cout << "// Auto-generated by src/bun.js/headergen/sizegen.cpp at " << buf
|
||||
<< ".\n";
|
||||
cout << "// These are the byte sizes for the different object types with "
|
||||
"bindings in JavaScriptCore.\n";
|
||||
cout << "// This allows us to safely return stack allocated C++ types to "
|
||||
"Zig.\n";
|
||||
cout << "// It is only safe to do this when these sizes are correct.\n";
|
||||
cout << "// That means:\n";
|
||||
cout << "// 1. We can't dynamically link JavaScriptCore\n";
|
||||
cout << "// 2. It's important that this is run whenever JavaScriptCore is "
|
||||
"updated or the bindings on the Zig side change.\n";
|
||||
cout << "// Failure to do so will lead to undefined behavior and probably "
|
||||
"some frustrated people.\n";
|
||||
cout << "// --- Regenerate this: --- \n";
|
||||
cout << "// 1. \"make headers\"\n";
|
||||
cout << "// 2. \"make sizegen\"\n";
|
||||
cout << "// 3. \"make headers\"\n";
|
||||
cout << "// ------------------------\n";
|
||||
cout << "// You can verify the numbers written in this file at runtime via "
|
||||
"the `extern`d types\n";
|
||||
cout << "// Run \"headers\" twice because it uses these values "
|
||||
"in the output. That's how all the bJSC__.* types are created - from "
|
||||
"these values. \n";
|
||||
int i = 0;
|
||||
int len = 31 - 3;
|
||||
for (i = 0; i < len; i++) {
|
||||
cout << "pub const " << names[i] << " = " << sizes[i] << ";\n";
|
||||
cout << "pub const " << names[i] << "_align = " << aligns[i] << ";\n";
|
||||
}
|
||||
cout << "pub const Bun_FFI_PointerOffsetToArgumentsList = "
|
||||
<< JSC::CallFrame::argumentOffset(0) << ";\n";
|
||||
cout << "pub const Bun_FFI_PointerOffsetToTypedArrayVector = "
|
||||
<< JSC::JSArrayBufferView::offsetOfVector() << ";\n";
|
||||
cout << "pub const Bun_FFI_PointerOffsetToTypedArrayLength = "
|
||||
<< JSC::JSArrayBufferView::offsetOfLength() << ";\n";
|
||||
cout << "pub const Bun_CallFrame__codeBlock = ";
|
||||
|
||||
cout << static_cast<int>(JSC::CallFrameSlot::codeBlock) << ";\n";
|
||||
cout << "pub const Bun_CallFrame__callee = ";
|
||||
|
||||
cout << static_cast<int>(JSC::CallFrameSlot::callee) << ";\n";
|
||||
cout << "pub const Bun_CallFrame__argumentCountIncludingThis = ";
|
||||
|
||||
cout << static_cast<int>(JSC::CallFrameSlot::argumentCountIncludingThis)
|
||||
<< ";\n";
|
||||
cout << "pub const Bun_CallFrame__thisArgument = ";
|
||||
|
||||
cout << static_cast<int>(JSC::CallFrameSlot::thisArgument) << ";\n";
|
||||
cout << "pub const Bun_CallFrame__firstArgument = ";
|
||||
|
||||
cout << static_cast<int>(JSC::CallFrameSlot::firstArgument) << ";\n";
|
||||
|
||||
cout << "pub const Bun_CallFrame__size = ";
|
||||
|
||||
cout << sizeof(JSC::CallFrame) << ";\n";
|
||||
|
||||
cout << "pub const Bun_CallFrame__align = ";
|
||||
|
||||
cout << alignof(JSC::CallFrame) << ";\n";
|
||||
return 0;
|
||||
}
|
||||
12
src/cli.zig
12
src/cli.zig
@@ -91,6 +91,7 @@ pub const PackCommand = @import("./cli/pack_command.zig").PackCommand;
|
||||
pub const AuditCommand = @import("./cli/audit_command.zig").AuditCommand;
|
||||
pub const InitCommand = @import("./cli/init_command.zig").InitCommand;
|
||||
pub const WhyCommand = @import("./cli/why_command.zig").WhyCommand;
|
||||
pub const FuzzilliCommand = @import("./cli/fuzzilli_command.zig").FuzzilliCommand;
|
||||
|
||||
pub const Arguments = @import("./cli/Arguments.zig");
|
||||
|
||||
@@ -624,6 +625,7 @@ pub const Command = struct {
|
||||
RootCommandMatcher.case("prune") => .ReservedCommand,
|
||||
RootCommandMatcher.case("list") => .PackageManagerCommand,
|
||||
RootCommandMatcher.case("why") => .WhyCommand,
|
||||
RootCommandMatcher.case("fuzzilli") => .FuzzilliCommand,
|
||||
|
||||
RootCommandMatcher.case("-e") => .AutoCommand,
|
||||
|
||||
@@ -933,6 +935,11 @@ pub const Command = struct {
|
||||
try ExecCommand.exec(ctx);
|
||||
} else Tag.printHelp(.ExecCommand, true);
|
||||
},
|
||||
.FuzzilliCommand => {
|
||||
const ctx = try Command.init(allocator, log, .FuzzilliCommand);
|
||||
try FuzzilliCommand.exec(ctx);
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,6 +975,7 @@ pub const Command = struct {
|
||||
PublishCommand,
|
||||
AuditCommand,
|
||||
WhyCommand,
|
||||
FuzzilliCommand,
|
||||
|
||||
/// Used by crash reports.
|
||||
///
|
||||
@@ -1005,6 +1013,7 @@ pub const Command = struct {
|
||||
.PublishCommand => 'k',
|
||||
.AuditCommand => 'A',
|
||||
.WhyCommand => 'W',
|
||||
.FuzzilliCommand => 'F',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1317,6 +1326,9 @@ pub const Command = struct {
|
||||
Output.pretty(intro_text, .{});
|
||||
Output.flush();
|
||||
},
|
||||
.FuzzilliCommand => {
|
||||
HelpCommand.printWithReason(.explicit, false);
|
||||
},
|
||||
else => {
|
||||
HelpCommand.printWithReason(.explicit);
|
||||
},
|
||||
|
||||
62
src/cli/fuzzilli_command.zig
Normal file
62
src/cli/fuzzilli_command.zig
Normal file
@@ -0,0 +1,62 @@
|
||||
/// C++ function that runs the Fuzzilli REPRL loop
|
||||
/// Takes a callback pointer for executing JavaScript
|
||||
extern "c" fn bun__fuzzilli__begin_with_global(callback: ?*const anyopaque) void;
|
||||
|
||||
/// Callback invoked by C++ to execute a JavaScript script
|
||||
/// Returns 0 on success, non-zero on exception or error
|
||||
fn executeScript(script_ptr: [*c]const u8, script_len: c_ulong) callconv(.c) c_int {
|
||||
const script_slice = script_ptr[0..script_len];
|
||||
|
||||
// Get path to current bun executable
|
||||
var exe_path_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
||||
const exe_path = std.fs.selfExePath(&exe_path_buf) catch {
|
||||
bun.Output.printErrorln("[Zig] ERROR: Failed to get self exe path", .{});
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Use `bun -e` to execute the script in a fresh process
|
||||
// This provides complete state isolation between executions
|
||||
const argv = [_][]const u8{
|
||||
exe_path,
|
||||
"-e",
|
||||
script_slice,
|
||||
};
|
||||
|
||||
var child = std.process.Child.init(&argv, bun.default_allocator);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Ignore;
|
||||
|
||||
const term = child.spawnAndWait() catch |err| {
|
||||
bun.Output.printErrorln("[Zig] ERROR: Failed to spawn: {}", .{err});
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Return 0 for success, 1 for any failure
|
||||
return switch (term) {
|
||||
.Exited => |code| if (code == 0) 0 else 1,
|
||||
else => 1,
|
||||
};
|
||||
}
|
||||
|
||||
pub const FuzzilliCommand = struct {
|
||||
pub fn exec(_: bun.cli.Command.Context) !void {
|
||||
bun.Output.printErrorln("[Zig] FuzzilliCommand.exec() called", .{});
|
||||
|
||||
// Initialize JSC
|
||||
bun.Output.printErrorln("[Zig] Initializing JSC", .{});
|
||||
JSC.initialize(false);
|
||||
bun.Output.printErrorln("[Zig] JSC initialized", .{});
|
||||
|
||||
// Call C++ to handle REPRL protocol, passing our execute callback
|
||||
bun.Output.printErrorln("[Zig] Calling bun__fuzzilli__begin_with_global()", .{});
|
||||
bun__fuzzilli__begin_with_global(@ptrCast(&executeScript));
|
||||
|
||||
bun.Output.printErrorln("[Zig] bun__fuzzilli__begin_with_global() returned (should never happen)", .{});
|
||||
}
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const bun = @import("bun");
|
||||
const JSC = bun.jsc;
|
||||
55
src/fuzzilli/client.cpp
Normal file
55
src/fuzzilli/client.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "log.hpp"
|
||||
#include <cstring>
|
||||
#ifdef BUN_FUZZILLI_ENABLED
|
||||
|
||||
#include "client.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
Client::Client(Log& log, ClientConfig config)
|
||||
: m_config(std::move(config)),
|
||||
m_log(log)
|
||||
{
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t Client::forceRead(int fd, std::span<char> buffer, std::size_t maxBytes)
|
||||
{
|
||||
const ssize_t res = read(fd, buffer.data(), maxBytes);
|
||||
if (res < 0) {
|
||||
m_log << "Error reading from fd " << fd << " -- " << strerror(errno) << "\n";
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>(res);
|
||||
}
|
||||
|
||||
void Client::forceWrite(int fd, std::string_view data)
|
||||
{
|
||||
const int written = write(fd, data.data(), data.size());
|
||||
if (written != static_cast<int>(data.size())) {
|
||||
m_log << "Error writing to fd " << fd << "\n";
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::sendCommand(std::string_view command)
|
||||
{
|
||||
forceWrite(m_config.commandWriteFD, command);
|
||||
}
|
||||
|
||||
void Client::sendData(std::string_view data)
|
||||
{
|
||||
forceWrite(m_config.dataWriteFD, data);
|
||||
}
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
|
||||
#endif // BUN_FUZZILLI_ENABLED
|
||||
83
src/fuzzilli/client.hpp
Normal file
83
src/fuzzilli/client.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "log.hpp"
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
#include <ranges>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
struct ClientConfig {
|
||||
int commandReadFD;
|
||||
int commandWriteFD;
|
||||
int dataReadFD;
|
||||
int dataWriteFD;
|
||||
|
||||
static constexpr ClientConfig defaultConfig()
|
||||
{
|
||||
return {
|
||||
.commandReadFD = 100,
|
||||
.commandWriteFD = 101,
|
||||
.dataReadFD = 102,
|
||||
.dataWriteFD = 103,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief A client that connects to the Fuzzilli runner.
|
||||
class Client {
|
||||
private:
|
||||
static constexpr auto defaultMaxCmdSize = 4 * 1024;
|
||||
static constexpr auto defaultMaxDataSize = 4 * 1024 * 1024;
|
||||
|
||||
public:
|
||||
Client(Log& log, ClientConfig config = ClientConfig::defaultConfig());
|
||||
~Client();
|
||||
|
||||
void sendCommand(std::string_view);
|
||||
void sendData(std::string_view);
|
||||
|
||||
template<typename It>
|
||||
std::size_t receiveFd(It it, int fd, std::size_t numBytes)
|
||||
{
|
||||
static constexpr std::size_t bufSize = 128;
|
||||
std::array<char, bufSize> buffer;
|
||||
|
||||
std::size_t written = 0;
|
||||
while (written < numBytes) {
|
||||
std::size_t toRead = std::min(bufSize, numBytes - written);
|
||||
std::size_t count = forceRead(fd, buffer, toRead);
|
||||
|
||||
if (count == 0) break; // EOF or error
|
||||
|
||||
it = std::ranges::copy_n(buffer.begin(), count, it).out;
|
||||
written += count;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
std::size_t receiveCommand(It it, std::size_t maxSize = defaultMaxCmdSize)
|
||||
{
|
||||
m_log << "Receiving command up to " << maxSize << " bytes\n";
|
||||
return receiveFd(it, m_config.commandReadFD, maxSize);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
std::size_t receiveData(It it, std::size_t maxSize = defaultMaxDataSize)
|
||||
{
|
||||
m_log << "Receiving data up to " << maxSize << " bytes\n";
|
||||
return receiveFd(it, m_config.dataReadFD, maxSize);
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t forceRead(int fd, std::span<char> buffer, std::size_t maxBytes);
|
||||
void forceWrite(int fd, std::string_view data);
|
||||
|
||||
ClientConfig m_config;
|
||||
Log& m_log;
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
94
src/fuzzilli/coverage.c
Normal file
94
src/fuzzilli/coverage.c
Normal file
@@ -0,0 +1,94 @@
|
||||
// SanitzerCoverage-based coverage collection code for libcoverage.
|
||||
// Copy+paste this code into the JavaScript shell binary.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
//
|
||||
// BEGIN FUZZING CODE
|
||||
//
|
||||
|
||||
#define REPRL_CRFD 100
|
||||
#define REPRL_CWFD 101
|
||||
#define REPRL_DRFD 102
|
||||
#define REPRL_DWFD 103
|
||||
|
||||
#define SHM_SIZE 0x200000
|
||||
#define MAX_EDGES ((SHM_SIZE - 4) * 8)
|
||||
|
||||
#define CHECK(cond) if (!(cond)) { fprintf(stderr, "\"" #cond "\" failed\n"); _exit(-1); }
|
||||
|
||||
struct shmem_data {
|
||||
uint32_t num_edges;
|
||||
unsigned char edges[];
|
||||
};
|
||||
|
||||
struct shmem_data* __shmem;
|
||||
uint32_t *__edges_start, *__edges_stop;
|
||||
|
||||
void __sanitizer_cov_reset_edgeguards() {
|
||||
uint64_t N = 0;
|
||||
for (uint32_t *x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++)
|
||||
*x = ++N;
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
// Avoid duplicate initialization
|
||||
if (start == stop || *start)
|
||||
return;
|
||||
|
||||
if (__edges_start != NULL || __edges_stop != NULL) {
|
||||
fprintf(stderr, "Coverage instrumentation is only supported for a single module\n");
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
__edges_start = start;
|
||||
__edges_stop = stop;
|
||||
|
||||
// Map the shared memory region
|
||||
const char* shm_key = getenv("SHM_ID");
|
||||
if (!shm_key) {
|
||||
puts("[COV] no shared memory bitmap available, skipping");
|
||||
__shmem = (struct shmem_data*) malloc(SHM_SIZE);
|
||||
} else {
|
||||
int fd = shm_open(shm_key, O_RDWR, S_IREAD | S_IWRITE);
|
||||
if (fd <= -1) {
|
||||
fprintf(stderr, "Failed to open shared memory region: %s\n", strerror(errno));
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
__shmem = (struct shmem_data*) mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (__shmem == MAP_FAILED) {
|
||||
fprintf(stderr, "Failed to mmap shared memory region\n");
|
||||
_exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
__sanitizer_cov_reset_edgeguards();
|
||||
|
||||
__shmem->num_edges = stop - start;
|
||||
printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n", shm_key, __shmem->num_edges);
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
|
||||
// There's a small race condition here: if this function executes in two threads for the same
|
||||
// edge at the same time, the first thread might disable the edge (by setting the guard to zero)
|
||||
// before the second thread fetches the guard value (and thus the index). However, our
|
||||
// instrumentation ignores the first edge (see libcoverage.c) and so the race is unproblematic.
|
||||
uint32_t index = *guard;
|
||||
// If this function is called before coverage instrumentation is properly initialized we want to return early.
|
||||
if (!index) return;
|
||||
__shmem->edges[index / 8] |= 1 << (index % 8);
|
||||
*guard = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// END FUZZING CODE
|
||||
//
|
||||
45
src/fuzzilli/data_stream.cpp
Normal file
45
src/fuzzilli/data_stream.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "data_stream.hpp"
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
MmapDataStreamBuf::MmapDataStreamBuf(int fd) : m_mapping([&] {
|
||||
void* addr = mmap(nullptr, reprlMaxDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
// TODO(markoejnovic): Log
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return reinterpret_cast<char*>(addr);
|
||||
}()) {
|
||||
setg(m_mapping, m_mapping, m_mapping + reprlMaxDataSize);
|
||||
}
|
||||
|
||||
MmapDataStreamBuf::~MmapDataStreamBuf() {
|
||||
if (m_mapping != nullptr) {
|
||||
munmap(m_mapping, reprlMaxDataSize);
|
||||
}
|
||||
}
|
||||
|
||||
DataStream DataStream::fromEnv(int dataReadFd) {
|
||||
return {
|
||||
[dataReadFd] -> std::unique_ptr<DataStreamBuf> {
|
||||
if (const char* shmKey = getenv("SHM_ID")) {
|
||||
const std::int32_t fd = shm_open(shmKey, O_RDWR, S_IREAD | S_IWRITE);
|
||||
if (fd < 0) {
|
||||
// TODO(markoejnovic): Log
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return std::make_unique<MmapDataStreamBuf>(fd);
|
||||
}
|
||||
|
||||
// Otherwise, we will be reading from the data stream.
|
||||
return std::make_unique<FileDataStreamBuf>(dataReadFd);
|
||||
}()
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
52
src/fuzzilli/data_stream.hpp
Normal file
52
src/fuzzilli/data_stream.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <streambuf>
|
||||
#include <variant>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
/// @brief Represents the stream of data exchanged by fuzzilli and bun.
|
||||
/// Fuzzilli will send us data through this stream.
|
||||
struct DataStreamBuf : public std::streambuf {};
|
||||
|
||||
struct MmapDataStreamBuf : public DataStreamBuf {
|
||||
private:
|
||||
static constexpr std::size_t reprlMaxDataSize = 16 << 20;
|
||||
|
||||
char* m_mapping = nullptr;
|
||||
|
||||
public:
|
||||
MmapDataStreamBuf(int fd);
|
||||
~MmapDataStreamBuf();
|
||||
};
|
||||
|
||||
/// @note This borrows the file descriptor; it does not take ownership of it.
|
||||
struct FileDataStreamBuf : public DataStreamBuf {
|
||||
constexpr FileDataStreamBuf(int fd)
|
||||
: m_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
struct DataStream {
|
||||
public:
|
||||
/// @brief Create the fuzzilli DataStream from the environment.
|
||||
///
|
||||
/// Reads `envp["SHM_ID"]` to determine whether to use shared memory or a file descriptor.
|
||||
/// If `SHM_ID` is set, uses shared memory; otherwise, falls back to file descriptor.
|
||||
///
|
||||
/// @note Borrows the file descriptor.
|
||||
static DataStream fromEnv(int dataReadFd);
|
||||
|
||||
private:
|
||||
constexpr DataStream(std::unique_ptr<DataStreamBuf>&& buf)
|
||||
: m_buf(std::move(buf)) {};
|
||||
|
||||
std::unique_ptr<DataStreamBuf> m_buf;
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
36
src/fuzzilli/log.cpp
Normal file
36
src/fuzzilli/log.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "log.hpp"
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
Log::Log(std::filesystem::path const& path)
|
||||
: m_fd([&]() {
|
||||
const int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) [[unlikely]] {
|
||||
std::abort();
|
||||
}
|
||||
return fd;
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
Log& Log::operator<<(std::string_view message)
|
||||
{
|
||||
const auto forceWrite = [this](std::string_view message) {
|
||||
const ssize_t bytesWritten = write(m_fd, message.data(), message.size());
|
||||
if (bytesWritten < 0 || static_cast<size_t>(bytesWritten) != message.size()) [[unlikely]] {
|
||||
std::abort();
|
||||
}
|
||||
};
|
||||
|
||||
forceWrite(message);
|
||||
fsync(m_fd);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Log& Log::operator<<(std::int64_t message)
|
||||
{
|
||||
return (*this << std::to_string(message));
|
||||
}
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
26
src/fuzzilli/log.hpp
Normal file
26
src/fuzzilli/log.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
class Log {
|
||||
public:
|
||||
constexpr Log(int fd)
|
||||
: m_fd(fd)
|
||||
{
|
||||
}
|
||||
Log(std::filesystem::path const& path);
|
||||
Log& operator<<(std::string_view message);
|
||||
Log& operator<<(std::int64_t message);
|
||||
|
||||
Log(const Log&) = delete;
|
||||
Log& operator=(const Log&) = delete;
|
||||
Log(Log&&) = delete;
|
||||
Log& operator=(Log&&) = delete;
|
||||
|
||||
private:
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
84
src/fuzzilli/reprl.cpp
Normal file
84
src/fuzzilli/reprl.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "reprl.hpp"
|
||||
#include "JavaScriptCore/Heap.h"
|
||||
#include "JavaScriptCore/JSLock.h"
|
||||
#include "JavaScriptCore/Completion.h"
|
||||
#include "JavaScriptCore/InitializeThreading.h"
|
||||
#include "JavaScriptCore/SourceCode.h"
|
||||
#include "JavaScriptCore/SourceOrigin.h"
|
||||
#include "JavaScriptCore/JSGlobalObject.h"
|
||||
#include "wtf/NakedPtr.h"
|
||||
#include <span>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
Reprl::Reprl() : m_vm(JSC::VM::create(JSC::HeapType::Large)) {
|
||||
fprintf(stderr, "[Fuzzilli] Reprl() constructor started\n");
|
||||
fprintf(stderr, "[Fuzzilli] VM created\n");
|
||||
|
||||
// Acquire heap access before creating the global object
|
||||
fprintf(stderr, "[Fuzzilli] About to acquire heap access\n");
|
||||
m_vm->heap.acquireAccess();
|
||||
fprintf(stderr, "[Fuzzilli] Heap access acquired\n");
|
||||
|
||||
fprintf(stderr, "[Fuzzilli] About to acquire JS lock\n");
|
||||
JSC::JSLockHolder locker(m_vm.get());
|
||||
fprintf(stderr, "[Fuzzilli] JS lock acquired\n");
|
||||
|
||||
// Use vanilla JSC::JSGlobalObject instead of Zig::GlobalObject
|
||||
// This avoids needing the full Bun VirtualMachine infrastructure
|
||||
fprintf(stderr, "[Fuzzilli] About to create global object structure\n");
|
||||
auto* structure = JSC::JSGlobalObject::createStructure(m_vm.get(), JSC::jsNull());
|
||||
if (!structure) {
|
||||
fprintf(stderr, "[Fuzzilli] ERROR: Failed to create global object structure\n");
|
||||
std::abort();
|
||||
}
|
||||
fprintf(stderr, "[Fuzzilli] Global object structure created\n");
|
||||
|
||||
fprintf(stderr, "[Fuzzilli] About to create global object\n");
|
||||
m_globalObject = JSC::JSGlobalObject::create(m_vm.get(), structure);
|
||||
if (!m_globalObject) {
|
||||
fprintf(stderr, "[Fuzzilli] ERROR: Failed to create global object\n");
|
||||
std::abort();
|
||||
}
|
||||
fprintf(stderr, "[Fuzzilli] Global object created successfully\n");
|
||||
fprintf(stderr, "[Fuzzilli] Reprl() constructor completed\n");
|
||||
}
|
||||
|
||||
Reprl::~Reprl() {
|
||||
}
|
||||
|
||||
int Reprl::execute(std::string_view script) {
|
||||
JSC::JSLockHolder locker(m_vm.get());
|
||||
|
||||
auto* globalObject = m_globalObject;
|
||||
|
||||
// Create the source code
|
||||
auto sourceCode = JSC::SourceCode(
|
||||
JSC::StringSourceProvider::create(
|
||||
WTF::String::fromUTF8(std::span { script.data(), script.length() }),
|
||||
JSC::SourceOrigin(),
|
||||
WTF::String(),
|
||||
JSC::SourceTaintedOrigin::Untainted,
|
||||
WTF::TextPosition(),
|
||||
JSC::SourceProviderSourceType::Program
|
||||
)
|
||||
);
|
||||
|
||||
// Evaluate the script
|
||||
WTF::NakedPtr<JSC::Exception> exception;
|
||||
JSC::evaluate(globalObject, sourceCode, JSC::JSValue(), exception);
|
||||
|
||||
if (exception) {
|
||||
// Script threw an exception - return non-zero status
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Reprl::reset() {
|
||||
JSC::JSLockHolder locker(m_vm.get());
|
||||
m_vm->heap.collectSync(JSC::CollectionScope::Full);
|
||||
}
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
23
src/fuzzilli/reprl.hpp
Normal file
23
src/fuzzilli/reprl.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "JavaScriptCore/VM.h"
|
||||
#include "JavaScriptCore/JSGlobalObject.h"
|
||||
#include "wtf/Ref.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
class Reprl {
|
||||
public:
|
||||
Reprl();
|
||||
~Reprl();
|
||||
|
||||
int execute(std::string_view script);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
Ref<JSC::VM> m_vm;
|
||||
JSC::JSGlobalObject* m_globalObject;
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
191
src/fuzzilli/session.cpp
Normal file
191
src/fuzzilli/session.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "log.hpp"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "session.hpp"
|
||||
#include "client.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
/// @brief Represents a long-running Fuzzilli session.
|
||||
///
|
||||
/// Fuzzilli will instantiate ONE bun instance, and this class manages that. Note that the same bun
|
||||
/// instance will be used for multiple fuzzing inputs.
|
||||
class FuzzilliSession {
|
||||
private:
|
||||
static constexpr std::string_view heloMessage = "HELO";
|
||||
|
||||
public:
|
||||
FuzzilliSession() noexcept {
|
||||
exchangeHelo();
|
||||
}
|
||||
|
||||
~FuzzilliSession() {}
|
||||
|
||||
private:
|
||||
Log m_log { "/tmp/fuzzilli-bun.log" };
|
||||
|
||||
Client m_client { m_log };
|
||||
|
||||
void exchangeHelo() {
|
||||
m_log << "[Session] Starting HELO exchange\n";
|
||||
m_client.sendCommand(heloMessage);
|
||||
m_log << "[Session] Sent HELO to Fuzzilli\n";
|
||||
|
||||
std::string response(heloMessage.size(), '\0');
|
||||
response.resize(m_client.receiveCommand(response.begin(), heloMessage.size()));
|
||||
m_log << "[Session] Received HELO response from Fuzzilli: '" << response << "' (length: " << response.size() << ")\n";
|
||||
|
||||
if (response != heloMessage) {
|
||||
m_log << "[Session] ERROR: Invalid HELO response from Fuzzilli: '" << response << "'\n";
|
||||
std::abort();
|
||||
}
|
||||
|
||||
m_log << "[Session] HELO exchange completed successfully\n";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
|
||||
// Type definition for the Zig callback
|
||||
using ExecuteCallback = int (*)(const char* script, size_t length);
|
||||
|
||||
// Global callback pointer set by Zig
|
||||
static ExecuteCallback g_execute_callback = nullptr;
|
||||
|
||||
extern "C" void bun__fuzzilli__begin_with_global(void* callback_ptr) {
|
||||
fprintf(stderr, "[C++] bun__fuzzilli__begin_with_global() entered\n");
|
||||
fflush(stderr);
|
||||
|
||||
g_execute_callback = reinterpret_cast<ExecuteCallback>(callback_ptr);
|
||||
if (!g_execute_callback) {
|
||||
fprintf(stderr, "[C++] ERROR: Execute callback is null!\n");
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
bun::fuzzilli::Log log("/tmp/fuzzilli-bun.log");
|
||||
|
||||
log << "[Main] ========================================\n";
|
||||
log << "[Main] bun__fuzzilli__begin() called\n";
|
||||
log << "[Main] ========================================\n";
|
||||
|
||||
fprintf(stderr, "[C++] About to create FuzzilliSession\n");
|
||||
fflush(stderr);
|
||||
|
||||
log << "[Main] Creating FuzzilliSession for HELO exchange\n";
|
||||
bun::fuzzilli::FuzzilliSession session;
|
||||
log << "[Main] FuzzilliSession created successfully\n";
|
||||
|
||||
fprintf(stderr, "[C++] FuzzilliSession created\n");
|
||||
fflush(stderr);
|
||||
|
||||
static constexpr auto REPRL_CRFD = 100;
|
||||
static constexpr auto REPRL_CWFD = 101;
|
||||
static constexpr auto REPRL_DRFD = 102;
|
||||
|
||||
log << "[Main] Entering REPRL loop\n";
|
||||
log << "[Main] REPRL FDs - CRFD: " << REPRL_CRFD << ", CWFD: " << REPRL_CWFD << ", DRFD: " << REPRL_DRFD << "\n";
|
||||
|
||||
int iteration = 0;
|
||||
while (true) {
|
||||
iteration++;
|
||||
log << "[Loop] ==================== Iteration " << iteration << " ====================\n";
|
||||
|
||||
// Check if control FD is still valid
|
||||
int fd_status = fcntl(REPRL_CRFD, F_GETFL);
|
||||
if (fd_status == -1) {
|
||||
log << "[Loop] ERROR: Control FD is invalid, errno: " << errno << " (" << strerror(errno) << ")\n";
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
// Read action (4 bytes, should be 'exec' = 0x63657865)
|
||||
unsigned action = 0;
|
||||
ssize_t nread = read(REPRL_CRFD, &action, 4);
|
||||
log << "[Loop] Read action: " << nread << " bytes\n";
|
||||
|
||||
fflush(0);
|
||||
if (nread != 4 || action != 0x63657865) { // 'exec'
|
||||
log << "[Loop] ERROR: Unknown action (expected 'exec'), nread=" << nread << "\n";
|
||||
_exit(-1);
|
||||
}
|
||||
log << "[Loop] Received 'exec' action\n";
|
||||
|
||||
// Read script size (8 bytes)
|
||||
size_t script_size = 0;
|
||||
nread = read(REPRL_CRFD, &script_size, 8);
|
||||
log << "[Loop] Read script size: " << nread << " bytes, size: " << script_size << " bytes\n";
|
||||
|
||||
if (nread != 8) {
|
||||
log << "[Loop] ERROR: Failed to read script size (got " << nread << " bytes instead of 8)\n";
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
if (script_size > 10 * 1024 * 1024) { // 10MB sanity check
|
||||
log << "[Loop] WARNING: Very large script size: " << script_size << " bytes\n";
|
||||
}
|
||||
|
||||
// Allocate buffer for script
|
||||
char* buf = reinterpret_cast<char*>(malloc(script_size + 1));
|
||||
if (!buf) {
|
||||
log << "[Loop] ERROR: Failed to allocate " << script_size << " bytes for script\n";
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
memset(buf, 0, script_size + 1);
|
||||
|
||||
// Read script data
|
||||
char* source_buffer_tail = buf;
|
||||
ssize_t remaining = static_cast<ssize_t>(script_size);
|
||||
log << "[Loop] Reading " << remaining << " bytes of script data from FD " << REPRL_DRFD << "\n";
|
||||
|
||||
size_t total_read = 0;
|
||||
while (remaining > 0) {
|
||||
ssize_t rv = read(REPRL_DRFD, source_buffer_tail, static_cast<size_t>(remaining));
|
||||
log << "[Loop] Read chunk: " << rv << " bytes (remaining: " << remaining << ", total read: " << total_read << ")\n";
|
||||
|
||||
if (rv <= 0) {
|
||||
log << "[Loop] ERROR: Failed to read script data (rv=" << rv << ", errno=" << errno << ": " << strerror(errno) << ")\n";
|
||||
free(buf);
|
||||
_exit(-1);
|
||||
}
|
||||
remaining -= rv;
|
||||
source_buffer_tail += rv;
|
||||
total_read += rv;
|
||||
}
|
||||
|
||||
buf[script_size] = '\0';
|
||||
log << "[Loop] Script data read successfully (total: " << total_read << " bytes)\n";
|
||||
|
||||
if (script_size > 0) {
|
||||
size_t preview_len = std::min(script_size, size_t(200));
|
||||
log << "[Loop] Script preview (first " << preview_len << " chars): " << std::string_view(buf, preview_len);
|
||||
if (script_size > preview_len) {
|
||||
log << "...";
|
||||
}
|
||||
log << "\n";
|
||||
}
|
||||
|
||||
// Execute the script via Zig callback
|
||||
log << "[Loop] Calling Zig execute callback\n";
|
||||
int status = g_execute_callback(buf, script_size);
|
||||
|
||||
// Clean up the script buffer
|
||||
free(buf);
|
||||
log << "[Loop] Freed script buffer\n";
|
||||
|
||||
log << "[Loop] Execution status: " << status << "\n";
|
||||
|
||||
// Send back the status to Fuzzilli (4 bytes as per REPRL protocol)
|
||||
log << "[Loop] Sending status " << status << " to Fuzzilli on FD " << REPRL_CWFD << "\n";
|
||||
ssize_t status_written = write(REPRL_CWFD, &status, 4);
|
||||
if (status_written != 4) {
|
||||
log << "[Loop] ERROR: Failed to write status (wrote " << status_written << " bytes instead of 4)\n";
|
||||
_exit(1);
|
||||
}
|
||||
log << "[Loop] Status sent successfully (" << status_written << " bytes)\n";
|
||||
log << "[Loop] Iteration " << iteration << " complete\n";
|
||||
}
|
||||
}
|
||||
9
src/fuzzilli/session.hpp
Normal file
9
src/fuzzilli/session.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
/// Type definition for the Zig execute callback
|
||||
/// Takes a script buffer and its length, returns exit status (0 = success, non-zero = failure/exception)
|
||||
typedef int (*FuzzilliExecuteCallback)(const char* script, unsigned long length);
|
||||
|
||||
/// Begins the Fuzzilli REPRL loop using the provided callback for script execution
|
||||
/// @param callback_ptr Pointer to the Zig execute callback function
|
||||
extern "C" void bun__fuzzilli__begin_with_global(void* callback_ptr);
|
||||
0
src/fuzzilli/shmem.cpp
Normal file
0
src/fuzzilli/shmem.cpp
Normal file
11
src/fuzzilli/shmem.hpp
Normal file
11
src/fuzzilli/shmem.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace bun::fuzzilli {
|
||||
|
||||
/// @brief Data shared between the fuzilling runner and the fuzzed process.
|
||||
struct Shmem {
|
||||
};
|
||||
|
||||
} // namespace bun::fuzzilli
|
||||
Reference in New Issue
Block a user