]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Suppress UBSan warnings from EXTRACT_.
authorGuy Harris <[email protected]>
Sat, 19 Aug 2017 03:11:43 +0000 (20:11 -0700)
committerGuy Harris <[email protected]>
Sat, 19 Aug 2017 03:11:43 +0000 (20:11 -0700)
Yes, the behavior of an access with an improperly-aligned pointer is
undefined according to the C standard, but if we're doing that in an
EXTRACT_ function/macro, we're doing it because we know it's safe and
because it's faster than picking the bytes out one by one and assembling
them, so suppress those warnings.

Pull over libpcap's funcattrs.h and use it to do a bunch of checks for
various function attributes; that defines __has_attribute(), so we can
use it to check for the "suppress sanitizer warnings" attribute.

While we're at it, use other things it defines to specify "this function
never returns", "this function is printf-like", and "this function
argument is a printf-style format argument", rather than using various
configure-script checks.  That should let us declare some function
attributes with Microsoft Visual Studio's compilers.

Makefile.in
extract.h
funcattrs.h [new file with mode: 0644]
netdissect-stdinc.h
netdissect.h
print.c
tcpdump.c

index c18d5ed91656ae5c29ee32b1b19e875f89ce1289..0941f0e5078fb3470569650b764057097d672afe 100644 (file)
@@ -263,6 +263,7 @@ HDR = \
        ether.h \
        ethertype.h \
        extract.h \
+       funcattrs.h \
        getopt_long.h \
        gmpls.h \
        gmt2local.h \
index 23623c289cb377be36c35680a45721c1309ac04b..2ea4ca807d12d5a3ae9d64fdbdee8724390f4e4f 100644 (file)
--- a/extract.h
+++ b/extract.h
  */
 
 /*
- * Macros to extract possibly-unaligned big-endian integral values.
+ * Inline functions or macros to extract possibly-unaligned big-endian
+ * integral values.
  */
+#include "funcattrs.h"
+
+/*
+ * If we have versions of GCC or Clang that support an __attribute__
+ * to say "if we're building with unsigned behavior sanitization,
+ * don't complain about undefined behavior in this function", we
+ * label these functions with that attribute - we *know* it's undefined
+ * in the C standard, but we *also* know it does what we want with
+ * the ISA we're targeting and the compiler we're using.
+ *
+ * For GCC 4.9.0 and later, we use __attribute__((no_sanitize_undefined));
+ * pre-5.0 GCC doesn't have __has_attribute, and I'm not sure whether
+ * GCC or Clang first had __attribute__((no_sanitize(XXX)).
+ *
+ * For Clang, we check for __attribute__((no_sanitize(XXX)) with
+ * __has_attribute, as there are versions of Clang that support
+ * __attribute__((no_sanitize("undefined")) but don't support
+ * __attribute__((no_sanitize_undefined)).
+ *
+ * We define this here, rather than in funcattrs.h, because we
+ * only want it used here, we don't want it to be broadly used.
+ * (Any printer will get this defined, but this should at least
+ * make it harder for people to find.)
+ */
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409)
+#define UNALIGNED_OK   __attribute__((no_sanitize_undefined))
+#elif __has_attribute(no_sanitize)
+#define UNALIGNED_OK   __attribute__((no_sanitize("undefined")))
+#else
+#define UNALIGNED_OK
+#endif
+
 #ifdef LBL_ALIGN
 /*
  * The processor doesn't natively handle unaligned loads.
@@ -31,7 +64,7 @@
      defined(__mips) || defined(__mips__))
 
 /*
- * This is a GCC-compatible compiler and we have __attribute__, which
+* This is a GCC-compatible compiler and we have __attribute__, which
  * we assume that mean we have __attribute__((packed)), and this is
  * MIPS or Alpha, which has instructions that can help when doing
  * unaligned loads.
@@ -88,19 +121,19 @@ typedef struct {
        uint32_t        val;
 } __attribute__((packed)) unaligned_uint32_t;
 
-static inline uint16_t
+UNALIGNED_OK static inline uint16_t
 EXTRACT_16BITS(const void *p)
 {
        return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
 }
 
-static inline uint32_t
+UNALIGNED_OK static inline uint32_t
 EXTRACT_32BITS(const void *p)
 {
        return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
 }
 
-static inline uint64_t
+UNALIGNED_OK static inline uint64_t
 EXTRACT_64BITS(const void *p)
 {
        return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
@@ -138,19 +171,19 @@ EXTRACT_64BITS(const void *p)
  * The processor natively handles unaligned loads, so we can just
  * cast the pointer and fetch through it.
  */
-static inline uint16_t
+static inline uint16_t UNALIGNED_OK
 EXTRACT_16BITS(const void *p)
 {
        return ((uint16_t)ntohs(*(const uint16_t *)(p)));
 }
 
-static inline uint32_t
+static inline uint32_t UNALIGNED_OK
 EXTRACT_32BITS(const void *p)
 {
        return ((uint32_t)ntohl(*(const uint32_t *)(p)));
 }
 
-static inline uint64_t
+static inline uint64_t UNALIGNED_OK
 EXTRACT_64BITS(const void *p)
 {
        return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
diff --git a/funcattrs.h b/funcattrs.h
new file mode 100644 (file)
index 0000000..63d3f56
--- /dev/null
@@ -0,0 +1,122 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the Computer Systems
+ *     Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_funcattrs_h
+#define lib_funcattrs_h
+
+/*
+ * Attributes to apply to functions and their arguments, using various
+ * compiler-specific extensions.
+ */
+
+/*
+ * This was introduced by Clang:
+ *
+ *     http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+ *
+ * in some version (which version?); it has been picked up by GCC 5.0.
+ */
+#ifndef __has_attribute
+  /*
+   * It's a macro, so you can check whether it's defined to check
+   * whether it's supported.
+   *
+   * If it's not, define it to always return 0, so that we move on to
+   * the fallback checks.
+   */
+  #define __has_attribute(x) 0
+#endif
+
+/*
+ * NORETURN, before a function declaration, means "this function
+ * never returns".  (It must go before the function declaration, e.g.
+ * "extern NORETURN func(...)" rather than after the function
+ * declaration, as the MSVC version has to go before the declaration.)
+ */
+#if __has_attribute(noreturn) \
+    || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \
+    || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \
+    || (defined(__xlC__) && __xlC__ >= 0x0A01) \
+    || (defined(__HP_aCC) && __HP_aCC >= 61000)
+  /*
+   * Compiler with support for __attribute((noreturn)), or GCC 2.5 and
+   * later, or Solaris Studio 12 (Sun C 5.9) and later, or IBM XL C 10.1
+   * and later (do any earlier versions of XL C support this?), or
+   * HP aCC A.06.10 and later.
+   */
+  #define NORETURN __attribute((noreturn))
+#elif defined(_MSC_VER)
+  /*
+   * MSVC.
+   */
+  #define NORETURN __declspec(noreturn)
+#else
+  #define NORETURN
+#endif
+
+/*
+ * PRINTFLIKE(x,y), after a function declaration, means "this function
+ * does printf-style formatting, with the xth argument being the format
+ * string and the yth argument being the first argument for the format
+ * string".
+ */
+#if __has_attribute(__format__) \
+    || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \
+    || (defined(__xlC__) && __xlC__ >= 0x0A01) \
+    || (defined(__HP_aCC) && __HP_aCC >= 61000)
+  /*
+   * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1
+   * and later (do any earlier versions of XL C support this?),
+   * or HP aCC A.06.10 and later.
+   */
+  #define PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y)))
+#else
+  #define PRINTFLIKE(x,y)
+#endif
+
+/*
+ * For flagging arguments as format strings in MSVC.
+ */
+#if _MSC_VER >= 1400
+ #include <sal.h>
+ #if _MSC_VER > 1400
+  #define FORMAT_STRING(p) _Printf_format_string_ p
+ #else
+  #define FORMAT_STRING(p) __format_string p
+ #endif
+#else
+ #define FORMAT_STRING(p) p
+#endif
+
+#endif /* lib_funcattrs_h */
index fb385fb9c5cd01cdabd88169552bab2388c936eb..9af1ca17bfc715383b9bbacc506f2bb84e54749e 100644 (file)
@@ -394,6 +394,11 @@ struct in6_addr {
  * end of Apple deprecation workaround macros
  */
 
+/*
+ * Function attributes, for various compilers.
+ */
+#include "funcattrs.h"
+
 #ifndef min
 #define min(a,b) ((a)>(b)?(b):(a))
 #endif
index 385e253bf2bf155a75e4690bcaddcb70d409b156..899e4b620f1d64caf54602ca8d0b808fa4dce525 100644 (file)
@@ -82,19 +82,13 @@ extern int32_t thiszone;    /* seconds offset from gmt to local time */
 extern const char istr[];
 
 #if !defined(HAVE_SNPRINTF)
-int snprintf (char *str, size_t sz, const char *format, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 3, 4)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
+int snprintf (char *str, size_t sz, FORMAT_STRING(const char *format), ...)
+     PRINTFLIKE(3, 4);
 #endif /* !defined(HAVE_SNPRINTF) */
 
 #if !defined(HAVE_VSNPRINTF)
-int vsnprintf (char *str, size_t sz, const char *format, va_list ap)
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 3, 0)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
+int vsnprintf (char *str, size_t sz, FORMAT_STRING(const char *format),
+     va_list ap) PRINTFLIKE(3, 0);
 #endif /* !defined(HAVE_VSNPRINTF) */
 
 #ifndef HAVE_STRLCAT
diff --git a/print.c b/print.c
index fb62e15c202880ea90b2e41275bffcf9034df760..15468d6f7b30b4e6f896580980c024a5aa2309fd 100644 (file)
--- a/print.c
+++ b/print.c
@@ -226,23 +226,16 @@ static const struct printer printers[] = {
 static void    ndo_default_print(netdissect_options *ndo, const u_char *bp,
                    u_int length);
 
-static void    ndo_error(netdissect_options *ndo, const char *fmt, ...)
-                   __attribute__((noreturn))
-#ifdef __ATTRIBUTE___FORMAT_OK
-                   __attribute__((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                   ;
-static void    ndo_warning(netdissect_options *ndo, const char *fmt, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-                   __attribute__((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                   ;
-
-static int     ndo_printf(netdissect_options *ndo, const char *fmt, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-                    __attribute ((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                    ;
+static void    ndo_error(netdissect_options *ndo,
+                   FORMAT_STRING(const char *fmt), ...)
+                   NORETURN PRINTFLIKE(2, 3);
+static void    ndo_warning(netdissect_options *ndo,
+                   FORMAT_STRING(const char *fmt), ...)
+                   PRINTFLIKE(2, 3);
+
+static int     ndo_printf(netdissect_options *ndo,
+                    FORMAT_STRING(const char *fmt), ...)
+                    PRINTFLIKE(2, 3);
 
 void
 init_print(netdissect_options *ndo, uint32_t localnet, uint32_t mask,
index 01bd7522c05f591bd250a75bf42447c6945d7381..86ccc50c9c27139aa2bb03a09159e1a782d52215 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -185,26 +185,17 @@ cap_channel_t *capdns;
 #endif
 
 /* Forwards */
-static void error(const char *, ...)
-     __attribute__((noreturn))
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void warning(const char *, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void exit_tcpdump(int) __attribute__((noreturn));
+static void error(FORMAT_STRING(const char *), ...) NORETURN PRINTFLIKE(1, 2);
+static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
+static void exit_tcpdump(int) NORETURN;
 static RETSIGTYPE cleanup(int);
 static RETSIGTYPE child_cleanup(int);
 static void print_version(void);
 static void print_usage(void);
-static void show_tstamp_types_and_exit(pcap_t *, const char *device) __attribute__((noreturn));
-static void show_dlts_and_exit(pcap_t *, const char *device) __attribute__((noreturn));
+static void show_tstamp_types_and_exit(pcap_t *, const char *device) NORETURN;
+static void show_dlts_and_exit(pcap_t *, const char *device) NORETURN;
 #ifdef HAVE_PCAP_FINDALLDEVS
-static void show_devices_and_exit (void) __attribute__((noreturn));
+static void show_devices_and_exit (void) NORETURN;
 #endif
 
 static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);