Просмотр исходного кода

Implemented basement to work with unaligned data

Evgeny Grin (Karlson2k) 4 лет назад
Родитель
Сommit
89387e53fe
4 измененных файлов с 168 добавлено и 17 удалено
  1. 50 0
      configure.ac
  2. 8 8
      src/microhttpd/Makefile.am
  3. 75 0
      src/microhttpd/mhd_align.h
  4. 35 9
      src/microhttpd/mhd_bithelpers.h

+ 50 - 0
configure.ac

@@ -307,6 +307,56 @@ AS_IF([[test "x$inln_prfx" != "xnone"]],
 AC_MSG_RESULT([[$inln_prfx]])
 CFLAGS="$save_CFLAGS"
 
+AC_CHECK_HEADERS([stdalign.h], [], [], [AC_INCLUDES_DEFAULT])
+AC_CACHE_CHECK([[for C11 'alignof()' support]], [[mhd_cv_c_alignof]],
+  [AC_COMPILE_IFELSE(
+     [AC_LANG_PROGRAM(
+        [[
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#endif
+        ]], [[
+#if (defined (__GNUC__) && __GNUC__ < 4 && __GNUC_MINOR__ < 9 && ! defined(__clang__)) || \
+    (defined (__clang__) && __clang_major__ < 8)
+/* GCC before 4.9 and clang before 8.0 have incorrect implementation of 'alignof()'
+   which returns preferred alignment instead of minimal required alignment */    
+#error Compiler has incorrect implementation of alignof()
+choke me now
+#endif
+          int var1[(alignof(int) >= 2) ? 1 : -1];
+          int var2[alignof(unsigned int) - 1];
+          int var3[(alignof(char) > 0) ? 1 : -1];
+          int var4[(alignof(long) >= 4) ? 1 : -1];
+          
+          /* Mute compiler warnings */
+          var1[0] = var2[0] = var3[0] = 0;
+          var4[0] = 1;
+          if (var1[0] + var2[0] + var3[0] == var4[0])
+            return 1;
+        ]])
+     ], [
+          AC_COMPILE_IFELSE(
+		    [AC_LANG_PROGRAM(
+		        [[
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#endif
+		        ]], [[
+		          /* Should fail if 'alignof()' works */
+		          int var1[alignof(nonexisting_type) - 1];
+		          
+		          /* Mute compiler warnings */
+		          var1[0] = 1;
+		          if (var1[0] + 1 == 1)
+		            return 1;
+		        ]])
+		    ], [[mhd_cv_c_alignof='no']], [[mhd_cv_c_alignof='yes']])
+        ], [[mhd_cv_c_alignof='no']])
+  ])
+AS_VAR_IF([mhd_cv_c_alignof], ["yes"],
+  [AC_DEFINE([[HAVE_C_ALIGNOF]], [1], [Define to 1 if your compiler supports 'alignof()'])])
+
+
 # Check system type
 shutdown_trig_select='no'
 AC_MSG_CHECKING([[for target host OS]])

+ 8 - 8
src/microhttpd/Makefile.am

@@ -59,7 +59,7 @@ libmicrohttpd_la_SOURCES = \
   internal.c internal.h \
   memorypool.c memorypool.h \
   mhd_mono_clock.c mhd_mono_clock.h \
-  mhd_limits.h mhd_byteorder.h \
+  mhd_limits.h \
   sysfdsetsize.c sysfdsetsize.h \
   mhd_str.c mhd_str.h \
   mhd_send.h mhd_send.c \
@@ -138,7 +138,7 @@ endif
 if ENABLE_DAUTH
 libmicrohttpd_la_SOURCES += \
   digestauth.c \
-  mhd_bithelpers.h \
+  mhd_bithelpers.h mhd_byteorder.h mhd_align.h \
   md5.c md5.h \
   sha256.c sha256.h
 endif
@@ -345,13 +345,13 @@ test_shutdown_poll_ignore_LDADD = \
 endif
 
 test_str_compare_SOURCES = \
-  test_str.c test_helpers.h mhd_str.c
+  test_str.c test_helpers.h mhd_str.c mhd_str.h
 
 test_str_to_value_SOURCES = \
-  test_str.c test_helpers.h mhd_str.c
+  test_str.c test_helpers.h mhd_str.c mhd_str.h
 
 test_str_token_SOURCES = \
-  test_str_token.c mhd_str.c
+  test_str_token.c mhd_str.c mhd_str.h
 
 test_http_reasons_SOURCES = \
   test_http_reasons.c \
@@ -359,15 +359,15 @@ test_http_reasons_SOURCES = \
 
 test_md5_SOURCES = \
   test_md5.c test_helpers.h \
-  md5.c md5.h mhd_bithelpers.h
+  md5.c md5.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
 
 test_sha256_SOURCES = \
   test_sha256.c test_helpers.h \
-  sha256.c sha256.h mhd_bithelpers.h
+  sha256.c sha256.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
 
 test_sha1_SOURCES = \
   test_sha1.c test_helpers.h \
-  sha1.c sha1.h mhd_bithelpers.h
+  sha1.c sha1.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
 
 test_options_SOURCES = \
   test_options.c

+ 75 - 0
src/microhttpd/mhd_align.h

@@ -0,0 +1,75 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2021 Karlson2k (Evgeny Grin)
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library.
+  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/mhd_align.h
+ * @brief  types alignment macros
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_ALIGN_H
+#define MHD_ALIGN_H 1
+
+#include <stdint.h>
+#include "mhd_options.h"
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_C_ALIGNOF
+
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#endif
+
+#define _MHD_ALIGNOF(type) alignof(type)
+
+#endif /* HAVE_C_ALIGNOF */
+
+#ifdef offsetof
+#define _MHD_OFFSETOF(strct, membr) offsetof(strct, membr)
+#else  /* ! offsetof */
+#define _MHD_OFFSETOF(strct, membr) (size_t)(((char*)&(((strct*)0)->membr)) - \
+                                     ((char*)((strct*)0)))
+#endif /* ! offsetof */
+
+/* Provide a limited set of alignment macros */
+/* The set could be extended as needed */
+#ifdef _MHD_ALIGNOF
+#define _MHD_UINT32_ALIGN _MHD_ALIGNOF(uint32_t)
+#define _MHD_UINT64_ALIGN _MHD_ALIGNOF(uint64_t)
+#else  /* ! _MHD_ALIGNOF */
+struct _mhd_dummy_uint32_offset_test
+{
+  char dummy;
+  uint32_t ui32;
+};
+#define _MHD_UINT32_ALIGN \
+  _MHD_OFFSETOF(struct _mhd_dummy_uint32_offset_test, ui32)
+
+struct _mhd_dummy_uint64_offset_test
+{
+  char dummy;
+  uint32_t ui64;
+};
+#define _MHD_UINT32_ALIGN \
+  _MHD_OFFSETOF(struct _mhd_dummy_uint64_offset_test, ui64)
+#endif /* ! _MHD_ALIGNOF */
+
+#endif /* ! MHD_ALIGN_H */

+ 35 - 9
src/microhttpd/mhd_bithelpers.h

@@ -32,8 +32,13 @@
 /* Declarations for VC & Clang/C2 built-ins */
 #include <intrin.h>
 #endif /* _MSC_FULL_VER  */
+#include "mhd_options.h"
 #include "mhd_assert.h"
 #include "mhd_byteorder.h"
+#if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN || _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
+#include "mhd_align.h"
+#endif /* _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN ||
+          _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
 
 #ifndef __has_builtin
 /* Avoid precompiler errors with non-clang */
@@ -158,15 +163,8 @@
  * put native-endian 64-bit value64 to addr
  * in big-endian mode.
  */
-#if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
-#define _MHD_PUT_64BIT_BE(addr, value64)             \
-  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
-#elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
-#define _MHD_PUT_64BIT_BE(addr, value64)             \
-  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
-#else  /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
-/* Endianness was not detected or non-standard like PDP-endian */
-#define _MHD_PUT_64BIT_BE(addr, value64) do {                            \
+/* Slow version that works with unaligned addr and with any bytes order */
+#define _MHD_PUT_64BIT_BE_SLOW(addr, value64) do {                       \
     ((uint8_t*) (addr))[7] = (uint8_t) ((uint64_t) (value64));           \
     ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 8);    \
     ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 16);   \
@@ -176,8 +174,32 @@
     ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 48);   \
     ((uint8_t*) (addr))[0] = (uint8_t) (((uint64_t) (value64)) >> 56);   \
 } while (0)
+#if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
+#define _MHD_PUT_64BIT_BE(addr, value64)             \
+  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
+#elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
+#define _MHD_PUT_64BIT_BE(addr, value64)             \
+  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
+#else  /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
+/* Endianness was not detected or non-standard like PDP-endian */
+#define _MHD_PUT_64BIT_BE(addr, value64) _MHD_PUT_64BIT_BE_SLOW(addr, value64)
+/* Indicate that _MHD_PUT_64BIT_BE does not need aligned pointer */
+#define _MHD_PUT_64BIT_BE_UNALIGNED 1
 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
 
+/* Put result safely to unaligned address */
+_MHD_static_inline void
+_MHD_PUT_64BIT_BE_SAFE (void *dst, uint64_t value)
+{
+#ifndef _MHD_PUT_64BIT_BE_UNALIGNED
+  if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN))
+    _MHD_PUT_64BIT_BE_SLOW (dst, value);
+  else
+#endif /* _MHD_BYTE_ORDER_IS_BIG_OR_LITTLE_ENDIAN */
+  _MHD_PUT_64BIT_BE (dst, value);
+}
+
+
 /* _MHD_PUT_32BIT_BE (addr, value32)
  * put native-endian 32-bit value32 to addr
  * in big-endian mode.
@@ -196,6 +218,8 @@
     ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 16);   \
     ((uint8_t*) (addr))[0] = (uint8_t) (((uint32_t) (value32)) >> 24);   \
 } while (0)
+/* Indicate that _MHD_PUT_32BIT_BE does not need aligned pointer */
+#define _MHD_PUT_32BIT_BE_UNALIGNED 1
 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
 
 /* _MHD_GET_32BIT_BE (addr)
@@ -215,6 +239,8 @@
     | (((uint32_t) (((const uint8_t*) addr)[1])) << 16)   \
     | (((uint32_t) (((const uint8_t*) addr)[2])) << 8)    \
     | ((uint32_t) (((const uint8_t*) addr)[3])) )
+/* Indicate that _MHD_GET_32BIT_BE does not need aligned pointer */
+#define _MHD_GET_32BIT_BE_UNALIGNED 1
 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */