Coverage Report

Created: 2026-09-04 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httrack/src/htssafe.h
Line
Count
Source
1
/* ------------------------------------------------------------ */
2
/*
3
HTTrack Website Copier, Offline Browser for Windows and Unix
4
Copyright (C) 2014 Xavier Roche and other contributors
5
6
SPDX-License-Identifier: GPL-3.0-or-later
7
8
This program is free software: you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation, either version 3 of the License, or
11
(at your option) any later version.
12
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
Ethical use: we kindly ask that you NOT use this software to harvest email
22
addresses or to collect any other private information about people. Doing so
23
would dishonor our work and waste the many hours we have spent on it.
24
25
Please visit our Website: http://www.httrack.com
26
*/
27
28
/* ------------------------------------------------------------ */
29
/* File: htssafe.h safe strings operations, and asserts         */
30
/* Author: Xavier Roche                                         */
31
/* ------------------------------------------------------------ */
32
33
#ifndef HTSSAFE_DEFH
34
#define HTSSAFE_DEFH
35
36
#include <stdarg.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "htsglobal.h"
42
43
/**
44
 * Emergency logging.
45
 * Default is to use libhttrack one.
46
 */
47
#if (!defined(HTSSAFE_ABORT_FUNCTION) && defined(LIBHTTRACK_EXPORTS))
48
49
/** Assert error callback. **/
50
#ifndef HTS_DEF_FWSTRUCT_htsErrorCallback
51
#define HTS_DEF_FWSTRUCT_htsErrorCallback
52
typedef void (*htsErrorCallback)(const char *msg, const char *file, int line);
53
#ifdef __cplusplus
54
extern "C" {
55
#endif
56
HTSEXT_API htsErrorCallback hts_get_error_callback(void);
57
#ifdef __cplusplus
58
}
59
#endif
60
#endif
61
62
#define HTSSAFE_ABORT_FUNCTION(A, B, C)                                        \
63
0
  do {                                                                         \
64
0
    htsErrorCallback callback = hts_get_error_callback();                      \
65
0
    if (callback != NULL) {                                                    \
66
0
      callback(A, B, C);                                                       \
67
0
    }                                                                          \
68
0
  } while (0)
69
70
#endif
71
72
/**
73
 * Log an abort condition, and calls abort().
74
 */
75
#define abortLog(a) abortf_(a, __FILE__, __LINE__)
76
77
/**
78
 * Fatal assertion check.
79
 */
80
#define assertf__(exp, sexp, file, line)                                       \
81
0
  (void) ((exp) || (abortf_(sexp, file, line), 0))
82
83
/**
84
 * Fatal assertion check.
85
 */
86
0
#define assertf_(exp, file, line) assertf__(exp, #exp, file, line)
87
88
/**
89
 * Fatal assertion check.
90
 */
91
0
#define assertf(exp) assertf_(exp, __FILE__, __LINE__)
92
93
0
static HTS_UNUSED void log_abort_(const char *msg, const char *file, int line) {
94
0
  fprintf(stderr, "%s failed at %s:%d\n", msg, file, line);
95
0
  fflush(stderr);
96
0
}
Unexecuted instantiation: fuzz-charset.c:log_abort_
Unexecuted instantiation: htscharset.c:log_abort_
Unexecuted instantiation: htslib.c:log_abort_
Unexecuted instantiation: htsconcat.c:log_abort_
Unexecuted instantiation: htswarc.c:log_abort_
Unexecuted instantiation: htsback.c:log_abort_
Unexecuted instantiation: htsftp.c:log_abort_
Unexecuted instantiation: htsthread.c:log_abort_
Unexecuted instantiation: htscore.c:log_abort_
Unexecuted instantiation: htshash.c:log_abort_
Unexecuted instantiation: htstools.c:log_abort_
Unexecuted instantiation: htscache.c:log_abort_
Unexecuted instantiation: htsdate.c:log_abort_
Unexecuted instantiation: htszlib.c:log_abort_
Unexecuted instantiation: htscodec.c:log_abort_
Unexecuted instantiation: htschanges.c:log_abort_
Unexecuted instantiation: htsmd5.c:log_abort_
Unexecuted instantiation: htsmodules.c:log_abort_
Unexecuted instantiation: htsbauth.c:log_abort_
Unexecuted instantiation: htsindex.c:log_abort_
Unexecuted instantiation: htsrobots.c:log_abort_
Unexecuted instantiation: htsfilters.c:log_abort_
Unexecuted instantiation: htssitemap.c:log_abort_
Unexecuted instantiation: htswizard.c:log_abort_
Unexecuted instantiation: htsparse.c:log_abort_
Unexecuted instantiation: htssinglefile.c:log_abort_
Unexecuted instantiation: htsname.c:log_abort_
Unexecuted instantiation: htsnet.c:log_abort_
Unexecuted instantiation: htsproxy.c:log_abort_
Unexecuted instantiation: htsencoding.c:log_abort_
Unexecuted instantiation: htssniff.c:log_abort_
97
98
static HTS_NORETURN HTS_UNUSED void abortf_(const char *exp, const char *file,
99
0
                                            int line) {
100
0
#ifdef HTSSAFE_ABORT_FUNCTION
101
0
  HTSSAFE_ABORT_FUNCTION(exp, file, line);
102
0
#endif
103
0
  log_abort_(exp, file, line);
104
0
  abort();
105
0
}
Unexecuted instantiation: fuzz-charset.c:abortf_
Unexecuted instantiation: htscharset.c:abortf_
Unexecuted instantiation: htslib.c:abortf_
Unexecuted instantiation: htsconcat.c:abortf_
Unexecuted instantiation: htswarc.c:abortf_
Unexecuted instantiation: htsback.c:abortf_
Unexecuted instantiation: htsftp.c:abortf_
Unexecuted instantiation: htsthread.c:abortf_
Unexecuted instantiation: htscore.c:abortf_
Unexecuted instantiation: htshash.c:abortf_
Unexecuted instantiation: htstools.c:abortf_
Unexecuted instantiation: htscache.c:abortf_
Unexecuted instantiation: htsdate.c:abortf_
Unexecuted instantiation: htszlib.c:abortf_
Unexecuted instantiation: htscodec.c:abortf_
Unexecuted instantiation: htschanges.c:abortf_
Unexecuted instantiation: htsmd5.c:abortf_
Unexecuted instantiation: htsmodules.c:abortf_
Unexecuted instantiation: htsbauth.c:abortf_
Unexecuted instantiation: htsindex.c:abortf_
Unexecuted instantiation: htsrobots.c:abortf_
Unexecuted instantiation: htsfilters.c:abortf_
Unexecuted instantiation: htssitemap.c:abortf_
Unexecuted instantiation: htswizard.c:abortf_
Unexecuted instantiation: htsparse.c:abortf_
Unexecuted instantiation: htssinglefile.c:abortf_
Unexecuted instantiation: htsname.c:abortf_
Unexecuted instantiation: htsnet.c:abortf_
Unexecuted instantiation: htsproxy.c:abortf_
Unexecuted instantiation: htsencoding.c:abortf_
Unexecuted instantiation: htssniff.c:abortf_
106
107
/**
108
 * Check whether 'VAR' is of type char[].
109
 */
110
#if (defined(__GNUC__) && !defined(__cplusplus))
111
112
/* Note: char[] and const char[] are compatible */
113
#define HTS_IS_CHAR_BUFFER(VAR)                                                \
114
0
  (__builtin_types_compatible_p(__typeof__(VAR), char[]))
115
#else
116
/* An array of exactly pointer size reads as a pointer and loses its bound:
117
   keep buff() destinations off char[8] (Win64) and char[4] (Win32). */
118
#define HTS_IS_CHAR_BUFFER(VAR) (sizeof(VAR) != sizeof(char *))
119
#endif
120
0
#define HTS_IS_NOT_CHAR_BUFFER(VAR) (!HTS_IS_CHAR_BUFFER(VAR))
121
122
/* Source capacity for the buff() family, (size_t)-1 when unknown; sizeof of the
123
   TYPE keeps a decayed operand ("buf + 1") off -Wsizeof-array-decay. */
124
#if (defined(__GNUC__) && !defined(__cplusplus))
125
#define HTS_SIZEOF_SRC_(B)                                                     \
126
0
  (HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(__typeof__(B)))
127
#else
128
#define HTS_SIZEOF_SRC_(B) (HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B))
129
#endif
130
131
/* Compile-time checks. */
132
0
static HTS_UNUSED void htssafe_compile_time_check_(void) {
133
0
  char array[32];
134
0
  char *pointer = array;
135
0
  char check_array[HTS_IS_CHAR_BUFFER(array) ? 1 : -1];
136
0
  char check_pointer[HTS_IS_CHAR_BUFFER(pointer) ? -1 : 1];
137
0
  (void) pointer;
138
0
  (void) check_array;
139
0
  (void) check_pointer;
140
0
}
Unexecuted instantiation: fuzz-charset.c:htssafe_compile_time_check_
Unexecuted instantiation: htscharset.c:htssafe_compile_time_check_
Unexecuted instantiation: htslib.c:htssafe_compile_time_check_
Unexecuted instantiation: htsconcat.c:htssafe_compile_time_check_
Unexecuted instantiation: htswarc.c:htssafe_compile_time_check_
Unexecuted instantiation: htsback.c:htssafe_compile_time_check_
Unexecuted instantiation: htsftp.c:htssafe_compile_time_check_
Unexecuted instantiation: htsthread.c:htssafe_compile_time_check_
Unexecuted instantiation: htscore.c:htssafe_compile_time_check_
Unexecuted instantiation: htshash.c:htssafe_compile_time_check_
Unexecuted instantiation: htstools.c:htssafe_compile_time_check_
Unexecuted instantiation: htscache.c:htssafe_compile_time_check_
Unexecuted instantiation: htsdate.c:htssafe_compile_time_check_
Unexecuted instantiation: htszlib.c:htssafe_compile_time_check_
Unexecuted instantiation: htscodec.c:htssafe_compile_time_check_
Unexecuted instantiation: htschanges.c:htssafe_compile_time_check_
Unexecuted instantiation: htsmd5.c:htssafe_compile_time_check_
Unexecuted instantiation: htsmodules.c:htssafe_compile_time_check_
Unexecuted instantiation: htsbauth.c:htssafe_compile_time_check_
Unexecuted instantiation: htsindex.c:htssafe_compile_time_check_
Unexecuted instantiation: htsrobots.c:htssafe_compile_time_check_
Unexecuted instantiation: htsfilters.c:htssafe_compile_time_check_
Unexecuted instantiation: htssitemap.c:htssafe_compile_time_check_
Unexecuted instantiation: htswizard.c:htssafe_compile_time_check_
Unexecuted instantiation: htsparse.c:htssafe_compile_time_check_
Unexecuted instantiation: htssinglefile.c:htssafe_compile_time_check_
Unexecuted instantiation: htsname.c:htssafe_compile_time_check_
Unexecuted instantiation: htsnet.c:htssafe_compile_time_check_
Unexecuted instantiation: htsproxy.c:htssafe_compile_time_check_
Unexecuted instantiation: htsencoding.c:htssafe_compile_time_check_
Unexecuted instantiation: htssniff.c:htssafe_compile_time_check_
141
142
/*
143
 * Pointer-destination diagnostics for the buff() macros (GCC/Clang, C only).
144
 *
145
 * strcpybuff()/strcatbuff()/strncatbuff() bounds-check only when the
146
 * destination is a sized char[] array (HTS_IS_CHAR_BUFFER). For a bare char*
147
 * the capacity is unknown, so the macro silently falls back to plain
148
 * strcpy()/strcat()/strncat() while still looking like a checked call.
149
 *
150
 * These stubs route that pointer case through __builtin_choose_expr() so the
151
 * 'warning' attribute fires only at pointer-destination sites; array sites use
152
 * the bounded *_safe_ helpers and stay quiet. The warning names the
153
 * explicit-size replacement (strlcpybuff/strlcatbuff). Diagnostic only: no
154
 * runtime or ABI change, built only on GCC/Clang in C mode. Other compilers
155
 * (MSVC, ...) keep the previous behavior via the #else branches.
156
 */
157
#if (defined(__GNUC__) && !defined(__cplusplus))
158
159
#if defined(__has_attribute)
160
161
#if __has_attribute(warning)
162
163
#define HTS_BUFF_PTR_ATTR(msg) __attribute__((unused, noinline, warning(msg)))
164
#endif
165
#endif
166
#ifndef HTS_BUFF_PTR_ATTR
167
/* 'warning' attribute unavailable: keep noinline so the migration can still
168
   grep for these symbols, but no compile-time diagnostic is emitted. */
169
#define HTS_BUFF_PTR_ATTR(msg) __attribute__((unused, noinline))
170
#endif
171
172
HTS_BUFF_PTR_ATTR("strcpybuff() destination is a pointer (capacity unknown): "
173
                  "NOT bounds-checked; use strlcpybuff(dst, src, size)")
174
175
0
static char *strcpybuff_ptr_(char *dest, const char *src) {
176
0
  return strcpy(dest, src);
177
0
}
Unexecuted instantiation: fuzz-charset.c:strcpybuff_ptr_
Unexecuted instantiation: htscharset.c:strcpybuff_ptr_
Unexecuted instantiation: htslib.c:strcpybuff_ptr_
Unexecuted instantiation: htsconcat.c:strcpybuff_ptr_
Unexecuted instantiation: htswarc.c:strcpybuff_ptr_
Unexecuted instantiation: htsback.c:strcpybuff_ptr_
Unexecuted instantiation: htsftp.c:strcpybuff_ptr_
Unexecuted instantiation: htsthread.c:strcpybuff_ptr_
Unexecuted instantiation: htscore.c:strcpybuff_ptr_
Unexecuted instantiation: htshash.c:strcpybuff_ptr_
Unexecuted instantiation: htstools.c:strcpybuff_ptr_
Unexecuted instantiation: htscache.c:strcpybuff_ptr_
Unexecuted instantiation: htsdate.c:strcpybuff_ptr_
Unexecuted instantiation: htszlib.c:strcpybuff_ptr_
Unexecuted instantiation: htscodec.c:strcpybuff_ptr_
Unexecuted instantiation: htschanges.c:strcpybuff_ptr_
Unexecuted instantiation: htsmd5.c:strcpybuff_ptr_
Unexecuted instantiation: htsmodules.c:strcpybuff_ptr_
Unexecuted instantiation: htsbauth.c:strcpybuff_ptr_
Unexecuted instantiation: htsindex.c:strcpybuff_ptr_
Unexecuted instantiation: htsrobots.c:strcpybuff_ptr_
Unexecuted instantiation: htsfilters.c:strcpybuff_ptr_
Unexecuted instantiation: htssitemap.c:strcpybuff_ptr_
Unexecuted instantiation: htswizard.c:strcpybuff_ptr_
Unexecuted instantiation: htsparse.c:strcpybuff_ptr_
Unexecuted instantiation: htssinglefile.c:strcpybuff_ptr_
Unexecuted instantiation: htsname.c:strcpybuff_ptr_
Unexecuted instantiation: htsnet.c:strcpybuff_ptr_
Unexecuted instantiation: htsproxy.c:strcpybuff_ptr_
Unexecuted instantiation: htsencoding.c:strcpybuff_ptr_
Unexecuted instantiation: htssniff.c:strcpybuff_ptr_
178
179
HTS_BUFF_PTR_ATTR("strcatbuff() destination is a pointer (capacity unknown): "
180
                  "NOT bounds-checked; use strlcatbuff(dst, src, size)")
181
182
0
static char *strcatbuff_ptr_(char *dest, const char *src) {
183
0
  return strcat(dest, src);
184
0
}
Unexecuted instantiation: fuzz-charset.c:strcatbuff_ptr_
Unexecuted instantiation: htscharset.c:strcatbuff_ptr_
Unexecuted instantiation: htslib.c:strcatbuff_ptr_
Unexecuted instantiation: htsconcat.c:strcatbuff_ptr_
Unexecuted instantiation: htswarc.c:strcatbuff_ptr_
Unexecuted instantiation: htsback.c:strcatbuff_ptr_
Unexecuted instantiation: htsftp.c:strcatbuff_ptr_
Unexecuted instantiation: htsthread.c:strcatbuff_ptr_
Unexecuted instantiation: htscore.c:strcatbuff_ptr_
Unexecuted instantiation: htshash.c:strcatbuff_ptr_
Unexecuted instantiation: htstools.c:strcatbuff_ptr_
Unexecuted instantiation: htscache.c:strcatbuff_ptr_
Unexecuted instantiation: htsdate.c:strcatbuff_ptr_
Unexecuted instantiation: htszlib.c:strcatbuff_ptr_
Unexecuted instantiation: htscodec.c:strcatbuff_ptr_
Unexecuted instantiation: htschanges.c:strcatbuff_ptr_
Unexecuted instantiation: htsmd5.c:strcatbuff_ptr_
Unexecuted instantiation: htsmodules.c:strcatbuff_ptr_
Unexecuted instantiation: htsbauth.c:strcatbuff_ptr_
Unexecuted instantiation: htsindex.c:strcatbuff_ptr_
Unexecuted instantiation: htsrobots.c:strcatbuff_ptr_
Unexecuted instantiation: htsfilters.c:strcatbuff_ptr_
Unexecuted instantiation: htssitemap.c:strcatbuff_ptr_
Unexecuted instantiation: htswizard.c:strcatbuff_ptr_
Unexecuted instantiation: htsparse.c:strcatbuff_ptr_
Unexecuted instantiation: htssinglefile.c:strcatbuff_ptr_
Unexecuted instantiation: htsname.c:strcatbuff_ptr_
Unexecuted instantiation: htsnet.c:strcatbuff_ptr_
Unexecuted instantiation: htsproxy.c:strcatbuff_ptr_
Unexecuted instantiation: htsencoding.c:strcatbuff_ptr_
Unexecuted instantiation: htssniff.c:strcatbuff_ptr_
185
186
HTS_BUFF_PTR_ATTR("strncatbuff() destination is a pointer (capacity unknown): "
187
                  "NOT bounds-checked; use strlcatbuff(dst, src, size)")
188
189
0
static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
190
0
  return strncat(dest, src, n);
191
0
}
Unexecuted instantiation: fuzz-charset.c:strncatbuff_ptr_
Unexecuted instantiation: htscharset.c:strncatbuff_ptr_
Unexecuted instantiation: htslib.c:strncatbuff_ptr_
Unexecuted instantiation: htsconcat.c:strncatbuff_ptr_
Unexecuted instantiation: htswarc.c:strncatbuff_ptr_
Unexecuted instantiation: htsback.c:strncatbuff_ptr_
Unexecuted instantiation: htsftp.c:strncatbuff_ptr_
Unexecuted instantiation: htsthread.c:strncatbuff_ptr_
Unexecuted instantiation: htscore.c:strncatbuff_ptr_
Unexecuted instantiation: htshash.c:strncatbuff_ptr_
Unexecuted instantiation: htstools.c:strncatbuff_ptr_
Unexecuted instantiation: htscache.c:strncatbuff_ptr_
Unexecuted instantiation: htsdate.c:strncatbuff_ptr_
Unexecuted instantiation: htszlib.c:strncatbuff_ptr_
Unexecuted instantiation: htscodec.c:strncatbuff_ptr_
Unexecuted instantiation: htschanges.c:strncatbuff_ptr_
Unexecuted instantiation: htsmd5.c:strncatbuff_ptr_
Unexecuted instantiation: htsmodules.c:strncatbuff_ptr_
Unexecuted instantiation: htsbauth.c:strncatbuff_ptr_
Unexecuted instantiation: htsindex.c:strncatbuff_ptr_
Unexecuted instantiation: htsrobots.c:strncatbuff_ptr_
Unexecuted instantiation: htsfilters.c:strncatbuff_ptr_
Unexecuted instantiation: htssitemap.c:strncatbuff_ptr_
Unexecuted instantiation: htswizard.c:strncatbuff_ptr_
Unexecuted instantiation: htsparse.c:strncatbuff_ptr_
Unexecuted instantiation: htssinglefile.c:strncatbuff_ptr_
Unexecuted instantiation: htsname.c:strncatbuff_ptr_
Unexecuted instantiation: htsnet.c:strncatbuff_ptr_
Unexecuted instantiation: htsproxy.c:strncatbuff_ptr_
Unexecuted instantiation: htsencoding.c:strncatbuff_ptr_
Unexecuted instantiation: htssniff.c:strncatbuff_ptr_
192
#endif
193
194
/*
195
 * SIZE CONTRACT shared by strcpybuff/strcatbuff/strncatbuff (the "buff"
196
 * family): the destination bound is taken from sizeof(A), so A MUST be a real
197
 * char[] array in scope. The bound is the full array size in bytes, INCLUDING
198
 * the terminating NUL. On overflow the *_safe_ helpers do NOT truncate: they
199
 * abort() (assertf). On success the result is always NUL-terminated.
200
 *
201
 * CRITICAL CAVEAT: if A is a bare char* pointer (not an array), sizeof(A) is
202
 * the pointer size, not the buffer capacity. There is no way to recover the
203
 * real capacity, so these macros SILENTLY DEGRADE to the unbounded raw
204
 * strcpy()/strcat()/strncat() while still looking like a checked call. The
205
 * bound is lost. On GCC/Clang (C) the pointer case routes through the
206
 * *_ptr_ stubs above, which carry a 'warning' attribute to flag the site at
207
 * compile time; on other compilers it is silent. When the destination is a
208
 * pointer of known capacity, call the explicit-size strlcpybuff/strlcatbuff
209
 * (passing the capacity, NUL included) instead.
210
 */
211
212
/**
213
 * Append at most N characters from "B" to "A".
214
 * If "A" is a char[] variable whose size is not sizeof(char*), then the size
215
 * is assumed to be the capacity of this array.
216
 */
217
#if (defined(__GNUC__) && !defined(__cplusplus))
218
219
#define strncatbuff(A, B, N)                                                   \
220
0
  __builtin_choose_expr(HTS_IS_CHAR_BUFFER(A),                                 \
221
0
                        strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), N,  \
222
0
                                      "overflow while appending '" #B          \
223
0
                                      "' to '" #A "'",                         \
224
0
                                      __FILE__, __LINE__),                     \
225
0
                        strncatbuff_ptr_((A), (B), (N)))
226
#else
227
#define strncatbuff(A, B, N)                                                   \
228
  (HTS_IS_NOT_CHAR_BUFFER(A)                                                   \
229
       ? strncat(A, B, N)                                                      \
230
       : strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), N,                 \
231
                       "overflow while appending '" #B "' to '" #A "'",        \
232
                       __FILE__, __LINE__))
233
#endif
234
235
/**
236
 * Append characters of "B" to "A".
237
 * If "A" is a char[] variable whose size is not sizeof(char*), then the size
238
 * is assumed to be the capacity of this array.
239
 */
240
#if (defined(__GNUC__) && !defined(__cplusplus))
241
242
#define strcatbuff(A, B)                                                       \
243
0
  __builtin_choose_expr(                                                       \
244
0
      HTS_IS_CHAR_BUFFER(A),                                                   \
245
0
      strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), (size_t) -1,          \
246
0
                    "overflow while appending '" #B "' to '" #A "'", __FILE__, \
247
0
                    __LINE__),                                                 \
248
0
      strcatbuff_ptr_((A), (B)))
249
#else
250
#define strcatbuff(A, B)                                                       \
251
  (HTS_IS_NOT_CHAR_BUFFER(A)                                                   \
252
       ? strcat(A, B)                                                          \
253
       : strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), (size_t) -1,       \
254
                       "overflow while appending '" #B "' to '" #A "'",        \
255
                       __FILE__, __LINE__))
256
#endif
257
258
/**
259
 * Copy characters from "B" to "A".
260
 * If "A" is a char[] variable whose size is not sizeof(char*), then the size
261
 * is assumed to be the capacity of this array.
262
 */
263
#if (defined(__GNUC__) && !defined(__cplusplus))
264
265
#define strcpybuff(A, B)                                                       \
266
0
  __builtin_choose_expr(HTS_IS_CHAR_BUFFER(A),                                 \
267
0
                        strcpy_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B),      \
268
0
                                     "overflow while copying '" #B "' to '" #A \
269
0
                                     "'",                                      \
270
0
                                     __FILE__, __LINE__),                      \
271
0
                        strcpybuff_ptr_((A), (B)))
272
#else
273
#define strcpybuff(A, B)                                                       \
274
  (HTS_IS_NOT_CHAR_BUFFER(A)                                                   \
275
       ? strcpy(A, B)                                                          \
276
       : strcpy_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B),                     \
277
                      "overflow while copying '" #B "' to '" #A "'", __FILE__, \
278
                      __LINE__))
279
#endif
280
281
/*
282
 * Explicit-size variants (strlcatbuff/strlncatbuff/strlcpybuff): the
283
 * destination capacity is the caller-supplied S (total bytes, NUL included),
284
 * NOT derived from sizeof(A). Use these when A is a pointer or its capacity is
285
 * not its sizeof. Same abort-on-overflow, always-NUL-terminated contract; no
286
 * silent pointer degradation since the bound is passed in.
287
 */
288
289
/**
290
 * Append characters of "B" to "A", "A" having a maximum capacity of "S".
291
 */
292
#define strlcatbuff(A, B, S)                                                   \
293
0
  strncat_safe_(A, S, B, HTS_SIZEOF_SRC_(B), (size_t) -1,                      \
294
0
                "overflow while appending '" #B "' to '" #A "'", __FILE__,     \
295
0
                __LINE__)
296
297
/**
298
 * Append at most "N" characters of "B" to "A", "A" having a maximum capacity
299
 * of "S".
300
 */
301
#define strlncatbuff(A, B, S, N)                                               \
302
0
  strncat_safe_(A, S, B, HTS_SIZEOF_SRC_(B), N,                                \
303
0
                "overflow while appending '" #B "' to '" #A "'", __FILE__,     \
304
0
                __LINE__)
305
306
/**
307
 * Copy characters of "B" to "A", "A" having a maximum capacity of "S".
308
 */
309
#define strlcpybuff(A, B, S)                                                   \
310
0
  strcpy_safe_(A, S, B, HTS_SIZEOF_SRC_(B),                                    \
311
0
               "overflow while copying '" #B "' to '" #A "'", __FILE__,        \
312
0
               __LINE__)
313
314
/* POSIX strnlen is hidden from a strict-ISO consumer (__STRICT_ANSI__) and
315
   absent on a few targets, so the inline helpers below use this instead. */
316
static HTS_INLINE HTS_UNUSED size_t htssafe_strnlen_(const char *s,
317
0
                                                     size_t maxlen) {
318
0
#if (defined(_WIN32) || (defined(HAVE_STRNLEN) && !defined(__STRICT_ANSI__)))
319
0
  return strnlen(s, maxlen);
320
#else
321
  size_t i;
322
  for (i = 0; i < maxlen && s[i] != '\0'; i++)
323
    ;
324
  return i;
325
#endif
326
0
}
Unexecuted instantiation: fuzz-charset.c:htssafe_strnlen_
Unexecuted instantiation: htscharset.c:htssafe_strnlen_
Unexecuted instantiation: htslib.c:htssafe_strnlen_
Unexecuted instantiation: htsconcat.c:htssafe_strnlen_
Unexecuted instantiation: htswarc.c:htssafe_strnlen_
Unexecuted instantiation: htsback.c:htssafe_strnlen_
Unexecuted instantiation: htsftp.c:htssafe_strnlen_
Unexecuted instantiation: htsthread.c:htssafe_strnlen_
Unexecuted instantiation: htscore.c:htssafe_strnlen_
Unexecuted instantiation: htshash.c:htssafe_strnlen_
Unexecuted instantiation: htstools.c:htssafe_strnlen_
Unexecuted instantiation: htscache.c:htssafe_strnlen_
Unexecuted instantiation: htsdate.c:htssafe_strnlen_
Unexecuted instantiation: htszlib.c:htssafe_strnlen_
Unexecuted instantiation: htscodec.c:htssafe_strnlen_
Unexecuted instantiation: htschanges.c:htssafe_strnlen_
Unexecuted instantiation: htsmd5.c:htssafe_strnlen_
Unexecuted instantiation: htsmodules.c:htssafe_strnlen_
Unexecuted instantiation: htsbauth.c:htssafe_strnlen_
Unexecuted instantiation: htsindex.c:htssafe_strnlen_
Unexecuted instantiation: htsrobots.c:htssafe_strnlen_
Unexecuted instantiation: htsfilters.c:htssafe_strnlen_
Unexecuted instantiation: htssitemap.c:htssafe_strnlen_
Unexecuted instantiation: htswizard.c:htssafe_strnlen_
Unexecuted instantiation: htsparse.c:htssafe_strnlen_
Unexecuted instantiation: htssinglefile.c:htssafe_strnlen_
Unexecuted instantiation: htsname.c:htssafe_strnlen_
Unexecuted instantiation: htsnet.c:htssafe_strnlen_
Unexecuted instantiation: htsproxy.c:htssafe_strnlen_
Unexecuted instantiation: htsencoding.c:htssafe_strnlen_
Unexecuted instantiation: htssniff.c:htssafe_strnlen_
327
328
/** strnlen replacement (autotools), for the engine sources that call it. **/
329
#if (!defined(_WIN32) && !defined(HAVE_STRNLEN))
330
331
static HTS_UNUSED size_t strnlen(const char *s, size_t maxlen) {
332
  return htssafe_strnlen_(s, maxlen);
333
}
334
#endif
335
336
/* strlen of source, but bounded by sizeof_source (its capacity, NUL included).
337
   Aborts if source is NULL or has no NUL within that capacity. The sentinel
338
   sizeof_source == (size_t)-1 means "capacity unknown", and falls back to the
339
   unbounded strlen (used when the source is a pointer rather than an array). */
340
static HTS_INLINE HTS_UNUSED size_t strlen_safe_(const char *source,
341
                                                 const size_t sizeof_source,
342
0
                                                 const char *file, int line) {
343
0
  size_t size;
344
0
  assertf_(source != NULL, file, line);
345
0
  size = sizeof_source != (size_t) -1 ? htssafe_strnlen_(source, sizeof_source)
346
0
                                      : strlen(source);
347
0
  assertf_(size < sizeof_source, file, line);
348
0
  return size;
349
0
}
Unexecuted instantiation: fuzz-charset.c:strlen_safe_
Unexecuted instantiation: htscharset.c:strlen_safe_
Unexecuted instantiation: htslib.c:strlen_safe_
Unexecuted instantiation: htsconcat.c:strlen_safe_
Unexecuted instantiation: htswarc.c:strlen_safe_
Unexecuted instantiation: htsback.c:strlen_safe_
Unexecuted instantiation: htsftp.c:strlen_safe_
Unexecuted instantiation: htsthread.c:strlen_safe_
Unexecuted instantiation: htscore.c:strlen_safe_
Unexecuted instantiation: htshash.c:strlen_safe_
Unexecuted instantiation: htstools.c:strlen_safe_
Unexecuted instantiation: htscache.c:strlen_safe_
Unexecuted instantiation: htsdate.c:strlen_safe_
Unexecuted instantiation: htszlib.c:strlen_safe_
Unexecuted instantiation: htscodec.c:strlen_safe_
Unexecuted instantiation: htschanges.c:strlen_safe_
Unexecuted instantiation: htsmd5.c:strlen_safe_
Unexecuted instantiation: htsmodules.c:strlen_safe_
Unexecuted instantiation: htsbauth.c:strlen_safe_
Unexecuted instantiation: htsindex.c:strlen_safe_
Unexecuted instantiation: htsrobots.c:strlen_safe_
Unexecuted instantiation: htsfilters.c:strlen_safe_
Unexecuted instantiation: htssitemap.c:strlen_safe_
Unexecuted instantiation: htswizard.c:strlen_safe_
Unexecuted instantiation: htsparse.c:strlen_safe_
Unexecuted instantiation: htssinglefile.c:strlen_safe_
Unexecuted instantiation: htsname.c:strlen_safe_
Unexecuted instantiation: htsnet.c:strlen_safe_
Unexecuted instantiation: htsproxy.c:strlen_safe_
Unexecuted instantiation: htsencoding.c:strlen_safe_
Unexecuted instantiation: htssniff.c:strlen_safe_
350
351
/* Core bounded append. Appends min(strlen(source), n) bytes of source onto
352
   dest. sizeof_dest is dest's total capacity (NUL included); sizeof_source is
353
   source's capacity or (size_t)-1 if unknown. Aborts if the result (existing
354
   dest length + appended bytes + NUL) would not fit sizeof_dest: this NEVER
355
   truncates. Always NUL-terminates on success. */
356
static HTS_INLINE HTS_UNUSED char *
357
strncat_safe_(char *const dest, const size_t sizeof_dest,
358
              const char *const source, const size_t sizeof_source,
359
0
              const size_t n, const char *exp, const char *file, int line) {
360
0
  const size_t source_len = strlen_safe_(source, sizeof_source, file, line);
361
0
  const size_t dest_len = strlen_safe_(dest, sizeof_dest, file, line);
362
  /* note: "size_t is an unsigned integral type" ((size_t) -1 is positive) */
363
0
  const size_t source_copy = source_len <= n ? source_len : n;
364
0
  const size_t dest_final_len = dest_len + source_copy;
365
0
  assertf__(dest_final_len < sizeof_dest, exp, file, line);
366
0
  memcpy(dest + dest_len, source, source_copy);
367
0
  dest[dest_final_len] = '\0';
368
0
  return dest;
369
0
}
Unexecuted instantiation: fuzz-charset.c:strncat_safe_
Unexecuted instantiation: htscharset.c:strncat_safe_
Unexecuted instantiation: htslib.c:strncat_safe_
Unexecuted instantiation: htsconcat.c:strncat_safe_
Unexecuted instantiation: htswarc.c:strncat_safe_
Unexecuted instantiation: htsback.c:strncat_safe_
Unexecuted instantiation: htsftp.c:strncat_safe_
Unexecuted instantiation: htsthread.c:strncat_safe_
Unexecuted instantiation: htscore.c:strncat_safe_
Unexecuted instantiation: htshash.c:strncat_safe_
Unexecuted instantiation: htstools.c:strncat_safe_
Unexecuted instantiation: htscache.c:strncat_safe_
Unexecuted instantiation: htsdate.c:strncat_safe_
Unexecuted instantiation: htszlib.c:strncat_safe_
Unexecuted instantiation: htscodec.c:strncat_safe_
Unexecuted instantiation: htschanges.c:strncat_safe_
Unexecuted instantiation: htsmd5.c:strncat_safe_
Unexecuted instantiation: htsmodules.c:strncat_safe_
Unexecuted instantiation: htsbauth.c:strncat_safe_
Unexecuted instantiation: htsindex.c:strncat_safe_
Unexecuted instantiation: htsrobots.c:strncat_safe_
Unexecuted instantiation: htsfilters.c:strncat_safe_
Unexecuted instantiation: htssitemap.c:strncat_safe_
Unexecuted instantiation: htswizard.c:strncat_safe_
Unexecuted instantiation: htsparse.c:strncat_safe_
Unexecuted instantiation: htssinglefile.c:strncat_safe_
Unexecuted instantiation: htsname.c:strncat_safe_
Unexecuted instantiation: htsnet.c:strncat_safe_
Unexecuted instantiation: htsproxy.c:strncat_safe_
Unexecuted instantiation: htsencoding.c:strncat_safe_
Unexecuted instantiation: htssniff.c:strncat_safe_
370
371
/* Core bounded copy: empties dest then appends all of source via
372
   strncat_safe_. sizeof_dest is dest's total capacity (NUL included). Aborts
373
   (no truncation) if source plus its NUL would not fit. */
374
static HTS_INLINE HTS_UNUSED char *
375
strcpy_safe_(char *const dest, const size_t sizeof_dest,
376
             const char *const source, const size_t sizeof_source,
377
0
             const char *exp, const char *file, int line) {
378
0
  assertf_(sizeof_dest != 0, file, line);
379
0
  dest[0] = '\0';
380
0
  return strncat_safe_(dest, sizeof_dest, source, sizeof_source, (size_t) -1,
381
0
                       exp, file, line);
382
0
}
Unexecuted instantiation: fuzz-charset.c:strcpy_safe_
Unexecuted instantiation: htscharset.c:strcpy_safe_
Unexecuted instantiation: htslib.c:strcpy_safe_
Unexecuted instantiation: htsconcat.c:strcpy_safe_
Unexecuted instantiation: htswarc.c:strcpy_safe_
Unexecuted instantiation: htsback.c:strcpy_safe_
Unexecuted instantiation: htsftp.c:strcpy_safe_
Unexecuted instantiation: htsthread.c:strcpy_safe_
Unexecuted instantiation: htscore.c:strcpy_safe_
Unexecuted instantiation: htshash.c:strcpy_safe_
Unexecuted instantiation: htstools.c:strcpy_safe_
Unexecuted instantiation: htscache.c:strcpy_safe_
Unexecuted instantiation: htsdate.c:strcpy_safe_
Unexecuted instantiation: htszlib.c:strcpy_safe_
Unexecuted instantiation: htscodec.c:strcpy_safe_
Unexecuted instantiation: htschanges.c:strcpy_safe_
Unexecuted instantiation: htsmd5.c:strcpy_safe_
Unexecuted instantiation: htsmodules.c:strcpy_safe_
Unexecuted instantiation: htsbauth.c:strcpy_safe_
Unexecuted instantiation: htsindex.c:strcpy_safe_
Unexecuted instantiation: htsrobots.c:strcpy_safe_
Unexecuted instantiation: htsfilters.c:strcpy_safe_
Unexecuted instantiation: htssitemap.c:strcpy_safe_
Unexecuted instantiation: htswizard.c:strcpy_safe_
Unexecuted instantiation: htsparse.c:strcpy_safe_
Unexecuted instantiation: htssinglefile.c:strcpy_safe_
Unexecuted instantiation: htsname.c:strcpy_safe_
Unexecuted instantiation: htsnet.c:strcpy_safe_
Unexecuted instantiation: htsproxy.c:strcpy_safe_
Unexecuted instantiation: htsencoding.c:strcpy_safe_
Unexecuted instantiation: htssniff.c:strcpy_safe_
383
384
/**
385
 * htsbuff: a non-owning bounded string builder over a fixed buffer.
386
 *
387
 * Companion to the strcpybuff()/strcatbuff() macros for the common case of a
388
 * cursor walking a buffer of known capacity (building a name into a fixed
389
 * array, assembling a status line, etc.). It tracks the write position, bounds
390
 * every write against the real capacity, and aborts on overflow (same contract
391
 * as the *_safe_ helpers), so the error-prone manual "p += strlen(p)" dance
392
 * goes away.
393
 *
394
 * Build one from an in-scope array with htsbuff_array() (capacity via sizeof,
395
 * so pass an array, not a pointer), or from a pointer of known capacity with
396
 * htsbuff_ptr(). The buffer is kept NUL-terminated; htsbuff_str() returns it.
397
 */
398
typedef struct {
399
  char *buf;  /* backing buffer (kept NUL-terminated) */
400
  size_t cap; /* total capacity of buf, including the NUL */
401
  size_t len; /* current length, excluding the NUL */
402
} htsbuff;
403
404
0
static HTS_INLINE HTS_UNUSED htsbuff htsbuff_ptr_(char *buf, size_t cap) {
405
0
  htsbuff b;
406
0
  b.buf = buf;
407
0
  b.cap = cap;
408
0
  b.len = 0;
409
0
  assertf(cap != 0);
410
0
  buf[0] = '\0';
411
0
  return b;
412
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_ptr_
Unexecuted instantiation: htscharset.c:htsbuff_ptr_
Unexecuted instantiation: htslib.c:htsbuff_ptr_
Unexecuted instantiation: htsconcat.c:htsbuff_ptr_
Unexecuted instantiation: htswarc.c:htsbuff_ptr_
Unexecuted instantiation: htsback.c:htsbuff_ptr_
Unexecuted instantiation: htsftp.c:htsbuff_ptr_
Unexecuted instantiation: htsthread.c:htsbuff_ptr_
Unexecuted instantiation: htscore.c:htsbuff_ptr_
Unexecuted instantiation: htshash.c:htsbuff_ptr_
Unexecuted instantiation: htstools.c:htsbuff_ptr_
Unexecuted instantiation: htscache.c:htsbuff_ptr_
Unexecuted instantiation: htsdate.c:htsbuff_ptr_
Unexecuted instantiation: htszlib.c:htsbuff_ptr_
Unexecuted instantiation: htscodec.c:htsbuff_ptr_
Unexecuted instantiation: htschanges.c:htsbuff_ptr_
Unexecuted instantiation: htsmd5.c:htsbuff_ptr_
Unexecuted instantiation: htsmodules.c:htsbuff_ptr_
Unexecuted instantiation: htsbauth.c:htsbuff_ptr_
Unexecuted instantiation: htsindex.c:htsbuff_ptr_
Unexecuted instantiation: htsrobots.c:htsbuff_ptr_
Unexecuted instantiation: htsfilters.c:htsbuff_ptr_
Unexecuted instantiation: htssitemap.c:htsbuff_ptr_
Unexecuted instantiation: htswizard.c:htsbuff_ptr_
Unexecuted instantiation: htsparse.c:htsbuff_ptr_
Unexecuted instantiation: htssinglefile.c:htsbuff_ptr_
Unexecuted instantiation: htsname.c:htsbuff_ptr_
Unexecuted instantiation: htsnet.c:htsbuff_ptr_
Unexecuted instantiation: htsproxy.c:htsbuff_ptr_
Unexecuted instantiation: htsencoding.c:htsbuff_ptr_
Unexecuted instantiation: htssniff.c:htsbuff_ptr_
413
414
/**
415
 * Builder over the in-scope array ARR (capacity = sizeof(ARR)).
416
 * On GCC/Clang this rejects a non-array (e.g. a char* pointer), whose sizeof
417
 * would be the pointer size and silently wrong; use htsbuff_ptr() for pointers.
418
 * On other compilers there is no such guard, so pass only true arrays there.
419
 */
420
#if (defined(__GNUC__) && !defined(__cplusplus))
421
422
/* 0 for an array, a -1 array-size compile error for a pointer. */
423
#define htsbuff_must_be_array_(A)                                              \
424
0
  (sizeof(char[1 - 2 * !!__builtin_types_compatible_p(__typeof__(A),           \
425
0
                                                      __typeof__(&(A)[0]))]) - \
426
0
   1)
427
428
#define htsbuff_array(ARR)                                                     \
429
0
  htsbuff_ptr_((ARR), sizeof(ARR) + htsbuff_must_be_array_(ARR))
430
#else
431
#define htsbuff_array(ARR) htsbuff_ptr_((ARR), sizeof(ARR))
432
#endif
433
/** Builder over pointer P of known capacity N (N includes the NUL). */
434
0
#define htsbuff_ptr(P, N) htsbuff_ptr_((P), (N))
435
436
/** Append at most n characters of s (stopping at its NUL). Aborts on overflow.
437
 */
438
static HTS_INLINE HTS_UNUSED void htsbuff_catn(htsbuff *b, const char *s,
439
0
                                               size_t n) {
440
  /* the (size_t)-1 "no limit" sentinel would reach strnlen as a bound past
441
     PTRDIFF_MAX */
442
0
  const size_t add = n != (size_t) -1 ? htssafe_strnlen_(s, n) : strlen(s);
443
  /* Overflow-safe: keep the (potentially huge) 'add' alone on one side. The
444
     maintained invariant len < cap makes 'cap - len' >= 1 (no underflow), so
445
     'add < cap - len' cannot wrap the way 'len + add < cap' could. */
446
0
  assertf__(add < b->cap - b->len, "htsbuff append overflow", __FILE__,
447
0
            __LINE__);
448
0
  memcpy(b->buf + b->len, s, add);
449
0
  b->len += add;
450
0
  b->buf[b->len] = '\0';
451
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_catn
Unexecuted instantiation: htscharset.c:htsbuff_catn
Unexecuted instantiation: htslib.c:htsbuff_catn
Unexecuted instantiation: htsconcat.c:htsbuff_catn
Unexecuted instantiation: htswarc.c:htsbuff_catn
Unexecuted instantiation: htsback.c:htsbuff_catn
Unexecuted instantiation: htsftp.c:htsbuff_catn
Unexecuted instantiation: htsthread.c:htsbuff_catn
Unexecuted instantiation: htscore.c:htsbuff_catn
Unexecuted instantiation: htshash.c:htsbuff_catn
Unexecuted instantiation: htstools.c:htsbuff_catn
Unexecuted instantiation: htscache.c:htsbuff_catn
Unexecuted instantiation: htsdate.c:htsbuff_catn
Unexecuted instantiation: htszlib.c:htsbuff_catn
Unexecuted instantiation: htscodec.c:htsbuff_catn
Unexecuted instantiation: htschanges.c:htsbuff_catn
Unexecuted instantiation: htsmd5.c:htsbuff_catn
Unexecuted instantiation: htsmodules.c:htsbuff_catn
Unexecuted instantiation: htsbauth.c:htsbuff_catn
Unexecuted instantiation: htsindex.c:htsbuff_catn
Unexecuted instantiation: htsrobots.c:htsbuff_catn
Unexecuted instantiation: htsfilters.c:htsbuff_catn
Unexecuted instantiation: htssitemap.c:htsbuff_catn
Unexecuted instantiation: htswizard.c:htsbuff_catn
Unexecuted instantiation: htsparse.c:htsbuff_catn
Unexecuted instantiation: htssinglefile.c:htsbuff_catn
Unexecuted instantiation: htsname.c:htsbuff_catn
Unexecuted instantiation: htsnet.c:htsbuff_catn
Unexecuted instantiation: htsproxy.c:htsbuff_catn
Unexecuted instantiation: htsencoding.c:htsbuff_catn
Unexecuted instantiation: htssniff.c:htsbuff_catn
452
453
/** Append s. Aborts on overflow. */
454
0
static HTS_INLINE HTS_UNUSED void htsbuff_cat(htsbuff *b, const char *s) {
455
0
  htsbuff_catn(b, s, (size_t) -1);
456
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_cat
Unexecuted instantiation: htscharset.c:htsbuff_cat
Unexecuted instantiation: htslib.c:htsbuff_cat
Unexecuted instantiation: htsconcat.c:htsbuff_cat
Unexecuted instantiation: htswarc.c:htsbuff_cat
Unexecuted instantiation: htsback.c:htsbuff_cat
Unexecuted instantiation: htsftp.c:htsbuff_cat
Unexecuted instantiation: htsthread.c:htsbuff_cat
Unexecuted instantiation: htscore.c:htsbuff_cat
Unexecuted instantiation: htshash.c:htsbuff_cat
Unexecuted instantiation: htstools.c:htsbuff_cat
Unexecuted instantiation: htscache.c:htsbuff_cat
Unexecuted instantiation: htsdate.c:htsbuff_cat
Unexecuted instantiation: htszlib.c:htsbuff_cat
Unexecuted instantiation: htscodec.c:htsbuff_cat
Unexecuted instantiation: htschanges.c:htsbuff_cat
Unexecuted instantiation: htsmd5.c:htsbuff_cat
Unexecuted instantiation: htsmodules.c:htsbuff_cat
Unexecuted instantiation: htsbauth.c:htsbuff_cat
Unexecuted instantiation: htsindex.c:htsbuff_cat
Unexecuted instantiation: htsrobots.c:htsbuff_cat
Unexecuted instantiation: htsfilters.c:htsbuff_cat
Unexecuted instantiation: htssitemap.c:htsbuff_cat
Unexecuted instantiation: htswizard.c:htsbuff_cat
Unexecuted instantiation: htsparse.c:htsbuff_cat
Unexecuted instantiation: htssinglefile.c:htsbuff_cat
Unexecuted instantiation: htsname.c:htsbuff_cat
Unexecuted instantiation: htsnet.c:htsbuff_cat
Unexecuted instantiation: htsproxy.c:htsbuff_cat
Unexecuted instantiation: htsencoding.c:htsbuff_cat
Unexecuted instantiation: htssniff.c:htsbuff_cat
457
458
/** Append a single character (including '\0' as data). Aborts on overflow. */
459
0
static HTS_INLINE HTS_UNUSED void htsbuff_catc(htsbuff *b, char c) {
460
0
  assertf__(1 < b->cap - b->len, "htsbuff append overflow", __FILE__, __LINE__);
461
0
  b->buf[b->len++] = c;
462
0
  b->buf[b->len] = '\0';
463
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_catc
Unexecuted instantiation: htscharset.c:htsbuff_catc
Unexecuted instantiation: htslib.c:htsbuff_catc
Unexecuted instantiation: htsconcat.c:htsbuff_catc
Unexecuted instantiation: htswarc.c:htsbuff_catc
Unexecuted instantiation: htsback.c:htsbuff_catc
Unexecuted instantiation: htsftp.c:htsbuff_catc
Unexecuted instantiation: htsthread.c:htsbuff_catc
Unexecuted instantiation: htscore.c:htsbuff_catc
Unexecuted instantiation: htshash.c:htsbuff_catc
Unexecuted instantiation: htstools.c:htsbuff_catc
Unexecuted instantiation: htscache.c:htsbuff_catc
Unexecuted instantiation: htsdate.c:htsbuff_catc
Unexecuted instantiation: htszlib.c:htsbuff_catc
Unexecuted instantiation: htscodec.c:htsbuff_catc
Unexecuted instantiation: htschanges.c:htsbuff_catc
Unexecuted instantiation: htsmd5.c:htsbuff_catc
Unexecuted instantiation: htsmodules.c:htsbuff_catc
Unexecuted instantiation: htsbauth.c:htsbuff_catc
Unexecuted instantiation: htsindex.c:htsbuff_catc
Unexecuted instantiation: htsrobots.c:htsbuff_catc
Unexecuted instantiation: htsfilters.c:htsbuff_catc
Unexecuted instantiation: htssitemap.c:htsbuff_catc
Unexecuted instantiation: htswizard.c:htsbuff_catc
Unexecuted instantiation: htsparse.c:htsbuff_catc
Unexecuted instantiation: htssinglefile.c:htsbuff_catc
Unexecuted instantiation: htsname.c:htsbuff_catc
Unexecuted instantiation: htsnet.c:htsbuff_catc
Unexecuted instantiation: htsproxy.c:htsbuff_catc
Unexecuted instantiation: htsencoding.c:htsbuff_catc
Unexecuted instantiation: htssniff.c:htsbuff_catc
464
465
/** Reset content to s. Aborts on overflow. */
466
0
static HTS_INLINE HTS_UNUSED void htsbuff_cpy(htsbuff *b, const char *s) {
467
0
  b->len = 0;
468
0
  htsbuff_catn(b, s, (size_t) -1);
469
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_cpy
Unexecuted instantiation: htscharset.c:htsbuff_cpy
Unexecuted instantiation: htslib.c:htsbuff_cpy
Unexecuted instantiation: htsconcat.c:htsbuff_cpy
Unexecuted instantiation: htswarc.c:htsbuff_cpy
Unexecuted instantiation: htsback.c:htsbuff_cpy
Unexecuted instantiation: htsftp.c:htsbuff_cpy
Unexecuted instantiation: htsthread.c:htsbuff_cpy
Unexecuted instantiation: htscore.c:htsbuff_cpy
Unexecuted instantiation: htshash.c:htsbuff_cpy
Unexecuted instantiation: htstools.c:htsbuff_cpy
Unexecuted instantiation: htscache.c:htsbuff_cpy
Unexecuted instantiation: htsdate.c:htsbuff_cpy
Unexecuted instantiation: htszlib.c:htsbuff_cpy
Unexecuted instantiation: htscodec.c:htsbuff_cpy
Unexecuted instantiation: htschanges.c:htsbuff_cpy
Unexecuted instantiation: htsmd5.c:htsbuff_cpy
Unexecuted instantiation: htsmodules.c:htsbuff_cpy
Unexecuted instantiation: htsbauth.c:htsbuff_cpy
Unexecuted instantiation: htsindex.c:htsbuff_cpy
Unexecuted instantiation: htsrobots.c:htsbuff_cpy
Unexecuted instantiation: htsfilters.c:htsbuff_cpy
Unexecuted instantiation: htssitemap.c:htsbuff_cpy
Unexecuted instantiation: htswizard.c:htsbuff_cpy
Unexecuted instantiation: htsparse.c:htsbuff_cpy
Unexecuted instantiation: htssinglefile.c:htsbuff_cpy
Unexecuted instantiation: htsname.c:htsbuff_cpy
Unexecuted instantiation: htsnet.c:htsbuff_cpy
Unexecuted instantiation: htsproxy.c:htsbuff_cpy
Unexecuted instantiation: htsencoding.c:htsbuff_cpy
Unexecuted instantiation: htssniff.c:htsbuff_cpy
470
471
/** Current NUL-terminated content. */
472
0
static HTS_INLINE HTS_UNUSED const char *htsbuff_str(const htsbuff *b) {
473
0
  return b->buf;
474
0
}
Unexecuted instantiation: fuzz-charset.c:htsbuff_str
Unexecuted instantiation: htscharset.c:htsbuff_str
Unexecuted instantiation: htslib.c:htsbuff_str
Unexecuted instantiation: htsconcat.c:htsbuff_str
Unexecuted instantiation: htswarc.c:htsbuff_str
Unexecuted instantiation: htsback.c:htsbuff_str
Unexecuted instantiation: htsftp.c:htsbuff_str
Unexecuted instantiation: htsthread.c:htsbuff_str
Unexecuted instantiation: htscore.c:htsbuff_str
Unexecuted instantiation: htshash.c:htsbuff_str
Unexecuted instantiation: htstools.c:htsbuff_str
Unexecuted instantiation: htscache.c:htsbuff_str
Unexecuted instantiation: htsdate.c:htsbuff_str
Unexecuted instantiation: htszlib.c:htsbuff_str
Unexecuted instantiation: htscodec.c:htsbuff_str
Unexecuted instantiation: htschanges.c:htsbuff_str
Unexecuted instantiation: htsmd5.c:htsbuff_str
Unexecuted instantiation: htsmodules.c:htsbuff_str
Unexecuted instantiation: htsbauth.c:htsbuff_str
Unexecuted instantiation: htsindex.c:htsbuff_str
Unexecuted instantiation: htsrobots.c:htsbuff_str
Unexecuted instantiation: htsfilters.c:htsbuff_str
Unexecuted instantiation: htssitemap.c:htsbuff_str
Unexecuted instantiation: htswizard.c:htsbuff_str
Unexecuted instantiation: htsparse.c:htsbuff_str
Unexecuted instantiation: htssinglefile.c:htsbuff_str
Unexecuted instantiation: htsname.c:htsbuff_str
Unexecuted instantiation: htsnet.c:htsbuff_str
Unexecuted instantiation: htsproxy.c:htsbuff_str
Unexecuted instantiation: htsencoding.c:htsbuff_str
Unexecuted instantiation: htssniff.c:htsbuff_str
475
476
/**
477
 * Copy src into dest (capacity size, NUL included), truncating to fit and
478
 * always NUL-terminating. Unlike strlcpybuff() it never aborts, so it suits a
479
 * value read back from a cache, a header or the wire, where refusing the whole
480
 * record is worse than keeping a clipped one. Returns HTS_TRUE if it all fit;
481
 * callers that clip on purpose ignore that, so it is not HTS_CHECK_RESULT.
482
 */
483
static HTS_INLINE HTS_UNUSED hts_boolean strclipbuff(char *dest, size_t size,
484
0
                                                     const char *src) {
485
0
  size_t len, copy;
486
487
0
  assertf(dest != NULL && src != NULL && size != 0);
488
0
  len = strlen(src);
489
0
  copy = len < size ? len : size - 1;
490
0
  memcpy(dest, src, copy);
491
0
  dest[copy] = '\0';
492
0
  return copy == len ? HTS_TRUE : HTS_FALSE;
493
0
}
Unexecuted instantiation: fuzz-charset.c:strclipbuff
Unexecuted instantiation: htscharset.c:strclipbuff
Unexecuted instantiation: htslib.c:strclipbuff
Unexecuted instantiation: htsconcat.c:strclipbuff
Unexecuted instantiation: htswarc.c:strclipbuff
Unexecuted instantiation: htsback.c:strclipbuff
Unexecuted instantiation: htsftp.c:strclipbuff
Unexecuted instantiation: htsthread.c:strclipbuff
Unexecuted instantiation: htscore.c:strclipbuff
Unexecuted instantiation: htshash.c:strclipbuff
Unexecuted instantiation: htstools.c:strclipbuff
Unexecuted instantiation: htscache.c:strclipbuff
Unexecuted instantiation: htsdate.c:strclipbuff
Unexecuted instantiation: htszlib.c:strclipbuff
Unexecuted instantiation: htscodec.c:strclipbuff
Unexecuted instantiation: htschanges.c:strclipbuff
Unexecuted instantiation: htsmd5.c:strclipbuff
Unexecuted instantiation: htsmodules.c:strclipbuff
Unexecuted instantiation: htsbauth.c:strclipbuff
Unexecuted instantiation: htsindex.c:strclipbuff
Unexecuted instantiation: htsrobots.c:strclipbuff
Unexecuted instantiation: htsfilters.c:strclipbuff
Unexecuted instantiation: htssitemap.c:strclipbuff
Unexecuted instantiation: htswizard.c:strclipbuff
Unexecuted instantiation: htsparse.c:strclipbuff
Unexecuted instantiation: htssinglefile.c:strclipbuff
Unexecuted instantiation: htsname.c:strclipbuff
Unexecuted instantiation: htsnet.c:strclipbuff
Unexecuted instantiation: htsproxy.c:strclipbuff
Unexecuted instantiation: htsencoding.c:strclipbuff
Unexecuted instantiation: htssniff.c:strclipbuff
494
495
/**
496
 * Callers that deliberately ignore truncation use this instead of
497
 * slprintfbuff(), so it is not HTS_CHECK_RESULT.
498
 */
499
static HTS_INLINE HTS_UNUSED HTS_PRINTF_FUN(3, 0) hts_boolean
500
0
    vslprintfbuff(char *dest, size_t size, const char *fmt, va_list args) {
501
0
  int ret;
502
503
0
  assertf(dest != NULL && size != 0);
504
  /* a vsnprintf failing outright may write nothing at all, leaving whatever
505
     the caller had on the stack for it to publish */
506
0
  dest[0] = '\0';
507
0
  ret = vsnprintf(dest, size, fmt, args);
508
  /* pre-C99 runtimes (msvcrt _vsnprintf) return -1 and do not terminate */
509
0
  dest[size - 1] = '\0';
510
0
  return ret >= 0 && (size_t) ret < size ? HTS_TRUE : HTS_FALSE;
511
0
}
Unexecuted instantiation: fuzz-charset.c:vslprintfbuff
Unexecuted instantiation: htscharset.c:vslprintfbuff
Unexecuted instantiation: htslib.c:vslprintfbuff
Unexecuted instantiation: htsconcat.c:vslprintfbuff
Unexecuted instantiation: htswarc.c:vslprintfbuff
Unexecuted instantiation: htsback.c:vslprintfbuff
Unexecuted instantiation: htsftp.c:vslprintfbuff
Unexecuted instantiation: htsthread.c:vslprintfbuff
Unexecuted instantiation: htscore.c:vslprintfbuff
Unexecuted instantiation: htshash.c:vslprintfbuff
Unexecuted instantiation: htstools.c:vslprintfbuff
Unexecuted instantiation: htscache.c:vslprintfbuff
Unexecuted instantiation: htsdate.c:vslprintfbuff
Unexecuted instantiation: htszlib.c:vslprintfbuff
Unexecuted instantiation: htscodec.c:vslprintfbuff
Unexecuted instantiation: htschanges.c:vslprintfbuff
Unexecuted instantiation: htsmd5.c:vslprintfbuff
Unexecuted instantiation: htsmodules.c:vslprintfbuff
Unexecuted instantiation: htsbauth.c:vslprintfbuff
Unexecuted instantiation: htsindex.c:vslprintfbuff
Unexecuted instantiation: htsrobots.c:vslprintfbuff
Unexecuted instantiation: htsfilters.c:vslprintfbuff
Unexecuted instantiation: htssitemap.c:vslprintfbuff
Unexecuted instantiation: htswizard.c:vslprintfbuff
Unexecuted instantiation: htsparse.c:vslprintfbuff
Unexecuted instantiation: htssinglefile.c:vslprintfbuff
Unexecuted instantiation: htsname.c:vslprintfbuff
Unexecuted instantiation: htsnet.c:vslprintfbuff
Unexecuted instantiation: htsproxy.c:vslprintfbuff
Unexecuted instantiation: htsencoding.c:vslprintfbuff
Unexecuted instantiation: htssniff.c:vslprintfbuff
512
513
/**
514
 * Formatted print into dest (capacity size, NUL included), truncating to fit
515
 * and always NUL-terminating. Returns HTS_TRUE if the whole output fit; the
516
 * result is the only truncation signal, so it must be acted on. Unlike
517
 * strcpybuff() it never aborts, so it suits text built from remote input.
518
 */
519
static HTS_INLINE HTS_UNUSED HTS_CHECK_RESULT HTS_PRINTF_FUN(3, 4) hts_boolean
520
0
    slprintfbuff(char *dest, size_t size, const char *fmt, ...) {
521
0
  va_list args;
522
0
  hts_boolean ret;
523
524
0
  va_start(args, fmt);
525
0
  ret = vslprintfbuff(dest, size, fmt, args);
526
0
  va_end(args);
527
0
  return ret;
528
0
}
Unexecuted instantiation: fuzz-charset.c:slprintfbuff
Unexecuted instantiation: htscharset.c:slprintfbuff
Unexecuted instantiation: htslib.c:slprintfbuff
Unexecuted instantiation: htsconcat.c:slprintfbuff
Unexecuted instantiation: htswarc.c:slprintfbuff
Unexecuted instantiation: htsback.c:slprintfbuff
Unexecuted instantiation: htsftp.c:slprintfbuff
Unexecuted instantiation: htsthread.c:slprintfbuff
Unexecuted instantiation: htscore.c:slprintfbuff
Unexecuted instantiation: htshash.c:slprintfbuff
Unexecuted instantiation: htstools.c:slprintfbuff
Unexecuted instantiation: htscache.c:slprintfbuff
Unexecuted instantiation: htsdate.c:slprintfbuff
Unexecuted instantiation: htszlib.c:slprintfbuff
Unexecuted instantiation: htscodec.c:slprintfbuff
Unexecuted instantiation: htschanges.c:slprintfbuff
Unexecuted instantiation: htsmd5.c:slprintfbuff
Unexecuted instantiation: htsmodules.c:slprintfbuff
Unexecuted instantiation: htsbauth.c:slprintfbuff
Unexecuted instantiation: htsindex.c:slprintfbuff
Unexecuted instantiation: htsrobots.c:slprintfbuff
Unexecuted instantiation: htsfilters.c:slprintfbuff
Unexecuted instantiation: htssitemap.c:slprintfbuff
Unexecuted instantiation: htswizard.c:slprintfbuff
Unexecuted instantiation: htsparse.c:slprintfbuff
Unexecuted instantiation: htssinglefile.c:slprintfbuff
Unexecuted instantiation: htsname.c:slprintfbuff
Unexecuted instantiation: htsnet.c:slprintfbuff
Unexecuted instantiation: htsproxy.c:slprintfbuff
Unexecuted instantiation: htsencoding.c:slprintfbuff
Unexecuted instantiation: htssniff.c:slprintfbuff
529
530
/**
531
 * Append formatted text at dest[*used] (dest capacity size, NUL included),
532
 * advancing *used past it. All-or-nothing: on overflow dest is left as it was
533
 * and HTS_FALSE returned, so a record parsed back field by field never carries
534
 * a half-written one.
535
 */
536
static HTS_INLINE HTS_UNUSED HTS_CHECK_RESULT HTS_PRINTF_FUN(4, 5) hts_boolean
537
    slcatprintfbuff(char *dest, size_t size, size_t *used, const char *fmt,
538
0
                    ...) {
539
0
  va_list args;
540
0
  hts_boolean fit;
541
542
0
  assertf(dest != NULL && used != NULL && *used < size);
543
0
  va_start(args, fmt);
544
0
  fit = vslprintfbuff(dest + *used, size - *used, fmt, args);
545
0
  va_end(args);
546
0
  if (fit) {
547
0
    *used += strlen(dest + *used);
548
0
  } else {
549
0
    dest[*used] = '\0';
550
0
  }
551
0
  return fit;
552
0
}
Unexecuted instantiation: fuzz-charset.c:slcatprintfbuff
Unexecuted instantiation: htscharset.c:slcatprintfbuff
Unexecuted instantiation: htslib.c:slcatprintfbuff
Unexecuted instantiation: htsconcat.c:slcatprintfbuff
Unexecuted instantiation: htswarc.c:slcatprintfbuff
Unexecuted instantiation: htsback.c:slcatprintfbuff
Unexecuted instantiation: htsftp.c:slcatprintfbuff
Unexecuted instantiation: htsthread.c:slcatprintfbuff
Unexecuted instantiation: htscore.c:slcatprintfbuff
Unexecuted instantiation: htshash.c:slcatprintfbuff
Unexecuted instantiation: htstools.c:slcatprintfbuff
Unexecuted instantiation: htscache.c:slcatprintfbuff
Unexecuted instantiation: htsdate.c:slcatprintfbuff
Unexecuted instantiation: htszlib.c:slcatprintfbuff
Unexecuted instantiation: htscodec.c:slcatprintfbuff
Unexecuted instantiation: htschanges.c:slcatprintfbuff
Unexecuted instantiation: htsmd5.c:slcatprintfbuff
Unexecuted instantiation: htsmodules.c:slcatprintfbuff
Unexecuted instantiation: htsbauth.c:slcatprintfbuff
Unexecuted instantiation: htsindex.c:slcatprintfbuff
Unexecuted instantiation: htsrobots.c:slcatprintfbuff
Unexecuted instantiation: htsfilters.c:slcatprintfbuff
Unexecuted instantiation: htssitemap.c:slcatprintfbuff
Unexecuted instantiation: htswizard.c:slcatprintfbuff
Unexecuted instantiation: htsparse.c:slcatprintfbuff
Unexecuted instantiation: htssinglefile.c:slcatprintfbuff
Unexecuted instantiation: htsname.c:slcatprintfbuff
Unexecuted instantiation: htsnet.c:slcatprintfbuff
Unexecuted instantiation: htsproxy.c:slcatprintfbuff
Unexecuted instantiation: htsencoding.c:slcatprintfbuff
Unexecuted instantiation: htssniff.c:slcatprintfbuff
553
554
/**
555
 * slprintfbuff() for diagnostics quoting remote or client text, which are
556
 * meant to be clipped: nothing to act on, hence not HTS_CHECK_RESULT. A (void)
557
 * cast on slprintfbuff() is no substitute, GCC warns through it.
558
 */
559
static HTS_INLINE HTS_UNUSED HTS_PRINTF_FUN(3, 4) void slprintfbuff_clip(
560
0
    char *dest, size_t size, const char *fmt, ...) {
561
0
  va_list args;
562
563
0
  va_start(args, fmt);
564
0
  (void) vslprintfbuff(dest, size, fmt, args);
565
0
  va_end(args);
566
0
}
Unexecuted instantiation: fuzz-charset.c:slprintfbuff_clip
Unexecuted instantiation: htscharset.c:slprintfbuff_clip
Unexecuted instantiation: htslib.c:slprintfbuff_clip
Unexecuted instantiation: htsconcat.c:slprintfbuff_clip
Unexecuted instantiation: htswarc.c:slprintfbuff_clip
Unexecuted instantiation: htsback.c:slprintfbuff_clip
Unexecuted instantiation: htsftp.c:slprintfbuff_clip
Unexecuted instantiation: htsthread.c:slprintfbuff_clip
Unexecuted instantiation: htscore.c:slprintfbuff_clip
Unexecuted instantiation: htshash.c:slprintfbuff_clip
Unexecuted instantiation: htstools.c:slprintfbuff_clip
Unexecuted instantiation: htscache.c:slprintfbuff_clip
Unexecuted instantiation: htsdate.c:slprintfbuff_clip
Unexecuted instantiation: htszlib.c:slprintfbuff_clip
Unexecuted instantiation: htscodec.c:slprintfbuff_clip
Unexecuted instantiation: htschanges.c:slprintfbuff_clip
Unexecuted instantiation: htsmd5.c:slprintfbuff_clip
Unexecuted instantiation: htsmodules.c:slprintfbuff_clip
Unexecuted instantiation: htsbauth.c:slprintfbuff_clip
Unexecuted instantiation: htsindex.c:slprintfbuff_clip
Unexecuted instantiation: htsrobots.c:slprintfbuff_clip
Unexecuted instantiation: htsfilters.c:slprintfbuff_clip
Unexecuted instantiation: htssitemap.c:slprintfbuff_clip
Unexecuted instantiation: htswizard.c:slprintfbuff_clip
Unexecuted instantiation: htsparse.c:slprintfbuff_clip
Unexecuted instantiation: htssinglefile.c:slprintfbuff_clip
Unexecuted instantiation: htsname.c:slprintfbuff_clip
Unexecuted instantiation: htsnet.c:slprintfbuff_clip
Unexecuted instantiation: htsproxy.c:slprintfbuff_clip
Unexecuted instantiation: htsencoding.c:slprintfbuff_clip
Unexecuted instantiation: htssniff.c:slprintfbuff_clip
567
568
/**
569
 * slprintfbuff() over the in-scope array ARR (capacity = sizeof(ARR)).
570
 * On GCC/Clang a pointer is a compile error; use slprintfbuff() for those.
571
 */
572
#if (defined(__GNUC__) && !defined(__cplusplus))
573
#define sprintfbuff(ARR, ...)                                                  \
574
0
  slprintfbuff((ARR), sizeof(ARR) + htsbuff_must_be_array_(ARR), __VA_ARGS__)
575
#else
576
#define sprintfbuff(ARR, ...) slprintfbuff((ARR), sizeof(ARR), __VA_ARGS__)
577
#endif
578
579
/* Last character of s, or '\0' when s is empty. Replaces s[strlen(s) - 1],
580
   which indexes one byte before the buffer on an empty string. */
581
0
static HTS_INLINE HTS_UNUSED char hts_lastchar(const char *s) {
582
0
  const size_t len = strlen(s);
583
584
0
  return len != 0 ? s[len - 1] : '\0';
585
0
}
Unexecuted instantiation: fuzz-charset.c:hts_lastchar
Unexecuted instantiation: htscharset.c:hts_lastchar
Unexecuted instantiation: htslib.c:hts_lastchar
Unexecuted instantiation: htsconcat.c:hts_lastchar
Unexecuted instantiation: htswarc.c:hts_lastchar
Unexecuted instantiation: htsback.c:hts_lastchar
Unexecuted instantiation: htsftp.c:hts_lastchar
Unexecuted instantiation: htsthread.c:hts_lastchar
Unexecuted instantiation: htscore.c:hts_lastchar
Unexecuted instantiation: htshash.c:hts_lastchar
Unexecuted instantiation: htstools.c:hts_lastchar
Unexecuted instantiation: htscache.c:hts_lastchar
Unexecuted instantiation: htsdate.c:hts_lastchar
Unexecuted instantiation: htszlib.c:hts_lastchar
Unexecuted instantiation: htscodec.c:hts_lastchar
Unexecuted instantiation: htschanges.c:hts_lastchar
Unexecuted instantiation: htsmd5.c:hts_lastchar
Unexecuted instantiation: htsmodules.c:hts_lastchar
Unexecuted instantiation: htsbauth.c:hts_lastchar
Unexecuted instantiation: htsindex.c:hts_lastchar
Unexecuted instantiation: htsrobots.c:hts_lastchar
Unexecuted instantiation: htsfilters.c:hts_lastchar
Unexecuted instantiation: htssitemap.c:hts_lastchar
Unexecuted instantiation: htswizard.c:hts_lastchar
Unexecuted instantiation: htsparse.c:hts_lastchar
Unexecuted instantiation: htssinglefile.c:hts_lastchar
Unexecuted instantiation: htsname.c:hts_lastchar
Unexecuted instantiation: htsnet.c:hts_lastchar
Unexecuted instantiation: htsproxy.c:hts_lastchar
Unexecuted instantiation: htsencoding.c:hts_lastchar
Unexecuted instantiation: htssniff.c:hts_lastchar
586
587
/* Drop a trailing c from s if present; HTS_TRUE if one was dropped. */
588
0
static HTS_INLINE HTS_UNUSED hts_boolean hts_striplastchar(char *s, char c) {
589
0
  const size_t len = strlen(s);
590
591
0
  if (len != 0 && s[len - 1] == c) {
592
0
    s[len - 1] = '\0';
593
0
    return HTS_TRUE;
594
0
  }
595
0
  return HTS_FALSE;
596
0
}
Unexecuted instantiation: fuzz-charset.c:hts_striplastchar
Unexecuted instantiation: htscharset.c:hts_striplastchar
Unexecuted instantiation: htslib.c:hts_striplastchar
Unexecuted instantiation: htsconcat.c:hts_striplastchar
Unexecuted instantiation: htswarc.c:hts_striplastchar
Unexecuted instantiation: htsback.c:hts_striplastchar
Unexecuted instantiation: htsftp.c:hts_striplastchar
Unexecuted instantiation: htsthread.c:hts_striplastchar
Unexecuted instantiation: htscore.c:hts_striplastchar
Unexecuted instantiation: htshash.c:hts_striplastchar
Unexecuted instantiation: htstools.c:hts_striplastchar
Unexecuted instantiation: htscache.c:hts_striplastchar
Unexecuted instantiation: htsdate.c:hts_striplastchar
Unexecuted instantiation: htszlib.c:hts_striplastchar
Unexecuted instantiation: htscodec.c:hts_striplastchar
Unexecuted instantiation: htschanges.c:hts_striplastchar
Unexecuted instantiation: htsmd5.c:hts_striplastchar
Unexecuted instantiation: htsmodules.c:hts_striplastchar
Unexecuted instantiation: htsbauth.c:hts_striplastchar
Unexecuted instantiation: htsindex.c:hts_striplastchar
Unexecuted instantiation: htsrobots.c:hts_striplastchar
Unexecuted instantiation: htsfilters.c:hts_striplastchar
Unexecuted instantiation: htssitemap.c:hts_striplastchar
Unexecuted instantiation: htswizard.c:hts_striplastchar
Unexecuted instantiation: htsparse.c:hts_striplastchar
Unexecuted instantiation: htssinglefile.c:hts_striplastchar
Unexecuted instantiation: htsname.c:hts_striplastchar
Unexecuted instantiation: htsnet.c:hts_striplastchar
Unexecuted instantiation: htsproxy.c:hts_striplastchar
Unexecuted instantiation: htsencoding.c:hts_striplastchar
Unexecuted instantiation: htssniff.c:hts_striplastchar
597
598
/* Drop the last character of s whatever it is; HTS_TRUE if s was not empty. */
599
0
static HTS_INLINE HTS_UNUSED hts_boolean hts_choplastchar(char *s) {
600
0
  const size_t len = strlen(s);
601
602
0
  if (len != 0) {
603
0
    s[len - 1] = '\0';
604
0
    return HTS_TRUE;
605
0
  }
606
0
  return HTS_FALSE;
607
0
}
Unexecuted instantiation: fuzz-charset.c:hts_choplastchar
Unexecuted instantiation: htscharset.c:hts_choplastchar
Unexecuted instantiation: htslib.c:hts_choplastchar
Unexecuted instantiation: htsconcat.c:hts_choplastchar
Unexecuted instantiation: htswarc.c:hts_choplastchar
Unexecuted instantiation: htsback.c:hts_choplastchar
Unexecuted instantiation: htsftp.c:hts_choplastchar
Unexecuted instantiation: htsthread.c:hts_choplastchar
Unexecuted instantiation: htscore.c:hts_choplastchar
Unexecuted instantiation: htshash.c:hts_choplastchar
Unexecuted instantiation: htstools.c:hts_choplastchar
Unexecuted instantiation: htscache.c:hts_choplastchar
Unexecuted instantiation: htsdate.c:hts_choplastchar
Unexecuted instantiation: htszlib.c:hts_choplastchar
Unexecuted instantiation: htscodec.c:hts_choplastchar
Unexecuted instantiation: htschanges.c:hts_choplastchar
Unexecuted instantiation: htsmd5.c:hts_choplastchar
Unexecuted instantiation: htsmodules.c:hts_choplastchar
Unexecuted instantiation: htsbauth.c:hts_choplastchar
Unexecuted instantiation: htsindex.c:hts_choplastchar
Unexecuted instantiation: htsrobots.c:hts_choplastchar
Unexecuted instantiation: htsfilters.c:hts_choplastchar
Unexecuted instantiation: htssitemap.c:hts_choplastchar
Unexecuted instantiation: htswizard.c:hts_choplastchar
Unexecuted instantiation: htsparse.c:hts_choplastchar
Unexecuted instantiation: htssinglefile.c:hts_choplastchar
Unexecuted instantiation: htsname.c:hts_choplastchar
Unexecuted instantiation: htsnet.c:hts_choplastchar
Unexecuted instantiation: htsproxy.c:hts_choplastchar
Unexecuted instantiation: htsencoding.c:hts_choplastchar
Unexecuted instantiation: htssniff.c:hts_choplastchar
608
609
/* htslib.h's is_space() and is_realspace() as hts_rtrim() sets; -#test=rtrim
610
   keeps them in sync. */
611
0
#define HTS_SPACES " \"\n\r\t\f\v'"
612
#define HTS_REALSPACES " \n\r\t\f\v"
613
614
/* Length of s once its trailing bytes from set are dropped; 0 if they all are.
615
   Counts down from the end, so it stops at s rather than below the buffer. */
616
static HTS_INLINE HTS_UNUSED size_t hts_rtrimlen(const char *s,
617
0
                                                 const char *set) {
618
0
  size_t len = strlen(s);
619
620
0
  while (len != 0 && strchr(set, s[len - 1]) != NULL)
621
0
    len--;
622
0
  return len;
623
0
}
Unexecuted instantiation: fuzz-charset.c:hts_rtrimlen
Unexecuted instantiation: htscharset.c:hts_rtrimlen
Unexecuted instantiation: htslib.c:hts_rtrimlen
Unexecuted instantiation: htsconcat.c:hts_rtrimlen
Unexecuted instantiation: htswarc.c:hts_rtrimlen
Unexecuted instantiation: htsback.c:hts_rtrimlen
Unexecuted instantiation: htsftp.c:hts_rtrimlen
Unexecuted instantiation: htsthread.c:hts_rtrimlen
Unexecuted instantiation: htscore.c:hts_rtrimlen
Unexecuted instantiation: htshash.c:hts_rtrimlen
Unexecuted instantiation: htstools.c:hts_rtrimlen
Unexecuted instantiation: htscache.c:hts_rtrimlen
Unexecuted instantiation: htsdate.c:hts_rtrimlen
Unexecuted instantiation: htszlib.c:hts_rtrimlen
Unexecuted instantiation: htscodec.c:hts_rtrimlen
Unexecuted instantiation: htschanges.c:hts_rtrimlen
Unexecuted instantiation: htsmd5.c:hts_rtrimlen
Unexecuted instantiation: htsmodules.c:hts_rtrimlen
Unexecuted instantiation: htsbauth.c:hts_rtrimlen
Unexecuted instantiation: htsindex.c:hts_rtrimlen
Unexecuted instantiation: htsrobots.c:hts_rtrimlen
Unexecuted instantiation: htsfilters.c:hts_rtrimlen
Unexecuted instantiation: htssitemap.c:hts_rtrimlen
Unexecuted instantiation: htswizard.c:hts_rtrimlen
Unexecuted instantiation: htsparse.c:hts_rtrimlen
Unexecuted instantiation: htssinglefile.c:hts_rtrimlen
Unexecuted instantiation: htsname.c:hts_rtrimlen
Unexecuted instantiation: htsnet.c:hts_rtrimlen
Unexecuted instantiation: htsproxy.c:hts_rtrimlen
Unexecuted instantiation: htsencoding.c:hts_rtrimlen
Unexecuted instantiation: htssniff.c:hts_rtrimlen
624
625
/* Drop the trailing bytes of s that occur in set. */
626
0
static HTS_INLINE HTS_UNUSED void hts_rtrim(char *s, const char *set) {
627
0
  s[hts_rtrimlen(s, set)] = '\0';
628
0
}
Unexecuted instantiation: fuzz-charset.c:hts_rtrim
Unexecuted instantiation: htscharset.c:hts_rtrim
Unexecuted instantiation: htslib.c:hts_rtrim
Unexecuted instantiation: htsconcat.c:hts_rtrim
Unexecuted instantiation: htswarc.c:hts_rtrim
Unexecuted instantiation: htsback.c:hts_rtrim
Unexecuted instantiation: htsftp.c:hts_rtrim
Unexecuted instantiation: htsthread.c:hts_rtrim
Unexecuted instantiation: htscore.c:hts_rtrim
Unexecuted instantiation: htshash.c:hts_rtrim
Unexecuted instantiation: htstools.c:hts_rtrim
Unexecuted instantiation: htscache.c:hts_rtrim
Unexecuted instantiation: htsdate.c:hts_rtrim
Unexecuted instantiation: htszlib.c:hts_rtrim
Unexecuted instantiation: htscodec.c:hts_rtrim
Unexecuted instantiation: htschanges.c:hts_rtrim
Unexecuted instantiation: htsmd5.c:hts_rtrim
Unexecuted instantiation: htsmodules.c:hts_rtrim
Unexecuted instantiation: htsbauth.c:hts_rtrim
Unexecuted instantiation: htsindex.c:hts_rtrim
Unexecuted instantiation: htsrobots.c:hts_rtrim
Unexecuted instantiation: htsfilters.c:hts_rtrim
Unexecuted instantiation: htssitemap.c:hts_rtrim
Unexecuted instantiation: htswizard.c:hts_rtrim
Unexecuted instantiation: htsparse.c:hts_rtrim
Unexecuted instantiation: htssinglefile.c:hts_rtrim
Unexecuted instantiation: htsname.c:hts_rtrim
Unexecuted instantiation: htsnet.c:hts_rtrim
Unexecuted instantiation: htsproxy.c:hts_rtrim
Unexecuted instantiation: htsencoding.c:hts_rtrim
Unexecuted instantiation: htssniff.c:hts_rtrim
629
630
/* Offset of the last character of s, or 0 when s is empty. */
631
0
static HTS_INLINE HTS_UNUSED size_t hts_lastcharoffset(const char *s) {
632
0
  const size_t len = strlen(s);
633
634
0
  return len != 0 ? len - 1 : 0;
635
0
}
Unexecuted instantiation: fuzz-charset.c:hts_lastcharoffset
Unexecuted instantiation: htscharset.c:hts_lastcharoffset
Unexecuted instantiation: htslib.c:hts_lastcharoffset
Unexecuted instantiation: htsconcat.c:hts_lastcharoffset
Unexecuted instantiation: htswarc.c:hts_lastcharoffset
Unexecuted instantiation: htsback.c:hts_lastcharoffset
Unexecuted instantiation: htsftp.c:hts_lastcharoffset
Unexecuted instantiation: htsthread.c:hts_lastcharoffset
Unexecuted instantiation: htscore.c:hts_lastcharoffset
Unexecuted instantiation: htshash.c:hts_lastcharoffset
Unexecuted instantiation: htstools.c:hts_lastcharoffset
Unexecuted instantiation: htscache.c:hts_lastcharoffset
Unexecuted instantiation: htsdate.c:hts_lastcharoffset
Unexecuted instantiation: htszlib.c:hts_lastcharoffset
Unexecuted instantiation: htscodec.c:hts_lastcharoffset
Unexecuted instantiation: htschanges.c:hts_lastcharoffset
Unexecuted instantiation: htsmd5.c:hts_lastcharoffset
Unexecuted instantiation: htsmodules.c:hts_lastcharoffset
Unexecuted instantiation: htsbauth.c:hts_lastcharoffset
Unexecuted instantiation: htsindex.c:hts_lastcharoffset
Unexecuted instantiation: htsrobots.c:hts_lastcharoffset
Unexecuted instantiation: htsfilters.c:hts_lastcharoffset
Unexecuted instantiation: htssitemap.c:hts_lastcharoffset
Unexecuted instantiation: htswizard.c:hts_lastcharoffset
Unexecuted instantiation: htsparse.c:hts_lastcharoffset
Unexecuted instantiation: htssinglefile.c:hts_lastcharoffset
Unexecuted instantiation: htsname.c:hts_lastcharoffset
Unexecuted instantiation: htsnet.c:hts_lastcharoffset
Unexecuted instantiation: htsproxy.c:hts_lastcharoffset
Unexecuted instantiation: htsencoding.c:hts_lastcharoffset
Unexecuted instantiation: htssniff.c:hts_lastcharoffset
636
637
/* Address of the last character of S, or of its terminating NUL when S is
638
   empty. S is evaluated twice, so pass an lvalue. */
639
0
#define hts_lastcharptr(S) ((S) + hts_lastcharoffset(S))
640
641
/* Thin aliases over the libc allocator/memcpy (historical "t" suffix); no
642
   added bounds checking. freet() also NULLs the freed pointer and tolerates
643
   NULL. memcpybuff() despite the name is a raw memcpy: the caller owns the
644
   bounds. */
645
2.06k
#define malloct(A) malloc(A)
646
647
0
#define calloct(A, B) calloc((A), (B))
648
649
#define freet(A)                                                               \
650
7.11k
  do {                                                                         \
651
7.11k
    if ((A) != NULL) {                                                         \
652
5.38k
      free(A);                                                                 \
653
5.38k
      (A) = NULL;                                                              \
654
5.38k
    }                                                                          \
655
7.11k
  } while (0)
656
657
0
#define strdupt(A) strdup(A)
658
659
0
#define realloct(A, B) realloc(A, B)
660
661
#define memcpybuff(A, B, N) memcpy((A), (B), (N))
662
663
#endif