/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 |