libmicrohttpd

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

mhd_check.h (8140B)


      1 /*
      2   This file is part of libmicrohttpd
      3   Copyright (C) 2026 Christian Grothoff
      4 
      5   This library is free software; you can redistribute it and/or
      6   modify it under the terms of the GNU Lesser General Public
      7   License as published by the Free Software Foundation; either
      8   version 2.1 of the License, or (at your option) any later version.
      9 
     10   This library is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13   Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General Public
     16   License along with this library.
     17   If not, see <http://www.gnu.org/licenses/>.
     18 */
     19 
     20 /**
     21  * @file microhttpd/mhd_check.h
     22  * @brief  macros for MHD_CHECK_(), always-compiled memory-safety invariants
     23  * @author Christian Grothoff
     24  *
     25  * mhd_assert() is compiled out in release builds (NDEBUG), which is the right
     26  * thing for the several hundred internal state assertions of this library but
     27  * the wrong thing for the handful of them that stand between attacker-supplied
     28  * data and a memmove()/memcpy()/array index.  For those, an assertion that is
     29  * absent in the shipped build is not a safety net at all.
     30  *
     31  * MHD_CHECK_() is the always-compiled companion for exactly that subset.  It
     32  * does NOT depend on NDEBUG, _DEBUG or --enable-asserts: the test is one
     33  * predictable, well-predicted branch that is present in every build.
     34  *
     35  * RULES FOR USING IT
     36  * ------------------
     37  * 1. Only invariants whose violation would mean memory-unsafe behaviour -
     38  *    pointer/offset arithmetic, buffer bounds, length subtractions that could
     39  *    underflow, indices into fixed-size arrays.  Ordinary state assertions
     40  *    stay mhd_assert().
     41  * 2. Check the *precondition*, not the symptom.  An assertion that compares
     42  *    two pointers after the bad one has already been derived is decoration:
     43  *    it happily passes on a NULL-derived pointer.  Assert what has to be true
     44  *    for the following arithmetic to be defined.  See commit 29eaa56b.
     45  * 3. A failing check must FAIL THE CONNECTION - close it, or reply 4xx/5xx -
     46  *    and must not continue and must not panic.  MHD_PANIC() aborts the whole
     47  *    daemon, which turns a bounded per-connection problem into a global
     48  *    denial of service; that is the opposite of what this is for.
     49  * 4. Deliberately no mhd_assert() inside: a check must behave identically in
     50  *    debug and in release builds, otherwise the debug build stops exercising
     51  *    the recovery path that the release build relies on.
     52  *
     53  * WHERE THE MACROS COME FROM
     54  * --------------------------
     55  * The connection-level macros below expand to the failure exits that
     56  * connection.c already uses - connection_close_error() /
     57  * CONNECTION_CLOSE_ERROR() and transmit_error_response_static() - rather than
     58  * introducing a parallel mechanism.  They are therefore usable only from
     59  * connection.c and only after those helpers have been defined; this header
     60  * intentionally does not include connection.c's internals, the macros are
     61  * expanded at the point of use.
     62  *
     63  * Translation units that have a `struct MHD_Daemon *` at hand (connection.c,
     64  * digestauth.c, postprocessor.c, ...) get a log line through the usual
     65  * MHD_DLOG()/HAVE_MESSAGES machinery; they must include "internal.h" before
     66  * this header.  Translation units without a daemon (memorypool.c, mhd_str.c)
     67  * use the MHD_CHECK_RET_() form, which is silent.
     68  */
     69 
     70 #ifndef MHD_CHECK_H
     71 #define MHD_CHECK_H 1
     72 
     73 #include "mhd_options.h"
     74 
     75 /**
     76  * Branch hint: an invariant violation is by construction the unlikely case.
     77  */
     78 #if defined(__GNUC__) || defined(__clang__)
     79 #  define MHD_CHECK_FAILED_(expr) (__builtin_expect (! (expr), 0))
     80 #else  /* ! __GNUC__ */
     81 #  define MHD_CHECK_FAILED_(expr) (! (expr))
     82 #endif /* ! __GNUC__ */
     83 
     84 /**
     85  * Report a violated invariant through the daemon's log.
     86  *
     87  * @param daemon the daemon to log to
     88  * @param expr_str the stringified invariant that was violated
     89  */
     90 #ifdef HAVE_MESSAGES
     91 #  define MHD_CHECK_LOG_(daemon,expr_str) \
     92         MHD_DLOG (daemon, \
     93                   _ ("Internal invariant violated at %s:%u: (%s). " \
     94                      "Failing the connection.\n"), \
     95                   __FILE__, \
     96                   (unsigned int) __LINE__, \
     97                   expr_str)
     98 #else  /* ! HAVE_MESSAGES */
     99 #  define MHD_CHECK_LOG_(daemon,expr_str) ((void) 0)
    100 #endif /* ! HAVE_MESSAGES */
    101 
    102 
    103 /**
    104  * The generic always-compiled invariant check.
    105  *
    106  * @param daemon the daemon to log to
    107  * @param expr the invariant, must evaluate to true
    108  * @param fail_stmt a single statement to execute when @a expr is false; it
    109  *                  must transfer control out of the current function
    110  *                  (return, goto or break), because execution must not
    111  *                  continue past a violated memory-safety invariant.
    112  *                  When the failure action needs several statements, spell
    113  *                  the check out instead - "if (MHD_CHECK_FAILED_ (expr)) {
    114  *                  MHD_CHECK_LOG_ (daemon, "expr"); ... }" - because a
    115  *                  braced block passed as a macro argument is re-indented
    116  *                  by contrib/uncrustify.cfg
    117  */
    118 #define MHD_CHECK_(daemon,expr,fail_stmt) \
    119         do { \
    120           if (MHD_CHECK_FAILED_ (expr)) \
    121           { \
    122             MHD_CHECK_LOG_ (daemon, #expr); \
    123             fail_stmt; \
    124           } \
    125         } while (0)
    126 
    127 
    128 /**
    129  * Always-compiled invariant check for translation units that have no daemon
    130  * pointer available for logging (memorypool.c, mhd_str.c).  Silent; the
    131  * caller is expected to turn the returned failure value into a log message
    132  * and a failed connection.
    133  *
    134  * @param expr the invariant, must evaluate to true
    135  * @param retval the value to return when @a expr is false
    136  */
    137 #define MHD_CHECK_RET_(expr,retval) \
    138         do { \
    139           if (MHD_CHECK_FAILED_ (expr)) \
    140             return retval; \
    141         } while (0)
    142 
    143 
    144 /**
    145  * Always-compiled invariant check that closes the connection with an error
    146  * and returns @a retval.  For use in connection.c only, and only after
    147  * connection_close_error() has been defined.
    148  *
    149  * @param c the connection to fail
    150  * @param expr the invariant, must evaluate to true
    151  * @param retval the value to return when @a expr is false
    152  */
    153 #define MHD_CHECK_CONN_CLOSE_RET_(c,expr,retval) \
    154         MHD_CHECK_ ((c)->daemon, \
    155                     expr, \
    156                     { \
    157                       connection_close_error ((c), \
    158                                               NULL); \
    159                       return retval; \
    160                     })
    161 
    162 
    163 /**
    164  * Always-compiled invariant check that closes the connection with an error
    165  * and returns from a void function.  For use in connection.c only, and only
    166  * after connection_close_error() has been defined.
    167  *
    168  * @param c the connection to fail
    169  * @param expr the invariant, must evaluate to true
    170  */
    171 #define MHD_CHECK_CONN_CLOSE_RET_VOID_(c,expr) \
    172         MHD_CHECK_ ((c)->daemon, \
    173                     expr, \
    174                     { \
    175                       connection_close_error ((c), \
    176                                               NULL); \
    177                       return; \
    178                     })
    179 
    180 
    181 /**
    182  * Always-compiled invariant check that queues a static error reply for the
    183  * connection and returns @a retval.  For use in connection.c only, and only
    184  * after transmit_error_response_static() has been defined.
    185  *
    186  * @param c the connection to fail
    187  * @param expr the invariant, must evaluate to true
    188  * @param code the HTTP status code to reply with
    189  * @param msg the static message to reply with
    190  * @param retval the value to return when @a expr is false
    191  */
    192 #define MHD_CHECK_CONN_REPLY_RET_(c,expr,code,msg,retval) \
    193         MHD_CHECK_ ((c)->daemon, \
    194                     expr, \
    195                     { \
    196                       transmit_error_response_static ((c), \
    197                                                       (code), \
    198                                                       msg); \
    199                       return retval; \
    200                     })
    201 
    202 #endif /* ! MHD_CHECK_H */