Estimated read time: 5 minutes
sanitizers (ASAN, UBSAN, etc.) is a
collection of tools to detect memory corruption bugs, undefined behavior and
more by instrumenting the code generated by the compiler. (That's the main
difference from valgrind.) From LibreOffice's perspective one more important
difference is that there is a
Jenkins_Linux_Ubsan tinderbox that
makes sure that the master branch is kept clean from errors detected by a
given configuration.
So when the tinderbox failed after a commit of mine, I wanted to set up a
similar environment locally, reproduce and fix the bug, and push the fix once
I saw that the fix indeed solves the problem. You can set many options both at
build and runtime, so while we have some
documentation on
the TDF wiki (and also Stephan was kind enough to share
his
config) on how to use these sanitizers, it wasn't clear to me what to do step
by step. So here is one possible setup that worked for me -- in my case I
wanted to reproduce a stack-use-after-return problem. If you haven't ever built
LibreOffice before, then go to
the Development wiki page,
first do a normal build, and if everything went fine, came back here.
Build options
My autogen.input looks like this:
CC=clang -fsanitize=address
CXX=clang++ -fsanitize=address
--enable-dbgutil
--disable-firebird-sdbc
Which is a normal clang debug build, except:
- you need to add
-fsanitize=... to CXX (not to CXXFLAGS), as explained
on the wiki
- you need to explicitly disable Firebird integration for now
Building
My first attempt failed at build time, as even the tools used only during the
build are instrumented, and some memory leak was detected there, which means
the build aborted before reaching the problem I was interested in. To disable
leak detection during build, and disable parallelism (I needed this, as I did
the build in the background while using the machine for something else):
make build-nocheck ASAN_OPTIONS=detect_leaks=0 PARALLELISM=1
This also means that I explicitly disabled running any tests, as I knew which
is the single unit test I want to run for the purposes of reproducing and
fixing the problem.
Testing
Once the build completed, it turns out that the stack-use-after-return detection is disabled at runtime by default, which means I could not see any problem locally. Here is the commandline to run one specific CppunitTest with this detection on:
cd sw; make -sr CppunitTest_sw_tiledrendering ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=1
Again, this is just one possible setup, you can use other -fsanitize=...
options, other environment variables during build and during testing -- but
hopefully it helps in the future to avoid pushing fixes for such problems
detected by sanitizers just blindly.
Update, 2019-01-25
The above described "do it yourself" way doesn't work with LibreOffice master
(towards 6.3) and openSUSE Leap 15.0 anymore. I tried to debug what is the
exact problem, but there are many moving parts here:
-
gcc version (providing libstdc++)
-
clang version (5.0.2 is too old; 7 failed to build the plugins, trunk
towards 9 also generated false positives for me)
-
various sanitizer-related environment variables
-
various sanitizer-related compiler options
So it's much easier to just use the combination used by the
Jenkins_Linux_Ubsan tinderbox than something custom. Doing that is
reasonably straightforward, but still there are a couple of non-trivial steps.
What worked for me is:
./setup --jenkins
./setup --jenkins-san
./setup --dev
cd $LODE_HOME/dev/core
This will build a working version of both gcc and clang for you.
- Instead of manually setting up the environment variables, do:
. $LODE_HOME/bin/lode_ubsan_env
- Instead of manually setting autogen options, use this autogen.input:
--with-distro=Jenkins/Linux_ubsan_master
- Finally to build the code and run a specific test based on tinderbox mail:
make build-nocheck
cd sw; make -sr CppunitTest_sw_unowriter CPPUNIT_TEST_NAME="testPasteListener"
Update, 2019-11-14
The 2019-01-25 setup can be fine-tuned further. Sadly LODE mixes two goals: setting up dependencies
/ environment and cloning repos. I recently added support for bypassing any cloning, so you can use
LODE even if you already built the code and want to keep using your own way. The tricks are:
-
Use autogen.env-san in
two ways: first comment out the second half to run the above ./setup --jenkins && ./setup
--jenkins-san, then to source the full environment. This means you get all the up to date
environment variables from LODE, but you don't need a chroot to avoid LODE messing up your
environment.
-
Use autogen.input-san
to again inherit all up to date autogen switches from LODE, but avoid the submodule pain that
would be the default. Now you can do a make check gb_SUPPRESS_TESTS=y to build (but not run) all
the code & tests.
-
Use up.sh to
build and run all Online code & tests -- with new enough
core.git master
and online.git
master the online.git make check passes for me in this environment.
I believe this setup mostly delegates (envrionment, config switches and toolchain) maintenance to
LODE, still allows not running in a chroot and managing your git clones without LODE.
Update, 2023-12-02
These days it works to use the system clang compiler, so no need to to execute ./setup in lode.git. This means:
-
Use (source)
autogen.env-san to set
the compiler flags and environment variables from LODE.
-
Use autogen.input-san
as autogen.input in the core.git build to set the autogen options.
-
Use up.sh to build Online the
usual way.