libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 89387e53fe9e5d876fb14f31eac5da7d690290ff
parent 7676e698a95df3825931b48652ff32be012e3a3c
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Tue, 18 May 2021 19:37:10 +0300

Implemented basement to work with unaligned data

Diffstat:
Mconfigure.ac | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/Makefile.am | 16++++++++--------
Asrc/microhttpd/mhd_align.h | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/mhd_bithelpers.h | 44+++++++++++++++++++++++++++++++++++---------
4 files changed, 168 insertions(+), 17 deletions(-)

diff --git a/configure.ac b/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]]) diff --git a/src/microhttpd/Makefile.am b/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 diff --git a/src/microhttpd/mhd_align.h b/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 */ diff --git a/src/microhttpd/mhd_bithelpers.h b/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 */