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 #ifndef TA_H_
17 #define TA_H_
18 
19 #include <stddef.h>
20 #include <stdbool.h>
21 #include <stdarg.h>
22 
23 #ifdef __GNUC__
24 #define TA_PRF(a1, a2) __attribute__ ((format(printf, a1, a2)))
25 #define TA_TYPEOF(t) __typeof__(t)
26 #else
27 #define TA_PRF(a1, a2)
28 #define TA_TYPEOF(t) void *
29 #endif
30 
31 // Broken crap with __USE_MINGW_ANSI_STDIO
32 #if defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
33 #undef TA_PRF
34 #define TA_PRF(a1, a2) __attribute__ ((format (gnu_printf, a1, a2)))
35 #endif
36 
37 #define TA_STRINGIFY_(x) # x
38 #define TA_STRINGIFY(x) TA_STRINGIFY_(x)
39 
40 #ifdef NDEBUG
41 #define TA_LOC ""
42 #else
43 #define TA_LOC __FILE__ ":" TA_STRINGIFY(__LINE__)
44 #endif
45 
46 // Core functions
47 void *ta_alloc_size(void *ta_parent, size_t size);
48 void *ta_zalloc_size(void *ta_parent, size_t size);
49 void *ta_realloc_size(void *ta_parent, void *ptr, size_t size);
50 size_t ta_get_size(void *ptr);
51 void ta_free(void *ptr);
52 void ta_free_children(void *ptr);
53 void ta_set_destructor(void *ptr, void (*destructor)(void *));
54 void ta_set_parent(void *ptr, void *ta_parent);
55 void *ta_get_parent(void *ptr);
56 
57 // Utility functions
58 size_t ta_calc_array_size(size_t element_size, size_t count);
59 size_t ta_calc_prealloc_elems(size_t nextidx);
60 void *ta_new_context(void *ta_parent);
61 void *ta_steal_(void *ta_parent, void *ptr);
62 void *ta_memdup(void *ta_parent, void *ptr, size_t size);
63 char *ta_strdup(void *ta_parent, const char *str);
64 bool ta_strdup_append(char **str, const char *a);
65 bool ta_strdup_append_buffer(char **str, const char *a);
66 char *ta_strndup(void *ta_parent, const char *str, size_t n);
67 bool ta_strndup_append(char **str, const char *a, size_t n);
68 bool ta_strndup_append_buffer(char **str, const char *a, size_t n);
69 char *ta_asprintf(void *ta_parent, const char *fmt, ...) TA_PRF(2, 3);
70 char *ta_vasprintf(void *ta_parent, const char *fmt, va_list ap) TA_PRF(2, 0);
71 bool ta_asprintf_append(char **str, const char *fmt, ...) TA_PRF(2, 3);
72 bool ta_vasprintf_append(char **str, const char *fmt, va_list ap) TA_PRF(2, 0);
73 bool ta_asprintf_append_buffer(char **str, const char *fmt, ...) TA_PRF(2, 3);
74 bool ta_vasprintf_append_buffer(char **str, const char *fmt, va_list ap) TA_PRF(2, 0);
75 
76 #define ta_new(ta_parent, type)  (type *)ta_alloc_size(ta_parent, sizeof(type))
77 #define ta_znew(ta_parent, type) (type *)ta_zalloc_size(ta_parent, sizeof(type))
78 
79 #define ta_new_array(ta_parent, type, count) \
80     (type *)ta_alloc_size(ta_parent, ta_calc_array_size(sizeof(type), count))
81 
82 #define ta_znew_array(ta_parent, type, count) \
83     (type *)ta_zalloc_size(ta_parent, ta_calc_array_size(sizeof(type), count))
84 
85 #define ta_new_array_size(ta_parent, element_size, count) \
86     ta_alloc_size(ta_parent, ta_calc_array_size(element_size, count))
87 
88 #define ta_realloc(ta_parent, ptr, type, count) \
89     (type *)ta_realloc_size(ta_parent, ptr, ta_calc_array_size(sizeof(type), count))
90 
91 #define ta_new_ptrtype(ta_parent, ptr) \
92     (TA_TYPEOF(ptr))ta_alloc_size(ta_parent, sizeof(*ptr))
93 
94 #define ta_new_array_ptrtype(ta_parent, ptr, count) \
95     (TA_TYPEOF(ptr))ta_new_array_size(ta_parent, sizeof(*(ptr)), count)
96 
97 #define ta_steal(ta_parent, ptr) (TA_TYPEOF(ptr))ta_steal_(ta_parent, ptr)
98 
99 #define ta_dup(ta_parent, ptr) \
100     (TA_TYPEOF(ptr))ta_memdup(ta_parent, ptr, sizeof(*(ptr)))
101 
102 // Ugly macros that crash on OOM.
103 // All of these mirror real functions (with a 'x' added after the 'ta_'
104 // prefix), and the only difference is that they will call abort() on allocation
105 // failures (such as out of memory conditions), instead of returning an error
106 // code.
107 #define ta_xalloc_size(...)             ta_oom_p(ta_alloc_size(__VA_ARGS__))
108 #define ta_xzalloc_size(...)            ta_oom_p(ta_zalloc_size(__VA_ARGS__))
109 #define ta_xnew_context(...)            ta_oom_p(ta_new_context(__VA_ARGS__))
110 #define ta_xstrdup_append(...)          ta_oom_b(ta_strdup_append(__VA_ARGS__))
111 #define ta_xstrdup_append_buffer(...)   ta_oom_b(ta_strdup_append_buffer(__VA_ARGS__))
112 #define ta_xstrndup_append(...)         ta_oom_b(ta_strndup_append(__VA_ARGS__))
113 #define ta_xstrndup_append_buffer(...)  ta_oom_b(ta_strndup_append_buffer(__VA_ARGS__))
114 #define ta_xasprintf(...)               ta_oom_s(ta_asprintf(__VA_ARGS__))
115 #define ta_xvasprintf(...)              ta_oom_s(ta_vasprintf(__VA_ARGS__))
116 #define ta_xasprintf_append(...)        ta_oom_b(ta_asprintf_append(__VA_ARGS__))
117 #define ta_xvasprintf_append(...)       ta_oom_b(ta_vasprintf_append(__VA_ARGS__))
118 #define ta_xasprintf_append_buffer(...) ta_oom_b(ta_asprintf_append_buffer(__VA_ARGS__))
119 #define ta_xvasprintf_append_buffer(...) ta_oom_b(ta_vasprintf_append_buffer(__VA_ARGS__))
120 #define ta_xnew(...)                    ta_oom_g(ta_new(__VA_ARGS__))
121 #define ta_xznew(...)                   ta_oom_g(ta_znew(__VA_ARGS__))
122 #define ta_xnew_array(...)              ta_oom_g(ta_new_array(__VA_ARGS__))
123 #define ta_xznew_array(...)             ta_oom_g(ta_znew_array(__VA_ARGS__))
124 #define ta_xnew_array_size(...)         ta_oom_p(ta_new_array_size(__VA_ARGS__))
125 #define ta_xnew_ptrtype(...)            ta_oom_g(ta_new_ptrtype(__VA_ARGS__))
126 #define ta_xnew_array_ptrtype(...)      ta_oom_g(ta_new_array_ptrtype(__VA_ARGS__))
127 #define ta_xdup(...)                    ta_oom_g(ta_dup(__VA_ARGS__))
128 
129 #define ta_xrealloc(ta_parent, ptr, type, count) \
130     (type *)ta_xrealloc_size(ta_parent, ptr, ta_calc_array_size(sizeof(type), count))
131 
132 // Can't be macros, because the OOM logic is slightly less trivial.
133 char *ta_xstrdup(void *ta_parent, const char *str);
134 char *ta_xstrndup(void *ta_parent, const char *str, size_t n);
135 void *ta_xmemdup(void *ta_parent, void *ptr, size_t size);
136 void *ta_xrealloc_size(void *ta_parent, void *ptr, size_t size);
137 
138 #ifndef TA_NO_WRAPPERS
139 #define ta_alloc_size(...)      ta_dbg_set_loc(ta_alloc_size(__VA_ARGS__), TA_LOC)
140 #define ta_zalloc_size(...)     ta_dbg_set_loc(ta_zalloc_size(__VA_ARGS__), TA_LOC)
141 #define ta_realloc_size(...)    ta_dbg_set_loc(ta_realloc_size(__VA_ARGS__), TA_LOC)
142 #define ta_memdup(...)          ta_dbg_set_loc(ta_memdup(__VA_ARGS__), TA_LOC)
143 #define ta_xmemdup(...)         ta_dbg_set_loc(ta_xmemdup(__VA_ARGS__), TA_LOC)
144 #define ta_xrealloc_size(...)   ta_dbg_set_loc(ta_xrealloc_size(__VA_ARGS__), TA_LOC)
145 #endif
146 
147 void ta_oom_b(bool b);
148 char *ta_oom_s(char *s);
149 void *ta_oom_p(void *p);
150 // Generic pointer
151 #define ta_oom_g(ptr) (TA_TYPEOF(ptr))ta_oom_p(ptr)
152 
153 void ta_enable_leak_report(void);
154 void *ta_dbg_set_loc(void *ptr, const char *name);
155 void *ta_dbg_mark_as_string(void *ptr);
156 
157 #endif
158