All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Smalley <sds@tycho.nsa.gov>
To: Nicolas Iooss <nicolas.iooss@m4x.org>, selinux@vger.kernel.org
Subject: Re: [PATCH] libsepol, libsemanage: add a macro to silence static analyzer warnings in tests
Date: Tue, 24 Sep 2019 13:10:56 -0400	[thread overview]
Message-ID: <9f87e1b0-8bfd-601f-31ba-4fffbcd64a78@tycho.nsa.gov> (raw)
In-Reply-To: <20190921213046.1121337-1-nicolas.iooss@m4x.org>

On 9/21/19 5:30 PM, Nicolas Iooss wrote:
> Several static analyzers (clang's one, Facebook Infer, etc.) warn about
> NULL pointer dereferences after a call to CU_ASSERT_PTR_NOT_NULL_FATAL()
> in the test code written using CUnit framework. This is because this
> CUnit macro is too complex for them to understand that the pointer
> cannot be NULL: it is translated to a call to CU_assertImplementation()
> with an argument as TRUE in order to mean that the call is fatal if the
> asserted condition failed (cf.
> http://cunit.sourceforge.net/doxdocs/group__Framework.html).
> 
> A possible solution could consist in replacing the
> CU_ASSERT_..._FATAL() calls by assert() ones, as most static analyzers
> know about assert(). Nevertheless this seems to go against CUnit's API.
> 
> An alternative solution consists in overriding CU_ASSERT_..._FATAL()
> macros in order to expand to assert() after a call to the matching
> CU_ASSERT_...() non-fatal macro. This appears to work fine and to remove
> many false-positive warnings from various static analyzers.
> 
> As this substitution should only occur when using static analyzer, put
> it under #ifdef __CHECKER__, which is the macro used by sparse when
> analyzing the Linux kernel.
> 
> Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
> ---
>   libsemanage/tests/test_utilities.c      |  2 ++
>   libsemanage/tests/utilities.h           | 24 ++++++++++++++++++++++
>   libsepol/tests/helpers.h                | 27 +++++++++++++++++++++++++
>   libsepol/tests/test-common.c            |  2 ++
>   libsepol/tests/test-deps.c              |  2 ++
>   libsepol/tests/test-expander-attr-map.c |  1 +
>   libsepol/tests/test-expander-roles.c    |  1 +
>   libsepol/tests/test-expander-users.c    |  1 +
>   scripts/run-scan-build                  |  6 +++++-
>   9 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/libsemanage/tests/test_utilities.c b/libsemanage/tests/test_utilities.c
> index 601508c2c386..ba995b5ae094 100644
> --- a/libsemanage/tests/test_utilities.c
> +++ b/libsemanage/tests/test_utilities.c
> @@ -34,6 +34,8 @@
>   #include <string.h>
>   #include <unistd.h>
>   
> +#include "utilities.h"
> +
>   void test_semanage_is_prefix(void);
>   void test_semanage_split_on_space(void);
>   void test_semanage_split(void);
> diff --git a/libsemanage/tests/utilities.h b/libsemanage/tests/utilities.h
> index c9d54d1e1b76..1d15a98d9db1 100644
> --- a/libsemanage/tests/utilities.h
> +++ b/libsemanage/tests/utilities.h
> @@ -41,6 +41,30 @@
>   		CU_ASSERT_STRING_EQUAL(__str, __str2); \
>   	} while (0)
>   
> +
> +/* Override CU_*_FATAL() in order to help static analyzers by really asserting that an assertion holds */
> +#ifdef __CHECKER__
> +
> +#undef CU_ASSERT_FATAL
> +#define CU_ASSERT_FATAL(value) do { \
> +		CU_ASSERT(value); \
> +		assert(value); \
> +	} while (0)

You only want to evaluate value once and save the result for use in both 
CU_ASSERT() and assert() or it could change, e.g.
         CU_ASSERT_FATAL(semanage_ibendport_del_local(sh, key) >= 0);

> +
> +#undef CU_FAIL_FATAL
> +#define CU_FAIL_FATAL(msg) do { \
> +		CU_FAIL(msg); \
> +		assert(0); \
> +	} while (0)
> +
> +#undef CU_ASSERT_PTR_NOT_NULL_FATAL
> +#define CU_ASSERT_PTR_NOT_NULL_FATAL(value) do { \
> +		CU_ASSERT_PTR_NOT_NULL(value); \
> +		assert((value) != NULL); \
> +	} while (0)

Ditto.

> +
> +#endif /* __CHECKER__ */
> +
>   #define I_NULL  -1
>   #define I_FIRST  0
>   #define I_SECOND 1
> diff --git a/libsepol/tests/helpers.h b/libsepol/tests/helpers.h
> index 10d390946499..34b8f21e10e0 100644
> --- a/libsepol/tests/helpers.h
> +++ b/libsepol/tests/helpers.h
> @@ -24,9 +24,36 @@
>   
>   #include <sepol/policydb/policydb.h>
>   #include <sepol/policydb/conditional.h>
> +#include <CUnit/Basic.h>
>   
>   /* helper functions */
>   
> +/* Override CU_*_FATAL() in order to help static analyzers by really asserting that an assertion holds */
> +#ifdef __CHECKER__
> +
> +#include <assert.h>
> +
> +#undef CU_ASSERT_FATAL
> +#define CU_ASSERT_FATAL(value) do { \
> +		CU_ASSERT(value); \
> +		assert(value); \
> +	} while (0)
> +
> +#undef CU_FAIL_FATAL
> +#define CU_FAIL_FATAL(msg) do { \
> +		CU_FAIL(msg); \
> +		assert(0); \
> +	} while (0)
> +
> +#undef CU_ASSERT_PTR_NOT_NULL_FATAL
> +#define CU_ASSERT_PTR_NOT_NULL_FATAL(value) do { \
> +		CU_ASSERT_PTR_NOT_NULL(value); \
> +		assert((value) != NULL); \
> +	} while (0)
> +
> +#endif /* __CHECKER__ */
> +
> +
>   /* Load a source policy into p. policydb_init will called within this function.
>    *
>    * Example: test_load_policy(p, POLICY_BASE, 1, "foo", "base.conf") will load the
> diff --git a/libsepol/tests/test-common.c b/libsepol/tests/test-common.c
> index 1d902880fe2e..f690635eee27 100644
> --- a/libsepol/tests/test-common.c
> +++ b/libsepol/tests/test-common.c
> @@ -26,6 +26,8 @@
>   
>   #include <CUnit/Basic.h>
>   
> +#include "helpers.h"
> +
>   void test_sym_presence(policydb_t * p, const char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len)
>   {
>   	scope_datum_t *scope;
> diff --git a/libsepol/tests/test-deps.c b/libsepol/tests/test-deps.c
> index 6bbba810564a..f4ab09ba0dbf 100644
> --- a/libsepol/tests/test-deps.c
> +++ b/libsepol/tests/test-deps.c
> @@ -66,6 +66,8 @@
>   #include <sepol/debug.h>
>   #include <sepol/handle.h>
>   
> +#include "helpers.h"
> +
>   #define BASE_MODREQ_TYPE_GLOBAL    0
>   #define BASE_MODREQ_ATTR_GLOBAL    1
>   #define BASE_MODREQ_OBJ_GLOBAL     2
> diff --git a/libsepol/tests/test-expander-attr-map.c b/libsepol/tests/test-expander-attr-map.c
> index d10636ca09a8..a9744541fe00 100644
> --- a/libsepol/tests/test-expander-attr-map.c
> +++ b/libsepol/tests/test-expander-attr-map.c
> @@ -21,6 +21,7 @@
>   
>   #include "test-expander-attr-map.h"
>   #include "test-common.h"
> +#include "helpers.h"
>   
>   #include <sepol/policydb/policydb.h>
>   #include <CUnit/Basic.h>
> diff --git a/libsepol/tests/test-expander-roles.c b/libsepol/tests/test-expander-roles.c
> index aba3c9bd19c4..74c781b85e68 100644
> --- a/libsepol/tests/test-expander-roles.c
> +++ b/libsepol/tests/test-expander-roles.c
> @@ -22,6 +22,7 @@
>   
>   #include "test-expander-roles.h"
>   #include "test-common.h"
> +#include "helpers.h"
>   
>   #include <sepol/policydb/policydb.h>
>   #include <CUnit/Basic.h>
> diff --git a/libsepol/tests/test-expander-users.c b/libsepol/tests/test-expander-users.c
> index 9d9c7a62f215..ab2265c110d5 100644
> --- a/libsepol/tests/test-expander-users.c
> +++ b/libsepol/tests/test-expander-users.c
> @@ -21,6 +21,7 @@
>    */
>   
>   #include "test-expander-users.h"
> +#include "helpers.h"
>   
>   #include <sepol/policydb/policydb.h>
>   #include <CUnit/Basic.h>
> diff --git a/scripts/run-scan-build b/scripts/run-scan-build
> index 88fe551ce698..ae5aa48b4a05 100755
> --- a/scripts/run-scan-build
> +++ b/scripts/run-scan-build
> @@ -22,7 +22,11 @@ export RUBYLIB="$DESTDIR/$(${RUBY:-ruby} -e 'puts RbConfig::CONFIG["vendorlibdir
>   
>   # Build and analyze
>   make -C .. CC=clang clean distclean -j"$(nproc)"
> -scan-build -analyze-headers -o "$OUTPUTDIR" make -C .. CC=clang DESTDIR="$DESTDIR" install install-pywrap install-rubywrap all test
> +scan-build -analyze-headers -o "$OUTPUTDIR" make -C .. \
> +    CC=clang \
> +    DESTDIR="$DESTDIR" \
> +    CFLAGS="-O2 -Wall -D__CHECKER__ -I$DESTDIR/usr/include" \
> +    install install-pywrap install-rubywrap all test
>   
>   # Reduce the verbosity in order to keep the message from scan-build saying
>   # "scan-build: Run 'scan-view /.../output-scan-build/2018-...' to examine bug reports.
> 


      reply	other threads:[~2019-09-24 17:15 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-21 21:30 [PATCH] libsepol, libsemanage: add a macro to silence static analyzer warnings in tests Nicolas Iooss
2019-09-24 17:10 ` Stephen Smalley [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9f87e1b0-8bfd-601f-31ba-4fffbcd64a78@tycho.nsa.gov \
    --to=sds@tycho.nsa.gov \
    --cc=nicolas.iooss@m4x.org \
    --cc=selinux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.