libmicrohttpd

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

test_str_bin_hex.c (21511B)


      1 /*
      2   This file is part of libmicrohttpd
      3   Copyright (C) 2022 Karlson2k (Evgeny Grin)
      4 
      5   This test tool is free software; you can redistribute it and/or
      6   modify it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 2, or
      8   (at your option) any later version.
      9 
     10   This test tool 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; if not, write to the Free Software
     17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18 */
     19 
     20 /**
     21  * @file microhttpd/test_str_bin_hex.c
     22  * @brief  Unit tests for hex strings <-> binary data processing
     23  * @author Karlson2k (Evgeny Grin)
     24  */
     25 
     26 #include "mhd_options.h"
     27 #include <string.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include "mhd_str.h"
     31 #include "mhd_assert.h"
     32 
     33 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     34    test into a marked, classifiable test error (TESTING.md, P5). */
     35 #include "mhd_panic_tripwire.h"
     36 
     37 #ifndef MHD_STATICSTR_LEN_
     38 /**
     39  * Determine length of static string / macro strings at compile time.
     40  */
     41 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
     42 #endif /* ! MHD_STATICSTR_LEN_ */
     43 
     44 
     45 static char tmp_bufs[4][4 * 1024]; /* should be enough for testing */
     46 static size_t buf_idx = 0;
     47 
     48 /* print non-printable chars as char codes */
     49 static char *
     50 n_prnt (const char *str, size_t len)
     51 {
     52   static char *buf;  /* should be enough for testing */
     53   static const size_t buf_size = sizeof(tmp_bufs[0]);
     54   size_t r_pos = 0;
     55   size_t w_pos = 0;
     56   if (++buf_idx >= (sizeof(tmp_bufs) / sizeof(tmp_bufs[0])))
     57     buf_idx = 0;
     58   buf = tmp_bufs[buf_idx];
     59 
     60   while (len > r_pos && w_pos + 1 < buf_size)
     61   {
     62     const unsigned char c = (unsigned char) str[r_pos];
     63     if ((c == '\\') || (c == '"') )
     64     {
     65       if (w_pos + 2 >= buf_size)
     66         break;
     67       buf[w_pos++] = '\\';
     68       buf[w_pos++] = (char) c;
     69     }
     70     else if ((c >= 0x20) && (c <= 0x7E) )
     71       buf[w_pos++] = (char) c;
     72     else
     73     {
     74       if (w_pos + 4 >= buf_size)
     75         break;
     76       if (snprintf (buf + w_pos, buf_size - w_pos, "\\x%02hX", (short unsigned
     77                                                                 int) c) != 4)
     78         break;
     79       w_pos += 4;
     80     }
     81     r_pos++;
     82   }
     83 
     84   if (len != r_pos)
     85   {   /* not full string is printed */
     86       /* enough space for "..." ? */
     87     if (w_pos + 3 > buf_size)
     88       w_pos = buf_size - 4;
     89     buf[w_pos++] = '.';
     90     buf[w_pos++] = '.';
     91     buf[w_pos++] = '.';
     92   }
     93   buf[w_pos] = 0;
     94   return buf;
     95 }
     96 
     97 
     98 #define TEST_BIN_MAX_SIZE (2 * 1024)
     99 
    100 /* return zero if succeed, number of failures otherwise */
    101 static unsigned int
    102 expect_decoded_n (const char *const hex, const size_t hex_len,
    103                   const uint8_t *const bin, const size_t bin_size,
    104                   const unsigned int line_num)
    105 {
    106   static const char fill_chr = '#';
    107   static char buf[TEST_BIN_MAX_SIZE];
    108   size_t res_size;
    109   unsigned int ret;
    110 
    111   mhd_assert (NULL != hex);
    112   mhd_assert (NULL != bin);
    113   mhd_assert (TEST_BIN_MAX_SIZE > bin_size + 1);
    114   mhd_assert (TEST_BIN_MAX_SIZE > hex_len + 1);
    115   mhd_assert (hex_len >= bin_size);
    116   mhd_assert (1 >= hex_len || hex_len > bin_size);
    117 
    118   ret = 0;
    119 
    120   /* check MHD_hex_to_bin() */
    121   if (1)
    122   {
    123     unsigned int check_res = 0;
    124 
    125     memset (buf, fill_chr, sizeof(buf)); /* Fill buffer with some character */
    126     res_size = MHD_hex_to_bin (hex, hex_len, buf);
    127     if (res_size != bin_size)
    128     {
    129       check_res = 1;
    130       fprintf (stderr,
    131                "'MHD_hex_to_bin ()' FAILED: "
    132                "Wrong returned value:\n");
    133     }
    134     else
    135     {
    136       if ((0 != bin_size) &&
    137           (0 != memcmp (buf, bin, bin_size)))
    138       {
    139         check_res = 1;
    140         fprintf (stderr,
    141                  "'MHD_hex_to_bin ()' FAILED: "
    142                  "Wrong output data:\n");
    143       }
    144     }
    145     if (((0 == res_size) && (fill_chr != buf[bin_size]))
    146         || ((0 != res_size) && (fill_chr != buf[res_size])))
    147     {
    148       check_res = 1;
    149       fprintf (stderr,
    150                "'MHD_hex_to_bin ()' FAILED: "
    151                "A char written outside the buffer:\n");
    152     }
    153     if (0 != check_res)
    154     {
    155       ret++;
    156       fprintf (stderr,
    157                "\tRESULT  : MHD_hex_to_bin (\"%s\", %u, "
    158                "->\"%s\") -> %u\n",
    159                n_prnt (hex, hex_len), (unsigned) hex_len,
    160                n_prnt (buf, res_size),
    161                (unsigned) res_size);
    162       fprintf (stderr,
    163                "\tEXPECTED: MHD_hex_to_bin (\"%s\", %u, "
    164                "->\"%s\") -> %u\n",
    165                n_prnt (hex, hex_len), (unsigned) hex_len,
    166                n_prnt ((const char *) bin, bin_size),
    167                (unsigned) bin_size);
    168     }
    169   }
    170 
    171   /* check MHD_bin_to_hex() */
    172   if (0 == hex_len % 2)
    173   {
    174     unsigned int check_res = 0;
    175 
    176     memset (buf, fill_chr, sizeof(buf)); /* Fill buffer with some character */
    177     res_size = MHD_bin_to_hex_z (bin, bin_size, buf);
    178 
    179     if (res_size != hex_len)
    180     {
    181       check_res = 1;
    182       fprintf (stderr,
    183                "'MHD_bin_to_hex ()' FAILED: "
    184                "Wrong returned value:\n");
    185     }
    186     else
    187     {
    188       if ((0 != hex_len) &&
    189           (! MHD_str_equal_caseless_bin_n_ (buf, hex, hex_len)))
    190       {
    191         check_res = 1;
    192         fprintf (stderr,
    193                  "'MHD_bin_to_hex ()' FAILED: "
    194                  "Wrong output string:\n");
    195       }
    196     }
    197     if (fill_chr != buf[res_size + 1])
    198     {
    199       check_res = 1;
    200       fprintf (stderr,
    201                "'MHD_bin_to_hex ()' FAILED: "
    202                "A char written outside the buffer:\n");
    203     }
    204     if (0 != buf[res_size])
    205     {
    206       check_res = 1;
    207       fprintf (stderr,
    208                "'MHD_bin_to_hex ()' FAILED: "
    209                "The result is not zero-terminated:\n");
    210     }
    211     if (0 != check_res)
    212     {
    213       ret++;
    214       fprintf (stderr,
    215                "\tRESULT  : MHD_bin_to_hex (\"%s\", %u, "
    216                "->\"%s\") -> %u\n",
    217                n_prnt ((const char *) bin, bin_size), (unsigned) bin_size,
    218                n_prnt (buf, res_size),
    219                (unsigned) res_size);
    220       fprintf (stderr,
    221                "\tEXPECTED: MHD_bin_to_hex (\"%s\", %u, "
    222                "->(lower case)\"%s\") -> %u\n",
    223                n_prnt ((const char *) bin, bin_size), (unsigned) bin_size,
    224                n_prnt (hex, hex_len),
    225                (unsigned) bin_size);
    226     }
    227   }
    228 
    229   if (0 != ret)
    230   {
    231     fprintf (stderr,
    232              "The check is at line: %u\n\n", line_num);
    233   }
    234   return ret;
    235 }
    236 
    237 
    238 #define expect_decoded_arr(h,a) \
    239         expect_decoded_n(h,MHD_STATICSTR_LEN_(h),\
    240                          a,(sizeof(a)/sizeof(a[0])), \
    241                          __LINE__)
    242 
    243 static unsigned int
    244 check_decode_bin (void)
    245 {
    246   unsigned int r = 0; /**< The number of errors */
    247 
    248   if (1)
    249   {
    250     static const uint8_t bin[256] =
    251     {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe,
    252      0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
    253      0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
    254      0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
    255      0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
    256      0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
    257      0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
    258      0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
    259      0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
    260      0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
    261      0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
    262      0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
    263      0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
    264      0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
    265      0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
    266      0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
    267      0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
    268      0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
    269      0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
    270      0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2,
    271      0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
    272      0xff };
    273     /* The lower case */
    274     r += expect_decoded_arr ("000102030405060708090a0b0c0d0e" \
    275                              "0f101112131415161718191a1b1c1d" \
    276                              "1e1f202122232425262728292a2b2c" \
    277                              "2d2e2f303132333435363738393a3b" \
    278                              "3c3d3e3f404142434445464748494a" \
    279                              "4b4c4d4e4f50515253545556575859" \
    280                              "5a5b5c5d5e5f606162636465666768" \
    281                              "696a6b6c6d6e6f7071727374757677" \
    282                              "78797a7b7c7d7e7f80818283848586" \
    283                              "8788898a8b8c8d8e8f909192939495" \
    284                              "969798999a9b9c9d9e9fa0a1a2a3a4" \
    285                              "a5a6a7a8a9aaabacadaeafb0b1b2b3" \
    286                              "b4b5b6b7b8b9babbbcbdbebfc0c1c2" \
    287                              "c3c4c5c6c7c8c9cacbcccdcecfd0d1" \
    288                              "d2d3d4d5d6d7d8d9dadbdcdddedfe0" \
    289                              "e1e2e3e4e5e6e7e8e9eaebecedeeef" \
    290                              "f0f1f2f3f4f5f6f7f8f9fafbfcfdfe" \
    291                              "ff", bin);
    292   }
    293 
    294   if (1)
    295   {
    296     static const uint8_t bin[256] =
    297     {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe,
    298      0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
    299      0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
    300      0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
    301      0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
    302      0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
    303      0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
    304      0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
    305      0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
    306      0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
    307      0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
    308      0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
    309      0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
    310      0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
    311      0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
    312      0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
    313      0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
    314      0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
    315      0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
    316      0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2,
    317      0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
    318      0xff };
    319     /* The upper case */
    320     r += expect_decoded_arr ("000102030405060708090A0B0C0D0E" \
    321                              "0F101112131415161718191A1B1C1D" \
    322                              "1E1F202122232425262728292A2B2C" \
    323                              "2D2E2F303132333435363738393A3B" \
    324                              "3C3D3E3F404142434445464748494A" \
    325                              "4B4C4D4E4F50515253545556575859" \
    326                              "5A5B5C5D5E5F606162636465666768" \
    327                              "696A6B6C6D6E6F7071727374757677" \
    328                              "78797A7B7C7D7E7F80818283848586" \
    329                              "8788898A8B8C8D8E8F909192939495" \
    330                              "969798999A9B9C9D9E9FA0A1A2A3A4" \
    331                              "A5A6A7A8A9AAABACADAEAFB0B1B2B3" \
    332                              "B4B5B6B7B8B9BABBBCBDBEBFC0C1C2" \
    333                              "C3C4C5C6C7C8C9CACBCCCDCECFD0D1" \
    334                              "D2D3D4D5D6D7D8D9DADBDCDDDEDFE0" \
    335                              "E1E2E3E4E5E6E7E8E9EAEBECEDEEEF" \
    336                              "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" \
    337                              "FF", bin);
    338   }
    339   if (1)
    340   {
    341     static const uint8_t bin[3] =
    342     {0x1, 0x2, 0x3};
    343     r += expect_decoded_arr ("010203", bin);
    344   }
    345   if (1)
    346   {
    347     static const uint8_t bin[3] =
    348     {0x1, 0x2, 0x3};
    349     r += expect_decoded_arr ("10203", bin);
    350   }
    351   if (1)
    352   {
    353     static const uint8_t bin[1] =
    354     {0x1};
    355     r += expect_decoded_arr ("01", bin);
    356   }
    357   if (1)
    358   {
    359     static const uint8_t bin[1] =
    360     {0x1};
    361     r += expect_decoded_arr ("1", bin);
    362   }
    363 
    364   return r;
    365 }
    366 
    367 
    368 /* return zero if succeed, number of failures otherwise */
    369 static unsigned int
    370 expect_failed_n (const char *const hex, const size_t hex_len,
    371                  const unsigned int line_num)
    372 {
    373   static const char fill_chr = '#';
    374   static char buf[TEST_BIN_MAX_SIZE];
    375   size_t res_size;
    376   unsigned int ret;
    377 
    378   mhd_assert (NULL != hex);
    379   mhd_assert (TEST_BIN_MAX_SIZE > hex_len + 1);
    380 
    381   ret = 0;
    382 
    383   /* check MHD_hex_to_bin() */
    384   if (1)
    385   {
    386     unsigned int check_res = 0;
    387 
    388     memset (buf, fill_chr, sizeof(buf)); /* Fill buffer with some character */
    389     res_size = MHD_hex_to_bin (hex, hex_len, buf);
    390     if (res_size != 0)
    391     {
    392       check_res = 1;
    393       fprintf (stderr,
    394                "'MHD_hex_to_bin ()' FAILED: "
    395                "Wrong returned value:\n");
    396     }
    397     if (0 != check_res)
    398     {
    399       ret++;
    400       fprintf (stderr,
    401                "\tRESULT  : MHD_hex_to_bin (\"%s\", %u, "
    402                "->\"%s\") -> %u\n",
    403                n_prnt (hex, hex_len), (unsigned) hex_len,
    404                n_prnt (buf, res_size),
    405                (unsigned) res_size);
    406       fprintf (stderr,
    407                "\tEXPECTED: MHD_hex_to_bin (\"%s\", %u, "
    408                "->(not defined)) -> 0\n",
    409                n_prnt (hex, hex_len), (unsigned) hex_len);
    410     }
    411   }
    412 
    413   if (0 != ret)
    414   {
    415     fprintf (stderr,
    416              "The check is at line: %u\n\n", line_num);
    417   }
    418   return ret;
    419 }
    420 
    421 
    422 #define expect_failed(h) \
    423         expect_failed_n(h,MHD_STATICSTR_LEN_(h), \
    424                          __LINE__)
    425 
    426 
    427 static unsigned int
    428 check_broken_str (void)
    429 {
    430   unsigned int r = 0; /**< The number of errors */
    431 
    432   r += expect_failed ("abcx");
    433   r += expect_failed ("X");
    434   r += expect_failed ("!");
    435   r += expect_failed ("01z");
    436   r += expect_failed ("0z");
    437   r += expect_failed ("00z");
    438   r += expect_failed ("000Y");
    439 
    440   return r;
    441 }
    442 
    443 
    444 /**
    445  * The maximum length of the hexadecimal input used by the exact-sized
    446  * output buffer checks.
    447  */
    448 #define TEST_EXACT_MAX_HEX_LEN 320
    449 
    450 /**
    451  * The number of the guard bytes placed right after the output buffer.
    452  */
    453 #define TEST_GUARD_SIZE 8
    454 
    455 /**
    456  * The value used to fill the guard bytes.
    457  */
    458 #define TEST_GUARD_CHR 0x5A
    459 
    460 /**
    461  * Check that MHD_hex_to_bin() writes no more than the documented number of
    462  * the output bytes, which is ((@a hex_len + 1) / 2).
    463  *
    464  * Every caller of MHD_hex_to_bin() must size the output buffer by that
    465  * formula.  A caller that sizes the buffer by the expected size of the
    466  * decoded value instead (like the digest authentication 'response' check
    467  * used to do) can be overflown by simply sending a longer hexadecimal
    468  * string, therefore this contract is checked here with buffers that have
    469  * no slack at all:
    470  * - an exactly-sized heap allocation, so that a run-time memory checker
    471  *   (ASAN, valgrind) traps any out-of-bounds write immediately, and
    472  * - an allocation with a known guard pattern right after the output area,
    473  *   so that the overflow is detected even without any such tool.
    474  *
    475  * @param hex the input string with hexadecimal digits
    476  * @param hex_len the length of @a hex
    477  * @param must_succeed non-zero if the decoding is expected to succeed
    478  * @param line_num the line number to report in case of failure
    479  * @return zero if succeed, number of failures otherwise
    480  */
    481 static unsigned int
    482 expect_exact_dest_n (const char *const hex,
    483                      const size_t hex_len,
    484                      const int must_succeed,
    485                      const unsigned int line_num)
    486 {
    487   const size_t max_out_size = (hex_len + 1) / 2;
    488   const size_t expected_size = must_succeed ? max_out_size : 0;
    489   uint8_t *buf;
    490   size_t res_size;
    491   size_t i;
    492   unsigned int ret;
    493 
    494   ret = 0;
    495 
    496   /* (1) The exactly-sized output buffer. */
    497   buf = (uint8_t *) malloc (0 != max_out_size ? max_out_size : 1);
    498   if (NULL == buf)
    499   {
    500     fprintf (stderr, "malloc() failed. Line: %u\n", line_num);
    501     return 1;
    502   }
    503   res_size = MHD_hex_to_bin (hex, hex_len, buf);
    504   free (buf);
    505   if (res_size != expected_size)
    506   {
    507     ret++;
    508     fprintf (stderr,
    509              "'MHD_hex_to_bin ()' FAILED: "
    510              "Wrong returned value with the exactly-sized buffer:\n");
    511     fprintf (stderr,
    512              "\tRESULT  : MHD_hex_to_bin (\"%s\", %u, ...) -> %u\n",
    513              n_prnt (hex, hex_len), (unsigned) hex_len,
    514              (unsigned) res_size);
    515     fprintf (stderr,
    516              "\tEXPECTED: MHD_hex_to_bin (\"%s\", %u, ...) -> %u\n",
    517              n_prnt (hex, hex_len), (unsigned) hex_len,
    518              (unsigned) expected_size);
    519   }
    520 
    521   /* (2) The output buffer followed by the guard bytes. */
    522   buf = (uint8_t *) malloc (max_out_size + TEST_GUARD_SIZE);
    523   if (NULL == buf)
    524   {
    525     fprintf (stderr, "malloc() failed. Line: %u\n", line_num);
    526     return ret + 1;
    527   }
    528   memset (buf, TEST_GUARD_CHR, max_out_size + TEST_GUARD_SIZE);
    529   res_size = MHD_hex_to_bin (hex, hex_len, buf);
    530   if (res_size > max_out_size)
    531   {
    532     ret++;
    533     fprintf (stderr,
    534              "'MHD_hex_to_bin ()' FAILED: "
    535              "Returned value is larger than the documented maximum "
    536              "output size: %u > %u\n",
    537              (unsigned) res_size, (unsigned) max_out_size);
    538   }
    539   for (i = 0; i < TEST_GUARD_SIZE; ++i)
    540   {
    541     if (TEST_GUARD_CHR != buf[max_out_size + i])
    542     {
    543       ret++;
    544       fprintf (stderr,
    545                "'MHD_hex_to_bin ()' FAILED: "
    546                "The guard byte number %u (of %u) after the output buffer "
    547                "has been overwritten:\n",
    548                (unsigned) i, (unsigned) TEST_GUARD_SIZE);
    549       fprintf (stderr,
    550                "\tINPUT   : MHD_hex_to_bin (\"%s\", %u, ...), "
    551                "the maximum output size is %u\n",
    552                n_prnt (hex, hex_len), (unsigned) hex_len,
    553                (unsigned) max_out_size);
    554       break;
    555     }
    556   }
    557   free (buf);
    558 
    559   if (0 != ret)
    560   {
    561     fprintf (stderr,
    562              "The check is at line: %u\n\n", line_num);
    563   }
    564   return ret;
    565 }
    566 
    567 
    568 #define expect_exact_dest(h,ms) \
    569         expect_exact_dest_n (h, MHD_STATICSTR_LEN_ (h), ms, __LINE__)
    570 
    571 
    572 /**
    573  * Check the output size contract of MHD_hex_to_bin() for every input length
    574  * up to #TEST_EXACT_MAX_HEX_LEN, for valid and for broken input.
    575  *
    576  * @return zero if succeed, number of failures otherwise
    577  */
    578 static unsigned int
    579 check_exact_dest_buffer (void)
    580 {
    581   static const char hex_digits[] = "0123456789abcdefABCDEF";
    582   static char hex[TEST_EXACT_MAX_HEX_LEN + 1];
    583   unsigned int r = 0; /**< The number of errors */
    584   size_t len;
    585 
    586   for (len = 0; len < sizeof(hex) - 1; ++len)
    587     hex[len] = hex_digits[len % (sizeof(hex_digits) - 1)];
    588   hex[sizeof(hex) - 1] = 0;
    589 
    590   /* Valid input of every length, including the odd lengths for which
    591      an extra leading zero is assumed and therefore one more byte is
    592      written than (hex_len / 2). */
    593   for (len = 0; len <= TEST_EXACT_MAX_HEX_LEN; ++len)
    594     r += expect_exact_dest_n (hex, len, 1, __LINE__);
    595 
    596   /* Broken input: a non-hexadecimal character at every possible position.
    597      The decoding fails, but the bytes decoded before the broken character
    598      have already been written and must still fit into the output buffer. */
    599   for (len = 1; len <= 64; ++len)
    600   {
    601     size_t pos;
    602 
    603     for (pos = 0; pos < len; ++pos)
    604     {
    605       const char saved = hex[pos];
    606 
    607       hex[pos] = 'z';
    608       r += expect_exact_dest_n (hex, len, 0, __LINE__);
    609       hex[pos] = saved;
    610     }
    611   }
    612 
    613   /* The lengths that matter for the HTTP Digest authentication code:
    614      twice the digest size is the largest input any caller may accept. */
    615   r += expect_exact_dest ("00112233445566778899aabbccddeeff", 1); /* MD5 */
    616   r += expect_exact_dest ("00112233445566778899aabbccddeeff"
    617                           "00112233445566778899aabbccddeeff", 1); /* SHA-256 */
    618   /* Twice as long as the largest supported digest: a caller that sizes the
    619      output buffer by the digest size only would be overflown here. */
    620   r += expect_exact_dest ("00112233445566778899aabbccddeeff"
    621                           "00112233445566778899aabbccddeeff"
    622                           "00112233445566778899aabbccddeeff"
    623                           "00112233445566778899aabbccddeeff", 1);
    624 
    625   return r;
    626 }
    627 
    628 
    629 int
    630 main (int argc, char *argv[])
    631 {
    632   unsigned int errcount = 0;
    633   (void) argc; (void) argv; /* Unused. Silent compiler warning. */
    634   errcount += check_decode_bin ();
    635   errcount += check_broken_str ();
    636   errcount += check_exact_dest_buffer ();
    637   if (0 == errcount)
    638     printf ("All tests have been passed without errors.\n");
    639   return errcount == 0 ? 0 : 1;
    640 }