diff --git a/INSTALL.md b/INSTALL.md index 4fa62ffe3c..5959791001 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -33,6 +33,22 @@ pro hand -p true -s false -n false SIGBUS pro hand -p true -s false -n false SIGSEGV ``` +### Sanitizers + +Sanitizers are supported for native builds only and you need to have `llvm-18` (and `clang-18` on linux) installed on your machine. + +For native linux builds this is the only situation where we actually build against the native abi. Normally we build agains musl even on native gnu machines. + +macOS: +```terminal +brew install llvm@18 +``` + +Debian/Ubuntu: +```terminal +apt-get install llvm-18 clang-18 +``` + ## Build Once you install `zig`, you're ready to build: @@ -79,6 +95,12 @@ Provide additional compiler flags. These propagate to all build artifacts. Example: `zig build -Dcopt="-g" -Dcopt="-fno-sanitize=all"` +#### `-Dasan` +Enable address sanitizer. Only supported nativelly. Requires `llvm@18`, see [prerequisites](#sanitizers). + +#### `-Dubsan` +Enable undefined behavior sanitizer. Only supported nativelly. Requires `llvm@18`, see [prerequisites](#sanitizers). + diff --git a/build.zig b/build.zig index 77afb66922..45e5d663b5 100644 --- a/build.zig +++ b/build.zig @@ -26,6 +26,8 @@ const BuildCfg = struct { mem_dbg: bool = false, c3dbg: bool = false, snapshot_validation: bool = false, + ubsan: bool = false, + asan: bool = false, }; pub fn build(b: *std.Build) !void { @@ -84,6 +86,24 @@ pub fn build(b: *std.Build) !void { "Binary name (Default: urbit)", ) orelse "urbit"; + const asan = if (target.query.isNative()) + b.option( + bool, + "asan", + "Enable address sanitizer (native only, requires llvm@18)", + ) orelse false + else + false; + + const ubsan = if (target.query.isNative()) + b.option( + bool, + "ubsan", + "Enable undefined behavior sanitizer (native only, requires llvm@18)", + ) orelse false + else + false; + // Parse short git rev var file = try std.fs.cwd().openFile(".git/logs/HEAD", .{}); defer file.close(); @@ -116,6 +136,8 @@ pub fn build(b: *std.Build) !void { .mem_dbg = mem_dbg, .c3dbg = c3dbg, .snapshot_validation = snapshot_validation, + .asan = asan, + .ubsan = ubsan, .include_test_steps = !all, }; @@ -127,7 +149,9 @@ pub fn build(b: *std.Build) !void { const t = target.result; try buildBinary( b, - if (t.os.tag == .linux and target.query.isNative()) + if (t.os.tag == .linux and + target.query.isNative() and + !asan and !ubsan) b.resolveTargetQuery(.{ .abi = .musl }) else target, @@ -155,12 +179,38 @@ fn buildBinary( try global_flags.appendSlice(cfg.flags); try global_flags.appendSlice(&.{ - "-fno-sanitize=all", "-g", "-Wall", "-Werror", }); + if (!cfg.asan and !cfg.ubsan) + try global_flags.appendSlice(&.{ + "-fno-sanitize=all", + }); + + if (cfg.asan and !cfg.ubsan) + try global_flags.appendSlice(&.{ + "-Wno-deprecated", + "-fsanitize=address", + "-fno-sanitize=undefined", + "-fno-sanitize-trap=undefined", + }); + + if (!cfg.asan and cfg.ubsan) + try global_flags.appendSlice(&.{ + "-fsanitize=undefined", + "-fno-sanitize-trap=undefined", + }); + + if (cfg.asan and cfg.ubsan) + try global_flags.appendSlice(&.{ + "-Wno-deprecated", + "-fsanitize=address", + "-fsanitize=undefined", + "-fno-sanitize-trap=undefined", + }); + // // C Opts for Urbit PKGs And Binary // @@ -367,6 +417,34 @@ fn buildBinary( urbit.linkLibrary(urcrypt.artifact("urcrypt")); urbit.linkLibrary(whereami.artifact("whereami")); + if (t.isDarwin()) { + // Requires llvm@18 homebrew installation + if (cfg.asan or cfg.ubsan) + urbit.addLibraryPath(.{ + .cwd_relative = "/opt/homebrew/opt/llvm@18/lib/clang/18/lib/darwin", + }); + if (cfg.asan) urbit.linkSystemLibrary("clang_rt.asan_osx_dynamic"); + if (cfg.ubsan) urbit.linkSystemLibrary("clang_rt.ubsan_osx_dynamic"); + } + + if (t.os.tag == .linux) { + // Requires llvm-18 and clang-18 installation + if (cfg.asan or cfg.ubsan) + urbit.addLibraryPath(.{ + .cwd_relative = "/usr/lib/clang/18/lib/linux", + }); + if (t.cpu.arch == .x86_64) { + if (cfg.asan) urbit.linkSystemLibrary("clang_rt.asan-x86_64"); + if (cfg.ubsan) + urbit.linkSystemLibrary("clang_rt.ubsan_standalone-x86_64"); + } + if (t.cpu.arch == .aarch64) { + if (cfg.asan) urbit.linkSystemLibrary("clang_rt.asan-aarch64"); + if (cfg.ubsan) + urbit.linkSystemLibrary("clang_rt.ubsan_standalone-aarch64"); + } + } + urbit.addCSourceFiles(.{ .root = b.path("pkg/vere"), .files = &.{ diff --git a/pkg/c3/portable.h b/pkg/c3/portable.h index 8de330ce9c..acc9f33f2d 100644 --- a/pkg/c3/portable.h +++ b/pkg/c3/portable.h @@ -128,7 +128,11 @@ # define U3_OS_LoomBits 30 # elif defined(U3_OS_osx) # ifdef __LP64__ -# define U3_OS_LoomBase 0x28000000000 +# ifdef ASAN_ENABLED +# define U3_OS_LoomBase 0x728000000000 +# else +# define U3_OS_LoomBase 0x28000000000 +# endif # else # define U3_OS_LoomBase 0x4000000 # endif diff --git a/pkg/vere/mdns.c b/pkg/vere/mdns.c index 80a2b3ac9a..8b1859905c 100644 --- a/pkg/vere/mdns.c +++ b/pkg/vere/mdns.c @@ -80,7 +80,7 @@ static void resolve_cb(DNSServiceRef sref, hints.ai_family = AF_INET; // Request only IPv4 addresses hints.ai_socktype = SOCK_STREAM; // TCP socket - uv_getaddrinfo_t* req = (uv_getaddrinfo_t*)c3_malloc(sizeof(uv_getaddrinfo_t)); + uv_getaddrinfo_t* req = (uv_getaddrinfo_t*)c3_calloc(sizeof(uv_getaddrinfo_t)); req->data = (void*)payload; uv_loop_t* loop = uv_default_loop(); @@ -126,7 +126,7 @@ static void browse_cb(DNSServiceRef s, // we are leaking payload because we don't know when we are done // browsing, luckily we only browse once mdns_payload* payload = (mdns_payload*)context; - mdns_payload* payload_copy = c3_malloc(sizeof *payload_copy); + mdns_payload* payload_copy = c3_calloc(sizeof *payload_copy); // copy to prevent asynchronous thrashing of payload memcpy(payload_copy, payload, sizeof(mdns_payload)); @@ -181,7 +181,7 @@ void mdns_init(uint16_t port, bool fake, char* our, mdns_cb* cb, void* context) setenv("DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/var/run/dbus/system_bus_socket", 0); # endif - mdns_payload* register_payload = (mdns_payload*)c3_malloc(sizeof(mdns_payload)); + mdns_payload* register_payload = (mdns_payload*)c3_calloc(sizeof(mdns_payload)); DNSServiceRef sref; DNSServiceErrorType err; @@ -215,7 +215,7 @@ void mdns_init(uint16_t port, bool fake, char* our, mdns_cb* cb, void* context) init_sref_poll(sref, register_payload); - mdns_payload* browse_payload = (mdns_payload*)c3_malloc(sizeof(mdns_payload)); + mdns_payload* browse_payload = (mdns_payload*)c3_calloc(sizeof(mdns_payload)); browse_payload->cb = cb; browse_payload->context = context;