1# Static Analysis in Zircon
2
3This document describes:
4
5* How to perform static analysis with the Clang Static Analyzer in Zircon;
6* How to enable ZirconHandleChecker;
7* How to add/modify annotate attributes to syscalls/functions and use annotate attributes to suppress false positives.
8
9## Steps to run Clang Static Analyzer
10
11Assuming you already obtained a local copy of Fuchsia workspace according to the instructions written in [getting_started.md](https://fuchsia.googlesource.com/docs/+/master/getting_started.md) and the source tree of fuchsia is located at `$LOCAL_DIR/fuchsia` and current working directory is `$LOCAL_DIR/fuchsia/zircon`. The Clang Static Analayzer can be run on Zircon by following commands:
12
13```sh
14./scripts/download-prebuilt
15./scripts/analyze-zircon
16```
17
18The Clang Static Analyzer will be run on Zircon code base with default checkers. After the finish of the analysis, you can see an outout in stdout similar to the one below:
19
20```
21scan-build: Run 'scan-view $LOCAL_DIR/fuchsia/zircon/AnalysisResult/scan-build-2017-08-08-11-26-25-914570-SKSE39' to examine bug reports.
22```
23
24Just type the command start with `scan-view` in a terminal and it will open your web browser and show the analysis reports.
25
26## Steps to enable ZirconHandleChecker
27
28At the time this document is written, all Zircon related checkers are still under review by upstream LLVM community:
29
30 * MutexInInterruptContext [D27854](https://reviews.llvm.org/D27854)
31 * SpinLockChecker [D26340](https://reviews.llvm.org/D26340)
32 * MutexChecker [D26342](https://reviews.llvm.org/D26342)
33 * ZirconHandleChecker [D35968](https://reviews.llvm.org/D35968) [D36022](https://reviews.llvm.org/D36022) [D36023](https://reviews.llvm.org/D36023) [D36024](https://reviews.llvm.org/D36024) [D36251](https://reviews.llvm.org/D36251) [D36475](https://reviews.llvm.org/D36475))
34
35They are enabled by default when you executed the 'analyze-zircon' script. We will update the 'analyze-zircon' script to enable them by default once they get landed.
36
37In the mean time, if you would like to try ZirconHandleChecker now, you can download the source code of LLVM with Clang and apply the patch from the diffs above and follow the instructions in [toolchain.md](https://fuchsia.googlesource.com/docs/+/master/development/build/toolchain.md) to build your own toolchain. Assuming you have built your own toolchain and it is located at `$LOCAL_TOOLCHAIN_PREFIX` and `$LOCAL_TOOLCHAIN_PREFIX/bin/clang` is the path to the `clang` command. The Clang Static Analyzer can be run with ZirconHandleChecker and other default checkers enabled by following command:
38
39```
40./scripts/analyze-zircon -p $LOCAL_TOOLCHAIN_PREFIX -m all
41```
42
43If you want to enable ZirconHandleChecker and disable other default checkers, please run following command:
44
45```
46./scripts/analyze-zircon -p $LOCAL_TOOLCHAIN_PREFIX -m zircon
47```
48
49The 'analyze-zircon' scripts have additional options such as changing the output directories and changing build targets, please refer the to help information printed by `./scripts/analyze-zircon -h`.
50
51## Steps to add/modify annotate attributes to syscalls/functions
52
53In Zircon code base, raw annotations like `__attribute__((annotate("string")))` should never be used in Zircon code base, all zircon related annotations should be wrapped by macros. In this section, we will discuss how to add or modify annotations in Zircon code base.
54
55### Annotations in syscall declaration
56
57As header files of Zircon syscalls are generated from syscalls.abigen, in order to add/modify annotations of syscalls, the syscalls.abigen should be modified directly.
58Let’s use `zx_channel_create syscall` as example. This syscall will allocate two handles when it is successfully executed. Without annotations, its declaration in abigen will be like:
59
60```c
61syscall channel_create
62    (options: uint32_t)
63    returns (zx_status_t, out0: zx_handle_t, out1: zx_handle_t);
64```
65
66As argument `out0` and `out1` will be allocated handles, we should add `handle_acquire` annotation to these arguments:
67
68```c
69syscall channel_create
70    (options: uint32_t)
71    returns (zx_status_t, out0: zx_handle_t handle_acquire,
72             out1: zx_handle_t handle_acquire);
73```
74
75This syscall declaration will be processed by abigen and converted to:
76
77```c
78extern zx_status_t zx_channel_create(
79uint32_t options,
80    ZX_SYSCALL_PARAM_ATTR(handle_acquire) zx_handle_t* out0,
81    ZX_SYSCALL_PARAM_ATTR(handle_acquire) zx_handle_t* out1));
82```
83
84The declaration of macro can be found in system/public/zircon/syscalls.h, which is:
85
86```c
87#if defined(__clang__)
88#define ZX_SYSCALL_PARAM_ATTR(x)   __attribute__((annotate("zx_" #x)))
89#else
90#define ZX_SYSCALL_PARAM_ATTR(x)   // no-op
91#endif
92```
93
94According to the definition of `ZX_SYSCALL_PARAM_ATTR`, the `zx_channel_create` will be parsed into:
95
96```c
97extern zx_status_t zx_channel_create(uint32_t options,
98__attribute__((annotate("zx_handle_acquire"))) zx_handle_t* out0,
99__attribute__((annotate("zx_handle_acquire"))) zx_handle_t* out1) __attribute__((__leaf__));;
100```
101
102The reason that we use macros to wrap these annotations is that annotate attribute is not supported by compilers other than Clang, e.g. GCC. Furthermore, it would be convenient if we decide to use annotation solutions other than the annotate attributes in the future. Otherwise we need to change each annotation one by one.
103
104### Annotations in other functions
105
106For functions other than syscalls, if `system/public/zircon/syscalls.h` is in current include path, you can use `ZX_SYSCALL_PARAM_ATTR` macro to wrap your annotations. If not, you should use macros similar to this one. The reason that functions other than syscalls may require annotations is that some functions contain known false positives and we can use annotation to suppress the warnings of these false positives. For example, in ZirconHandleChecker’s test file we have:
107
108```c
109#if defined(__clang__)
110#define ZX_ANALYZER_SUPPRESS   __attribute__((annotate("zx_suppress_warning)))
111#else
112#define ZX_ANALYZER_SUPPRESS   // no-op
113#endif
114void checkSuppressWarning() ZX_ANALYZER_SUPPRESS {
115  zx_handle_t sa, sb;
116  if (zx_channel_create(0, &sa, &sb) < 0) {
117    return;
118  }
119  zx_handle_close(sa); // Should not report any bugs here
120}
121```
122
123The analyzer will suppress the warnings on the bug it discovered in `checkSuppressWarning` function. If you don’t want to define your own macro for this purpose, and the `syscalls.h` is in the include path, you can use `_SYSCALL_PARAM_ATTR(suppress_warning)` instead, it will suppress the warnings of all bugs discovered in the functions with this annotation.
124
125Similar to `zx_suppress_warning` annotation, we have `zx_create_sink` annotation which currently used to suppress warnings on assertion failures. This annotation is unlikely to be used for other purpose, however, if you would like to know how it works, please refer to the discussions in CL[46428](https://fuchsia-review.googlesource.com/c/46428).
126
127To manually annotate non-syscall functions, the "ZX_SYSCALL_PARAM_ATTR" macro can be applied to function arguments, emulating the effect of the abigen attributes. For example, here, we annotate a regular function which might be used to call the "zx_create_channel" function without passing the "options" argument:
128
129```c
130zx_status_t create_channel(
131  ZX_SYSCALL_PARAM_ATTR(handle_acquire) zx_handle_t* out0,
132  ZX_SYSCALL_PARAM_ATTR(handle_acquire) zx_handle_t* out1);
133```
134Another example, we have another function `takeover_handle` that will take care the lifecycle of a handle if it is successfully executed and do nothing if it failed, we can declare this function in header file like this:
135
136```c
137zx_status_t takeover_handle(
138  ZX_SYSCALL_PARAM_ATTR(handle_escape) zx_handle_t in)
139  ZX_SYSCALL_PARAM_ATTR(may_fail);
140```
141
142The `zx_may_fail` annotation here will cause state bifurcation when ZirconHandleChecker is evaluating calls to this function. So both succeeded and failed states will be covered.
143
144If the `ZX_SYSCALL_PARAM_ATTR` is not available in the file that declares the function, you can define your own macros, as long as it will not expanded into annotate attribute if it is not compiled by Clang.
145