blob: 16d11acee418c75b877c2a5b0521651b3c9b2b97 [file]
#!/bin/bash
# require sparse to build to prevent bugs
which sparse > /dev/null 2>&1
if [ "$?" != 0 ]; then
echo "Must install sparse to build"
exit 1
fi
#
# one of the problems with using sparse in userspace is that it picks up
# things in system headers that we don't care about. We're willing to
# take on the burden of filtering them out so that we can have it tell
# us about problems in our code.
#
# system headers using __transparent_union__
RE="^/.*error: ignoring attribute __transparent_union__"
# we don't care if system headers have gcc attributes sparse doesn't
# know about
RE="$RE|error: attribute '__leaf__': unknown attribute"
# yes, sparse, that's the size of memseting a 4 meg buffer all right
RE="$RE|warning: memset with byte count of 4194304"
# some sparse versions don't know about some builtins
RE="$RE|error: undefined identifier '__builtin_fpclassify'"
# I didn't really dig in, but io_uring and glibc are fighting
RE="$RE|note: .*through.*uring"
RE="$RE|RWF.* redefined"
RE="$RE|uio-ext.h.*original definition"
#
# don't filter out 'too many errors' here, it can signify that
# sparse doesn't understand something and is throwing a *ton*
# of useless errors before giving up and existing. Check
# unfiltered sparse output.
#
#
# I'm not sure this is needed.
#
search=$(gcc -print-search-dirs | awk '($1 == "install:"){print "-I" $2}')
#
# We're trying to use sparse against glibc headers which go wild trying to
# use internal compiler macros to test features. We copy gcc's and give
# them to sparse. But not __SIZE_TYPE__ 'cause sparse defines that one.
#
defines=".sparse.gcc-defines.h"
gcc -dM -E -x c - < /dev/null | grep -v __SIZE_TYPE__ > $defines
include="-include $defines"
#
# I have no idea why, but sometime sparse gets angry at the
# __PRETTY_FUNCTION__ generated by glibc's bonkers assert() macro. It
# isn't consistent, hitting (for example) 2 of 11 identical call sites
# in a file. As in, extract the statements, normalize the line numbers,
# and the text is identical. It only hits the function family
# (__PRETTY_FUNCTION__, __FUNCTION__, __func__). Built-in string
# identifiers like __FILE__ or __DATE__ are fine.
#
# We don't need meaningful strings here, so just use one that works.
#
echo "#define __PRETTY_FUNCTION__ __FILE__ " >> $defines
#
# As gcc's default standard support has increased, sparse can be left
# behind. As of this writing, there are a handful of headers that we
# use that used to provide defines for functionality that is now
# natively supported by gcc. In each of these cases you can look at the
# gcc header and find "__STDC_VERSION__ <=> 201710L" tests. This tests
# the version of the standard that gcc is building against and restores
# the defines for sparse in the cases where the headers were emitting
# code for gcc that sparse doesn't understand.
#
. <(awk '
($2 == "__STDC_VERSION__") {
print $2 "=" substr($3, 1, length($3) - 1)
}' < .sparse.gcc-defines.h )
if [ $__STDC_VERSION__ -gt 201710 ]; then
cat >> $defines <<EOF
// stdbool.h
#define bool _Bool
#define true 1
#define false 0
// assert.h
#define static_assert _Static_assert
// stdarg.h
#define __builtin_c23_va_start __builtin_va_start
EOF
fi
#
# sparse doesn't seem to notice when it's on a 64bit host. It warns that
# 64bit values don't fit in 'unsigned long' without this.
#
if grep -q "__LP64__ 1" $defines; then
m64="-m64"
else
m64=""
fi
sparse $m64 $include $search/include "$@" 2>&1 | grep -E -v "($RE)" | tee .sparse.output
if [ -s .sparse.output ]; then
exit 1
else
exit 0
fi