1 /*
2 * Copyright (c) 2018-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * Copyright (c) 2021-2022 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #ifndef STRACE_XSTRING_H
10 # define STRACE_XSTRING_H
11
12 # include <stdarg.h>
13 # include <stdio.h>
14
15 # include "error_prints.h"
16 # include "macros.h"
17
18 /**
19 * Print to static buffer and die on (really unexpected) errors and overflows.
20 * Shouldn't be used directly; please refer to helper macros xsnprintf and
21 * xsprintf instead.
22 *
23 * @param str String buffer to print into.
24 * @param size Size of the string buffer in bytes.
25 * @param func Function name from which this function is called.
26 * @param argstr Stringified arguments (including format argument).
27 * @param format Format string.
28 * @param ... Format arguments.
29 * @return Number of characters printed, excluding terminating null byte
30 * (the same as s(n)printf).
31 */
32 static inline int ATTRIBUTE_FORMAT((printf, 5, 6))
33 xsnprintf_(char *str, size_t size, const char *func, const char *argstr,
34 const char *format, ...)
35 {
36 int ret;
37 va_list ap;
38
39 va_start(ap, format);
40 ret = vsnprintf(str, size, format, ap);
41 va_end(ap);
42
43 if (ret < 0 || (unsigned int) ret >= size)
44 error_msg_and_die("%s: got unexpected return value %d for "
45 "snprintf(buf, %zu, %s)",
46 func, ret, size, argstr);
47
48 return ret;
49 }
50
51 /**
52 * snprintf that dies on (really unexpected) errors and overflows.
53 *
54 * @param str_ String buffer to print into.
55 * @param size_ Size of the string buffer in bytes.
56 * @param fmt_ Format string.
57 * @param ... Format arguments.
58 */
59 # define xsnprintf(str_, size_, fmt_, ...) \
60 xsnprintf_((str_), (size_), __func__, #fmt_ ", " #__VA_ARGS__, \
61 (fmt_), ##__VA_ARGS__)
62
63 /**
64 * Print to a character array buffer and die on (really unexpected) errors and
65 * overflows. Buffer size is obtained with sizeof().
66 *
67 * @param str_ Character array buffer to print into.
68 * @param fmt_ Format string.
69 * @param ... Format arguments.
70 */
71 # define xsprintf(str_, fmt_, ...) \
72 xsnprintf((str_), sizeof(str_) + MUST_BE_ARRAY(str_), (fmt_), \
73 ##__VA_ARGS__)
74
75 static inline size_t
76 get_pos_diff_(char *str, size_t size, char *pos, const char *func,
77 const char *call)
78 {
79 if ((str + size) < str)
80 error_msg_and_die("%s: string size overflow (%p+%zu) in %s",
81 func, str, size, call);
82
83 if (pos > (str + size))
84 error_msg_and_die("%s: got position (%p) beyond string "
85 "(%p+%zu) in %s",
86 func, pos, str, size, call);
87
88 if (pos < str)
89 error_msg_and_die("%s: got position %p before string %p in %s",
90 func, pos, str, call);
91
92 return pos - str;
93 }
94
95 /**
96 * Helper function for constructing string in a character array by appending
97 * new formatted parts. Returns new position. Fails on error or buffer
98 * overflow, in line with the rest of x* functions. Obtains buffer size via
99 * sizeof(str_).
100 *
101 * @param str_ Character array buffer to print into.
102 * @param pos_ Current position.
103 * @param fmt_ Format string.
104 * @param ... Format arguments.
105 * @return New position.
106 */
107 # define xappendstr(str_, pos_, fmt_, ...) \
108 (xsnprintf((pos_), sizeof(str_) + MUST_BE_ARRAY(str_) - \
109 get_pos_diff_((str_), sizeof(str_), (pos_), __func__, \
110 "xappendstr(" #str_ ", " #pos_ ", " #fmt_ ", " \
111 #__VA_ARGS__ ")"), \
112 (fmt_), ##__VA_ARGS__) + (pos_))
113
114 #endif /* !STRACE_XSTRING_H */