From c8eef74f095bae10ccdb8218a339de863a6b9882 Mon Sep 17 00:00:00 2001 From: Santeri Hannula Date: Wed, 9 Oct 2024 15:39:14 +0300 Subject: [PATCH 1/5] build: add build opts for enabling sanitizers --- INSTALL.md | 22 +++++++++++++ build.zig | 80 ++++++++++++++++++++++++++++++++++++++++++++++- pkg/c3/portable.h | 6 +++- 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 4fa62ffe3c..00bc2798ae 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 + +Musl does not have proper sanitizer support, so until we support native (GNU) linux builds, these are limited to mac only. + +In order to use address sanitizer (`-Dasan`) and undefined behavior sanitizer (`-Dubsan`), you need to have version 18 of llvm installed on your machine. You also have to build natively, since cross-compilation is not supported. + +macOS: +```terminal +brew install llvm@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 in native macos builds. Requires llvm 18, see [prerequisites](#sanitizers). + +#### `-Dubsan` +Enable undefined behavior sanitizer. Only supported in native macos builds. Requires llvm 18, see [prerequisites](#sanitizers). + diff --git a/build.zig b/build.zig index 77afb66922..15073c590f 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,26 @@ pub fn build(b: *std.Build) !void { "Binary name (Default: urbit)", ) orelse "urbit"; + // Sanitizers are not properly supported in musl => mac only + + const asan = if (target.query.isNative() and target.result.isDarwin()) + b.option( + bool, + "asan", + "Enable address sanitizer (native only, requires llvm@18)", + ) orelse false + else + false; + + const ubsan = if (target.query.isNative() and target.result.isDarwin()) + 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 +138,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, }; @@ -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 From 70650807024840ffa3cd27f0e73880973fb07cc1 Mon Sep 17 00:00:00 2001 From: Santeri Hannula Date: Thu, 14 Nov 2024 15:47:29 +0200 Subject: [PATCH 2/5] build: enable sanitizer opts on native linux --- build.zig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 15073c590f..8f11d5df7b 100644 --- a/build.zig +++ b/build.zig @@ -86,9 +86,7 @@ pub fn build(b: *std.Build) !void { "Binary name (Default: urbit)", ) orelse "urbit"; - // Sanitizers are not properly supported in musl => mac only - - const asan = if (target.query.isNative() and target.result.isDarwin()) + const asan = if (target.query.isNative()) b.option( bool, "asan", @@ -97,7 +95,7 @@ pub fn build(b: *std.Build) !void { else false; - const ubsan = if (target.query.isNative() and target.result.isDarwin()) + const ubsan = if (target.query.isNative()) b.option( bool, "ubsan", From 21ca28b7971030f1ae3cafe1bbef1511510df0a4 Mon Sep 17 00:00:00 2001 From: Santeri Hannula Date: Thu, 14 Nov 2024 15:47:46 +0200 Subject: [PATCH 3/5] build: force musl on native linux builds only if sanitizers are off --- build.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 8f11d5df7b..45e5d663b5 100644 --- a/build.zig +++ b/build.zig @@ -149,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, From e4ad03e3067e21fec75e7a089e3adb034bc83417 Mon Sep 17 00:00:00 2001 From: Santeri Hannula Date: Thu, 14 Nov 2024 16:23:11 +0200 Subject: [PATCH 4/5] docs: update sanitizers section in `INSTALL.md` --- INSTALL.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 00bc2798ae..5959791001 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -35,19 +35,19 @@ pro hand -p true -s false -n false SIGSEGV ### Sanitizers -Musl does not have proper sanitizer support, so until we support native (GNU) linux builds, these are limited to mac only. +Sanitizers are supported for native builds only and you need to have `llvm-18` (and `clang-18` on linux) installed on your machine. -In order to use address sanitizer (`-Dasan`) and undefined behavior sanitizer (`-Dubsan`), you need to have version 18 of llvm installed on your machine. You also have to build natively, since cross-compilation is not supported. +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 @@ -96,10 +96,10 @@ 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 in native macos builds. Requires llvm 18, see [prerequisites](#sanitizers). +Enable address sanitizer. Only supported nativelly. Requires `llvm@18`, see [prerequisites](#sanitizers). #### `-Dubsan` -Enable undefined behavior sanitizer. Only supported in native macos builds. Requires llvm 18, see [prerequisites](#sanitizers). +Enable undefined behavior sanitizer. Only supported nativelly. Requires `llvm@18`, see [prerequisites](#sanitizers). From bd59366a73dbd566467b3a813fb659cf1a475c23 Mon Sep 17 00:00:00 2001 From: Santeri Hannula Date: Thu, 14 Nov 2024 17:59:32 +0200 Subject: [PATCH 5/5] mdns: change `c3_malloc` to `c3_calloc` --- pkg/vere/mdns.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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;