OpenVPN
buffer.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include "common.h"
30#include "buffer.h"
31#include "error.h"
32#include "mtu.h"
33#include "misc.h"
34
35#include "memdbg.h"
36
37#include <wchar.h>
38
39size_t
40array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
41{
42 const size_t limit = ALLOC_SIZE_MAX;
43 unsigned long long res =
44 (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra;
45 if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit)
46 || unlikely(res > (unsigned long long)limit))
47 {
48 msg(M_FATAL, "attempted allocation of excessively large array");
49 }
50 return (size_t)res;
51}
52
53void
54buf_size_error(const size_t size)
55{
56 msg(M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size);
57}
58
59struct buffer
61alloc_buf_debug(size_t size, const char *file, int line)
62#else
63alloc_buf(size_t size)
64#endif
65{
66 struct buffer buf;
67
68 if (!buf_size_valid(size))
69 {
70 buf_size_error(size);
71 }
72 buf.capacity = (int)size;
73 buf.offset = 0;
74 buf.len = 0;
75#ifdef DMALLOC
76 buf.data = openvpn_dmalloc(file, line, size);
77#else
78 buf.data = calloc(1, size);
79#endif
81
82 return buf;
83}
84
85struct buffer
87alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line)
88#else
89alloc_buf_gc(size_t size, struct gc_arena *gc)
90#endif
91{
92 struct buffer buf;
93 if (!buf_size_valid(size))
94 {
95 buf_size_error(size);
96 }
97 buf.capacity = (int)size;
98 buf.offset = 0;
99 buf.len = 0;
100#ifdef DMALLOC
101 buf.data = (uint8_t *)gc_malloc_debug(size, false, gc, file, line);
102#else
103 buf.data = (uint8_t *)gc_malloc(size, false, gc);
104#endif
105 if (size)
106 {
107 *buf.data = 0;
108 }
109 return buf;
110}
111
112struct buffer
114clone_buf_debug(const struct buffer *buf, const char *file, int line)
115#else
116clone_buf(const struct buffer *buf)
117#endif
118{
119 struct buffer ret;
120 ret.capacity = buf->capacity;
121 ret.offset = buf->offset;
122 ret.len = buf->len;
123#ifdef DMALLOC
124 ret.data = (uint8_t *)openvpn_dmalloc(file, line, buf->capacity);
125#else
126 ret.data = (uint8_t *)malloc(buf->capacity);
127#endif
129 memcpy(BPTR(&ret), BPTR(buf), BLEN(buf));
130 return ret;
131}
132
133#ifdef BUF_INIT_TRACKING
134
135bool
136buf_init_debug(struct buffer *buf, int offset, const char *file, int line)
137{
138 buf->debug_file = file;
139 buf->debug_line = line;
140 return buf_init_dowork(buf, offset);
141}
142
143static inline int
144buf_debug_line(const struct buffer *buf)
145{
146 return buf->debug_line;
147}
148
149static const char *
150buf_debug_file(const struct buffer *buf)
151{
152 return buf->debug_file;
153}
154
155#else /* ifdef BUF_INIT_TRACKING */
156
157#define buf_debug_line(buf) 0
158#define buf_debug_file(buf) "[UNDEF]"
159
160#endif /* ifdef BUF_INIT_TRACKING */
161
162void
163buf_clear(struct buffer *buf)
164{
165 if (buf->capacity > 0)
166 {
167 secure_memzero(buf->data, buf->capacity);
168 }
169 buf->len = 0;
170 buf->offset = 0;
171}
172
173bool
174buf_assign(struct buffer *dest, const struct buffer *src)
175{
176 if (!buf_init(dest, src->offset))
177 {
178 return false;
179 }
180 return buf_write(dest, BPTR(src), BLEN(src));
181}
182
183void
184free_buf(struct buffer *buf)
185{
186 free(buf->data);
187 CLEAR(*buf);
188}
189
190static void
191free_buf_gc(struct buffer *buf, struct gc_arena *gc)
192{
193 if (gc)
194 {
195 struct gc_entry **e = &gc->list;
196
197 while (*e)
198 {
199 /* check if this object is the one we want to delete */
200 if ((uint8_t *)(*e + 1) == buf->data)
201 {
202 struct gc_entry *to_delete = *e;
203
204 /* remove element from linked list and free it */
205 *e = (*e)->next;
206 free(to_delete);
207
208 break;
209 }
210
211 e = &(*e)->next;
212 }
213 }
214
215 CLEAR(*buf);
216}
217
218/*
219 * Return a buffer for write that is a subset of another buffer
220 */
221struct buffer
222buf_sub(struct buffer *buf, int size, bool prepend)
223{
224 struct buffer ret;
225 uint8_t *data;
226
227 CLEAR(ret);
228 data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
229 if (data)
230 {
231 ret.capacity = size;
232 ret.data = data;
233 }
234 return ret;
235}
236
237/*
238 * printf append to a buffer with overflow check
239 */
240bool
241buf_printf(struct buffer *buf, const char *format, ...)
242{
243 int ret = false;
244 if (buf_defined(buf))
245 {
247 uint8_t *ptr = BEND(buf);
248 int cap = buf_forward_capacity(buf);
249
250 if (cap > 0)
251 {
252 int stat;
254 stat = vsnprintf((char *)ptr, cap, format, arglist);
256 *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
257 buf->len += (int)strlen((char *)ptr);
258 if (stat >= 0 && stat < cap)
259 {
260 ret = true;
261 }
262 }
263 }
264 return ret;
265}
266
267bool
268buf_puts(struct buffer *buf, const char *str)
269{
270 int ret = false;
271 uint8_t *ptr = BEND(buf);
272 int cap = buf_forward_capacity(buf);
273 if (cap > 0)
274 {
275 strncpynt((char *)ptr, str, cap);
276 *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
277 buf->len += (int)strlen((char *)ptr);
278 ret = true;
279 }
280 return ret;
281}
282
283/*
284 * write a string to the end of a buffer that was
285 * truncated by buf_printf
286 */
287void
288buf_catrunc(struct buffer *buf, const char *str)
289{
290 if (buf_forward_capacity(buf) <= 1)
291 {
292 size_t len = strlen(str) + 1;
294 {
295 memcpy(buf->data + buf->capacity - len, str, len);
296 }
297 }
298}
299
300bool
301buffer_write_file(const char *filename, const struct buffer *buf)
302{
303 bool ret = false;
304 int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
305 if (fd == -1)
306 {
307 msg(M_ERRNO, "Cannot open file '%s' for write", filename);
308 return false;
309 }
310
311 const ssize_t size = write(fd, BPTR(buf), BLEN(buf));
312 if (size != BLEN(buf))
313 {
314 msg(M_ERRNO, "Write error on file '%s'", filename);
315 goto cleanup;
316 }
317
318 ret = true;
319cleanup:
320 if (close(fd) < 0)
321 {
322 msg(M_ERRNO, "Close error on file %s", filename);
323 ret = false;
324 }
325 return ret;
326}
327
328/*
329 * Garbage collection
330 */
331
332void *
333#ifdef DMALLOC
334gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line)
335#else
336gc_malloc(size_t size, bool clear, struct gc_arena *a)
337#endif
338{
339 void *ret;
340 if (a)
341 {
342 struct gc_entry *e;
343#ifdef DMALLOC
344 e = (struct gc_entry *)openvpn_dmalloc(file, line, size + sizeof(struct gc_entry));
345#else
346 e = (struct gc_entry *)malloc(size + sizeof(struct gc_entry));
347#endif
349 ret = (char *)e + sizeof(struct gc_entry);
350 e->next = a->list;
351 a->list = e;
352 }
353 else
354 {
355#ifdef DMALLOC
356 ret = openvpn_dmalloc(file, line, size);
357#else
358 ret = malloc(size);
359#endif
361 }
362#ifndef ZERO_BUFFER_ON_ALLOC
363 if (clear)
364#endif
365 memset(ret, 0, size);
366 return ret;
367}
368
369void *
370gc_realloc(void *ptr, size_t size, struct gc_arena *a)
371{
372 void *ret = realloc(ptr, size);
374 if (a)
375 {
376 if (ptr && ptr != ret)
377 {
378 /* find the old entry and modify it if realloc changed
379 * the pointer */
380 struct gc_entry_special *e = NULL;
381 for (e = a->list_special; e != NULL; e = e->next)
382 {
383 if (e->addr == ptr)
384 {
385 break;
386 }
387 }
388 ASSERT(e);
389 ASSERT(e->addr == ptr);
390 e->addr = ret;
391 }
392 else if (!ptr)
393 {
394 /* sets e->addr to newptr */
395 gc_addspecial(ret, free, a);
396 }
397 }
398
399 return ret;
400}
401
402void
404{
405 struct gc_entry *e;
406 e = a->list;
407 a->list = NULL;
408
409 while (e != NULL)
410 {
411 struct gc_entry *next = e->next;
412 free(e);
413 e = next;
414 }
415}
416
417/*
418 * Functions to handle special objects in gc_entries
419 */
420
421void
423{
424 struct gc_entry_special *e;
425 e = a->list_special;
426 a->list_special = NULL;
427
428 while (e != NULL)
429 {
430 struct gc_entry_special *next = e->next;
431 e->free_fnc(e->addr);
432 free(e);
433 e = next;
434 }
435}
436
437void
438gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a)
439{
440 ASSERT(a);
441 struct gc_entry_special *e;
442#ifdef DMALLOC
443 e = (struct gc_entry_special *)openvpn_dmalloc(file, line, sizeof(struct gc_entry_special));
444#else
445 e = (struct gc_entry_special *)malloc(sizeof(struct gc_entry_special));
446#endif
448 e->free_fnc = free_function;
449 e->addr = addr;
450
451 e->next = a->list_special;
452 a->list_special = e;
453}
454
455
456/*
457 * Transfer src arena to dest, resetting src to an empty arena.
458 */
459void
460gc_transfer(struct gc_arena *dest, struct gc_arena *src)
461{
462 if (dest && src)
463 {
464 struct gc_entry *e = src->list;
465 if (e)
466 {
467 while (e->next != NULL)
468 {
469 e = e->next;
470 }
471 e->next = dest->list;
472 dest->list = src->list;
473 src->list = NULL;
474 }
475 }
476}
477
478/*
479 * Hex dump -- Output a binary buffer to a hex string and return it.
480 */
481
482char *
483format_hex_ex(const uint8_t *data, size_t size, size_t maxoutput, unsigned int space_break_flags,
484 const char *separator, struct gc_arena *gc)
485{
486 const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK;
487 const size_t separator_len = separator ? strlen(separator) : 0;
488 const size_t out_len = maxoutput > 0
489 ? maxoutput
490 : ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2);
491
492 struct buffer out = alloc_buf_gc(out_len, gc);
493 for (size_t i = 0; i < size; ++i)
494 {
495 if (separator && i && !(i % bytes_per_hexblock))
496 {
497 buf_printf(&out, "%s", separator);
498 }
500 {
501 buf_printf(&out, "%02X", data[i]);
502 }
503 else
504 {
505 buf_printf(&out, "%02x", data[i]);
506 }
507 }
508 buf_catrunc(&out, "[more...]");
509 return (char *)out.data;
510}
511
512/*
513 * remove specific trailing character
514 */
515
516void
518{
519 uint8_t *cp = BLAST(buf);
520 if (cp && *cp == remove)
521 {
522 *cp = '\0';
523 --buf->len;
524 }
525}
526
527/*
528 * force a null termination even it requires
529 * truncation of the last char.
530 */
531void
533{
534 char *last = (char *)BLAST(buf);
535 if (last && *last == '\0') /* already terminated? */
536 {
537 return;
538 }
539
540 if (!buf_safe(buf, 1)) /* make space for trailing null */
541 {
542 buf_inc_len(buf, -1);
543 }
544
545 buf_write_u8(buf, 0);
546}
547
548/*
549 * Remove trailing \r and \n chars and ensure
550 * null termination.
551 */
552void
553buf_chomp(struct buffer *buf)
554{
555 while (true)
556 {
557 char *last = (char *)BLAST(buf);
558 if (!last)
559 {
560 break;
561 }
562 if (char_class(*last, CC_CRLF | CC_NULL))
563 {
564 if (!buf_inc_len(buf, -1))
565 {
566 break;
567 }
568 }
569 else
570 {
571 break;
572 }
573 }
575}
576
577const char *
579{
580 while (*str)
581 {
582 const char c = *str;
583 if (!(c == ' ' || c == '\t'))
584 {
585 break;
586 }
587 ++str;
588 }
589 return str;
590}
591
592/*
593 * like buf_null_terminate, but operate on strings
594 */
595void
597{
599 if (len < capacity)
600 {
601 *(str + len) = '\0';
602 }
603 else if (len == capacity)
604 {
605 *(str + len - 1) = '\0';
606 }
607}
608
609/*
610 * Remove trailing \r and \n chars.
611 */
612void
613chomp(char *str)
614{
615 rm_trailing_chars(str, "\r\n");
616}
617
618/*
619 * Remove trailing chars
620 */
621void
623{
624 bool modified;
625 do
626 {
627 const size_t len = strlen(str);
628 modified = false;
629 if (len > 0)
630 {
631 char *cp = str + (len - 1);
632 if (strchr(what_to_delete, *cp) != NULL)
633 {
634 *cp = '\0';
635 modified = true;
636 }
637 }
638 } while (modified);
639}
640
641/*
642 * Allocate a string
643 */
644char *
645#ifdef DMALLOC
646string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line)
647#else
648string_alloc(const char *str, struct gc_arena *gc)
649#endif
650{
651 if (str)
652 {
653 const size_t n = strlen(str) + 1;
654 char *ret;
655
656 if (gc)
657 {
658#ifdef DMALLOC
659 ret = (char *)gc_malloc_debug(n, false, gc, file, line);
660#else
661 ret = (char *)gc_malloc(n, false, gc);
662#endif
663 }
664 else
665 {
666 /* If there are no garbage collector available, it's expected
667 * that the caller cleans up afterwards. This is coherent with the
668 * earlier behaviour when gc_malloc() would be called with gc == NULL
669 */
670#ifdef DMALLOC
671 ret = openvpn_dmalloc(file, line, n);
672#else
673 ret = calloc(1, n);
674#endif
676 }
677 memcpy(ret, str, n);
678 return ret;
679 }
680 else
681 {
682 return NULL;
683 }
684}
685
686/*
687 * Erase all characters in a string
688 */
689void
691{
692 if (str)
693 {
695 }
696}
697
698/*
699 * Return the length of a string array
700 */
701int
702string_array_len(const char **array)
703{
704 int i = 0;
705 if (array)
706 {
707 while (array[i])
708 {
709 ++i;
710 }
711 }
712 return i;
713}
714
715char *
716print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
717{
718 struct buffer out = alloc_buf_gc(256, gc);
719 int i = 0;
720 for (;;)
721 {
722 const char *cp = *p++;
723 if (!cp)
724 {
725 break;
726 }
727 if (i)
728 {
729 buf_printf(&out, " ");
730 }
731 if (flags & PA_BRACKET)
732 {
733 buf_printf(&out, "[%s]", cp);
734 }
735 else
736 {
737 buf_printf(&out, "%s", cp);
738 }
739 ++i;
740 }
741 return BSTR(&out);
742}
743
744/*
745 * Allocate a string inside a buffer
746 */
747struct buffer
749string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line)
750#else
751string_alloc_buf(const char *str, struct gc_arena *gc)
752#endif
753{
754 struct buffer buf;
755
756 ASSERT(str);
757
758#ifdef DMALLOC
759 buf_set_read(&buf, (uint8_t *)string_alloc_debug(str, gc, file, line), strlen(str) + 1);
760#else
761 buf_set_read(&buf, (uint8_t *)string_alloc(str, gc), strlen(str) + 1);
762#endif
763
764 if (buf.len > 0) /* Don't count trailing '\0' as part of length */
765 {
766 --buf.len;
767 }
768
769 return buf;
770}
771
772/*
773 * String comparison
774 */
775
776bool
777buf_string_match_head_str(const struct buffer *src, const char *match)
778{
779 const size_t size = strlen(match);
780 if (size > src->len)
781 {
782 return false;
783 }
784 return memcmp(BPTR(src), match, size) == 0;
785}
786
787bool
789{
791 {
792 buf_advance(src, (int)strlen(match));
793 return true;
794 }
795 else
796 {
797 return false;
798 }
799}
800
801int
802buf_substring_len(const struct buffer *buf, int delim)
803{
804 int i = 0;
805 struct buffer tmp = *buf;
806 int c;
807
808 while ((c = buf_read_u8(&tmp)) >= 0)
809 {
810 ++i;
811 if (c == delim)
812 {
813 return i;
814 }
815 }
816 return -1;
817}
818
819/*
820 * String parsing
821 */
822
823bool
824buf_parse(struct buffer *buf, const int delim, char *line, const int size)
825{
826 bool eol = false;
827 int n = 0;
828 int c;
829
830 ASSERT(size > 0);
831
832 do
833 {
834 c = buf_peek_u8(buf);
835 if (c < 0)
836 {
837 eol = true;
838 line[n] = 0;
839 break;
840 }
841 if (c == delim)
842 {
843 buf_advance(buf, 1);
844 line[n] = 0;
845 break;
846 }
847 if (n >= (size - 1))
848 {
849 break;
850 }
851 buf_advance(buf, 1);
852 line[n++] = (char)c;
853 } while (c);
854
855 line[size - 1] = '\0';
856 return !(eol && !strlen(line));
857}
858
859/*
860 * Print a string which might be NULL
861 */
862const char *
863np(const char *str)
864{
865 if (str)
866 {
867 return str;
868 }
869 else
870 {
871 return "[NULL]";
872 }
873}
874
875/*
876 * Classify and mutate strings based on character types.
877 */
878
879bool
880char_class(const unsigned char c, const unsigned int flags)
881{
882 if (!flags)
883 {
884 return false;
885 }
886 if (flags & CC_ANY)
887 {
888 return true;
889 }
890
891 if ((flags & CC_NULL) && c == '\0')
892 {
893 return true;
894 }
895
896 if ((flags & CC_ALNUM) && isalnum(c))
897 {
898 return true;
899 }
900 if ((flags & CC_ALPHA) && isalpha(c))
901 {
902 return true;
903 }
904 if ((flags & CC_ASCII) && isascii(c))
905 {
906 return true;
907 }
908 if ((flags & CC_CNTRL) && iscntrl(c))
909 {
910 return true;
911 }
912 if ((flags & CC_DIGIT) && isdigit(c))
913 {
914 return true;
915 }
916 /* allow ascii non-control and UTF-8, consider DEL to be a control */
917 if ((flags & CC_PRINT) && (c >= 32 && c != 127))
918 {
919 return true;
920 }
921 if ((flags & CC_PUNCT) && ispunct(c))
922 {
923 return true;
924 }
925 if ((flags & CC_SPACE) && isspace(c))
926 {
927 return true;
928 }
929 if ((flags & CC_XDIGIT) && isxdigit(c))
930 {
931 return true;
932 }
933
934 if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
935 {
936 return true;
937 }
938 if ((flags & CC_NEWLINE) && c == '\n')
939 {
940 return true;
941 }
942 if ((flags & CC_CR) && c == '\r')
943 {
944 return true;
945 }
946
947 if ((flags & CC_BACKSLASH) && c == '\\')
948 {
949 return true;
950 }
951 if ((flags & CC_UNDERBAR) && c == '_')
952 {
953 return true;
954 }
955 if ((flags & CC_DASH) && c == '-')
956 {
957 return true;
958 }
959 if ((flags & CC_DOT) && c == '.')
960 {
961 return true;
962 }
963 if ((flags & CC_COMMA) && c == ',')
964 {
965 return true;
966 }
967 if ((flags & CC_COLON) && c == ':')
968 {
969 return true;
970 }
971 if ((flags & CC_SLASH) && c == '/')
972 {
973 return true;
974 }
975 if ((flags & CC_SINGLE_QUOTE) && c == '\'')
976 {
977 return true;
978 }
979 if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
980 {
981 return true;
982 }
983 if ((flags & CC_REVERSE_QUOTE) && c == '`')
984 {
985 return true;
986 }
987 if ((flags & CC_AT) && c == '@')
988 {
989 return true;
990 }
991 if ((flags & CC_EQUAL) && c == '=')
992 {
993 return true;
994 }
995 if ((flags & CC_LESS_THAN) && c == '<')
996 {
997 return true;
998 }
999 if ((flags & CC_GREATER_THAN) && c == '>')
1000 {
1001 return true;
1002 }
1003 if ((flags & CC_PIPE) && c == '|')
1004 {
1005 return true;
1006 }
1007 if ((flags & CC_QUESTION_MARK) && c == '?')
1008 {
1009 return true;
1010 }
1011 if ((flags & CC_ASTERISK) && c == '*')
1012 {
1013 return true;
1014 }
1015
1016 return false;
1017}
1018
1019static inline bool
1020char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
1021{
1022 return char_class(c, inclusive) && !char_class(c, exclusive);
1023}
1024
1025bool
1026string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
1027{
1028 char c;
1029 ASSERT(str);
1030 while ((c = *str++))
1031 {
1033 {
1034 return false;
1035 }
1036 }
1037 return true;
1038}
1039
1040/*
1041 * Modify string in place.
1042 * Guaranteed to not increase string length.
1043 */
1044bool
1045string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive,
1046 const char replace)
1047{
1048 const char *in = str;
1049 bool ret = true;
1050
1051 ASSERT(str);
1052
1053 while (true)
1054 {
1055 char c = *in++;
1056 if (c)
1057 {
1059 {
1060 c = replace;
1061 ret = false;
1062 }
1063 if (c)
1064 {
1065 *str++ = c;
1066 }
1067 }
1068 else
1069 {
1070 *str = '\0';
1071 break;
1072 }
1073 }
1074 return ret;
1075}
1076
1077bool
1078string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
1079{
1080 ASSERT(buf);
1081
1082 for (int i = 0; i < BLEN(buf); i++)
1083 {
1084 char c = BSTR(buf)[i];
1085
1087 {
1088 return false;
1089 }
1090 }
1091 return true;
1092}
1093
1094const char *
1095string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive,
1096 const char replace, struct gc_arena *gc)
1097{
1098 if (str)
1099 {
1100 char *buf = string_alloc(str, gc);
1102 return buf;
1103 }
1104 else
1105 {
1106 return NULL;
1107 }
1108}
1109
1110void
1111string_replace_leading(char *str, const char match, const char replace)
1112{
1113 ASSERT(match != '\0');
1114 while (*str)
1115 {
1116 if (*str == match)
1117 {
1118 *str = replace;
1119 }
1120 else
1121 {
1122 break;
1123 }
1124 ++str;
1125 }
1126}
1127
1128#ifdef VERIFY_ALIGNMENT
1129void
1130valign4(const struct buffer *buf, const char *file, const int line)
1131{
1132 if (buf && buf->len)
1133 {
1134 msglvl_t msglevel = D_ALIGN_DEBUG;
1135 const unsigned int u = (unsigned int)BPTR(buf);
1136
1137 if (u & (PAYLOAD_ALIGN - 1))
1138 {
1139 msglevel = D_ALIGN_ERRORS;
1140 }
1141
1142 msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1143 (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "", file, line, (ptr_type)buf->data,
1144 buf->offset, buf->len, buf->capacity, buf_debug_file(buf), buf_debug_line(buf));
1145 }
1146}
1147#endif /* ifdef VERIFY_ALIGNMENT */
1148
1149/*
1150 * struct buffer_list
1151 */
1152struct buffer_list *
1154{
1155 struct buffer_list *ret;
1156 ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1157 ret->size = 0;
1158 return ret;
1159}
1160
1161void
1163{
1164 if (ol)
1165 {
1167 free(ol);
1168 }
1169}
1170
1171bool
1173{
1174 return ol && ol->head != NULL;
1175}
1176
1177void
1179{
1180 struct buffer_entry *e = ol->head;
1181 while (e)
1182 {
1183 struct buffer_entry *next = e->next;
1184 free_buf(&e->buf);
1185 free(e);
1186 e = next;
1187 }
1188 ol->head = ol->tail = NULL;
1189 ol->size = 0;
1190}
1191
1192void
1193buffer_list_push(struct buffer_list *ol, const char *str)
1194{
1195 if (str)
1196 {
1197 const size_t len = strlen((const char *)str);
1198 struct buffer_entry *e = buffer_list_push_data(ol, str, len + 1);
1199 if (e)
1200 {
1201 e->buf.len = (int)len; /* Don't count trailing '\0' as part of length */
1202 }
1203 }
1204}
1205
1206struct buffer_entry *
1207buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1208{
1209 struct buffer_entry *e = NULL;
1210 if (data)
1211 {
1212 ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1213
1214 ++ol->size;
1215 if (ol->tail)
1216 {
1217 ASSERT(ol->head);
1218 ol->tail->next = e;
1219 }
1220 else
1221 {
1222 ASSERT(!ol->head);
1223 ol->head = e;
1224 }
1225 e->buf = alloc_buf(size);
1226 memcpy(e->buf.data, data, size);
1227 e->buf.len = (int)size;
1228 ol->tail = e;
1229 }
1230 return e;
1231}
1232
1233struct buffer *
1235{
1236 if (ol && ol->head)
1237 {
1238 return &ol->head->buf;
1239 }
1240 else
1241 {
1242 return NULL;
1243 }
1244}
1245
1246void
1247buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
1248{
1249 const size_t sep_len = strlen(sep);
1250 struct buffer_entry *more = bl->head;
1251 size_t size = 0;
1252 int count = 0;
1253 for (count = 0; more; ++count)
1254 {
1255 size_t extra_len = BLEN(&more->buf) + sep_len;
1256 if (size + extra_len > max_len)
1257 {
1258 break;
1259 }
1260
1261 size += extra_len;
1262 more = more->next;
1263 }
1264
1265 if (count >= 2)
1266 {
1267 struct buffer_entry *f;
1268 ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1269 f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1270
1271 struct buffer_entry *e = bl->head;
1272 for (size_t i = 0; e && i < count; ++i)
1273 {
1274 struct buffer_entry *next = e->next;
1275 buf_copy(&f->buf, &e->buf);
1276 buf_write(&f->buf, sep, sep_len);
1277 free_buf(&e->buf);
1278 free(e);
1279 e = next;
1280 }
1281 bl->head = f;
1282 bl->size -= count - 1;
1283 f->next = more;
1284 if (!more)
1285 {
1286 bl->tail = f;
1287 }
1288 }
1289}
1290
1291void
1292buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1293{
1295}
1296
1297void
1299{
1300 if (ol && ol->head)
1301 {
1302 struct buffer_entry *e = ol->head->next;
1303 free_buf(&ol->head->buf);
1304 free(ol->head);
1305 ol->head = e;
1306 --ol->size;
1307 if (!e)
1308 {
1309 ol->tail = NULL;
1310 }
1311 }
1312}
1313
1314void
1316{
1317 if (ol->head)
1318 {
1319 struct buffer *buf = &ol->head->buf;
1320 ASSERT(buf_advance(buf, n));
1321 if (!BLEN(buf))
1322 {
1324 }
1325 }
1326}
1327
1328struct buffer_list *
1329buffer_list_file(const char *fn, int max_line_len)
1330{
1331 FILE *fp = platform_fopen(fn, "r");
1332 struct buffer_list *bl = NULL;
1333
1334 if (fp)
1335 {
1336 char *line = (char *)malloc(max_line_len);
1337 if (line)
1338 {
1339 bl = buffer_list_new();
1340 while (fgets(line, max_line_len, fp) != NULL)
1341 {
1342 buffer_list_push(bl, line);
1343 }
1344 free(line);
1345 }
1346 fclose(fp);
1347 }
1348 return bl;
1349}
1350
1351struct buffer
1353{
1354 struct buffer ret = { 0 };
1355
1356 platform_stat_t file_stat = { 0 };
1357 if (platform_stat(filename, &file_stat) < 0)
1358 {
1359 return ret;
1360 }
1361
1362 FILE *fp = platform_fopen(filename, "r");
1363 if (!fp)
1364 {
1365 return ret;
1366 }
1367
1368 const size_t size = file_stat.st_size;
1369 ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1370 size_t read_size = fread(BPTR(&ret), 1, size, fp);
1371 if (read_size == 0)
1372 {
1373 free_buf_gc(&ret, gc);
1374 goto cleanup;
1375 }
1376 ASSERT(buf_inc_len(&ret, (int)read_size));
1377 buf_null_terminate(&ret);
1378
1379cleanup:
1380 fclose(fp);
1381 return ret;
1382}
bool buffer_list_defined(const struct buffer_list *ol)
Checks if the list is valid and non-empty.
Definition buffer.c:1172
bool buf_string_compare_advance(struct buffer *src, const char *match)
Definition buffer.c:788
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition buffer.c:1207
void rm_trailing_chars(char *str, const char *what_to_delete)
Definition buffer.c:622
void string_null_terminate(char *str, int len, int capacity)
Definition buffer.c:596
void buffer_list_advance(struct buffer_list *ol, int n)
Definition buffer.c:1315
void free_buf(struct buffer *buf)
Definition buffer.c:184
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1247
static bool char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
Definition buffer.c:1020
void buf_clear(struct buffer *buf)
Definition buffer.c:163
void buffer_list_reset(struct buffer_list *ol)
Empty the list ol and frees all the contained buffers.
Definition buffer.c:1178
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition buffer.c:191
const char * skip_leading_whitespace(const char *str)
Definition buffer.c:578
void buffer_list_aggregate(struct buffer_list *bl, const size_t max)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1292
struct buffer clone_buf(const struct buffer *buf)
Definition buffer.c:116
void x_gc_freespecial(struct gc_arena *a)
Definition buffer.c:422
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition buffer.c:301
void buf_catrunc(struct buffer *buf, const char *str)
Definition buffer.c:288
#define buf_debug_file(buf)
Definition buffer.c:158
void buffer_list_pop(struct buffer_list *ol)
Definition buffer.c:1298
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:241
void string_replace_leading(char *str, const char match, const char replace)
Definition buffer.c:1111
bool buf_puts(struct buffer *buf, const char *str)
Definition buffer.c:268
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Definition buffer.c:1329
void string_clear(char *str)
Definition buffer.c:690
#define buf_debug_line(buf)
Definition buffer.c:157
void gc_transfer(struct gc_arena *dest, struct gc_arena *src)
Definition buffer.c:460
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Definition buffer.c:1026
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition buffer.c:716
void buf_null_terminate(struct buffer *buf)
Definition buffer.c:532
struct buffer buf_sub(struct buffer *buf, int size, bool prepend)
Definition buffer.c:222
void * gc_realloc(void *ptr, size_t size, struct gc_arena *a)
allows to realloc a pointer previously allocated by gc_malloc or gc_realloc
Definition buffer.c:370
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1153
void chomp(char *str)
Definition buffer.c:613
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition buffer.c:1234
const char * np(const char *str)
Definition buffer.c:863
bool string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition buffer.c:1078
size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
Definition buffer.c:40
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1162
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
bool buf_assign(struct buffer *dest, const struct buffer *src)
Definition buffer.c:174
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:89
char * format_hex_ex(const uint8_t *data, size_t size, size_t maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition buffer.c:1045
struct buffer alloc_buf(size_t size)
Definition buffer.c:63
const char * string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace, struct gc_arena *gc)
Returns a copy of a string with certain classes of characters of it replaced with a specified charact...
Definition buffer.c:1095
void gc_addspecial(void *addr, void(*free_function)(void *), struct gc_arena *a)
Definition buffer.c:438
int string_array_len(const char **array)
Definition buffer.c:702
struct buffer buffer_read_from_file(const char *filename, struct gc_arena *gc)
buffer_read_from_file - copy the content of a file into a buffer
Definition buffer.c:1352
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition buffer.c:517
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Definition buffer.c:824
void buf_size_error(const size_t size)
Definition buffer.c:54
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:648
struct buffer string_alloc_buf(const char *str, struct gc_arena *gc)
Definition buffer.c:751
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition buffer.c:1193
void x_gc_free(struct gc_arena *a)
Definition buffer.c:403
void buf_chomp(struct buffer *buf)
Definition buffer.c:553
bool char_class(const unsigned char c, const unsigned int flags)
Definition buffer.c:880
bool buf_string_match_head_str(const struct buffer *src, const char *match)
Definition buffer.c:777
int buf_substring_len(const struct buffer *buf, int delim)
Definition buffer.c:802
#define CC_COMMA
comma
Definition buffer.h:898
#define BEND(buf)
Definition buffer.h:124
#define CC_DASH
dash
Definition buffer.h:896
static bool buf_size_valid(const size_t size)
Definition buffer.h:285
#define CC_DOUBLE_QUOTE
double quote
Definition buffer.h:902
#define BLAST(buf)
Definition buffer.h:125
#define CC_BLANK
space or tab
Definition buffer.h:890
static bool buf_init_dowork(struct buffer *buf, int offset)
Definition buffer.h:319
#define CC_PIPE
pipe
Definition buffer.h:908
#define BSTR(buf)
Definition buffer.h:128
static bool buf_copy(struct buffer *dest, const struct buffer *src)
Definition buffer.h:704
#define CC_ANY
any character
Definition buffer.h:877
#define BPTR(buf)
Definition buffer.h:123
#define CC_AT
at sign
Definition buffer.h:904
static int buf_peek_u8(struct buffer *buf)
Definition buffer.h:774
#define CC_XDIGIT
hex digit isxdigit()
Definition buffer.h:888
#define CC_COLON
colon
Definition buffer.h:899
#define CC_SINGLE_QUOTE
single quote
Definition buffer.h:901
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:588
#define CC_DIGIT
digit isdigit()
Definition buffer.h:884
#define PA_BRACKET
Definition buffer.h:143
#define CC_DOT
dot
Definition buffer.h:897
#define CC_CRLF
carriage return or newline
Definition buffer.h:914
static bool buf_safe(const struct buffer *buf, size_t len)
Definition buffer.h:518
#define ALLOC_SIZE_MAX
Definition buffer.h:1054
#define CC_ASTERISK
asterisk
Definition buffer.h:910
#define CC_ALPHA
alphabetic isalpha()
Definition buffer.h:881
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:616
#define CC_NEWLINE
newline
Definition buffer.h:891
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition buffer.h:348
static int buf_forward_capacity(const struct buffer *buf)
Definition buffer.h:539
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:414
static uint8_t * buf_write_alloc(struct buffer *buf, size_t size)
Definition buffer.h:633
#define CC_REVERSE_QUOTE
reverse quote
Definition buffer.h:903
#define CC_SPACE
whitespace isspace()
Definition buffer.h:887
#define CC_ASCII
ASCII character.
Definition buffer.h:882
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:660
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition buffer.h:604
#define CC_BACKSLASH
backslash
Definition buffer.h:894
#define CC_CNTRL
control character iscntrl()
Definition buffer.h:883
#define CC_LESS_THAN
less than sign
Definition buffer.h:906
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition buffer.h:684
static int buf_read_u8(struct buffer *buf)
Definition buffer.h:786
#define BLEN(buf)
Definition buffer.h:126
#define CC_CR
carriage return
Definition buffer.h:892
#define CC_SLASH
slash
Definition buffer.h:900
#define CC_UNDERBAR
underscore
Definition buffer.h:895
#define CC_GREATER_THAN
greater than sign
Definition buffer.h:907
static void strncpynt(char *dest, const char *src, size_t maxlen)
Definition buffer.h:361
static void check_malloc_return(void *p)
Definition buffer.h:1107
#define CC_NULL
null character \0
Definition buffer.h:878
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:885
#define CC_QUESTION_MARK
question mark
Definition buffer.h:909
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1064
static bool buf_defined(const struct buffer *buf)
Definition buffer.h:228
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:880
#define buf_init(buf, offset)
Definition buffer.h:209
#define CC_EQUAL
equal sign
Definition buffer.h:905
#define FHE_SPACE_BREAK_MASK
Definition buffer.h:497
#define CC_PUNCT
punctuation ispunct()
Definition buffer.h:886
#define FHE_CAPS
Definition buffer.h:498
static int buf_forward_capacity_total(const struct buffer *buf)
Definition buffer.h:557
unsigned long ptr_type
Definition common.h:59
#define ptr_format
Definition common.h:50
#define D_ALIGN_ERRORS
Definition errlevel.h:69
#define D_ALIGN_DEBUG
Definition errlevel.h:141
@ write
#define PAYLOAD_ALIGN
Definition mtu.h:95
#define CLEAR(x)
Definition basic.h:32
#define M_FATAL
Definition error.h:90
#define msg(flags,...)
Definition error.h:152
unsigned int msglvl_t
Definition error.h:77
#define ASSERT(x)
Definition error.h:219
#define M_ERRNO
Definition error.h:95
FILE * platform_fopen(const char *path, const char *mode)
Definition platform.c:500
int platform_open(const char *path, int flags, int mode)
Definition platform.c:513
int platform_stat(const char *path, platform_stat_t *buf)
Definition platform.c:526
struct _stat platform_stat_t
Definition platform.h:118
Definition buffer.h:1119
struct buffer_entry * next
Definition buffer.h:1121
struct buffer buf
Definition buffer.h:1120
struct buffer_entry * tail
Definition buffer.h:1127
struct buffer_entry * head
Definition buffer.h:1126
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
int capacity
Size in bytes of memory allocated by malloc().
Definition buffer.h:61
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:67
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
int offset
Offset in bytes of the actual content within the allocated memory.
Definition buffer.h:63
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
struct gc_entry_special * list_special
Definition buffer.h:119
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:117
Garbage collection entry for a specially allocated structure that needs a custom free function to be ...
Definition buffer.h:98
void(* free_fnc)(void *)
Definition buffer.h:100
void * addr
Definition buffer.h:101
struct gc_entry_special * next
Definition buffer.h:99
Garbage collection entry for one dynamically allocated block of memory.
Definition buffer.h:87
struct gc_entry * next
Pointer to the next item in the linked list.
Definition buffer.h:88
#define unlikely(x)
Definition syshead.h:35
static int cleanup(void **state)
struct gc_arena gc
Definition test_ssl.c:131