]> git.ipfire.org Git - thirdparty/systemd.git/blob - docs/TESTING_WITH_SANITIZERS.md
install-file: make fs_make_very_read_only() static
[thirdparty/systemd.git] / docs / TESTING_WITH_SANITIZERS.md
1 ---
2 title: Testing systemd Using Sanitizers
3 category: Contributing
4 layout: default
5 SPDX-License-Identifier: LGPL-2.1-or-later
6 ---
7
8 # Testing systemd Using Sanitizers
9
10 To catch the *nastier* kind of bugs, you can run your code with [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
11 and [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
12 This is mostly done automagically by various CI systems for each PR, but you may
13 want to do it locally as well. The process slightly varies depending on the
14 compiler you want to use and which part of the test suite you want to run.
15
16 ## mkosi
17
18 To build with sanitizers in mkosi, create a file `mkosi.local.conf` and add the following contents:
19
20 ```
21 [Content]
22 Environment=SANITIZERS=address,undefined
23 ```
24
25 The value of `SANITIZERS` is passed directly to meson's `b_sanitize` option, See
26 https://mesonbuild.com/Builtin-options.html#base-options for the format expected by the option. Currently,
27 only the sanitizers supported by gcc can be used, which are `address` and `undefined`.
28
29 Note that this will only work with a recent version of mkosi (>= 14 or by running mkosi directly from source).
30
31 ## gcc
32 gcc compiles in sanitizer libraries dynamically by default, so you need to get
33 the shared libraries first - on Fedora these are shipped as separate packages
34 (`libasan` for Address Sanitizer and `libubsan` for Undefined Behavior Sanitizer).
35
36 The compilation itself is then a matter of simply adding `-Db_sanitize=address,undefined`
37 to `meson`. That's it - following executions of `meson test` and integration tests
38 under `test/` subdirectory will run with sanitizers enabled. However, to get
39 truly useful results, you should tweak the runtime configuration of respective
40 sanitizers; e.g. in systemd we set the following environment variables:
41
42 ```bash
43 ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
44 UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
45 ```
46 ## clang
47 In case of clang things are somewhat different - the sanitizer libraries are
48 compiled in statically by default. This is not an issue if you plan to run
49 only the unit tests, but for integration tests you'll need to convince clang
50 to use the dynamic versions of sanitizer libraries.
51
52 First of all, pass `-shared-libsan` to both `clang` and `clang++`:
53
54 ```bash
55 CFLAGS=-shared-libasan
56 CXXFLAGS=-shared-libasan
57 ```
58
59 The `CXXFLAGS` are necessary for `src/libsystemd/sd-bus/test-bus-vtable-cc.c`. Compilation
60 is then the same as in case of gcc, simply add `-Db_sanitize=address,undefined`
61 to the `meson` call and use the same environment variables for runtime configuration.
62
63 ```bash
64 ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
65 UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
66 ```
67
68 After this, you'll probably notice that all compiled binaries complain about
69 missing `libclang_rt.asan*` library. To fix this, you have to install clang's
70 runtime libraries, usually shipped in the `compiler-rt` package. As these libraries
71 are installed in a non-standard location (non-standard for `ldconfig`), you'll
72 need to manually direct binaries to the respective runtime libraries.
73
74 ```
75 # Optionally locate the respective runtime DSO
76 $ ldd build/systemd | grep libclang_rt.asan
77 libclang_rt.asan-x86_64.so => not found
78 libclang_rt.asan-x86_64.so => not found
79 $ find /usr/lib* /usr/local/lib* -type f -name libclang_rt.asan-x86_64.so 2>/dev/null
80 /usr/lib64/clang/7.0.1/lib/libclang_rt.asan-x86_64.so
81
82 # Set the LD_LIBRARY_PATH accordingly
83 export LD_LIBRARY_PATH=/usr/lib64/clang/7.0.1/lib/
84
85 # If the path is correct, the "not found" message should change to an actual path
86 $ ldd build/systemd | grep libclang_rt.asan
87 libclang_rt.asan-x86_64.so => /usr/lib64/clang/7.0.1/lib/libclang_rt.asan-x86_64.so (0x00007fa9752fc000)
88 ```
89
90 This should help binaries to correctly find necessary sanitizer DSOs.
91
92 Also, to make the reports useful, `llvm-symbolizer` tool is required (usually
93 part of the `llvm` package).
94
95 ## Background notes
96 The reason why you need to force dynamic linking in case of `clang` is that some
97 applications make use of `libsystemd`, which is compiled with sanitizers as well.
98 However, if a *standard* (uninstrumented) application loads an instrumented library,
99 it will immediately fail due to unresolved symbols. To fix/workaround this, you
100 need to pre-load the ASan DSO using `LD_PRELOAD=/path/to/asan/dso`, which will
101 make things work as expected in most cases. This will, obviously, not work with
102 statically linked sanitizer libraries.
103
104 These shenanigans are performed automatically when running the integration test
105 suite (i.e. `test/TEST-??-*`) and are located in `test/test-functions` (mainly,
106 but not only, in the `create_asan_wrapper` function).