]> granicus.if.org Git - check/commitdiff
change how assertions are called, to support source code analyzers
authorbrarcher <brarcher@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Mon, 16 Dec 2013 23:27:14 +0000 (23:27 +0000)
committerbrarcher <brarcher@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Mon, 16 Dec 2013 23:27:14 +0000 (23:27 +0000)
The assert functions that check provides are really macros that
funnel down to the _ck_assert_msg() function. That function receives
the result from the operation being checked, then decides if the unit
test should continue or should halt.

The assert function in C is sometimes also a macro. For example, the
following:

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

on OSX when preprocessed actually becomes:

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

The __assert_rtn function is marked as "noreturn", and only gets invoked
when an assertion has failed. Because it only gets called when something
bad has happened, static code analysis can reason about when it is and is
not called, and make assumptions about the code being compiled.

To the point, this change refactors check's assert macros in such a way
that they result in a function being called only when the assertion
fails, and thus static code analyzers (such as clang's scan-build tool)
can reason when something is possible and impossible in test code. As a
result, if one wanted to run static analysis on unit test code, there
would be far fewer false positives.

git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@870 64e312b2-a51f-0410-8e61-82d0ca0eb02a

src/check.c
src/check.h.in

index d7806d705fafdfa5dabe0c3bf3170295cc2077c3..94d9dbf2e475eb1d50870f104768075a79d24de6 100644 (file)
@@ -253,30 +253,28 @@ void _mark_point (const char *file, int line)
   send_loc_info (file, line);
 }
 
-void _ck_assert_msg (int result, const char *file,
+void _ck_assert_failed (const char *file,
                    int line, const char *expr, ...)
 {
   const char *msg;
-    
+  va_list ap;
+  char buf[BUFSIZ];
+
   send_loc_info (file, line);
-  if (!result) {
-    va_list ap;
-    char buf[BUFSIZ];
-    
-    va_start(ap,expr);
-    msg = (const char*)va_arg(ap, char *);
-    if (msg == NULL)
-      msg = expr;
-    vsnprintf(buf, BUFSIZ, msg, ap);
-    va_end(ap);
-    send_failure_info (buf);
-    if (cur_fork_status() == CK_FORK) {
-#ifdef HAVE_FORK
-      exit(1);
-#endif /* HAVE_FORK */
-    } else {
-      longjmp(error_jmp_buffer, 1);
-    }
+
+  va_start(ap,expr);
+  msg = (const char*)va_arg(ap, char *);
+  if (msg == NULL)
+    msg = expr;
+  vsnprintf(buf, BUFSIZ, msg, ap);
+  va_end(ap);
+  send_failure_info (buf);
+  if (cur_fork_status() == CK_FORK) {
+  #ifdef HAVE_FORK
+    exit(1);
+  #endif /* HAVE_FORK */
+  } else {
+    longjmp(error_jmp_buffer, 1);
   }
 }
 
index 3d886ae12d3b5d9d0552a8adb8a4f9178e281b12..d14056e40a867524092fe31536ce4d770bb130f3 100644 (file)
@@ -259,14 +259,14 @@ static void __testname (int _i CK_ATTRIBUTE_UNUSED)\
    FIXME:   strcmp (str1, str2) due to excessive string length.
 */
 #define fail_if(expr, ...)\
-  _ck_assert_msg(!(expr), __FILE__, __LINE__,\
-    "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL)
+  (expr) ? \
+     _ck_assert_failed(__FILE__, __LINE__, "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL) \
+     : _mark_point(__FILE__, __LINE__)
 
 #define fail ck_abort_msg
 
-/* Non macro version of #ck_assert_msg, with more complicated interface */
-void CK_EXPORT _ck_assert_msg (int result, const char *file,
-                             int line, const char *expr, ...);
+/* This is called whenever an assertion fails */
+void CK_EXPORT _ck_assert_failed (const char *file, int line, const char *expr, ...) CK_ATTRIBUTE_NORETURN;
 
 /* New check fail API. */
 
@@ -276,12 +276,13 @@ void CK_EXPORT _ck_assert_msg (int result, const char *file,
 */
 #define ck_assert(C) ck_assert_msg(C, NULL)
 #define ck_assert_msg(expr, ...) \
-  _ck_assert_msg(expr, __FILE__, __LINE__,\
-    "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
+  (expr) ? \
+     _mark_point(__FILE__, __LINE__) : \
+     _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
 
 /* Always fail */
 #define ck_abort() ck_abort_msg(NULL)
-#define ck_abort_msg(...) _ck_assert_msg(0, __FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+#define ck_abort_msg(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
 
 /* Signed and unsigned integer comparsion macros with improved output compared to ck_assert(). */
 /* OP may be any comparion operator. */