[LTP] [PATCH 1/7] Add Sparse based checker and TST_RET/ERR check
Richard Palethorpe
rpalethorpe@suse.de
Fri Jul 9 09:47:39 CEST 2021
Hello Cyril,
Cyril Hrubis <chrubis@suse.cz> writes:
> Hi!
>> Vendors in Sparse as a git module. Then uses it to check for stores to
>> TST_RET/ERR within the library.
>
> This sounds reasonable enough.
>
> It would probably be even easier to copy the sources to the LTP tree and
> synchronize them manually, depending on how often is sparse updated it
> may end up better than a submodule.
It is not updated often. Indeed Smatch did this, but I don't think that
has helped adoption of either Smatch or Sparse.
>
> Also isn't the submodule frozen on a given commit anyways (unless we add
> git submodule --remote --merge into the build steps)?
>
Yes. Submodules can be a pain, however I see a few advantages:
* You can easily upstream any changes made to the sub project. (no copy
and paste)
* You get the full Git history without a seperate clone of upstream
* If someone already has upstream cloned they can just point the
submodule towards it (not that it really matters with Sparse)
It is easy to get in a mess with submodules, but that is mainly just a
concern for whoever is updating Sparse.
>> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
>> ---
>> .gitmodules | 3 +
>> tools/sparse/.gitignore | 1 +
>> tools/sparse/Makefile | 20 ++++++
>> tools/sparse/README.md | 34 +++++++++
>> tools/sparse/main.c | 148 ++++++++++++++++++++++++++++++++++++++++
>> tools/sparse/sparse-src | 1 +
>> 6 files changed, 207 insertions(+)
>> create mode 100644 tools/sparse/.gitignore
>> create mode 100644 tools/sparse/Makefile
>> create mode 100644 tools/sparse/README.md
>> create mode 100644 tools/sparse/main.c
>> create mode 160000 tools/sparse/sparse-src
>>
>> diff --git a/.gitmodules b/.gitmodules
>> index 1c9e9c38a..a3c34af4b 100644
>> --- a/.gitmodules
>> +++ b/.gitmodules
>> @@ -1,3 +1,6 @@
>> [submodule "testcases/kernel/mce-test"]
>> path = testcases/kernel/mce-test
>> url = git://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/mce-test.git
>> +[submodule "tools/sparse/sparse-src"]
>> + path = tools/sparse/sparse-src
>> + url = git://git.kernel.org/pub/scm/devel/sparse/sparse.git
>> diff --git a/tools/sparse/.gitignore b/tools/sparse/.gitignore
>> new file mode 100644
>> index 000000000..ba2906d06
>> --- /dev/null
>> +++ b/tools/sparse/.gitignore
>> @@ -0,0 +1 @@
>> +main
>> diff --git a/tools/sparse/Makefile b/tools/sparse/Makefile
>> new file mode 100644
>> index 000000000..cf4ccdb60
>> --- /dev/null
>> +++ b/tools/sparse/Makefile
>> @@ -0,0 +1,20 @@
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +# Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com>
>> +
>> +top_srcdir ?= ../..
>> +
>> +include $(top_srcdir)/include/mk/env_pre.mk
>> +include $(top_srcdir)/include/mk/functions.mk
>> +
>> +SPARSE_SRC ?= sparse-src
>> +
>> +$(SPARSE_SRC)/libsparse.a:
>> + $(error "You need to build Sparse. See tools/sparse/README.md")
>> +
>> +HOST_MAKE_TARGETS := main
>> +MAKE_DEPS += $(SPARSE_SRC)/libsparse.a
>> +HOST_CFLAGS += -I$(SPARSE_SRC)
>> +HOST_LDLIBS += $(SPARSE_SRC)/libsparse.a
>> +
>> +
>> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
>> diff --git a/tools/sparse/README.md b/tools/sparse/README.md
>> new file mode 100644
>> index 000000000..368cd7d99
>> --- /dev/null
>> +++ b/tools/sparse/README.md
>> @@ -0,0 +1,34 @@
>> +# Sparse based linting
>> +
>> +This tool checks LTP test and library code for common problems.
>> +
>> +## Building
>> +
>> +The bad news is you must get and build Sparse[^1]. The good news this only
>> +takes a minute.
>> +
>> +If you already have the Sparse source code, then do the
>> +following. Where `$SRC_PATH` is the path to the Sparse directory.
>> +
>> +```sh
>> +$ cd tools/sparse
>> +$ make -C $SRC_PATH -j$(nproc) # Optional
>> +$ make SPARSE_SRC=$SRC_PATH
>> +```
>> +If not then you can fetch it via the git submodule
>> +
>> +```sh
>> +$ cd tools/sparse
>> +$ git submodule update --init
>> +$ cd sparse-src
>> +$ make -C sparse-src -j$(nproc)
>> +$ make
>> +```
>
> Can we add a build.sh script into the tools/sparse/ directory that will
> do exactly these steps?
+1
>
>> +## Usage
>> +
>> +It is integrated with the LTP build system. Just run `make check` or
>> +`make check-a_test01`, where `a_test01` is an arbitrary test
>> +executable or object file.
>> +
>> +[1]: Many distributions have a Sparse package. This only contains some executables. There is no shared library
>> diff --git a/tools/sparse/main.c b/tools/sparse/main.c
>> new file mode 100644
>> index 000000000..58f9a549c
>> --- /dev/null
>> +++ b/tools/sparse/main.c
>> @@ -0,0 +1,148 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (C) 2021 SUSE LLC <rpalethorpe@suse.com>
>> + *
>> + * Sparse allows us to perform checks on the AST (struct symbol) or on
>> + * a linearized representation. In the latter case we are given a set
>> + * of entry points (functions) containing basic blocks of
>> + * instructions.
>> + *
>> + * The basic blocks contain byte code in SSA form. This is similar to
>> + * the the intermediate representation most compilers use during
>> + * optimisation.
>> + */
>> +#include <stdarg.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <ctype.h>
>> +#include <unistd.h>
>> +#include <fcntl.h>
>> +
>> +#include "lib.h"
>> +#include "allocate.h"
>> +#include "opcode.h"
>> +#include "token.h"
>> +#include "parse.h"
>> +#include "symbol.h"
>> +#include "expression.h"
>> +#include "linearize.h"
>> +
>> +/* The rules for test, library and tool code are different */
>> +enum ltp_tu_kind {
>> + LTP_LIB,
>> + LTP_OTHER,
>> +};
>> +
>> +static enum ltp_tu_kind tu_kind = LTP_OTHER;
>> +
>> +/* Check for LTP-002
>> + *
>> + * Inspects the destination symbol of each store instruction. If it is
>> + * TST_RET or TST_ERR then emit a warning.
>> + */
>> +static void check_lib_sets_TEST_vars(const struct instruction *insn)
>> +{
>> + static struct ident *TST_RES_id, *TST_ERR_id;
>> +
>> + if (!TST_RES_id) {
>> + TST_RES_id = built_in_ident("TST_RET");
>> + TST_ERR_id = built_in_ident("TST_ERR");
>> + }
>> +
>> + if (insn->opcode != OP_STORE)
>> + return;
>> + if (insn->src->ident != TST_RES_id &&
>> + insn->src->ident != TST_ERR_id)
>> + return;
>> +
>> + warning(insn->pos,
>> + "LTP-002: Library should not write to TST_RET or TST_ERR");
>> +}
>> +
>> +static void do_basicblock_checks(struct basic_block *bb)
>> +{
>> + struct instruction *insn;
>> +
>> + FOR_EACH_PTR(bb->insns, insn) {
>> + if (!bb_reachable(insn->bb))
>> + continue;
>> +
>> + if (tu_kind == LTP_LIB)
>> + check_lib_sets_TEST_vars(insn);
>> + } END_FOR_EACH_PTR(insn);
>> +}
>> +
>> +static void do_entrypoint_checks(struct entrypoint *ep)
>> +{
>> + struct basic_block *bb;
>> +
>> + FOR_EACH_PTR(ep->bbs, bb) {
>> + do_basicblock_checks(bb);
>> + } END_FOR_EACH_PTR(bb);
>> +}
>> +
>> +/* Compile the AST into a graph of basicblocks */
>> +static void process_symbols(struct symbol_list *list)
>> +{
>> + struct symbol *sym;
>> +
>> + FOR_EACH_PTR(list, sym) {
>> + struct entrypoint *ep;
>> +
>> + expand_symbol(sym);
>> + ep = linearize_symbol(sym);
>> + if (!ep || !ep->entry)
>> + continue;
>> +
>> + do_entrypoint_checks(ep);
>> +
>> + if (dbg_entry)
>> + show_entry(ep);
>> + } END_FOR_EACH_PTR(sym);
>> +}
>> +
>> +static void collect_info_from_args(const int argc, char *const *const argv)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < argc; i++) {
>> + if (!strcmp("-DLTPLIB", argv[i])) {
>> + tu_kind = LTP_LIB;
>> + }
>> + }
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> + struct string_list *filelist = NULL;
>> + char *file;
>> +
>> + Waddress_space = 0;
>> + Wbitwise = 0;
>> + Wcast_truncate = 0;
>> + Wcontext = 0;
>> + Wdecl = 0;
>> + Wexternal_function_has_definition = 0;
>> + Wflexible_array_array = 0;
>> + Wimplicit_int = 0;
>> + Wint_to_pointer_cast = 0;
>> + Wmemcpy_max_count = 0;
>> + Wnon_pointer_null = 0;
>> + Wone_bit_signed_bitfield = 0;
>> + Woverride_init = 0;
>> + Wpointer_to_int_cast = 0;
>> + Wvla = 0;
>> +
>> + do_output = 0;
>> +
>> + collect_info_from_args(argc, argv);
>> +
>> + process_symbols(sparse_initialize(argc, argv, &filelist));
>> + FOR_EACH_PTR(filelist, file) {
>> + process_symbols(sparse(file));
>> + } END_FOR_EACH_PTR(file);
>> +
>> + report_stats();
>> + return 0;
>> +}
>> diff --git a/tools/sparse/sparse-src b/tools/sparse/sparse-src
>> new file mode 160000
>> index 000000000..8af243292
>> --- /dev/null
>> +++ b/tools/sparse/sparse-src
>> @@ -0,0 +1 @@
>> +Subproject commit 8af2432923486c753ab52cae70b94ee684121080
>> --
>> 2.31.1
>>
>>
>> --
>> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Thank you,
Richard.
More information about the ltp
mailing list