How to compile C++ with libFuzzer?

Hi!

Today, I’ve decided to spend some time fuzzing a random C++ library on github. I hit an unfortunate roadblock: I can’t get the code to link properly.

I think I need the following:

  • clang-based stdenv
  • clang’s libcxx based stdenv
  • llvm’s linker

Here’s what I have

13:32:51|~/tmp/f
λ bat -p shell.nix
with import <nixpkgs> {};
llvmPackages_11.libcxxStdenv.mkDerivation {
  name = "clang-nix-shell";
  buildInputs = [ /* add libraries here */ ];
}

13:32:56|~/tmp/f
λ bat -p main.cpp 
#include "stdint.h"
#include "stddef.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  return 0;  // Non-zero return values are reserved for future use.
}

13:32:59|~/tmp/f
λ nix-shell

[nix-shell:~/tmp/f]$ clang++ -fuse-ld=lld -fsanitize=fuzzer,address main.cpp
ld.lld: error: undefined symbol: std::_Hash_bytes(void const*, unsigned long, unsigned long)
...
...
...

ld.lld: error: undefined symbol: std::istream& std::istream::_M_extract<unsigned long>(unsigned long&)
>>> referenced by FuzzerDataFlowTrace.cpp.o:(fuzzer::BlockCoverage::AppendCoverage(std::istream&)) in archive /nix/store/rm09lg48s2qxz7ydsm9b1ld1152j8fgx-clang-wrapper-11.1.0/resource-root/lib/linux/libclang_rt.fuzzer-x86_64.a
>>> referenced by FuzzerFork.cpp.o:(fuzzer::GlobalEnv::RunOneMergeJob(fuzzer::FuzzJob*)) in archive /nix/store/rm09lg48s2qxz7ydsm9b1ld1152j8fgx-clang-wrapper-11.1.0/resource-root/lib/linux/libclang_rt.fuzzer-x86_64.a
>>> referenced by FuzzerMerge.cpp.o:(fuzzer::Merger::Parse(std::istream&, bool)) in archive /nix/store/rm09lg48s2qxz7ydsm9b1ld1152j8fgx-clang-wrapper-11.1.0/resource-root/lib/linux/libclang_rt.fuzzer-x86_64.a
>>> referenced 5 more times

ld.lld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)

Two questions here:

  • How do I solve the immediate problem of getting this to compile?
  • Meta question: how do I go debugging such issues? I am a bit frustrated that something conceptually simple as “follow llvm’s tutorial on fuzzing” quickly ended in errors, where I understand the general problem (linkers are hard), but have very little visibility into what’s going on exactly, and don’t know what is the next step in debugging (short of crying for help:) )
  1. I don’t think you have to use llvm’s linker. I managed to compile binaries for fuzzing without specifying -fuse-ld=lld (AFAIR, it uses gold).

  2. Have you tried using clang11Stdenv (instead of llvm_packages11.libcxxStdenv?

On the meta side of things, this is something that I am struggling with myself too.

Sadly, documentation about “how things work under the hood” does not exist (nix pills only gives the “general idea” of how things work), and the mechanics behind compilers packaging are definitely non-trivial…

I end up greping nixpkgs a lot, reading expressions, even adding buildins.trace here and there to “see the flow” better… and asking questions on Matrix.

1 Like

Yeah, the clang11Stdenv give errors about duplicate symobls with gcc’s libstdc++. That was a surprise to me (I’d assume clang’s stdenv would use clang’s STL), and that’s why I switched to libcxxStdenv which I think is “clang, but also use clang’s libraries” (might be talking nonsense here – I know only enough C++ linking to be dangerous!)