2323#endif
2424
2525#include <inttypes.h> /* intmax_t, uintmax_t, PRI* */
26- #include <stddef.h> /* size_t */
26+ #include <stddef.h> /* size_t, offsetof */
2727
2828typedef void (* ctest_setup_func )(void * );
2929typedef void (* ctest_teardown_func )(void * );
3030
3131#define CTEST_IMPL_PRAGMA (x ) _Pragma (#x)
3232
33- #if defined(__GNUC__ )
34- #if defined(__clang__ ) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 )
33+ #define CTEST_IMPL_COMPILER_MINIMUM_VERSION (exp_major , exp_minor , \
34+ real_major , real_minor ) \
35+ (((real_major) > (exp_major)) \
36+ || ((real_major) == (exp_major) && (real_minor) >= (exp_minor)))
37+
38+ #if defined(__GNUC__ ) && !defined(__clang__ )
39+ # define CTEST_IMPL_GCC_MINIMUM_VERSION (major , minor ) \
40+ CTEST_IMPL_COMPILER_MINIMUM_VERSION(major, minor, \
41+ __GNUC__, __GNUC_MINOR__)
42+ #else
43+ # define CTEST_IMPL_GCC_MINIMUM_VERSION (major , minor ) 0
44+ #endif
45+
46+ #ifdef __clang__
47+ # define CTEST_IMPL_CLANG_MINIMUM_VERSION (major , minor ) \
48+ CTEST_IMPL_COMPILER_MINIMUM_VERSION(major, minor, \
49+ __clang_major__, __clang_minor__)
50+ #else
51+ # define CTEST_IMPL_CLANG_MINIMUM_VERSION (major , minor ) 0
52+ #endif
53+
54+ #if CTEST_IMPL_GCC_MINIMUM_VERSION (4 , 6 ) || defined(__clang__ )
3555/* the GCC argument will work for both gcc and clang */
3656#define CTEST_IMPL_DIAG_PUSH_IGNORED (w ) \
3757 CTEST_IMPL_PRAGMA(GCC diagnostic push) \
3858 CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w)
3959#define CTEST_IMPL_DIAG_POP () \
4060 CTEST_IMPL_PRAGMA(GCC diagnostic pop)
41- #else
61+ #elif defined( __GNUC__ )
4262/* the push/pop functionality wasn't in gcc until 4.6, fallback to "ignored" */
4363#define CTEST_IMPL_DIAG_PUSH_IGNORED (w ) \
4464 CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w)
4565#define CTEST_IMPL_DIAG_POP ()
46- #endif
4766#else
4867/* leave them out entirely for non-GNUC compilers */
4968#define CTEST_IMPL_DIAG_PUSH_IGNORED (w )
5069#define CTEST_IMPL_DIAG_POP ()
5170#endif
5271
72+ #if CTEST_IMPL_GCC_MINIMUM_VERSION (4 , 8 )
73+ # define CTEST_IMPL_NO_ASAN_FUNCTION __attribute__ ((no_sanitize_address))
74+ # define CTEST_IMPL_NO_ASAN_VARIABLE
75+ #elif CTEST_IMPL_CLANG_MINIMUM_VERSION (4 , 0 )
76+ # define CTEST_IMPL_NO_ASAN_FUNCTION __attribute__ ((no_sanitize_address))
77+ # define CTEST_IMPL_NO_ASAN_VARIABLE __attribute__ ((no_sanitize_address))
78+ #elif CTEST_IMPL_CLANG_MINIMUM_VERSION (3 , 1 ) && __has_feature (address_sanitizer )
79+ # warning "Clang 3.x AddressSanitizer may interfere with ctest, proceed with caution!"
80+ # define CTEST_IMPL_NO_ASAN_FUNCTION __attribute__ ((no_sanitize_address))
81+ # define CTEST_IMPL_NO_ASAN_VARIABLE
82+ # define CTEST_IMPL_CLANG_POISIONED_GLOBALS
83+ #else
84+ # define CTEST_IMPL_NO_ASAN_FUNCTION
85+ # define CTEST_IMPL_NO_ASAN_VARIABLE
86+ #endif
87+
5388CTEST_IMPL_DIAG_PUSH_IGNORED (strict - prototypes )
5489
5590struct ctest {
91+ unsigned int magic1 ; // must be first!
92+
5693 const char * ssname ; // suite name
5794 const char * ttname ; // test name
5895 void (* run )();
@@ -63,7 +100,7 @@ struct ctest {
63100
64101 int skip ;
65102
66- unsigned int magic ;
103+ unsigned int magic2 ; // must be last!
67104};
68105
69106CTEST_IMPL_DIAG_POP ()
@@ -86,15 +123,19 @@ CTEST_IMPL_DIAG_POP()
86123#endif
87124
88125#define CTEST_IMPL_STRUCT (sname , tname , tskip , tdata , tsetup , tteardown ) \
89- static struct ctest CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_SECTION = { \
126+ CTEST_IMPL_NO_ASAN_VARIABLE \
127+ CTEST_IMPL_SECTION \
128+ static struct ctest CTEST_IMPL_TNAME(sname, tname) = { \
129+ .magic1 = CTEST_IMPL_MAGIC, \
90130 .ssname=#sname, \
91131 .ttname=#tname, \
92132 .run = CTEST_IMPL_FNAME(sname, tname), \
93133 .data = tdata, \
94134 .setup = (ctest_setup_func*) tsetup, \
95135 .teardown = (ctest_teardown_func*) tteardown, \
96136 .skip = tskip, \
97- .magic = CTEST_IMPL_MAGIC }
137+ .magic2 = CTEST_IMPL_MAGIC, \
138+ }
98139
99140#define CTEST_SETUP (sname ) \
100141 static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
@@ -188,12 +229,13 @@ void assert_dbl_far(double exp, double real, double tol, const char* caller, int
188229
189230#include <setjmp.h>
190231#include <stdarg.h>
232+ #include <stdbool.h>
233+ #include <stdint.h>
191234#include <stdio.h>
235+ #include <stdlib.h>
192236#include <string.h>
193237#include <sys/time.h>
194238#include <unistd.h>
195- #include <stdint.h>
196- #include <stdlib.h>
197239#include <wchar.h>
198240
199241static size_t ctest_errorsize ;
@@ -449,9 +491,42 @@ static void sighandler(int signum)
449491}
450492#endif
451493
452- int ctest_main (int argc , const char * argv []);
494+ #ifdef CTEST_IMPL_CLANG_POISIONED_GLOBALS
495+ #include <sanitizer/asan_interface.h>
496+ #endif
497+
498+ static struct ctest * ctest_adjacent_test (const struct ctest * test ,
499+ int direction , size_t offset )
500+ {
501+ const volatile unsigned int * magic = (const unsigned int * )
502+ ((const char * )
503+ (test + direction ) + offset );
504+
505+ #if CTEST_IMPL_POISIONED_GLOBALS
506+ while (ASAN_UNPOISON_MEMORY_REGION (magic , sizeof (* magic )), * magic == 0 ) {
507+ magic += direction ;
508+ }
509+ #endif
510+
511+ CTEST_IMPL_DIAG_PUSH_IGNORED (cast - qual )
512+ return * magic == CTEST_IMPL_MAGIC ? (struct ctest * )
513+ ((char * )magic - offset )
514+ : NULL ;
515+ CTEST_IMPL_DIAG_POP ()
516+ }
453517
454- __attribute__((no_sanitize_address )) int ctest_main (int argc , const char * argv [])
518+ static struct ctest * ctest_next_test (const struct ctest * test )
519+ {
520+ return ctest_adjacent_test (test , 1 , offsetof(struct ctest , magic1 ));
521+ }
522+
523+ static struct ctest * ctest_prev_test (const struct ctest * test )
524+ {
525+ return ctest_adjacent_test (test , -1 , offsetof(struct ctest , magic2 ));
526+ }
527+
528+ CTEST_IMPL_NO_ASAN_FUNCTION
529+ int ctest_main (int argc , const char * argv [])
455530{
456531 static int total = 0 ;
457532 static int num_ok = 0 ;
@@ -476,27 +551,19 @@ __attribute__((no_sanitize_address)) int ctest_main(int argc, const char *argv[]
476551 uint64_t t1 = getCurrentTime ();
477552
478553 struct ctest * ctest_begin = & CTEST_IMPL_TNAME (suite , test );
479- struct ctest * ctest_end = & CTEST_IMPL_TNAME (suite , test );
480- // find begin and end of section by comparing magics
481- while (1 ) {
482- struct ctest * t = ctest_begin - 1 ;
483- if (t -> magic != CTEST_IMPL_MAGIC ) break ;
484- ctest_begin -- ;
485- }
486554 while (1 ) {
487- struct ctest * t = ctest_end + 1 ;
488- if (t -> magic != CTEST_IMPL_MAGIC ) break ;
489- ctest_end ++ ;
555+ struct ctest * t = ctest_prev_test ( ctest_begin ) ;
556+ if (t == NULL ) break ;
557+ ctest_begin = t ;
490558 }
491- ctest_end ++ ; // end after last one
492559
493560 static struct ctest * test ;
494- for (test = ctest_begin ; test != ctest_end ; test ++ ) {
561+ for (test = ctest_begin ; test != NULL ; test = ctest_next_test ( test ) ) {
495562 if (test == & CTEST_IMPL_TNAME (suite , test )) continue ;
496563 if (filter (test )) total ++ ;
497564 }
498565
499- for (test = ctest_begin ; test != ctest_end ; test ++ ) {
566+ for (test = ctest_begin ; test != NULL ; test = ctest_next_test ( test ) ) {
500567 if (test == & CTEST_IMPL_TNAME (suite , test )) continue ;
501568 if (filter (test )) {
502569 ctest_errorbuffer [0 ] = 0 ;
0 commit comments