From fb170eaebb89cf3e6c13a4fb9935b7e251379d65 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Wed, 15 May 2024 18:11:36 +0200 Subject: [PATCH 1/8] Add dependency tracking for Developer Studio 12.6 --- Makefile.in | 2 +- configure.ac | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index bbac03c..70394f6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -11,7 +11,7 @@ HASWELL = @HAVE_HASWELL@ CC = @CC@ CPPFLAGS = @CPPFLAGS@ -I$(SOURCE)/include -I$(SOURCE)/src -I. CFLAGS = @CFLAGS@ -DEPFLAGS = -MT $@ -MMD -MP -MF $(@:.o=.d) +DEPFLAGS = @DEPFLAGS@ VPATH = @srcdir@ SOURCE = @srcdir@ diff --git a/configure.ac b/configure.ac index 836e549..c34aac0 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,13 @@ case "$enable_haswell" in yes|*) enable_haswell=yes ;; esac +# GCC and Clang +AX_CHECK_COMPILE_FLAG([-MMD],DEPFLAGS="-MMD -MP") +# Oracle Developer Studio (no -MP) +AX_CHECK_COMPILE_FLAG([-xMMD],DEPFLAGS="-xMMD") + +AC_SUBST([DEPFLAGS]) + # Figure out the canonical target architecture. AC_CANONICAL_TARGET From f21c31dda4190d93c84d6730a19374229da88455 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Mon, 1 Jul 2024 10:28:46 +0200 Subject: [PATCH 2/8] Fix compile issues under Developer Studio 12.6 --- CMakeLists.txt | 4 +- src/attributes.h | 8 ++- src/bench.c | 2 +- src/fallback/bits.h | 45 ++++++++++++++++ src/generic/base16.h | 6 +++ src/generic/base64.h | 6 +++ src/generic/endian.h | 118 +++++++++++++++++++++++++++++++++++++++--- src/generic/types.h | 47 +++++++---------- src/haswell/base32.h | 4 +- src/haswell/bits.h | 25 +++++++-- src/westmere/base32.h | 4 +- src/westmere/bits.h | 29 +++++++++-- src/westmere/time.h | 5 ++ src/zone.c | 2 + tests/CMakeLists.txt | 2 +- tests/base32.c | 1 + tests/bounds.c | 3 +- tests/include.c | 28 +++------- tests/syntax.c | 3 +- tests/time.c | 1 + tests/tools.c | 79 ++++++++++++++++++++++++++++ tests/tools.h | 16 ++++++ 22 files changed, 365 insertions(+), 73 deletions(-) create mode 100644 tests/tools.c create mode 100644 tests/tools.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40c0bb5..d54ba01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ endif() include(CheckIncludeFile) include(CheckCCompilerFlag) include(CheckCSourceCompiles) +include(CheckSymbolExists) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(GNUInstallDirs) @@ -169,7 +170,8 @@ target_link_libraries(zone-bench PRIVATE zone) check_include_file(endian.h HAVE_ENDIAN_H) check_include_file(unistd.h HAVE_UNISTD_H) -if(NOT HAVE_UNISTD_H) +check_symbol_exists(getopt unistd.h HAVE_GETOPT) +if(NOT HAVE_UNISTD_H OR NOT HAVE_GETOPT) target_include_directories( zone-bench PRIVATE $) target_sources(zone-bench PRIVATE compat/getopt.c) diff --git a/src/attributes.h b/src/attributes.h index 533bcef..5ca7e1b 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -24,6 +24,12 @@ # define unlikely(params) (params) #else // _MSC_VER +#if defined __has_builtin +# define has_builtin(params) __has_builtin(params) +#else +# define has_builtin(params) (0) +#endif + # if (zone_has_attribute(always_inline) || zone_has_gnuc(3, 1)) && ! defined __NO_INLINE__ // Compilation using GCC 4.2.1 without optimizations fails. // sorry, unimplemented: inlining failed in call to ... @@ -52,7 +58,7 @@ # define no_sanitize_undefined __attribute__((no_sanitize("undefined"))) # elif zone_has_attribute(no_sanitize_undefined) // GCC 4.9.0 added the UndefinedBehaviorSanitizer (ubsan) and the - // no_sanitize_undefined function attribute. + // no_sanitize_undefined function attribute. # define no_sanitize_undefined # else # define no_sanitize_undefined diff --git a/src/bench.c b/src/bench.c index 5d3938d..79e1525 100644 --- a/src/bench.c +++ b/src/bench.c @@ -10,7 +10,7 @@ #include #include #include -#if _WIN32 +#if !defined(HAVE_GETOPT) # include "getopt.h" #else # include diff --git a/src/fallback/bits.h b/src/fallback/bits.h index 31857a5..2bca65a 100644 --- a/src/fallback/bits.h +++ b/src/fallback/bits.h @@ -29,15 +29,60 @@ static really_inline uint64_t leading_zeroes(uint64_t mask) else return 64; } + #else + static really_inline uint64_t trailing_zeroes(uint64_t mask) { +#if has_builtin(__builtin_ctzll) return (uint64_t)__builtin_ctzll(mask); +#else + // Code by Kim Walish from https://www.chessprogramming.org/BitScan. + // Distributed under CC BY-SA 3.0. + static const uint64_t magic = 0x03f79d71b4cb0a89ull; + const int magictable[64] = { + 0, 47, 1, 56, 48, 27, 2, 60, + 57, 49, 41, 37, 28, 16, 3, 61, + 54, 58, 35, 52, 50, 42, 21, 44, + 38, 32, 29, 23, 17, 11, 4, 62, + 46, 55, 26, 59, 40, 36, 15, 53, + 34, 51, 20, 43, 31, 22, 10, 45, + 25, 39, 14, 33, 19, 30, 9, 24, + 13, 18, 8, 12, 7, 6, 5, 63 + }; + + return magictable[((mask ^ (mask - 1)) * magic) >> 58]; +#endif } static really_inline uint64_t leading_zeroes(uint64_t mask) { +#if has_builtin(__builtin_clzll) return (uint64_t)__builtin_clzll(mask); +#else + // Code by Kim Walish from https://www.chessprogramming.org/BitScan. + // Distributed under CC BY-SA 3.0. + static const uint64_t magic = 0x03f79d71b4cb0a89ull; + const int magictable[64] = { + 63, 16, 62, 7, 15, 36, 61, 3, + 6, 14, 22, 26, 35, 47, 60, 2, + 9, 5, 28, 11, 13, 21, 42, 19, + 25, 31, 34, 40, 46, 52, 59, 1, + 17, 8, 37, 4, 23, 27, 48, 10, + 29, 12, 43, 20, 32, 41, 53, 18, + 38, 24, 49, 30, 44, 33, 54, 39, + 50, 45, 55, 51, 56, 57, 58, 0 + }; + + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask |= mask >> 32; + + return magictable[(mask * magic) >> 58]; +#endif } #endif // _MSC_VER #endif // BITS_H diff --git a/src/generic/base16.h b/src/generic/base16.h index 599d8f3..3510944 100644 --- a/src/generic/base16.h +++ b/src/generic/base16.h @@ -173,7 +173,13 @@ static really_inline int base16_stream_decode( // Duff's device again: switch (st.bytes) { +#if defined(__SUNPRO_C) +#pragma error_messages(off, E_STATEMENT_NOT_REACHED) +#endif for (;;) +#if defined(__SUNPRO_C) +#pragma error_messages(default, E_STATEMENT_NOT_REACHED) +#endif { case 0: base16_dec_loop_generic_32(&s, &slen, &o, &olen); diff --git a/src/generic/base64.h b/src/generic/base64.h index a04ba06..ac9ef29 100644 --- a/src/generic/base64.h +++ b/src/generic/base64.h @@ -575,7 +575,13 @@ static really_inline int base64_stream_decode( // Duff's device again: switch (st.bytes) { +#if defined(__SUNPRO_C) +#pragma error_messages(off, E_STATEMENT_NOT_REACHED) +#endif for (;;) +#if defined(__SUNPRO_C) +#pragma error_messages(default, E_STATEMENT_NOT_REACHED) +#endif { case 0: dec_loop_generic_32(&s, &slen, &o, &olen); diff --git a/src/generic/endian.h b/src/generic/endian.h index 3e1b772..62f19e2 100644 --- a/src/generic/endian.h +++ b/src/generic/endian.h @@ -86,17 +86,123 @@ #include #endif -#if !defined BYTE_ORDER -#error "missing definition of BYTE_ORDER" +#if !defined(LITTLE_ENDIAN) +# if defined(__ORDER_LITTLE_ENDIAN__) +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# else +# define LITTLE_ENDIAN 1234 +# endif #endif -#if !defined LITTLE_ENDIAN -#error "missing definition of LITTLE_ENDIAN" +#if !defined(BIG_ENDIAN) +# if defined(__ORDER_BIG_ENDIAN__) +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# else +# define BIG_ENDIAN 4321 +# endif #endif -#if !defined BIG_ENDIAN -#error "missing definition of BIG_ENDIAN" +#if !defined(BYTE_ORDER) +# if defined(__BYTE_ORDER__) +# define BYTE_ORDER __BYTE_ORDER__ +# elif defined(__BYTE_ORDER) +# define BYTE_ORDER __BYTE_ORDER +# elif defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || \ + defined(__x86) || defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64) || defined(__amd64__) +# define BYTE_ORDER LITTLE_ENDIAN +# elif defined(sparc) || defined(__sparc) || defined(__sparc__) || \ + defined(POWERPC) || defined(mc68000) || defined(sel) +# define BYTE_ORDER BIG_ENDIAN +# else +# error "missing definition of BYTE_ORDER" +# endif #endif + +static really_inline uint16_t bswap16(uint16_t x) +{ + // Copied from src/common/lib/libc/gen/bswap16.c in NetBSD + // Written by Manuel Bouyer . + // Public domain. + return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff); +} + +static really_inline uint32_t bswap32(uint32_t x) +{ + // Copied from src/common/lib/libc/gen/bswap32.c in NetBSD + // Written by Manuel Bouyer . + // Public domain. + return ( (x << 24) & 0xff000000 ) | + ( (x << 8) & 0x00ff0000 ) | + ( (x >> 8) & 0x0000ff00 ) | + ( (x >> 24) & 0x000000ff ); +} + +static really_inline uint64_t bswap64(uint64_t x) +{ + // Copied from src/common/lib/libc/gen/bswap64.c in NetBSD + // Written by Manuel Bouyer . + // Public domain. + return ( (x << 56) & 0xff00000000000000ull ) | + ( (x << 40) & 0x00ff000000000000ull ) | + ( (x << 24) & 0x0000ff0000000000ull ) | + ( (x << 8) & 0x000000ff00000000ull ) | + ( (x >> 8) & 0x00000000ff000000ull ) | + ( (x >> 24) & 0x0000000000ff0000ull ) | + ( (x >> 40) & 0x000000000000ff00ull ) | + ( (x >> 56) & 0x00000000000000ffull ); +} + +# if BYTE_ORDER == LITTLE_ENDIAN +# define htobe(bits, x) bswap ## bits((x)) +# define htole(bits, x) (x) +# define betoh(bits, x) bswap ## bits((x)) +# define letoh(bits, x) (x) +# else +# define htobe(bits, x) (x) +# define htole(bits, x) bswap ## bits((x)) +# define betoh(bits, x) (x) +# define letoh(bits, x) bswap ## bits((x)) +# endif + +# if !defined htobe16 +# define htobe16(x) htobe(16,(x)) +# endif +# if !defined htobe32 +# define htobe32(x) htobe(32,(x)) +# endif +# if !defined htobe64 +# define htobe64(x) htobe(64,(x)) +# endif +# if !defined htole16 +# define htole16(x) htole(16,(x)) +# endif +# if !defined htole32 +# define htole32(x) htole(32,(x)) +# endif +# if !defined htole64 +# define htole64(x) htole(64,(x)) +# endif + +# if !defined be16toh +# define be16toh(x) betoh(16,(x)) +# endif +# if !defined be32toh +# define be32toh(x) betoh(32,(x)) +# endif +# if !defined be64toh +# define be64toh(x) betoh(64,(x)) +# endif +# if !defined le16toh +# define le16toh(x) letoh(16,(x)) +# endif +# if !defined le32toh +# define le32toh(x) letoh(32,(x)) +# endif +# if !defined le64toh +# define le64toh(x) letoh(64,(x)) +# endif #endif #endif // ENDIAN_H diff --git a/src/generic/types.h b/src/generic/types.h index aa1d6f6..36ddd8e 100644 --- a/src/generic/types.h +++ b/src/generic/types.h @@ -66,15 +66,8 @@ static really_inline int32_t parse_text( #define UNKNOWN_TYPE(code) \ { { { "", 0 }, code }, 0, false, false, { 0, NULL }, check_generic_rr, parse_unknown_rdata } -#if _WIN32 -// FIXME: check functions can be simplified as int32_t is wide enough to -// represent errors and the maximum length of rdata. -#include -typedef SSIZE_T ssize_t; -#endif - nonnull((1,2,3,4)) -static really_inline ssize_t check_bytes( +static really_inline int32_t check_bytes( parser_t *parser, const type_info_t *type, const rdata_info_t *field, @@ -85,7 +78,7 @@ static really_inline ssize_t check_bytes( (void)data; if (length < size) SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); - return (ssize_t)size; + return (int32_t)size; } #define check_int8(...) check_bytes(__VA_ARGS__, sizeof(uint8_t)) @@ -101,7 +94,7 @@ static really_inline ssize_t check_bytes( #define check_ilnp64(...) check_bytes(__VA_ARGS__, sizeof(uint64_t)) nonnull((1,2,3,4)) -static really_inline ssize_t check_ttl( +static really_inline int32_t check_ttl( parser_t *parser, const type_info_t *type, const rdata_info_t *field, @@ -123,57 +116,57 @@ static really_inline ssize_t check_ttl( } zone_nonnull((1,2,3,4)) -static really_inline ssize_t check_name( +static really_inline int32_t check_name( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { - size_t label = 0, count = 0; - while (count < length) { + int32_t label = 0, count = 0; + while (count < (int32_t)length) { label = data[count]; count += 1 + label; if (!label) break; } - if (!count || count > length) + if (!count || count > (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - return (ssize_t)count; + return count; } zone_nonnull((1,2,3,4)) -static really_inline ssize_t check_string( +static really_inline int32_t check_string( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { - size_t count; + int32_t count; - if (!length || (count = 1 + (size_t)data[0]) > length) + if (!length || (count = 1 + (int32_t)data[0]) > (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - return (ssize_t)count; + return count; } zone_nonnull((1,2,3,4)) -static really_inline ssize_t check_nsec( +static really_inline int32_t check_nsec( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { - size_t count = 0; + int32_t count = 0; int32_t last_window = -1; - while ((count + 2) < length) { + while ((count + 2) < (int32_t)length) { const int32_t window = (int32_t)data[0]; - const size_t blocks = (size_t)data[1]; + const int32_t blocks = (int32_t)data[1]; if (window <= last_window) SYNTAX_ERROR(parser, "Invalid %s in %s, windows are out-of-order", NAME(field), NAME(type)); @@ -184,17 +177,17 @@ static really_inline ssize_t check_nsec( last_window = window; } - if (count != length) + if (count != (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - return (ssize_t)count; + return count; } zone_nonnull((1)) -static really_inline int32_t check(size_t *length, ssize_t count) +static really_inline int32_t check(size_t *length, int32_t count) { if (count < 0) - return (int32_t)count; + return count; *length += (size_t)count; return 0; } diff --git a/src/haswell/base32.h b/src/haswell/base32.h index 0e15ac2..d2d44bf 100644 --- a/src/haswell/base32.h +++ b/src/haswell/base32.h @@ -10,8 +10,6 @@ #define BASE32_H #include -#include // update if we need to support Windows. - ////////////////////////// /// Source: Wojciech Muła, Daniel Lemire, Faster Base64 Encoding and Decoding Using AVX2 Instructions, @@ -44,7 +42,7 @@ static size_t base32hex_avx(uint8_t *dst, const uint8_t *src) { unsigned int m = (unsigned)_mm256_movemask_epi8(check); if (m) { - int length = __builtin_ctz(m); + int length = (int)trailing_zeroes(m); if (length == 0) { break; } diff --git a/src/haswell/bits.h b/src/haswell/bits.h index 6e4ef7d..a9e90c0 100644 --- a/src/haswell/bits.h +++ b/src/haswell/bits.h @@ -14,7 +14,12 @@ #include static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { +#if has_builtin(__builtin_uaddll_overflow) return __builtin_uaddll_overflow(value1, value2, (unsigned long long *)result); +#else + *result = value1 + value2; + return *result < value1; +#endif } static inline uint64_t count_ones(uint64_t bits) { @@ -23,7 +28,7 @@ static inline uint64_t count_ones(uint64_t bits) { no_sanitize_undefined static inline uint64_t trailing_zeroes(uint64_t bits) { - return (uint64_t)__builtin_ctzll(bits); + return (uint64_t)_tzcnt_u64(bits); } // result might be undefined when bits is zero @@ -32,15 +37,25 @@ static inline uint64_t clear_lowest_bit(uint64_t bits) { } static inline uint64_t leading_zeroes(uint64_t bits) { - return (uint64_t)__builtin_clzll(bits); + return (uint64_t)_lzcnt_u64(bits); } static inline uint64_t prefix_xor(const uint64_t bitmask) { + __m128i all_ones = _mm_set1_epi8('\xFF'); + __m128i mask = _mm_set_epi64x(0ULL, (long long)bitmask); +#if defined __SUNPRO_C + // Oracle Developer Studio has issues generating vpclmulqdq + // Oracle Solaris and Intel assembler use the opposite order for source and + // destination operands. See x86 Assemble Language Reference Manual. + __asm volatile ("vpclmulqdq $0,%[all_ones],%[mask],%[mask]" + : [mask] "+x" (mask) + : [all_ones] "x" (all_ones)); +#else // There should be no such thing with a processor supporting avx2 // but not clmul. - __m128i all_ones = _mm_set1_epi8('\xFF'); - __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, (long long)bitmask), all_ones, 0); - return (uint64_t)_mm_cvtsi128_si64(result); + mask = _mm_clmulepi64_si128(mask, all_ones, 0); +#endif + return (uint64_t)_mm_cvtsi128_si64(mask); } #endif // BITS_H diff --git a/src/westmere/base32.h b/src/westmere/base32.h index 981bb57..e049382 100644 --- a/src/westmere/base32.h +++ b/src/westmere/base32.h @@ -10,7 +10,7 @@ #define BASE32_H #include -#include // update if we need to support Windows. +#include ////////////////////////// @@ -37,7 +37,7 @@ static size_t base32hex_sse(uint8_t *dst, const uint8_t *src) { unsigned int m = (unsigned)_mm_movemask_epi8(check); if (m) { - int length = __builtin_ctz(m); + int length = (int)trailing_zeroes(m); if (length == 0) { break; } diff --git a/src/westmere/bits.h b/src/westmere/bits.h index d9570e9..a73f501 100644 --- a/src/westmere/bits.h +++ b/src/westmere/bits.h @@ -13,7 +13,12 @@ #include static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { +#if has_builtin(__builtin_uaddll_overflow) return __builtin_uaddll_overflow(value1, value2, (unsigned long long *)result); +#else + *result = value1 + value2; + return *result < value1; +#endif } static inline uint64_t count_ones(uint64_t input_num) { @@ -21,8 +26,16 @@ static inline uint64_t count_ones(uint64_t input_num) { } no_sanitize_undefined -static inline uint64_t trailing_zeroes(uint64_t input_num) { - return (uint64_t)__builtin_ctzll(input_num); +static inline uint64_t trailing_zeroes(uint64_t mask) { +#if has_builtin(__builtin_ctzll) + return (uint64_t)__builtin_ctzll(mask); +#else + uint64_t result; + asm("bsfq %[mask], %[result]" + : [result] "=r" (result) + : [mask] "mr" (mask)); + return result; +#endif } // result might be undefined when input_num is zero @@ -30,8 +43,16 @@ static inline uint64_t clear_lowest_bit(uint64_t input_num) { return input_num & (input_num-1); } -static inline uint64_t leading_zeroes(uint64_t input_num) { - return (uint64_t)__builtin_clzll(input_num); +static inline uint64_t leading_zeroes(uint64_t mask) { +#if has_builtin(__builtin_clzll) + return (uint64_t)__builtin_clzll(mask); +#else + uint64_t result; + asm("bsrq %[mask], %[result]" : + [result] "=r" (result) : + [mask] "mr" (mask)); + return 63 ^ (int)result; +#endif } static inline uint64_t prefix_xor(const uint64_t bitmask) { diff --git a/src/westmere/time.h b/src/westmere/time.h index 937e094..6e183d1 100644 --- a/src/westmere/time.h +++ b/src/westmere/time.h @@ -59,8 +59,13 @@ static bool sse_parse_time(const char *date_string, uint32_t *time_in_second) { // or if months are in the range 12 to 19. __m128i abide_by_limits = _mm_subs_epu8(v, limit); // must be all zero +#if defined __SUNPRO_C + __m128i byteflip = _mm_setr_epi64((__m64){0x0607040502030001ULL}, + (__m64){0x0e0f0c0d0a0b0809ULL}); +#else __m128i byteflip = _mm_setr_epi64((__m64)0x0607040502030001ULL, (__m64)0x0e0f0c0d0a0b0809ULL); +#endif __m128i little_endian = _mm_shuffle_epi8(v, byteflip); __m128i limit16 = _mm_setr_epi16(0x0909, 0x0909, 0x0102, 0x0301, 0x0203, diff --git a/src/zone.c b/src/zone.c index 046d7e5..d3dda5f 100644 --- a/src/zone.c +++ b/src/zone.c @@ -32,6 +32,8 @@ typedef zone_file_t file_t; #if _MSC_VER # define strcasecmp(s1, s2) _stricmp(s1, s2) # define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) +#else +#include #endif static const char not_a_file[] = ""; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3215fe5..3b1b18f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,7 +14,7 @@ add_custom_command( add_custom_target(generate_xbounds_c DEPENDS "${xbounds_c}") target_link_libraries(zone-tests PRIVATE zone) -target_sources(zone-tests PRIVATE "${xbounds_c}") +target_sources(zone-tests PRIVATE "${xbounds_c}" tools.c) add_dependencies(zone-tests generate_xbounds_c) if(CMAKE_C_COMPILER_ID MATCHES "Clang") target_compile_options(zone-tests PRIVATE -Wno-missing-prototypes -Wno-deprecated-declarations) diff --git a/tests/base32.c b/tests/base32.c index c657f6f..86f78c6 100644 --- a/tests/base32.c +++ b/tests/base32.c @@ -12,6 +12,7 @@ #include #include "zone.h" +#include "attributes.h" #include "generic/endian.h" static int32_t add_rr( diff --git a/tests/bounds.c b/tests/bounds.c index 5c4a001..08f7460 100644 --- a/tests/bounds.c +++ b/tests/bounds.c @@ -13,6 +13,7 @@ #include #include "zone.h" +#include "tools.h" // indexer(s) scans in 64-byte chunks, use white space for positioning @@ -228,7 +229,7 @@ void contiguous_on_buffer_boundary(void **state) zone_buffers_t buffers = { 1, &owner, &rdata }; // generate zone file to parse - char *path = tempnam(NULL, "xbounds"); + char *path = get_tempnam(NULL, "xbounds"); assert_non_null(path); FILE *handle = fopen(path, "wb"); assert_non_null(handle); diff --git a/tests/include.c b/tests/include.c index 177aa44..278ba6f 100644 --- a/tests/include.c +++ b/tests/include.c @@ -24,6 +24,7 @@ #include "zone.h" #include "diagnostic.h" +#include "tools.h" #ifndef PATH_MAX #define PATH_MAX 4096 @@ -52,13 +53,13 @@ int teardown(void **state) if (input->includer.handle) { (void)fclose(input->includer.handle); assert(input->includer.path); - unlink(input->includer.path); + remove(input->includer.path); } if (input->include.handle) { (void)fclose(input->include.handle); assert(input->include.path); - unlink(input->include.path); + remove(input->include.path); } if (input->includer.path) @@ -86,7 +87,7 @@ int setup(void **state) for (int i=0; i < 100 && !input->includer.handle; i++) { if (input->includer.path) free(input->includer.path); - input->includer.path = tempnam(NULL, "zone"); + input->includer.path = get_tempnam(NULL, "zone"); if (!input->includer.path) goto err; input->includer.handle = fopen(input->includer.path, "wbx"); @@ -98,7 +99,7 @@ int setup(void **state) for (int i=0; i < 100 && !input->include.handle; i++) { if (input->include.path) free(input->include.path); - input->include.path = tempnam(NULL, "zone"); + input->include.path = get_tempnam(NULL, "zone"); if (!input->includer.path) goto err; input->include.handle = fopen(input->include.path, "wbx"); @@ -135,23 +136,10 @@ int setup(void **state) return -1; } -static char *temporary_name(void) -{ -#if _WIN32 - int pid = _getpid(); -#else - pid_t pid = getpid(); -#endif - - char format[128]; - snprintf(format, sizeof(format), "zone.%d", pid); - return tempnam(NULL, format); -} - static char *generate_include(const char *text) { for (int i=0; i < 100; i++) { - char *path = temporary_name(); + char *path = get_tempnam(NULL, "zone"); if (path) { FILE *handle = fopen(path, "wbx"); if (handle) { @@ -326,7 +314,7 @@ void the_file_that_wasnt(void **state) (void)state; - char *non_file = temporary_name(); + char *non_file = get_tempnam(NULL, "zone"); assert_non_null(non_file); memset(&test, 0, sizeof(test)); @@ -356,7 +344,7 @@ void the_include_that_wasnt(void **state) (void)state; - char *non_include = temporary_name(); + char *non_include = get_tempnam(NULL, "zone"); assert_non_null(non_include); char buffer[16]; diff --git a/tests/syntax.c b/tests/syntax.c index 7bb7cad..06e5e1d 100644 --- a/tests/syntax.c +++ b/tests/syntax.c @@ -19,6 +19,7 @@ #include "zone.h" #include "diagnostic.h" +#include "tools.h" #define PAD(literal) \ literal \ @@ -592,7 +593,7 @@ static int32_t parse(const char *text, size_t *count) static char *generate_include(const char *text) { - char *path = tempnam(NULL, "zone"); + char *path = get_tempnam(NULL, "zone"); if (path) { FILE *handle = fopen(path, "wbx"); if (handle) { diff --git a/tests/time.c b/tests/time.c index 7dab690..0183bab 100644 --- a/tests/time.c +++ b/tests/time.c @@ -13,6 +13,7 @@ #include #include "zone.h" +#include "attributes.h" #include "generic/endian.h" static int32_t add_rr( diff --git a/tests/tools.c b/tests/tools.c new file mode 100644 index 0000000..b154a42 --- /dev/null +++ b/tests/tools.c @@ -0,0 +1,79 @@ +/* + * tools.c -- convenience tools for testing + * + * Copyright (c) 2023, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include +#if _WIN32 +#include +#include +#include +#else +#include +#include +#endif + +static bool is_dir(const char *dir) +{ + struct stat sb; + if (stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))// & S_IFMT) == S_IFDIR) + return true; + return false; +} + +static const char *get_tmpdir(const char *dir) +{ + const char *tmpdir = NULL; + +#if _WIN32 + tmpdir = getenv("TMP"); +#else + tmpdir = getenv("TMPDIR"); +#endif + if (is_dir(tmpdir)) + return tmpdir; + if (dir && is_dir(tmpdir)) + return dir; +#if defined(P_tmpdir) + if (is_dir(P_tmpdir)) + return P_tmpdir; +#elif !_WIN32 + if (is_dir("/tmp")) + return "/tmp"; +#endif + return NULL; +} + +char *get_tempnam(const char *dir, const char *pfx) +{ + const char *tmpdir = get_tmpdir(dir); + if (!tmpdir) + return NULL; + + static unsigned int count = 0; + + srand(getpid() + count++); + + for (unsigned int i = 0; i < 1000; i++) { + char tmp[16]; + int rnd = rand(); + int len = snprintf(tmp, sizeof(tmp), "%s/%s.%d", tmpdir, pfx, rnd); + assert(len != -1); + char *tmpfile = malloc(len + 1); + if (!tmpfile) + return NULL; + (void)snprintf(tmpfile, len + 1, "%s/%s.%d", tmpdir, pfx, rnd); + struct stat sb; + if (stat(tmpfile, &sb) == -1) + return tmpfile; + free(tmpfile); + } + + return NULL; +} diff --git a/tests/tools.h b/tests/tools.h new file mode 100644 index 0000000..f2a5d31 --- /dev/null +++ b/tests/tools.h @@ -0,0 +1,16 @@ +/* + * tools.c -- convenience tools for testing + * + * Copyright (c) 2023, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef TOOLS_H +#define TOOLS_H + +// this is not safe to use in a production environment, but it's good enough +// for tests +char *get_tempnam(const char *dir, const char *prefix); + +#endif // TOOLS_H From 3d6b8a0f9b7131456db8bca7b90365382d7d87aa Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Wed, 3 Jul 2024 10:25:36 +0200 Subject: [PATCH 3/8] Add unit tests for bit manipulation instructions --- src/westmere/bits.h | 1 + tests/CMakeLists.txt | 14 ++++- tests/bits.c | 138 ++++++++++++++++++++++++++++++++++++++++++ tests/fallback/bits.c | 39 ++++++++++++ tests/haswell/bits.c | 73 ++++++++++++++++++++++ tests/tools.c | 25 ++++++-- tests/westmere/bits.c | 73 ++++++++++++++++++++++ 7 files changed, 356 insertions(+), 7 deletions(-) create mode 100644 tests/bits.c create mode 100644 tests/fallback/bits.c create mode 100644 tests/haswell/bits.c create mode 100644 tests/westmere/bits.c diff --git a/src/westmere/bits.h b/src/westmere/bits.h index a73f501..6b6d34d 100644 --- a/src/westmere/bits.h +++ b/src/westmere/bits.h @@ -11,6 +11,7 @@ #include #include +#include static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { #if has_builtin(__builtin_uaddll_overflow) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3b1b18f..77112af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,15 @@ find_package(cmocka REQUIRED) -cmocka_add_tests(zone-tests types.c include.c ip4.c time.c base32.c svcb.c syntax.c eui.c bounds.c) + +if(HAVE_WESTMERE) + set(sources ${sources} westmere/bits.c) + set_source_files_properties(westmere/bits.c PROPERTIES COMPILE_FLAGS "-march=westmere") +endif() +if(HAVE_HASWELL) + set(sources ${sources} haswell/bits.c) + set_source_files_properties(haswell/bits.c PROPERTIES COMPILE_FLAGS "-march=haswell") +endif() + +cmocka_add_tests(zone-tests types.c include.c ip4.c time.c base32.c svcb.c syntax.c eui.c bounds.c bits.c) set(xbounds ${CMAKE_CURRENT_SOURCE_DIR}/zones/xbounds.zone) set(xbounds_c "${CMAKE_CURRENT_BINARY_DIR}/xbounds.c") @@ -14,7 +24,7 @@ add_custom_command( add_custom_target(generate_xbounds_c DEPENDS "${xbounds_c}") target_link_libraries(zone-tests PRIVATE zone) -target_sources(zone-tests PRIVATE "${xbounds_c}" tools.c) +target_sources(zone-tests PRIVATE "${xbounds_c}" tools.c fallback/bits.c ${sources}) add_dependencies(zone-tests generate_xbounds_c) if(CMAKE_C_COMPILER_ID MATCHES "Clang") target_compile_options(zone-tests PRIVATE -Wno-missing-prototypes -Wno-deprecated-declarations) diff --git a/tests/bits.c b/tests/bits.c new file mode 100644 index 0000000..749f2cb --- /dev/null +++ b/tests/bits.c @@ -0,0 +1,138 @@ +/* + * bits.c -- test bit manipulation instructions + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "attributes.h" +#include "isadetection.h" + +#if _MSC_VER +# define strcasecmp(s1, s2) _stricmp(s1, s2) +# define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) +#else +#include +#endif + +#include "diagnostic.h" + +struct kernel { + const char *name; + uint32_t instruction_set; + void (*test_trailing_zeroes)(void **state); + void (*test_leading_zeroes)(void **state); + void (*test_prefix_xor)(void **state); + void (*test_add_overflow)(void **state); +}; + +#if HAVE_HASWELL +extern void test_haswell_trailing_zeroes(void **); +extern void test_haswell_leading_zeroes(void **); +extern void test_haswell_prefix_xor(void **); +extern void test_haswell_add_overflow(void **); +#endif + +#if HAVE_WESTMERE +extern void test_westmere_trailing_zeroes(void **); +extern void test_westmere_leading_zeroes(void **); +extern void test_westmere_prefix_xor(void **); +extern void test_westmere_add_overflow(void **); +#endif + +extern void test_fallback_trailing_zeroes(void **); +extern void test_fallback_leading_zeroes(void **); + +static const struct kernel kernels[] = { +#if HAVE_HASWELL + { "haswell", AVX2, &test_haswell_trailing_zeroes, + &test_haswell_leading_zeroes, + &test_haswell_prefix_xor, + &test_haswell_add_overflow }, +#endif +#if HAVE_WESTMERE + { "westmere", SSE42, &test_westmere_trailing_zeroes, + &test_westmere_leading_zeroes, + &test_westmere_prefix_xor, + &test_westmere_add_overflow }, +#endif + { "fallback", DEFAULT, &test_fallback_trailing_zeroes, + &test_fallback_leading_zeroes, + 0, 0 } +}; + +static inline const struct kernel * +select_kernel(void) +{ + const char *preferred; + const uint32_t supported = detect_supported_architectures(); + const size_t length = sizeof(kernels)/sizeof(kernels[0]); + size_t count = 0; + +diagnostic_push() +msvc_diagnostic_ignored(4996) + preferred = getenv("ZONE_KERNEL"); +diagnostic_pop() + + if (preferred) { + for (; count < length; count++) + if (strcasecmp(preferred, kernels[count].name) == 0) + break; + if (count == length) + count = 0; + } + + for (; count < length; count++) + if ((kernels[count].instruction_set & supported) == (kernels[count].instruction_set)) + return &kernels[count]; + + return &kernels[length - 1]; +} + +/*!cmocka */ +void test_trailing_zeroes(void **state) +{ + const struct kernel *kernel = select_kernel(); + assert(kernel); + kernel->test_trailing_zeroes(state); +} + +/*!cmocka */ +void test_leading_zeroes(void **state) +{ + const struct kernel *kernel = select_kernel(); + assert(kernel); + kernel->test_leading_zeroes(state); +} + +/*!cmocka */ +void test_prefix_xor(void **state) +{ + const struct kernel *kernel = select_kernel(); + assert(kernel); + if (kernel->test_prefix_xor) + kernel->test_prefix_xor(state); + else + assert_true(1); +} + +/*!cmocka */ +void test_add_overflow(void **state) +{ + const struct kernel *kernel = select_kernel(); + assert(kernel); + if (kernel->test_add_overflow) + kernel->test_add_overflow(state); + else + assert_true(1); +} diff --git a/tests/fallback/bits.c b/tests/fallback/bits.c new file mode 100644 index 0000000..a89ea65 --- /dev/null +++ b/tests/fallback/bits.c @@ -0,0 +1,39 @@ +/* + * bits.c -- test bit manipulation instructions + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "fallback/bits.h" + +void test_fallback_trailing_zeroes(void **state) +{ + (void)state; + fprintf(stderr, "test_fallback_trailing_zeroes\n"); + for (uint64_t shift = 0; shift < 63; shift++) { + uint64_t bit = 1llu << shift; + uint64_t tz = trailing_zeroes(bit); + assert_int_equal(tz, shift); + } +} + +void test_fallback_leading_zeroes(void **state) +{ + (void)state; + fprintf(stderr, "test_fallback_leading_zeroes\n"); + for (uint64_t shift = 0; shift < 63; shift++) { + const uint64_t bit = 1llu << shift; + uint64_t lz = leading_zeroes(bit); + assert_int_equal(lz, 63 - shift); + } +} diff --git a/tests/haswell/bits.c b/tests/haswell/bits.c new file mode 100644 index 0000000..e99e423 --- /dev/null +++ b/tests/haswell/bits.c @@ -0,0 +1,73 @@ +/* + * bits-haswell.c -- test Haswell specific bit manipulation instructions + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "haswell/bits.h" + +void test_haswell_trailing_zeroes(void **state) +{ + (void)state; + fprintf(stderr, "test_haswell_trailing_zeroes\n"); + for (uint64_t shift = 0; shift < 63; shift++) { + uint64_t bit = 1llu << shift; + uint64_t tz = trailing_zeroes(bit); + assert_int_equal(tz, shift); + } +} + +void test_haswell_leading_zeroes(void **state) +{ + (void)state; + fprintf(stderr, "test_haswell_leading_zeroes\n"); + for (uint64_t shift = 0; shift < 63; shift++) { + const uint64_t bit = 1llu << shift; + uint64_t lz = leading_zeroes(bit); + assert_int_equal(lz, 63 - shift); + } +} + +void test_haswell_prefix_xor(void **state) +{ + (void)state; + fprintf(stderr, "test_haswell_prefix_xor\n"); + // "0001 0001 0000 0101 0000 0110 0000 0000" + uint64_t mask = + (1llu << 28) | (1llu << 24) | + (1llu << 18) | (1llu << 16) | + (1llu << 10) | (1llu << 9); + // "0000 1111 0000 0011 0000 0010 0000 0000" + uint64_t prefix_mask = + (1llu << 27) | (1llu << 26) | (1llu << 25) | (1llu << 24) | + (1llu << 17) | (1llu << 16) | + (1llu << 9); + + assert_int_equal(prefix_xor(mask), prefix_mask); +} + +void test_haswell_add_overflow(void **state) +{ + (void)state; + fprintf(stderr, "test_haswell_add_overflow\n"); + uint64_t all_ones = UINT64_MAX; + uint64_t result = 0; + uint64_t overflow = add_overflow(all_ones, 2llu, &result); + assert_int_equal(result, 1llu); + assert_true(overflow); + overflow = add_overflow(all_ones, 1llu, &result); + assert_int_equal(result, 0llu); + assert_true(overflow); + overflow = add_overflow(all_ones, 0llu, &result); + assert_int_equal(result, all_ones); + assert_false(overflow); +} diff --git a/tests/tools.c b/tests/tools.c index b154a42..3876cf0 100644 --- a/tests/tools.c +++ b/tests/tools.c @@ -14,15 +14,21 @@ #include #include #include + +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif #else #include #include #endif +#include "diagnostic.h" + static bool is_dir(const char *dir) { struct stat sb; - if (stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))// & S_IFMT) == S_IFDIR) + if (stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) return true; return false; } @@ -32,7 +38,10 @@ static const char *get_tmpdir(const char *dir) const char *tmpdir = NULL; #if _WIN32 +diagnostic_push() +msvc_diagnostic_ignored(4996) tmpdir = getenv("TMP"); +diagnostic_pop() #else tmpdir = getenv("TMPDIR"); #endif @@ -57,18 +66,24 @@ char *get_tempnam(const char *dir, const char *pfx) return NULL; static unsigned int count = 0; + unsigned int pid; + +diagnostic_push() +msvc_diagnostic_ignored(4996) + pid = (unsigned int)getpid(); +diagnostic_pop() - srand(getpid() + count++); + srand(pid + count++); for (unsigned int i = 0; i < 1000; i++) { char tmp[16]; int rnd = rand(); int len = snprintf(tmp, sizeof(tmp), "%s/%s.%d", tmpdir, pfx, rnd); - assert(len != -1); - char *tmpfile = malloc(len + 1); + assert(len >= 0); + char *tmpfile = malloc((unsigned int)len + 1); if (!tmpfile) return NULL; - (void)snprintf(tmpfile, len + 1, "%s/%s.%d", tmpdir, pfx, rnd); + (void)snprintf(tmpfile, (unsigned int)len + 1, "%s/%s.%d", tmpdir, pfx, rnd); struct stat sb; if (stat(tmpfile, &sb) == -1) return tmpfile; diff --git a/tests/westmere/bits.c b/tests/westmere/bits.c new file mode 100644 index 0000000..6087f4e --- /dev/null +++ b/tests/westmere/bits.c @@ -0,0 +1,73 @@ +/* + * bits-westmere.c -- test Westmere specific bit manipulation instructions + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "westmere/bits.h" + +void test_westmere_trailing_zeroes(void **state) +{ + fprintf(stderr, "test_westmere_trailing_zeroes\n"); + (void)state; + for (uint64_t shift = 0; shift < 63; shift++) { + uint64_t bit = 1llu << shift; + uint64_t tz = trailing_zeroes(bit); + assert_int_equal(tz, shift); + } +} + +void test_westmere_leading_zeroes(void **state) +{ + (void)state; + fprintf(stderr, "test_westmere_leading_zeroes\n"); + for (uint64_t shift = 0; shift < 63; shift++) { + const uint64_t bit = 1llu << shift; + uint64_t lz = leading_zeroes(bit); + assert_int_equal(lz, 63 - shift); + } +} + +void test_westmere_prefix_xor(void **state) +{ + (void)state; + fprintf(stderr, "test_westmere_prefix_xor\n"); + // "0001 0001 0000 0101 0000 0110 0000 0000" + uint64_t mask = + (1llu << 28) | (1llu << 24) | + (1llu << 18) | (1llu << 16) | + (1llu << 10) | (1llu << 9); + // "0000 1111 0000 0011 0000 0010 0000 0000" + uint64_t prefix_mask = + (1llu << 27) | (1llu << 26) | (1llu << 25) | (1llu << 24) | + (1llu << 17) | (1llu << 16) | + (1llu << 9); + + assert_int_equal(prefix_xor(mask), prefix_mask); +} + +void test_westmere_add_overflow(void **state) +{ + (void)state; + fprintf(stderr, "test_westmere_add_overflow\n"); + uint64_t all_ones = UINT64_MAX; + uint64_t result = 0; + uint64_t overflow = add_overflow(all_ones, 2llu, &result); + assert_int_equal(result, 1llu); + assert_true(overflow); + overflow = add_overflow(all_ones, 1llu, &result); + assert_int_equal(result, 0llu); + assert_true(overflow); + overflow = add_overflow(all_ones, 0llu, &result); + assert_int_equal(result, all_ones); + assert_false(overflow); +} From 25d0531110f29cea720cd4332dd39d266d90b047 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Thu, 4 Jul 2024 09:29:44 +0200 Subject: [PATCH 4/8] Fix some Developer Studio compiler warnings --- src/bench.c | 3 ++- src/zone.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bench.c b/src/bench.c index 79e1525..e435a7b 100644 --- a/src/bench.c +++ b/src/bench.c @@ -14,7 +14,6 @@ # include "getopt.h" #else # include -# include #endif #include "zone.h" @@ -26,6 +25,8 @@ #if _MSC_VER #define strcasecmp(s1, s2) _stricmp(s1, s2) #define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) +#else +#include #endif typedef zone_parser_t parser_t; diff --git a/src/zone.c b/src/zone.c index d3dda5f..99dfe16 100644 --- a/src/zone.c +++ b/src/zone.c @@ -293,8 +293,10 @@ static int32_t open_file( file->fields.tape[1] = &file->buffer.data[0]; if(file == &parser->first && strcmp(file->name, "-") == 0) { - if(!(file->path = strdup(file->name))) + if (!(file->path = malloc(2))) return (void)close_file(parser, file), ZONE_OUT_OF_MEMORY; + file->path[0] = '-'; + file->path[1] = '\0'; } else { /* The file is resolved relative to the working directory. */ char workdir[PATH_MAX]; From 80ad4a789327af7f995de8a2146bd2bf50d39109 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Thu, 11 Jul 2024 15:45:33 +0200 Subject: [PATCH 5/8] Fix issues building on Solaris 10 --- CMakeLists.txt | 2 +- src/attributes.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d54ba01..00c47c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,7 @@ target_link_libraries(zone-bench PRIVATE zone) check_include_file(endian.h HAVE_ENDIAN_H) check_include_file(unistd.h HAVE_UNISTD_H) -check_symbol_exists(getopt unistd.h HAVE_GETOPT) +check_symbol_exists(getopt "stdio.h;unistd.h" HAVE_GETOPT) if(NOT HAVE_UNISTD_H OR NOT HAVE_GETOPT) target_include_directories( zone-bench PRIVATE $) diff --git a/src/attributes.h b/src/attributes.h index 5ca7e1b..baaac5e 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -64,8 +64,13 @@ # define no_sanitize_undefined # endif -# define likely(params) __builtin_expect(!!(params), 1) -# define unlikely(params) __builtin_expect(!!(params), 0) +# if has_builtin(__builtin_expect) +# define likely(params) __builtin_expect(!!(params), 1) +# define unlikely(params) __builtin_expect(!!(params), 0) +# else +# define likely(params) (params) +# define unlikely(params) (params) +# endif #endif #endif // ATTRIBUTES_H From 456d9bdf73c901485d1ace49be4cb83bf2a7b55c Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Thu, 11 Jul 2024 17:04:43 +0200 Subject: [PATCH 6/8] Solaris requires a buffer for realpath --- src/zone.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/zone.c b/src/zone.c index 99dfe16..ce39682 100644 --- a/src/zone.c +++ b/src/zone.c @@ -176,9 +176,11 @@ nonnull_all static int32_t resolve_path( const char *includer, const char *include, char **path) { + char *resolved; + char buffer[PATH_MAX + 1]; + if (*includer && *include != '/') { assert(*includer == '/'); - char buffer[16]; int length = snprintf( buffer, sizeof(buffer), "%s/%s", includer, include); if (length < 0) @@ -188,15 +190,21 @@ static int32_t resolve_path( return ZONE_OUT_OF_MEMORY; (void)snprintf( absolute, (size_t)length + 1, "%s/%s", includer, include); - *path = realpath(absolute, NULL); + resolved = realpath(absolute, buffer); free(absolute); } else { - *path = realpath(include, NULL); + resolved = realpath(include, buffer); } - if (*path) - return 0; - return (errno == ENOMEM) ? ZONE_OUT_OF_MEMORY : ZONE_NOT_A_FILE; + if (!resolved) + return (errno == ENOMEM) ? ZONE_OUT_OF_MEMORY : ZONE_NOT_A_FILE; + assert(resolved == buffer); + size_t length = strlen(buffer); + if (!(resolved = malloc(length + 1))) + return ZONE_OUT_OF_MEMORY; + memcpy(resolved, buffer, length + 1); + *path = resolved; + return 0; } #endif @@ -280,6 +288,7 @@ static int32_t open_file( initialize_file(parser, file); + file->path = NULL; if (!(file->name = malloc(length + 1))) return ZONE_OUT_OF_MEMORY; memcpy(file->name, include, length); From f66f867dc43ace415983ed54b97166cc1c9722c4 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Tue, 16 Jul 2024 15:23:16 +0200 Subject: [PATCH 7/8] Split CMake and Autoconf logic --- CMakeLists.txt | 54 +++++++++++++------------------------------- configure.ac | 11 ++++++++- src/config.h.in | 29 ++++++++++++++++++++++++ src/generic/endian.h | 2 ++ src/zone.c | 3 ++- tests/include.c | 9 ++++---- 6 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 src/config.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c47c5..48c08e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,15 +168,27 @@ target_include_directories( target_link_libraries(zone-bench PRIVATE zone) check_include_file(endian.h HAVE_ENDIAN_H) - check_include_file(unistd.h HAVE_UNISTD_H) -check_symbol_exists(getopt "stdio.h;unistd.h" HAVE_GETOPT) -if(NOT HAVE_UNISTD_H OR NOT HAVE_GETOPT) + +set(CMAKE_REQUIRED_DEFINITIONS "-D_DEFAULT_SOURCE=1") +check_symbol_exists(getopt "stdlib.h;unistd.h" HAVE_GETOPT) +unset(CMAKE_REQUIRED_DEFINITIONS) +if(NOT HAVE_GETOPT) target_include_directories( zone-bench PRIVATE $) target_sources(zone-bench PRIVATE compat/getopt.c) endif() +if(NOT WIN32) + # _fullpath is used on Microsoft Windows. + set(CMAKE_REQUIRED_DEFINITIONS "-D_DEFAULT_SOURCE=1") + check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH) + unset(CMAKE_REQUIRED_DEFINITIONS) + if(NOT HAVE_REALPATH) + message(FATAL_ERROR "realpath is not available") + endif() +endif() + # Multiple instruction sets may be supported by a specific architecture. # e.g. x86_64 may (or may not) support any of SSE42, AVX2 and AVX-512. The # best instruction set is automatically selected at runtime, but the compiler @@ -223,41 +235,7 @@ if(architecture STREQUAL "x86_64" OR architecture STREQUAL "amd64") endif() -# Autoconf is supported for easy inclusion of simdzone in NSD. To avoid having -# to maintain multiple configuration headers, instead of using configure_file, -# read configure.ac and replace occurences of "AC_SUBST([])". If an -# instance of AC_SUBST does not match expectations, throw an error. -file(READ configure.ac template) - -set(pattern "(^|\n)[ \t]*AC_SUBST\([^\n]*)[ \t]*(\n|$)") -string(REGEX MATCHALL "${pattern}" matches "${template}") -foreach(match ${matches}) - if (match MATCHES "[ \t]*AC_SUBST\\(\\[([a-zA-Z0-9_]+)\\]\\)[ \t]*") - set(variable "${CMAKE_MATCH_1}") - # Ignore any variables that do not start with HAVE_ - if (variable MATCHES "^HAVE_") - if(NOT DEFINED ${variable} OR NOT ${variable} OR - ${variable} MATCHES "^[Ff][Aa][Ll][Ss][Ee]$" OR - ${variable} MATCHES "^[Oo][Ff][Ff]") - string(APPEND header "/* #undef ${variable} */\n") - elseif(${variable} MATCHES "^[Tt][Rr][Uu][Ee]$" OR - ${variable} MATCHES "^[Oo][Nn]$") - string(APPEND header "#define ${variable} 1\n") - elseif(${variable} MATCHES "^[01234567890]+$") - string(APPEND header "#define ${variable} ${${variable}}\n") - else() - string(APPEND header "#define ${variable} \"${${variable}}\"\n") - endif() - else() - continue() - endif() - - else() - message(FATAL_ERROR "Found AC_SUBST that not match expression") - endif() -endforeach() - -file(GENERATE OUTPUT config.h CONTENT "${header}") +configure_file(src/config.h.in config.h) if(BUILD_TESTING) add_subdirectory(tests) diff --git a/configure.ac b/configure.ac index c34aac0..b2cde1d 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ AC_CONFIG_FILES([Makefile]) m4_include(m4/ax_check_compile_flag.m4) m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC]) -AC_CHECK_HEADER(endian.h, AC_DEFINE(HAVE_ENDIAN_H, 1, [Wether or not have the header file])) +AC_CHECK_HEADER(endian.h, AC_DEFINE(HAVE_ENDIAN_H, 1, [Define to 1 if you have the header file.])) AC_ARG_ENABLE(westmere, AS_HELP_STRING([--disable-westmere],[Disable Westmere (SSE4.2) kernel])) case "$enable_westmere" in @@ -95,8 +95,17 @@ if test $x86_64 = "yes"; then fi fi +AC_CHECK_FUNCS([realpath],,[AC_MSG_ERROR([realpath is not available])]) + AC_SUBST([HAVE_ENDIAN_H]) AC_SUBST([HAVE_WESTMERE]) AC_SUBST([HAVE_HASWELL]) +AH_BOTTOM([ +/* Defines _XOPEN_SOURCE and _POSIX_C_SOURCE implicitly in features.h */ +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif +]) + AC_OUTPUT diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..db84c73 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,29 @@ +/* + * config.h.in -- configuration header template + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef CONFIG_H +#define CONFIG_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the `getopt' function. */ +#cmakedefine HAVE_GETOPT 1 + +/* Wether or not to compile support for AVX2 */ +#cmakedefine HAVE_HASWELL 1 + +/* Wether or not to compile support for SSE4.2 */ +#cmakedefine HAVE_WESTMERE 1 + +/* Defines _XOPEN_SOURCE and _POSIX_C_SOURCE implicitly in features.h */ +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif + +#endif // CONFIG_H diff --git a/src/generic/endian.h b/src/generic/endian.h index 62f19e2..7c9fdb3 100644 --- a/src/generic/endian.h +++ b/src/generic/endian.h @@ -11,6 +11,8 @@ #include "config.h" +// https://www.austingroupbugs.net/view.php?id=162#c665 + #if _WIN32 #include diff --git a/src/zone.c b/src/zone.c index ce39682..0b4930b 100644 --- a/src/zone.c +++ b/src/zone.c @@ -6,6 +6,8 @@ * SPDX-License-Identifier: BSD-3-Clause * */ +#include "config.h" + #include #include #include @@ -38,7 +40,6 @@ typedef zone_file_t file_t; static const char not_a_file[] = ""; -#include "config.h" #include "isadetection.h" #ifndef PATH_MAX diff --git a/tests/include.c b/tests/include.c index 278ba6f..ce14836 100644 --- a/tests/include.c +++ b/tests/include.c @@ -526,11 +526,10 @@ void include_relative(void **state) options.default_class = 1; options.include_limit = 1; -#if _WIN32 - int pid = _getpid(); -#else - pid_t pid = getpid(); -#endif +diagnostic_push() +msvc_diagnostic_ignored(4996) + unsigned int pid = (unsigned int)getpid(); +diagnostic_pop() char* inc1file = "content.inc"; char* inc2file = "example.com.zone"; From 9a4f38ed59730cbd942cbc18e52ade4cef769e57 Mon Sep 17 00:00:00 2001 From: Jeroen Koekkoek Date: Tue, 16 Jul 2024 15:39:21 +0200 Subject: [PATCH 8/8] Remove temporary zone file generated by test --- tests/bounds.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bounds.c b/tests/bounds.c index 08f7460..e86fca8 100644 --- a/tests/bounds.c +++ b/tests/bounds.c @@ -6,6 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause * */ +#include #include #include #include @@ -238,6 +239,7 @@ void contiguous_on_buffer_boundary(void **state) (void)fclose(handle); size_t count = 0; int32_t code = zone_parse(&parser, &options, &buffers, path, &count); + remove(path); assert_int_equal(code, ZONE_SUCCESS); assert_int_equal(count, 3); free(path);