Coverage Report

Created: 2026-06-25 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/ta/ta_utils.c
Line
Count
Source
1
/* Copyright (C) 2017 the mpv developers
2
 *
3
 * Permission to use, copy, modify, and/or distribute this software for any
4
 * purpose with or without fee is hereby granted, provided that the above
5
 * copyright notice and this permission notice appear in all copies.
6
 *
7
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
 */
15
16
#include <stdlib.h>
17
#include <string.h>
18
#include <stdio.h>
19
#include <assert.h>
20
#include "osdep/strnlen.h"
21
22
#define TA_NO_WRAPPERS
23
#include "ta.h"
24
25
// Return element_size * count. If it overflows, return (size_t)-1 (SIZE_MAX).
26
// I.e. this returns the equivalent of: MIN(element_size * count, SIZE_MAX).
27
// The idea is that every real memory allocator will reject (size_t)-1, thus
28
// this is a valid way to handle too large array allocation requests.
29
size_t ta_calc_array_size(size_t element_size, size_t count)
30
88.7M
{
31
88.7M
    if (count > (((size_t)-1) / element_size))
32
0
        return (size_t)-1;
33
88.7M
    return element_size * count;
34
88.7M
}
35
36
// This is used when an array has to be enlarged for appending new elements.
37
// Return a "good" size for the new array (in number of elements). This returns
38
// a value > nextidx, unless the calculation overflows, in which case SIZE_MAX
39
// is returned.
40
size_t ta_calc_prealloc_elems(size_t nextidx)
41
58.4M
{
42
58.4M
    if (nextidx >= ((size_t)-1) / 2 - 1)
43
0
        return (size_t)-1;
44
58.4M
    return (nextidx + 1) * 2;
45
58.4M
}
46
47
/* Create an empty (size 0) TA allocation.
48
 */
49
void *ta_new_context(void *ta_parent)
50
24.8M
{
51
24.8M
    return ta_alloc_size(ta_parent, 0);
52
24.8M
}
53
54
/* Set parent of ptr to ta_parent, return the ptr.
55
 * Note that ta_parent==NULL will simply unset the current parent of ptr.
56
 */
57
void *ta_steal_(void *ta_parent, void *ptr)
58
10.6M
{
59
10.6M
    ta_set_parent(ptr, ta_parent);
60
10.6M
    return ptr;
61
10.6M
}
62
63
/* Duplicate the memory at ptr with the given size.
64
 */
65
void *ta_memdup(void *ta_parent, void *ptr, size_t size)
66
7.53M
{
67
7.53M
    if (!ptr) {
68
2.45M
        assert(!size);
69
2.45M
        return NULL;
70
2.45M
    }
71
5.08M
    void *res = ta_alloc_size(ta_parent, size);
72
5.08M
    if (!res)
73
0
        return NULL;
74
5.08M
    memcpy(res, ptr, size);
75
5.08M
    return res;
76
5.08M
}
77
78
// *str = *str[0..at] + append[0..append_len]
79
// (append_len being a maximum length; shorter if embedded \0s are encountered)
80
static bool strndup_append_at(char **str, size_t at, const char *append,
81
                              size_t append_len)
82
712M
{
83
712M
    assert(ta_get_size(*str) >= at);
84
85
712M
    if (!*str && !append)
86
0
        return true; // stays NULL, but not an OOM condition
87
88
712M
    size_t real_len = append ? strnlen(append, append_len) : 0;
89
712M
    if (append_len > real_len)
90
2.08M
        append_len = real_len;
91
92
712M
    if (ta_get_size(*str) < at + append_len + 1) {
93
712M
        char *t = ta_realloc_size(NULL, *str, at + append_len + 1);
94
712M
        if (!t)
95
0
            return false;
96
712M
        *str = t;
97
712M
    }
98
99
712M
    if (append_len)
100
706M
        memcpy(*str + at, append, append_len);
101
102
712M
    (*str)[at + append_len] = '\0';
103
104
712M
    ta_dbg_mark_as_string(*str);
105
106
712M
    return true;
107
712M
}
108
109
/* Return a copy of str.
110
 * Returns NULL on OOM.
111
 */
112
char *ta_strdup(void *ta_parent, const char *str)
113
572M
{
114
572M
    return ta_strndup(ta_parent, str, str ? strlen(str) : 0);
115
572M
}
116
117
/* Return a copy of str. If the string is longer than n, copy only n characters
118
 * (the returned allocation will be n+1 bytes and contain a terminating '\0').
119
 * The returned string will have the length MIN(strlen(str), n)
120
 * If str==NULL, return NULL. Returns NULL on OOM as well.
121
 */
122
char *ta_strndup(void *ta_parent, const char *str, size_t n)
123
780M
{
124
780M
    if (!str)
125
71.2M
        return NULL;
126
709M
    char *new = NULL;
127
709M
    strndup_append_at(&new, 0, str, n);
128
709M
    ta_set_parent(new, ta_parent);
129
709M
    return new;
130
780M
}
131
132
/* Append a to *str. If *str is NULL, the string is newly allocated, otherwise
133
 * ta_realloc() is used on *str as needed.
134
 * Return success or failure (it can fail due to OOM only).
135
 */
136
bool ta_strdup_append(char **str, const char *a)
137
377k
{
138
377k
    return strndup_append_at(str, *str ? strlen(*str) : 0, a, (size_t)-1);
139
377k
}
140
141
/* Like ta_strdup_append(), but use ta_get_size(*str)-1 instead of strlen(*str).
142
 * (See also: ta_asprintf_append_buffer())
143
 */
144
bool ta_strdup_append_buffer(char **str, const char *a)
145
1.64M
{
146
1.64M
    size_t size = ta_get_size(*str);
147
1.64M
    if (size > 0)
148
1.64M
        size -= 1;
149
1.64M
    return strndup_append_at(str, size, a, (size_t)-1);
150
1.64M
}
151
152
/* Like ta_strdup_append(), but limit the length of a with n.
153
 * (See also: ta_strndup())
154
 */
155
bool ta_strndup_append(char **str, const char *a, size_t n)
156
0
{
157
0
    return strndup_append_at(str, *str ? strlen(*str) : 0, a, n);
158
0
}
159
160
/* Like ta_strdup_append_buffer(), but limit the length of a with n.
161
 * (See also: ta_strndup())
162
 */
163
bool ta_strndup_append_buffer(char **str, const char *a, size_t n)
164
1.63M
{
165
1.63M
    size_t size = ta_get_size(*str);
166
1.63M
    if (size > 0)
167
1.63M
        size -= 1;
168
1.63M
    return strndup_append_at(str, size, a, n);
169
1.63M
}
170
171
TA_PRF(3, 0)
172
static bool ta_vasprintf_append_at(char **str, size_t at, const char *fmt,
173
                                   va_list ap)
174
27.3M
{
175
27.3M
    assert(ta_get_size(*str) >= at);
176
177
27.3M
    int size;
178
27.3M
    va_list copy;
179
27.3M
    va_copy(copy, ap);
180
27.3M
    char c;
181
27.3M
    size = vsnprintf(&c, 1, fmt, copy);
182
27.3M
    va_end(copy);
183
184
27.3M
    if (size < 0)
185
0
        return false;
186
187
27.3M
    if (ta_get_size(*str) < at + size + 1) {
188
27.3M
        char *t = ta_realloc_size(NULL, *str, at + size + 1);
189
27.3M
        if (!t)
190
0
            return false;
191
27.3M
        *str = t;
192
27.3M
    }
193
27.3M
    vsnprintf(*str + at, size + 1, fmt, ap);
194
195
27.3M
    ta_dbg_mark_as_string(*str);
196
197
27.3M
    return true;
198
27.3M
}
199
200
/* Like snprintf(); returns the formatted string as allocation (or NULL on OOM
201
 * or snprintf() errors).
202
 */
203
char *ta_asprintf(void *ta_parent, const char *fmt, ...)
204
25.7M
{
205
25.7M
    char *res;
206
25.7M
    va_list ap;
207
25.7M
    va_start(ap, fmt);
208
25.7M
    res = ta_vasprintf(ta_parent, fmt, ap);
209
25.7M
    va_end(ap);
210
25.7M
    return res;
211
25.7M
}
212
213
char *ta_vasprintf(void *ta_parent, const char *fmt, va_list ap)
214
25.7M
{
215
25.7M
    char *res = NULL;
216
25.7M
    ta_vasprintf_append_at(&res, 0, fmt, ap);
217
25.7M
    ta_set_parent(res, ta_parent);
218
25.7M
    if (!res) {
219
0
        ta_free(res);
220
0
        return NULL;
221
0
    }
222
25.7M
    return res;
223
25.7M
}
224
225
/* Append the formatted string to *str (after strlen(*str)). The allocation is
226
 * ta_realloced if needed.
227
 * Returns false on OOM or snprintf() errors, with *str left untouched.
228
 */
229
bool ta_asprintf_append(char **str, const char *fmt, ...)
230
1.51M
{
231
1.51M
    bool res;
232
1.51M
    va_list ap;
233
1.51M
    va_start(ap, fmt);
234
1.51M
    res = ta_vasprintf_append(str, fmt, ap);
235
1.51M
    va_end(ap);
236
1.51M
    return res;
237
1.51M
}
238
239
bool ta_vasprintf_append(char **str, const char *fmt, va_list ap)
240
1.51M
{
241
1.51M
    return ta_vasprintf_append_at(str, *str ? strlen(*str) : 0, fmt, ap);
242
1.51M
}
243
244
/* Append the formatted string at the end of the allocation of *str. It
245
 * overwrites the last byte of the allocation too (which is assumed to be the
246
 * '\0' terminating the string). Compared to ta_asprintf_append(), this is
247
 * useful if you know that the string ends with the allocation, so that the
248
 * extra strlen() can be avoided for better performance.
249
 * Returns false on OOM or snprintf() errors, with *str left untouched.
250
 */
251
bool ta_asprintf_append_buffer(char **str, const char *fmt, ...)
252
0
{
253
0
    bool res;
254
0
    va_list ap;
255
0
    va_start(ap, fmt);
256
0
    res = ta_vasprintf_append_buffer(str, fmt, ap);
257
0
    va_end(ap);
258
0
    return res;
259
0
}
260
261
bool ta_vasprintf_append_buffer(char **str, const char *fmt, va_list ap)
262
97.3k
{
263
97.3k
    size_t size = ta_get_size(*str);
264
97.3k
    if (size > 0)
265
97.3k
        size -= 1;
266
97.3k
    return ta_vasprintf_append_at(str, size, fmt, ap);
267
97.3k
}
268
269
void *ta_xmemdup(void *ta_parent, void *ptr, size_t size)
270
5.96M
{
271
5.96M
    void *new = ta_memdup(ta_parent, ptr, size);
272
5.96M
    ta_oom_b(new || !ptr);
273
5.96M
    return new;
274
5.96M
}
275
276
void *ta_xrealloc_size(void *ta_parent, void *ptr, size_t size)
277
103M
{
278
103M
    ptr = ta_realloc_size(ta_parent, ptr, size);
279
103M
    ta_oom_b(ptr || !size);
280
103M
    return ptr;
281
103M
}
282
283
char *ta_xstrdup(void *ta_parent, const char *str)
284
572M
{
285
572M
    char *res = ta_strdup(ta_parent, str);
286
572M
    ta_oom_b(res || !str);
287
572M
    return res;
288
572M
}
289
290
char *ta_xstrndup(void *ta_parent, const char *str, size_t n)
291
208M
{
292
208M
    char *res = ta_strndup(ta_parent, str, n);
293
208M
    ta_oom_b(res || !str);
294
208M
    return res;
295
208M
}