Q: Custom Assertion Handlers

Hi All,

According to http://clang-analyzer.llvm.org/annotations.html#custom_assertions:

<QUOTE>
void foo(int *p) {
  assert(p != NULL);
}

When this code is preprocessed on Mac OS X it expands to the following:

void foo(int *p) {
  (__builtin_expect(!(p != NULL), 0) ? __assert_rtn(__func__, "t.c",
4, "p != NULL") : (void)0);
}

In this example, the assertion handler is __assert_rtn. When called,
most assertion handlers typically print an error and terminate the
program. The analyzer can exploit such semantics by ending the
analysis of a path once it hits a call to an assertion handler....

The analyzer knows about several well-known assertion handlers, but
can automatically infer if a function should be treated as an
assertion handler if it is annotated with the 'noreturn' attribute or
the (Clang-specific) 'analyzer_noreturn' attribute. Note that,
currently, clang does not support these attributes on Objective-C
methods and C++ methods.
</QUOTE>

I work with source files compiled under a number of compilers,
including GCC, ICC/ICPC, MSVC, and Clang. Some of the compilers don't
support GCC notations.

(1) Is there a way to pass the assertion handler to Clang on the
command line? (I typically use `ASSERT` rather than `assert`).

(2) Is there a way to indicate the failed assertion does *not*
terminate? (Calling abort() is useless behavior during development
(i.e., Debug builds), so my ASSERT raises a SIGTRAP on *nix. Plus,
Release builds don't include 'diagnostics' such as assert, so they are
not present in release builds).

Jeff

Hi, Jeffrey. You’re not going to be able to pass the assertion handler on the command line, but there are several well-established techniques for adding compiler-specific source annotations. The usual one looks something like this (from LLVM itself):

#ifdef GNUC

#define LLVM_ATTRIBUTE_NORETURN attribute((noreturn))

#elif defined(_MSC_VER)

#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)

#else

#define LLVM_ATTRIBUTE_NORETURN

#endif

The analyzer actually has its own specific guard macro, clang_analyzer, so you could do something like this:

#ifdef clang_analyzer
#define ANALYZER_NORETURN attribute((analyzer_noreturn))
#else
#define ANALYZER_NORETURN
#endif

As for termination, neither ‘noreturn’ nor ‘analyzer_noreturn’ actually relies on the program immediately terminating. The former just promises that the function, well, won’t return, and SIGTRAP to get into a debugger (and then terminating from the debugger later) is a perfectly reasonable way to accomplish that.

Still, if you aren’t sure ‘noreturn’ fully describes your situation, just use ‘analyzer_noreturn’. This tells the analyzer to stop analyzing this particular path (as if the program had terminated), but does not affect compilation in any way.

Hope that helps,
Jordan