I’ve been struggling to add a memory sanitizer job as part of #186.
I’ve having problems getting MemorySanitizer to be usable in nix though. Opening this issue to document the problem and avoid spending too much more time on this.
Using -fsanitize=memory alone doesn’t work because although the build succeeds, running any program shows false positive errors unless other dependencies are also built with -fsanitize. (From https://github.com/google/sanitizers/wiki/memorysanitizer “It is critical that you should build all the code in your program (including libraries it uses, in particular, C++ standard library) with MSan.”)
So I tried to add support for this in shell.nix :
0{ pkgs ? import <nixpkgs> {}
1, crossPkgs ? pkgs
2, enableClang ? false # use clang instead of gcc
3, enableLibcxx ? false # use libc++ instead of libstdc++
4, enableMsan ? false # build all C/C++ code with -fsanitize=memory
5, enableTools ? false # enable clang-tools like clang-tidy
6}:
7
8let
9 lib = pkgs.lib;
10 llvm = crossPkgs.llvmPackages_20;
11 addFlags = p: p.overrideAttrs (old: {
12 env.CXXFLAGS = (old.env.CXXFLAGS or "") + " -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer";
13 });
14 capnproto = addFlags (crossPkgs.capnproto.override { clangStdenv = stdenv; });
15 libcxx = addFlags llvm.libcxx;
16 clang = if enableLibcxx then llvm.libcxxClang else llvm.clang;
17 stdenv = if enableClang then stdenvClang else crossPkgs.stdenv;
18 stdenvClang = if enableLibcxx then llvm.libcxxStdenv else llvm.stdenv;
19 clang-tools = llvm.clang-tools.override { inherit enableLibcxx; };
20in (crossPkgs.mkShell.override { stdenv = stdenv; }) {
21
22 buildInputs = [
23 capnproto
24 ] ++ lib.optionals enableLibcxx [libcxx]
25 ++ lib.optionals enableMsan [llvm.compiler-rt];
26
27 nativeBuildInputs = with pkgs; [
28 cmake
29 include-what-you-use
30 ninja
31 ] ++ lib.optionals enableClang [
32 clang
33 ] ++ lib.optionals enableTools [
34 clang-tools
35 ];
36
37 # Tell IWYU where its libc++ mapping lives
38 IWYU_MAPPING_FILE = if enableLibcxx then "${llvm.libcxx.dev}/include/c++/v1/libcxx.imp" else null;
39
40 shellHook = lib.optionalString enableMsan ''
41 export MSAN_SYMBOLIZER_PATH=${llvm.bintools}/bin/llvm-symbolizer
42 '';
43}
Build libc++ and cap’n proto with
0nix-shell shell.nix --arg enableClang true --arg enableLibcxx true --arg enableMsan true
But this results in errors from cmake building libcxx which I don’t understand:
0 > clang++: warning: argument unused during compilation: '-rtlib=compiler-rt' [-Wunused-command-line-argument]
1 > [2/2] : && /nix/store/xmbmym1mayyr2327lkap5yihq3g88z3x-clang-wrapper-20.1.5/bin/clang++ -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer CMakeFiles/cmTC_de5b8.dir/testCXXCompiler.cxx.o -o cmTC_de5b8 && :
2 > FAILED: cmTC_de5b8
3 > : && /nix/store/xmbmym1mayyr2327lkap5yihq3g88z3x-clang-wrapper-20.1.5/bin/clang++ -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer CMakeFiles/cmTC_de5b8.dir/testCXXCompiler.cxx.o -o cmTC_de5b8 && :
4 > /nix/store/v63bxfiacw082c7ijshf60alvvrpfxsq-binutils-2.44/bin/ld: cannot find /nix/store/xmbmym1mayyr2327lkap5yihq3g88z3x-clang-wrapper-20.1.5/resource-root/lib/x86_64-unknown-linux-gnu/libclang_rt.msan.a: No such file or directory
5 > /nix/store/v63bxfiacw082c7ijshf60alvvrpfxsq-binutils-2.44/bin/ld: cannot find /nix/store/xmbmym1mayyr2327lkap5yihq3g88z3x-clang-wrapper-20.1.5/resource-root/lib/x86_64-unknown-linux-gnu/libclang_rt.msan_cxx.a: No such file or directory
6 > clang++: error: linker command failed with exit code 1 (use -v to see invocation)
7 > ninja: build stopped: subcommand failed.
It seems like missing msan libraries are present in the compiler-rt-libc package but the clang-wrapper package doesn’t seem to link to them, so need to figure that out or take a different approach if this is not the right one.