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-2026 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 > 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=%zu", size);
57}
58
59struct buffer
60alloc_buf(size_t size)
61{
62 struct buffer buf;
63 CLEAR(buf);
64
65 if (!buf_size_valid(size))
66 {
67 buf_size_error(size);
68 }
69 buf.capacity = (int)size;
70 buf.data = calloc(1, size);
72
73 return buf;
74}
75
76struct buffer
77alloc_buf_gc(size_t size, struct gc_arena *gc)
78{
79 struct buffer buf;
80 CLEAR(buf);
81
82 if (!buf_size_valid(size))
83 {
84 buf_size_error(size);
85 }
86 buf.capacity = (int)size;
87 buf.data = (uint8_t *)gc_malloc(size, false, gc);
88 if (size)
89 {
90 *buf.data = 0;
91 }
92 return buf;
93}
94
95struct buffer
96#ifdef BUF_INIT_TRACKING
97clone_buf_debug(const struct buffer *buf, const char *file, int line)
98#else
99clone_buf(const struct buffer *buf)
100#endif
101{
102 struct buffer ret;
103 ret.capacity = buf->capacity;
104 ret.offset = buf->offset;
105 ret.len = buf->len;
106#ifdef BUF_INIT_TRACKING
107 ret.debug_file = buf->debug_file;
108 ret.debug_line = buf->debug_line;
109#endif
110 ret.data = (uint8_t *)malloc(buf->capacity);
112 memcpy(BPTR(&ret), CBPTR(buf), BLENZ(buf));
113 return ret;
114}
115
116#ifdef BUF_INIT_TRACKING
117
118bool
119buf_init_debug(struct buffer *buf, int offset, const char *file, int line)
120{
121 buf->debug_file = file;
122 buf->debug_line = line;
123 return buf_init_dowork(buf, offset);
124}
125
126#ifdef VERIFY_ALIGNMENT
127static inline int
128buf_debug_line(const struct buffer *buf)
129{
130 return buf->debug_line;
131}
132
133static const char *
134buf_debug_file(const struct buffer *buf)
135{
136 return buf->debug_file;
137}
138#endif
139
140#else /* ifdef BUF_INIT_TRACKING */
141
142#define buf_debug_line(buf) 0
143#define buf_debug_file(buf) "[UNDEF]"
144
145#endif /* ifdef BUF_INIT_TRACKING */
146
147void
148buf_clear(struct buffer *buf)
149{
150 if (buf->capacity > 0)
151 {
152 secure_memzero(buf->data, buf->capacity);
153 }
154 buf->len = 0;
155 buf->offset = 0;
156}
157
158bool
159buf_assign(struct buffer *dest, const struct buffer *src)
160{
161 if (!buf_init(dest, src->offset))
162 {
163 return false;
164 }
165 return buf_write(dest, CBPTR(src), BLENZ(src));
166}
167
168void
169free_buf(struct buffer *buf)
170{
171 free(buf->data);
172 CLEAR(*buf);
173}
174
175static void
176free_buf_gc(struct buffer *buf, struct gc_arena *gc)
177{
178 if (gc)
179 {
180 struct gc_entry **e = &gc->list;
181
182 while (*e)
183 {
184 /* check if this object is the one we want to delete */
185 if ((uint8_t *)(*e + 1) == buf->data)
186 {
187 struct gc_entry *to_delete = *e;
188
189 /* remove element from linked list and free it */
190 *e = (*e)->next;
191 free(to_delete);
192
193 break;
194 }
195
196 e = &(*e)->next;
197 }
198 }
199
200 CLEAR(*buf);
201}
202
203/*
204 * Return a buffer for write that is a subset of another buffer
205 */
206struct buffer
207buf_sub(struct buffer *buf, int size, bool prepend)
208{
209 struct buffer ret;
210 uint8_t *data;
211
212 CLEAR(ret);
213 data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
214 if (data)
215 {
216 ret.capacity = size;
217 ret.data = data;
218 }
219 return ret;
220}
221
222/*
223 * printf append to a buffer with overflow check
224 */
225bool
226buf_printf(struct buffer *buf, const char *format, ...)
227{
228 bool ret = false;
229 if (buf_defined(buf))
230 {
231 char *ptr = (char *)BEND(buf);
232 int cap = buf_forward_capacity(buf);
233
234 if (cap > 1) /* can write more than \0 */
235 {
236 int stat;
237 va_list arglist;
238 va_start(arglist, format);
239 stat = vsnprintf(ptr, cap, format, arglist);
240 va_end(arglist);
241 buf->len += (int)strlen(ptr);
242 if (stat >= 0 && stat < cap)
243 {
244 ret = true;
245 }
246 }
247 }
248 return ret;
249}
250
251void
252buf_puts(struct buffer *buf, const char *str)
253{
254 char *ptr = (char *)BEND(buf);
255 int cap = buf_forward_capacity(buf);
256 if (cap > 1) /* can write more than \0 */
257 {
258 int str_len = (int)strlcpy(ptr, str, cap);
259 buf->len += (str_len < cap) ? str_len : cap - 1;
260 }
261}
262
263/*
264 * write a string to the end of a buffer that was
265 * truncated by buf_printf
266 */
267void
268buf_catrunc(struct buffer *buf, const char *str)
269{
270 if (buf_forward_capacity(buf) <= 1)
271 {
272 size_t len = strlen(str) + 1;
274 {
275 memcpy(buf->data + buf->capacity - len, str, len);
276 }
277 }
278}
279
280bool
281buffer_write_file(const char *filename, const struct buffer *buf)
282{
283 bool ret = false;
284 int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
285 if (fd == -1)
286 {
287 msg(M_ERRNO, "Cannot open file '%s' for write", filename);
288 return false;
289 }
290
291 const ssize_t size = write(fd, CBPTR(buf), (unsigned int)BLEN(buf));
292 if (size != BLEN(buf))
293 {
294 msg(M_ERRNO, "Write error on file '%s'", filename);
295 goto cleanup;
296 }
297
298 ret = true;
299cleanup:
300 if (close(fd) < 0)
301 {
302 msg(M_ERRNO, "Close error on file %s", filename);
303 ret = false;
304 }
305 return ret;
306}
307
308/*
309 * Garbage collection
310 */
311
312void *
313gc_malloc(size_t size, bool clear, struct gc_arena *a)
314{
315 void *ret;
316 if (a)
317 {
318 struct gc_entry *e;
319 e = (struct gc_entry *)malloc(size + sizeof(struct gc_entry));
321 ret = (char *)e + sizeof(struct gc_entry);
322 e->next = a->list;
323 a->list = e;
324 }
325 else
326 {
327 ret = malloc(size);
329 }
330#ifndef ZERO_BUFFER_ON_ALLOC
331 if (clear)
332#endif
333 memset(ret, 0, size);
334 return ret;
335}
336
337void *
338gc_realloc(void *ptr, size_t size, struct gc_arena *a)
339{
340 void *ret = realloc(ptr, size);
342 if (a)
343 {
344 if (ptr && ptr != ret)
345 {
346 /* find the old entry and modify it if realloc changed
347 * the pointer */
348 struct gc_entry_special *e = NULL;
349 for (e = a->list_special; e != NULL; e = e->next)
350 {
351 if (e->addr == ptr)
352 {
353 break;
354 }
355 }
356 ASSERT(e);
357 ASSERT(e->addr == ptr);
358 e->addr = ret;
359 }
360 else if (!ptr)
361 {
362 /* sets e->addr to newptr */
363 gc_addspecial(ret, free, a);
364 }
365 }
366
367 return ret;
368}
369
370void
372{
373 struct gc_entry *e;
374 e = a->list;
375 a->list = NULL;
376
377 while (e != NULL)
378 {
379 struct gc_entry *next = e->next;
380 free(e);
381 e = next;
382 }
383}
384
385/*
386 * Functions to handle special objects in gc_entries
387 */
388
389void
391{
392 struct gc_entry_special *e;
393 e = a->list_special;
394 a->list_special = NULL;
395
396 while (e != NULL)
397 {
398 struct gc_entry_special *next = e->next;
399 e->free_fnc(e->addr);
400 free(e);
401 e = next;
402 }
403}
404
405void
406gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a)
407{
408 ASSERT(a);
409 struct gc_entry_special *e;
410 e = (struct gc_entry_special *)malloc(sizeof(struct gc_entry_special));
412 e->free_fnc = free_function;
413 e->addr = addr;
414
415 e->next = a->list_special;
416 a->list_special = e;
417}
418
419
420/*
421 * Transfer src arena to dest, resetting src to an empty arena.
422 */
423void
424gc_transfer(struct gc_arena *dest, struct gc_arena *src)
425{
426 if (dest && src)
427 {
428 struct gc_entry *e = src->list;
429 if (e)
430 {
431 while (e->next != NULL)
432 {
433 e = e->next;
434 }
435 e->next = dest->list;
436 dest->list = src->list;
437 src->list = NULL;
438 }
439 }
440}
441
442/*
443 * Hex dump -- Output a binary buffer to a hex string and return it.
444 */
445
446char *
447format_hex_ex(const uint8_t *data, size_t size, size_t maxoutput, unsigned int space_break_flags,
448 const char *separator, struct gc_arena *gc)
449{
450 const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK;
451 const size_t separator_len = separator ? strlen(separator) : 0;
452 const size_t out_len = maxoutput > 0
453 ? maxoutput
454 : ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2);
455
456 struct buffer out = alloc_buf_gc(out_len, gc);
457 for (size_t i = 0; i < size; ++i)
458 {
459 if (separator && i && !(i % bytes_per_hexblock))
460 {
461 buf_printf(&out, "%s", separator);
462 }
463 if (space_break_flags & FHE_CAPS)
464 {
465 buf_printf(&out, "%02X", data[i]);
466 }
467 else
468 {
469 buf_printf(&out, "%02x", data[i]);
470 }
471 }
472 buf_catrunc(&out, "[more...]");
473 return (char *)out.data;
474}
475
476/*
477 * remove specific trailing character
478 */
479
480void
481buf_rmtail(struct buffer *buf, uint8_t remove)
482{
483 uint8_t *cp = BLAST(buf);
484 if (cp && *cp == remove)
485 {
486 *cp = '\0';
487 --buf->len;
488 }
489}
490
491/*
492 * force a null termination even it requires
493 * truncation of the last char.
494 */
495void
497{
498 const uint8_t *last = BLAST(buf);
499 if (last && *last == '\0') /* already terminated? */
500 {
501 return;
502 }
503
504 if (!buf_safe(buf, 1)) /* make space for trailing null */
505 {
506 buf_inc_len(buf, -1);
507 }
508
509 buf_write_u8(buf, 0);
510}
511
512/*
513 * Remove trailing \r and \n chars and ensure
514 * null termination.
515 */
516void
517buf_chomp(struct buffer *buf)
518{
519 while (true)
520 {
521 const uint8_t *last = BLAST(buf);
522 if (!last)
523 {
524 break;
525 }
526 if (char_class(*last, CC_CRLF | CC_NULL))
527 {
528 if (!buf_inc_len(buf, -1))
529 {
530 break;
531 }
532 }
533 else
534 {
535 break;
536 }
537 }
539}
540
541const char *
543{
544 while (*str)
545 {
546 const char c = *str;
547 if (!(c == ' ' || c == '\t'))
548 {
549 break;
550 }
551 ++str;
552 }
553 return str;
554}
555
556#ifdef _WIN32
557/*
558 * like buf_null_terminate, but operate on strings
559 */
560void
562{
564 if (len < capacity)
565 {
566 *(str + len) = '\0';
567 }
568 else if (len == capacity)
569 {
570 *(str + len - 1) = '\0';
571 }
572}
573#endif
574
575/*
576 * Remove trailing \r and \n chars.
577 */
578void
579chomp(char *str)
580{
581 rm_trailing_chars(str, "\r\n");
582}
583
584/*
585 * Remove trailing chars
586 */
587void
588rm_trailing_chars(char *str, const char *what_to_delete)
589{
590 size_t len = strlen(str);
591 while (len > 0 && strchr(what_to_delete, str[len - 1]) != NULL)
592 {
593 str[--len] = '\0';
594 }
595}
596
597/*
598 * Allocate a string
599 */
600char *
601string_alloc(const char *str, struct gc_arena *gc)
602{
603 if (str)
604 {
605 const size_t n = strlen(str) + 1;
606 char *ret;
607
608 if (gc)
609 {
610 ret = (char *)gc_malloc(n, false, gc);
611 }
612 else
613 {
614 /* If there are no garbage collector available, it's expected
615 * that the caller cleans up afterwards. This is coherent with the
616 * earlier behaviour when gc_malloc() would be called with gc == NULL
617 */
618 ret = calloc(1, n);
620 }
621 memcpy(ret, str, n);
622 return ret;
623 }
624 else
625 {
626 return NULL;
627 }
628}
629
630/*
631 * Erase all characters in a string
632 */
633void
634string_clear(char *str)
635{
636 if (str)
637 {
638 secure_memzero(str, strlen(str));
639 }
640}
641
642/*
643 * Return the length of a string array
644 */
645int
646string_array_len(const char **array)
647{
648 int i = 0;
649 if (array)
650 {
651 while (array[i])
652 {
653 ++i;
654 }
655 }
656 return i;
657}
658
659char *
660print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
661{
662 struct buffer out = alloc_buf_gc(256, gc);
663 int i = 0;
664 for (;;)
665 {
666 const char *cp = *p++;
667 if (!cp)
668 {
669 break;
670 }
671 if (i)
672 {
673 buf_printf(&out, " ");
674 }
675 if (flags & PA_BRACKET)
676 {
677 buf_printf(&out, "[%s]", cp);
678 }
679 else
680 {
681 buf_printf(&out, "%s", cp);
682 }
683 ++i;
684 }
685 return BSTR(&out);
686}
687
688/*
689 * Allocate a string inside a buffer
690 */
691struct buffer
692string_alloc_buf(const char *str, struct gc_arena *gc)
693{
694 struct buffer buf;
695
696 ASSERT(str);
697
698 buf_set_read(&buf, (uint8_t *)string_alloc(str, gc), strlen(str) + 1);
699
700 if (buf.len > 0) /* Don't count trailing '\0' as part of length */
701 {
702 --buf.len;
703 }
704
705 return buf;
706}
707
708/*
709 * String comparison
710 */
711
712bool
713buf_string_match_head_str(const struct buffer *src, const char *match)
714{
715 const size_t size = strlen(match);
716 if (!buf_size_valid(size) || (int)size > src->len)
717 {
718 return false;
719 }
720 return memcmp(CBPTR(src), match, size) == 0;
721}
722
723bool
724buf_string_compare_advance(struct buffer *src, const char *match)
725{
726 if (buf_string_match_head_str(src, match))
727 {
728 buf_advance(src, strlen(match));
729 return true;
730 }
731 else
732 {
733 return false;
734 }
735}
736
737int
738buf_substring_len(const struct buffer *buf, int delim)
739{
740 int i = 0;
741 struct buffer tmp = *buf;
742 int c;
743
744 while ((c = buf_read_u8(&tmp)) >= 0)
745 {
746 ++i;
747 if (c == delim)
748 {
749 return i;
750 }
751 }
752 return -1;
753}
754
755/*
756 * String parsing
757 */
758
759bool
760buf_parse(struct buffer *buf, const int delim, char *line, const int size)
761{
762 bool eol = false;
763 int n = 0;
764 int c;
765
766 ASSERT(size > 0);
767
768 do
769 {
770 c = buf_peek_u8(buf);
771 if (c < 0)
772 {
773 eol = true;
774 line[n] = 0;
775 break;
776 }
777 if (c == delim)
778 {
779 buf_advance(buf, 1);
780 line[n] = 0;
781 break;
782 }
783 if (n >= (size - 1))
784 {
785 break;
786 }
787 buf_advance(buf, 1);
788 line[n++] = (char)c;
789 } while (c);
790
791 line[size - 1] = '\0';
792 return !(eol && !strlen(line));
793}
794
795/*
796 * Print a string which might be NULL
797 */
798const char *
799np(const char *str)
800{
801 if (str)
802 {
803 return str;
804 }
805 else
806 {
807 return "[NULL]";
808 }
809}
810
811/*
812 * Classify and mutate strings based on character types.
813 */
814
815/* Note 1: This functions depends on getting an unsigned
816 char. Both the is*() functions and our own checks expect it
817 this way.
818 Note 2: For CC_PRINT we just accept everything >= 32, so
819 if we ingest non-ASCII UTF-8 we will classify it as
820 printable since it will be >= 128. Other encodings are
821 not officially supported.
822*/
823bool
824char_class(const unsigned char c, const unsigned int flags)
825{
826 if (!flags)
827 {
828 return false;
829 }
830 if (flags & CC_ANY)
831 {
832 return true;
833 }
834
835 if ((flags & CC_NULL) && c == '\0')
836 {
837 return true;
838 }
839
840 if ((flags & CC_ALNUM) && isalnum(c))
841 {
842 return true;
843 }
844 if ((flags & CC_ALPHA) && isalpha(c))
845 {
846 return true;
847 }
848 if ((flags & CC_ASCII) && isascii(c))
849 {
850 return true;
851 }
852 if ((flags & CC_CNTRL) && iscntrl(c))
853 {
854 return true;
855 }
856 if ((flags & CC_DIGIT) && isdigit(c))
857 {
858 return true;
859 }
860 /* allow ascii non-control and UTF-8, consider DEL to be a control */
861 if ((flags & CC_PRINT) && (c >= 32 && c != 127))
862 {
863 return true;
864 }
865 if ((flags & CC_PUNCT) && ispunct(c))
866 {
867 return true;
868 }
869 if ((flags & CC_SPACE) && isspace(c))
870 {
871 return true;
872 }
873 if ((flags & CC_XDIGIT) && isxdigit(c))
874 {
875 return true;
876 }
877
878 if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
879 {
880 return true;
881 }
882 if ((flags & CC_NEWLINE) && c == '\n')
883 {
884 return true;
885 }
886 if ((flags & CC_CR) && c == '\r')
887 {
888 return true;
889 }
890
891 if ((flags & CC_BACKSLASH) && c == '\\')
892 {
893 return true;
894 }
895 if ((flags & CC_UNDERBAR) && c == '_')
896 {
897 return true;
898 }
899 if ((flags & CC_DASH) && c == '-')
900 {
901 return true;
902 }
903 if ((flags & CC_DOT) && c == '.')
904 {
905 return true;
906 }
907 if ((flags & CC_COMMA) && c == ',')
908 {
909 return true;
910 }
911 if ((flags & CC_COLON) && c == ':')
912 {
913 return true;
914 }
915 if ((flags & CC_SLASH) && c == '/')
916 {
917 return true;
918 }
919 if ((flags & CC_SINGLE_QUOTE) && c == '\'')
920 {
921 return true;
922 }
923 if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
924 {
925 return true;
926 }
927 if ((flags & CC_REVERSE_QUOTE) && c == '`')
928 {
929 return true;
930 }
931 if ((flags & CC_PERCENT) && c == '%')
932 {
933 return true;
934 }
935 if ((flags & CC_EXCLAMATION) && c == '!')
936 {
937 return true;
938 }
939 if ((flags & CC_LESS_THAN) && c == '<')
940 {
941 return true;
942 }
943 if ((flags & CC_GREATER_THAN) && c == '>')
944 {
945 return true;
946 }
947 if ((flags & CC_PIPE) && c == '|')
948 {
949 return true;
950 }
951 if ((flags & CC_QUESTION_MARK) && c == '?')
952 {
953 return true;
954 }
955 if ((flags & CC_ASTERISK) && c == '*')
956 {
957 return true;
958 }
959
960 return false;
961}
962
963static inline bool
964char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
965{
966 return char_class((unsigned char)c, inclusive)
967 && !char_class((unsigned char)c, exclusive);
968}
969
970bool
971string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
972{
973 char c;
974 ASSERT(str);
975 while ((c = *str++))
976 {
977 if (!char_inc_exc(c, inclusive, exclusive))
978 {
979 return false;
980 }
981 }
982 return true;
983}
984
985/*
986 * Modify string in place.
987 * Guaranteed to not increase string length.
988 */
989bool
990string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive,
991 const char replace)
992{
993 const char *in = str;
994 bool ret = true;
995
996 ASSERT(str);
997
998 while (true)
999 {
1000 char c = *in++;
1001 if (c)
1002 {
1003 if (!char_inc_exc(c, inclusive, exclusive))
1004 {
1005 c = replace;
1006 ret = false;
1007 }
1008 if (c)
1009 {
1010 *str++ = c;
1011 }
1012 }
1013 else
1014 {
1015 *str = '\0';
1016 break;
1017 }
1018 }
1019 return ret;
1020}
1021
1022bool
1023string_check_buf(const struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
1024{
1025 ASSERT(buf);
1026
1027 for (int i = 0; i < BLEN(buf); i++)
1028 {
1029 char c = CBSTR(buf)[i];
1030
1031 if (!char_inc_exc(c, inclusive, exclusive))
1032 {
1033 return false;
1034 }
1035 }
1036 return true;
1037}
1038
1039const char *
1040string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive,
1041 const char replace, struct gc_arena *gc)
1042{
1043 if (str)
1044 {
1045 char *buf = string_alloc(str, gc);
1046 string_mod(buf, inclusive, exclusive, replace);
1047 return buf;
1048 }
1049 else
1050 {
1051 return NULL;
1052 }
1053}
1054
1055void
1056string_replace_leading(char *str, const char match, const char replace)
1057{
1058 ASSERT(match != '\0');
1059 while (*str)
1060 {
1061 if (*str == match)
1062 {
1063 *str = replace;
1064 }
1065 else
1066 {
1067 break;
1068 }
1069 ++str;
1070 }
1071}
1072
1073bool
1074string_defined_equal(const char *s1, const char *s2)
1075{
1076 if (s1 && s2)
1077 {
1078 return !strcmp(s1, s2);
1079 }
1080 else
1081 {
1082 return false;
1083 }
1084}
1085
1086bool
1087streqnull(const char *a, const char *b)
1088{
1089 if (a == NULL && b == NULL)
1090 {
1091 return true;
1092 }
1093 else if (a == NULL || b == NULL)
1094 {
1095 return false;
1096 }
1097 else
1098 {
1099 return streq(a, b);
1100 }
1101}
1102
1103char *
1104string_substitute(const char *src, char from, char to, struct gc_arena *gc)
1105{
1106 char *ret = (char *)gc_malloc(strlen(src) + 1, true, gc);
1107 char *dest = ret;
1108 char c;
1109
1110 do
1111 {
1112 c = *src++;
1113 if (c == from)
1114 {
1115 c = to;
1116 }
1117 *dest++ = c;
1118 } while (c);
1119 return ret;
1120}
1121
1122bool
1123checked_snprintf(char *str, size_t size, const char *format, ...)
1124{
1125 va_list arglist;
1126 va_start(arglist, format);
1127 ASSERT(size < INT_MAX);
1128 int len = vsnprintf(str, size, format, arglist);
1129 va_end(arglist);
1130 return (len >= 0 && len < (ssize_t)size);
1131}
1132
1133#ifdef VERIFY_ALIGNMENT
1134void
1135valign4(const struct buffer *buf, const char *file, const int line)
1136{
1137 if (buf && buf->len)
1138 {
1139 msglvl_t msglevel = D_ALIGN_DEBUG;
1140 const uintptr_t u = (uintptr_t)CBPTR(buf);
1141
1142 if (u & (PAYLOAD_ALIGN - 1))
1143 {
1144 msglevel = D_ALIGN_ERRORS;
1145 }
1146
1147 msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1148 (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "", file, line, (ptr_type)buf->data,
1149 buf->offset, buf->len, buf->capacity, buf_debug_file(buf), buf_debug_line(buf));
1150 }
1151}
1152#endif /* ifdef VERIFY_ALIGNMENT */
1153
1154/*
1155 * struct buffer_list
1156 */
1157struct buffer_list *
1159{
1160 struct buffer_list *ret;
1161 ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1162 ret->size = 0;
1163 return ret;
1164}
1165
1166void
1168{
1169 if (ol)
1170 {
1172 free(ol);
1173 }
1174}
1175
1176bool
1178{
1179 return ol && ol->head != NULL && ol->size > 0;
1180}
1181
1182void
1184{
1185 struct buffer_entry *e = ol->head;
1186 while (e)
1187 {
1188 struct buffer_entry *next = e->next;
1189 free_buf(&e->buf);
1190 free(e);
1191 e = next;
1192 }
1193 ol->head = ol->tail = NULL;
1194 ol->size = 0;
1195}
1196
1197void
1198buffer_list_push(struct buffer_list *ol, const char *str)
1199{
1200 if (str)
1201 {
1202 const size_t len = strlen((const char *)str);
1203 struct buffer_entry *e = buffer_list_push_data(ol, str, len + 1);
1204 if (e)
1205 {
1206 e->buf.len--; /* Don't count trailing '\0' as part of length */
1207 }
1208 }
1209}
1210
1211struct buffer_entry *
1212buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1213{
1214 struct buffer_entry *e = NULL;
1215 if (data)
1216 {
1217 ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1218
1219 ++ol->size;
1220 if (ol->tail)
1221 {
1222 ASSERT(ol->head);
1223 ol->tail->next = e;
1224 }
1225 else
1226 {
1227 ASSERT(!ol->head);
1228 ol->head = e;
1229 }
1230 e->buf = alloc_buf(size);
1231 memcpy(e->buf.data, data, size);
1232 /* Note: size implicitly checked by alloc_buf */
1233 e->buf.len = (int)size;
1234 ol->tail = e;
1235 }
1236 return e;
1237}
1238
1239struct buffer *
1241{
1242 if (ol && ol->head)
1243 {
1244 return &ol->head->buf;
1245 }
1246 else
1247 {
1248 return NULL;
1249 }
1250}
1251
1252void
1253buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
1254{
1255 const size_t sep_len = strlen(sep);
1256 struct buffer_entry *more = bl->head;
1257 size_t size = 0;
1258 size_t count = 0;
1259 for (; more; ++count)
1260 {
1261 size_t extra_len = BLENZ(&more->buf) + sep_len;
1262 if (size + extra_len > max_len)
1263 {
1264 break;
1265 }
1266
1267 size += extra_len;
1268 more = more->next;
1269 }
1270
1271 if (count >= 2)
1272 {
1273 struct buffer_entry *f;
1274 ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1275 f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1276
1277 struct buffer_entry *e = bl->head;
1278 for (size_t i = 0; e && i < count; ++i)
1279 {
1280 struct buffer_entry *next = e->next;
1281 buf_copy(&f->buf, &e->buf);
1282 buf_write(&f->buf, sep, sep_len);
1283 free_buf(&e->buf);
1284 free(e);
1285 e = next;
1286 }
1287 bl->head = f;
1288 bl->size -= count - 1;
1289 f->next = more;
1290 if (!more)
1291 {
1292 bl->tail = f;
1293 }
1294 }
1295}
1296
1297void
1298buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1299{
1301}
1302
1303void
1305{
1306 if (buffer_list_defined(ol))
1307 {
1308 struct buffer_entry *e = ol->head->next;
1309 free_buf(&ol->head->buf);
1310 free(ol->head);
1311 ol->head = e;
1312 --ol->size;
1313 if (!e)
1314 {
1315 ol->tail = NULL;
1316 }
1317 }
1318}
1319
1320void
1321buffer_list_advance(struct buffer_list *ol, ssize_t n)
1322{
1323 if (ol->head)
1324 {
1325 struct buffer *buf = &ol->head->buf;
1326 ASSERT(buf_advance(buf, n));
1327 if (!BLEN(buf))
1328 {
1329 buffer_list_pop(ol);
1330 }
1331 }
1332}
1333
1334struct buffer_list *
1335buffer_list_file(const char *fn, int max_line_len)
1336{
1337 FILE *fp = platform_fopen(fn, "r");
1338 struct buffer_list *bl = NULL;
1339
1340 if (fp)
1341 {
1342 char *line = (char *)malloc(max_line_len);
1343 if (line)
1344 {
1345 bl = buffer_list_new();
1346 while (fgets(line, max_line_len, fp) != NULL)
1347 {
1348 buffer_list_push(bl, line);
1349 }
1350 free(line);
1351 }
1352 fclose(fp);
1353 }
1354 return bl;
1355}
1356
1357struct buffer
1358buffer_read_from_file(const char *filename, struct gc_arena *gc)
1359{
1360 struct buffer ret = { 0 };
1361
1362 platform_stat_t file_stat = { 0 };
1363 if (platform_stat(filename, &file_stat) < 0)
1364 {
1365 return ret;
1366 }
1367
1368 FILE *fp = platform_fopen(filename, "r");
1369 if (!fp)
1370 {
1371 return ret;
1372 }
1373
1374 const size_t size = file_stat.st_size;
1375 ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1376 size_t read_size = fread(BPTR(&ret), 1, size, fp);
1377 if (read_size == 0)
1378 {
1379 free_buf_gc(&ret, gc);
1380 goto cleanup;
1381 }
1382 ASSERT(buf_inc_len(&ret, (int)read_size));
1383 buf_null_terminate(&ret);
1384
1385cleanup:
1386 fclose(fp);
1387 return ret;
1388}
1389
1390char *
1391buf_extract_field(struct buffer *buf, char sep, struct gc_arena *gc)
1392{
1393 if (!buf_valid(buf))
1394 {
1395 return NULL;
1396 }
1397
1398 const uint8_t *seppos = memchr(CBPTR(buf), sep, buf_len(buf));
1399 if (!seppos)
1400 {
1401 return NULL;
1402 }
1403 size_t field_len = seppos - CBPTR(buf);
1404
1405 char *field = gc_malloc(field_len + 1, false, gc);
1406
1407 memcpy(field, CBPTR(buf), field_len);
1408 field[field_len] = 0;
1409
1410 buf_advance(buf, field_len + 1);
1411 return field;
1412}
bool buffer_list_defined(const struct buffer_list *ol)
Checks if the list is valid and non-empty.
Definition buffer.c:1177
bool buf_string_compare_advance(struct buffer *src, const char *match)
Compare the head of src with match and advance past it if equal.
Definition buffer.c:724
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:1212
void rm_trailing_chars(char *str, const char *what_to_delete)
Remove all trailing characters that appear in a given set.
Definition buffer.c:588
void string_null_terminate(char *str, int len, int capacity)
Null-terminate a fixed-length string buffer.
Definition buffer.c:561
void free_buf(struct buffer *buf)
Free the memory allocated for a buffer.
Definition buffer.c:169
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:1253
static bool char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
Definition buffer.c:964
void buf_clear(struct buffer *buf)
Zeroise and reset a buffer.
Definition buffer.c:148
void buffer_list_reset(struct buffer_list *ol)
Empty the list ol and frees all the contained buffers.
Definition buffer.c:1183
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition buffer.c:176
const char * skip_leading_whitespace(const char *str)
Return a pointer past any leading whitespace in a string.
Definition buffer.c:542
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:1298
struct buffer clone_buf(const struct buffer *buf)
Duplicate a buffer, including its content.
Definition buffer.c:99
void x_gc_freespecial(struct gc_arena *a)
Free all specially-allocated entries in a garbage collection arena.
Definition buffer.c:390
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition buffer.c:281
void buf_catrunc(struct buffer *buf, const char *str)
Append a string to the physical end of a buffer that was truncated by buf_printf().
Definition buffer.c:268
#define buf_debug_file(buf)
Definition buffer.c:143
void buffer_list_pop(struct buffer_list *ol)
Remove and free the head buffer of the list.
Definition buffer.c:1304
bool buf_printf(struct buffer *buf, const char *format,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
void string_replace_leading(char *str, const char match, const char replace)
Replace all leading occurrences of a character in a string.
Definition buffer.c:1056
char * buf_extract_field(struct buffer *buf, char sep, struct gc_arena *gc)
Extract a field from buf that ends with the sep character.
Definition buffer.c:1391
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Read a file into a buffer list, one buffer per line.
Definition buffer.c:1335
void string_clear(char *str)
Securely clear a null-terminated string.
Definition buffer.c:634
#define buf_debug_line(buf)
Definition buffer.c:142
void gc_transfer(struct gc_arena *dest, struct gc_arena *src)
Move all allocations from one garbage collection arena to another.
Definition buffer.c:424
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Test whether all characters in a string satisfy a character class filter.
Definition buffer.c:971
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Format a NULL-terminated argument vector as a single string.
Definition buffer.c:660
void buf_null_terminate(struct buffer *buf)
Force a null terminator at the end of the buffer content.
Definition buffer.c:496
struct buffer buf_sub(struct buffer *buf, int size, bool prepend)
Return a sub-buffer of another buffer.
Definition buffer.c:207
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:338
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1158
void chomp(char *str)
Remove trailing newline and carriage-return characters from a string.
Definition buffer.c:579
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition buffer.c:1240
const char * np(const char *str)
Return a printable representation of a string that might be NULL.
Definition buffer.c:799
bool string_defined_equal(const char *s1, const char *s2)
compare two strings which might be NULL, but NULL is never equal
Definition buffer.c:1074
size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
Safely compute the product of two sizes plus an extra amount.
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:1167
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:313
void buf_puts(struct buffer *buf, const char *str)
Append a string to a buffer with overflow check.
Definition buffer.c:252
bool buf_assign(struct buffer *dest, const struct buffer *src)
Assign the content of one buffer to another.
Definition buffer.c:159
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
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)
Format a binary buffer as a hex string.
Definition buffer.c:447
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:990
struct buffer alloc_buf(size_t size)
Allocate a buffer of the given size.
Definition buffer.c:60
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:1040
void gc_addspecial(void *addr, void(*free_function)(void *), struct gc_arena *a)
Register an address with a custom free function in a garbage collection arena.
Definition buffer.c:406
void buffer_list_advance(struct buffer_list *ol, ssize_t n)
Advance past n bytes in the head buffer, popping it if it becomes empty.
Definition buffer.c:1321
int string_array_len(const char **array)
Return the number of elements in a NULL-terminated array of strings.
Definition buffer.c:646
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:1358
void buf_rmtail(struct buffer *buf, uint8_t remove)
Remove all occurrences of a specific byte from the end of a buffer.
Definition buffer.c:481
char * string_substitute(const char *src, char from, char to, struct gc_arena *gc)
Definition buffer.c:1104
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Extract the next token from a buffer, delimited by a given character.
Definition buffer.c:760
bool checked_snprintf(char *str, size_t size, const char *format,...)
Like snprintf() but returns an boolean.
Definition buffer.c:1123
void buf_size_error(const size_t size)
Report a buffer size error and abort.
Definition buffer.c:54
char * string_alloc(const char *str, struct gc_arena *gc)
Duplicate a string, allocating memory under garbage collection.
Definition buffer.c:601
struct buffer string_alloc_buf(const char *str, struct gc_arena *gc)
Allocate a buffer containing a copy of the given string.
Definition buffer.c:692
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:1198
void x_gc_free(struct gc_arena *a)
Free all plain allocations in a garbage collection arena.
Definition buffer.c:371
void buf_chomp(struct buffer *buf)
Remove trailing newline and carriage-return characters from a buffer.
Definition buffer.c:517
bool string_check_buf(const struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition buffer.c:1023
bool char_class(const unsigned char c, const unsigned int flags)
Test whether a character belongs to one or more character classes.
Definition buffer.c:824
bool buf_string_match_head_str(const struct buffer *src, const char *match)
Return true if the head of src matches the string match.
Definition buffer.c:713
int buf_substring_len(const struct buffer *buf, int delim)
Return the number of bytes in a buffer up to and including a delimiter.
Definition buffer.c:738
bool streqnull(const char *a, const char *b)
compare two strings which might be NULL
Definition buffer.c:1087
Buffer management functions and garbage collection.
#define CC_EXCLAMATION
exclamation mark
Definition buffer.h:1705
#define CC_PERCENT
percent sign
Definition buffer.h:1704
#define CC_COMMA
comma
Definition buffer.h:1698
#define BEND(buf)
Return a pointer one past the end of the buffer content.
Definition buffer.h:143
#define CC_DASH
dash
Definition buffer.h:1696
static bool buf_size_valid(const size_t size)
Return true iff size is within the allowed buffer size range.
Definition buffer.h:543
#define CC_DOUBLE_QUOTE
double quote
Definition buffer.h:1702
#define BLAST(buf)
Return a pointer to the last byte of the buffer content, or NULL if empty.
Definition buffer.h:147
#define CC_BLANK
space or tab
Definition buffer.h:1690
static bool buf_init_dowork(struct buffer *buf, int offset)
Initialise a buffer with a given initial offset.
Definition buffer.h:635
#define CC_PIPE
pipe
Definition buffer.h:1708
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:157
static bool buf_copy(struct buffer *dest, const struct buffer *src)
Copy the content of one buffer to the end of another.
Definition buffer.h:1342
#define CC_ANY
any character
Definition buffer.h:1677
#define BPTR(buf)
Return a pointer to the start of the buffer content.
Definition buffer.h:139
#define CC_XDIGIT
hex digit isxdigit()
Definition buffer.h:1688
#define CC_COLON
colon
Definition buffer.h:1699
#define CC_SINGLE_QUOTE
single quote
Definition buffer.h:1701
#define streq(x, y)
helper to work around the semantics of the strcmp() return value
Definition buffer.h:1813
static bool buf_inc_len(struct buffer *buf, int inc)
Increase or decrease the length of a buffer.
Definition buffer.h:1119
#define CC_DIGIT
digit isdigit()
Definition buffer.h:1684
static bool buf_valid(const struct buffer *buf)
Return true iff buf is valid.
Definition buffer.h:414
#define PA_BRACKET
Flag for print_argv(): wrap each argument in square brackets.
Definition buffer.h:229
#define CC_DOT
dot
Definition buffer.h:1697
#define CC_CRLF
carriage return or newline
Definition buffer.h:1714
static bool buf_safe(const struct buffer *buf, size_t len)
Check whether len bytes can be appended to a buffer.
Definition buffer.h:994
#define ALLOC_SIZE_MAX
Maximum size for a single array allocation (checked by array_mult_safe()).
Definition buffer.h:2002
#define CC_ASTERISK
asterisk
Definition buffer.h:1710
#define CC_ALPHA
alphabetic isalpha()
Definition buffer.h:1681
#define CC_NEWLINE
newline
Definition buffer.h:1691
static uint8_t * buf_prepend(struct buffer *buf, ssize_t size)
Make space at the front of a buffer for prepending data.
Definition buffer.h:1142
static int buf_len(const struct buffer *buf)
Return the length of the buffer content.
Definition buffer.h:462
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Initialise a buffer with an externally provided read-only memory region.
Definition buffer.h:687
static int buf_forward_capacity(const struct buffer *buf)
Return the number of bytes that can still be appended to the buffer.
Definition buffer.h:1038
#define CBPTR(buf)
Return a const pointer to the start of the buffer content.
Definition buffer.h:141
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:748
static uint8_t * buf_write_alloc(struct buffer *buf, size_t size)
Reserve space at the end of a buffer for writing.
Definition buffer.h:1189
static bool buf_advance(struct buffer *buf, ssize_t size)
Advance the content start of a buffer, consuming bytes from the front.
Definition buffer.h:1165
#define CC_REVERSE_QUOTE
reverse quote
Definition buffer.h:1703
static int buf_peek_u8(const struct buffer *buf)
Return the first byte of the buffer without consuming it.
Definition buffer.h:1471
#define CC_SPACE
whitespace isspace()
Definition buffer.h:1687
#define CC_ASCII
ASCII character.
Definition buffer.h:1682
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Append data to a buffer.
Definition buffer.h:1239
#define CC_BACKSLASH
backslash
Definition buffer.h:1694
#define CC_CNTRL
control character iscntrl()
Definition buffer.h:1683
#define CC_LESS_THAN
less than sign
Definition buffer.h:1706
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Append a uint8_t to a buffer.
Definition buffer.h:1283
static int buf_read_u8(struct buffer *buf)
Read and consume a uint8_t from the front of a buffer.
Definition buffer.h:1490
#define BLEN(buf)
Return the length of the buffer content in bytes.
Definition buffer.h:151
#define CC_CR
carriage return
Definition buffer.h:1692
#define CC_SLASH
slash
Definition buffer.h:1700
#define CC_UNDERBAR
underscore
Definition buffer.h:1695
#define CC_GREATER_THAN
greater than sign
Definition buffer.h:1707
#define BLENZ(buf)
Return the length of the buffer content as a size_t.
Definition buffer.h:153
void buf_size_error(const size_t size)
Report a buffer size error and abort.
Definition buffer.c:54
static void check_malloc_return(void *p)
Abort if a memory allocation returned NULL.
Definition buffer.h:2135
#define CC_NULL
null character \0
Definition buffer.h:1678
#define CBSTR(buf)
Return the buffer content pointer cast to const char *.
Definition buffer.h:159
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:1685
#define CC_QUESTION_MARK
question mark
Definition buffer.h:1709
#define ALLOC_OBJ_CLEAR(dptr, type)
Allocate and zero-initialise memory for a single object of the given type.
Definition buffer.h:2027
static bool buf_defined(const struct buffer *buf)
Return true iff buf has a non-NULL data pointer.
Definition buffer.h:399
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:1680
#define buf_init(buf, offset)
Definition buffer.h:364
#define FHE_SPACE_BREAK_MASK
Mask for the space_break_flags field of format_hex_ex(): number of bytes between separators (lower 8 ...
Definition buffer.h:925
#define CC_PUNCT
punctuation ispunct()
Definition buffer.h:1686
#define FHE_CAPS
Flag for format_hex_ex(): output hex digits in upper case.
Definition buffer.h:927
static int buf_forward_capacity_total(const struct buffer *buf)
Return the total number of bytes available from the current offset to the end of the allocated memory...
Definition buffer.h:1067
unsigned long ptr_type
Definition common.h:59
#define ptr_format
Definition common.h:50
size_t strlcpy(char *dest, const char *src, size_t maxlen)
#define D_ALIGN_ERRORS
Definition errlevel.h:69
#define D_ALIGN_DEBUG
Definition errlevel.h:141
@ write
#define PAYLOAD_ALIGN
Definition mtu.h:100
#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:221
#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
One node in a buffer_list linked list.
Definition buffer.h:2152
struct buffer_entry * next
Pointer to the next node, or NULL.
Definition buffer.h:2154
struct buffer buf
The buffer stored in this list node.
Definition buffer.h:2153
A singly-linked list of buffers, with head/tail pointers for O(1) push.
Definition buffer.h:2159
size_t size
Current number of entries.
Definition buffer.h:2162
struct buffer_entry * tail
Last item pushed.
Definition buffer.h:2161
struct buffer_entry * head
Next item to pop/peek.
Definition buffer.h:2160
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int capacity
Size in bytes of memory allocated by malloc().
Definition buffer.h:72
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:78
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
int offset
Offset in bytes of the actual content within the allocated memory.
Definition buffer.h:74
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
struct gc_entry_special * list_special
First element of the linked list of gc_entry_special structures for allocations requiring a custom fr...
Definition buffer.h:130
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:128
Garbage collection entry for a specially allocated structure that needs a custom free function to be ...
Definition buffer.h:109
void(* free_fnc)(void *)
Definition buffer.h:111
void * addr
Definition buffer.h:112
struct gc_entry_special * next
Definition buffer.h:110
Garbage collection entry for one dynamically allocated block of memory.
Definition buffer.h:98
struct gc_entry * next
Pointer to the next item in the linked list.
Definition buffer.h:99
#define unlikely(x)
Definition syshead.h:35
static int cleanup(void **state)
struct gc_arena gc
Definition test_ssl.c:122