1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3    Copyright (C) 2010 Red Hat, Inc.
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <config.h>
19 
20 #include "mem.h"
21 
22 #include <string.h>
23 
24 #ifndef MALLOC_ERROR
25 #define MALLOC_ERROR(...) SPICE_STMT_START {    \
26     spice_error(__VA_ARGS__);                   \
27     abort();                                    \
28 } SPICE_STMT_END
29 #endif
30 
spice_strnlen(const char * str,size_t max_len)31 size_t spice_strnlen(const char *str, size_t max_len)
32 {
33     size_t len = 0;
34 
35     while (len < max_len && *str != 0) {
36         len++;
37         str++;
38     }
39 
40     return len;
41 }
42 
spice_strdup(const char * str)43 char *spice_strdup(const char *str)
44 {
45     char *copy;
46     size_t len;
47 
48     if (str == NULL) {
49         return NULL;
50     }
51 
52     len = strlen(str) + 1;
53     copy = (char *)spice_malloc(len);
54     memcpy(copy, str, len);
55     return copy;
56 }
57 
spice_strndup(const char * str,size_t n_bytes)58 char *spice_strndup(const char *str, size_t n_bytes)
59 {
60     char *copy;
61 
62     if (str == NULL) {
63         return NULL;
64     }
65 
66     copy = (char *)spice_malloc(n_bytes + 1);
67     strncpy(copy, str, n_bytes);
68     copy[n_bytes] = 0;
69     return copy;
70 }
71 
spice_memdup(const void * mem,size_t n_bytes)72 void *spice_memdup(const void *mem, size_t n_bytes)
73 {
74     void *copy;
75 
76     if (mem == NULL) {
77         return NULL;
78     }
79 
80     copy = spice_malloc(n_bytes);
81     memcpy(copy, mem, n_bytes);
82     return copy;
83 }
84 
spice_malloc(size_t n_bytes)85 void *spice_malloc(size_t n_bytes)
86 {
87     void *mem;
88 
89     if (SPICE_LIKELY(n_bytes)) {
90         mem = malloc(n_bytes);
91 
92         if (SPICE_LIKELY(mem != NULL)) {
93             return mem;
94         }
95 
96         MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
97     }
98     return NULL;
99 }
100 
spice_malloc0(size_t n_bytes)101 void *spice_malloc0(size_t n_bytes)
102 {
103     void *mem;
104 
105     if (SPICE_LIKELY(n_bytes)) {
106         mem = calloc(1, n_bytes);
107 
108         if (SPICE_LIKELY(mem != NULL)) {
109             return mem;
110         }
111 
112         MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
113     }
114     return NULL;
115 }
116 
spice_realloc(void * mem,size_t n_bytes)117 void *spice_realloc(void *mem, size_t n_bytes)
118 {
119     if (SPICE_LIKELY(n_bytes)) {
120         mem = realloc(mem, n_bytes);
121 
122         if (SPICE_LIKELY(mem != NULL)) {
123             return mem;
124         }
125 
126         MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
127     }
128 
129     free(mem);
130 
131     return NULL;
132 }
133 
134 #define SIZE_OVERFLOWS(a,b) (SPICE_UNLIKELY ((a) > SIZE_MAX / (b)))
135 
spice_malloc_n(size_t n_blocks,size_t n_block_bytes)136 void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
137 {
138     if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
139         MALLOC_ERROR("overflow allocating %lu*%lu bytes",
140                      (unsigned long)n_blocks, (unsigned long)n_block_bytes);
141     }
142 
143     return spice_malloc(n_blocks * n_block_bytes);
144 }
145 
spice_malloc_n_m(size_t n_blocks,size_t n_block_bytes,size_t extra_size)146 void *spice_malloc_n_m(size_t n_blocks, size_t n_block_bytes, size_t extra_size)
147 {
148     size_t size1, size2;
149     if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
150         MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu + %lubytes",
151                      (unsigned long)n_blocks, (unsigned long)n_block_bytes, (unsigned long)extra_size);
152     }
153     size1 = n_blocks * n_block_bytes;
154     size2 = size1 + extra_size;
155     if (size2 < size1) {
156         MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu + %lubytes",
157                      (unsigned long)n_blocks, (unsigned long)n_block_bytes, (unsigned long)extra_size);
158     }
159     return spice_malloc(size2);
160 }
161 
162 
spice_malloc0_n(size_t n_blocks,size_t n_block_bytes)163 void *spice_malloc0_n(size_t n_blocks, size_t n_block_bytes)
164 {
165     if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
166         MALLOC_ERROR("spice_malloc0_n: overflow allocating %lu*%lu bytes",
167                      (unsigned long)n_blocks, (unsigned long)n_block_bytes);
168     }
169 
170     return spice_malloc0 (n_blocks * n_block_bytes);
171 }
172 
spice_realloc_n(void * mem,size_t n_blocks,size_t n_block_bytes)173 void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes)
174 {
175     if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
176         MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
177                      (unsigned long)n_blocks, (unsigned long)n_block_bytes);
178     }
179 
180     return spice_realloc(mem, n_blocks * n_block_bytes);
181 }
182 
spice_chunks_new(uint32_t count)183 SpiceChunks *spice_chunks_new(uint32_t count)
184 {
185     SpiceChunks *chunks;
186 
187     chunks = (SpiceChunks *)spice_malloc_n_m(count, sizeof(SpiceChunk), sizeof(SpiceChunks));
188     chunks->flags = 0;
189     chunks->num_chunks = count;
190 
191     return chunks;
192 }
193 
spice_chunks_new_linear(uint8_t * data,uint32_t len)194 SpiceChunks *spice_chunks_new_linear(uint8_t *data, uint32_t len)
195 {
196     SpiceChunks *chunks;
197 
198     chunks = spice_chunks_new(1);
199     chunks->data_size = chunks->chunk[0].len = len;
200     chunks->chunk[0].data = data;
201     return chunks;
202 }
203 
spice_chunks_destroy(SpiceChunks * chunks)204 void spice_chunks_destroy(SpiceChunks *chunks)
205 {
206     unsigned int i;
207 
208     if (chunks->flags & SPICE_CHUNKS_FLAGS_FREE) {
209         for (i = 0; i < chunks->num_chunks; i++) {
210             free(chunks->chunk[i].data);
211         }
212     }
213 
214     free(chunks);
215 }
216 
spice_chunks_linearize(SpiceChunks * chunks)217 void spice_chunks_linearize(SpiceChunks *chunks)
218 {
219     uint8_t *data, *p;
220     unsigned int i;
221 
222     if (chunks->num_chunks > 1) {
223         data = (uint8_t*)spice_malloc(chunks->data_size);
224         for (p = data, i = 0; i < chunks->num_chunks; i++) {
225             memcpy(p, chunks->chunk[i].data,
226                    chunks->chunk[i].len);
227             p += chunks->chunk[i].len;
228         }
229         if (chunks->flags & SPICE_CHUNKS_FLAGS_FREE) {
230             for (i = 0; i < chunks->num_chunks; i++) {
231                 free(chunks->chunk[i].data);
232             }
233         }
234         chunks->num_chunks = 1;
235         chunks->flags |= SPICE_CHUNKS_FLAGS_FREE;
236         chunks->flags &= ~SPICE_CHUNKS_FLAGS_UNSTABLE;
237         chunks->chunk[0].data = data;
238         chunks->chunk[0].len = chunks->data_size;
239     }
240 }
241 
spice_buffer_reserve(SpiceBuffer * buffer,size_t len)242 void spice_buffer_reserve(SpiceBuffer *buffer, size_t len)
243 {
244     if ((buffer->capacity - buffer->offset) < len) {
245         buffer->capacity += (len + 1024);
246         buffer->buffer = (uint8_t*)spice_realloc(buffer->buffer, buffer->capacity);
247     }
248 }
249 
spice_buffer_empty(SpiceBuffer * buffer)250 int spice_buffer_empty(SpiceBuffer *buffer)
251 {
252     return buffer->offset == 0;
253 }
254 
spice_buffer_end(SpiceBuffer * buffer)255 uint8_t *spice_buffer_end(SpiceBuffer *buffer)
256 {
257     return buffer->buffer + buffer->offset;
258 }
259 
spice_buffer_reset(SpiceBuffer * buffer)260 void spice_buffer_reset(SpiceBuffer *buffer)
261 {
262     buffer->offset = 0;
263 }
264 
spice_buffer_free(SpiceBuffer * buffer)265 void spice_buffer_free(SpiceBuffer *buffer)
266 {
267     free(buffer->buffer);
268     buffer->offset = 0;
269     buffer->capacity = 0;
270     buffer->buffer = NULL;
271 }
272 
spice_buffer_append(SpiceBuffer * buffer,const void * data,size_t len)273 void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len)
274 {
275     spice_buffer_reserve(buffer, len);
276     memcpy(buffer->buffer + buffer->offset, data, len);
277     buffer->offset += len;
278 }
279 
spice_buffer_copy(SpiceBuffer * buffer,void * dest,size_t len)280 size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len)
281 {
282     len = MIN(buffer->offset, len);
283     memcpy(dest, buffer->buffer, len);
284     return len;
285 }
286 
spice_buffer_remove(SpiceBuffer * buffer,size_t len)287 size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
288 {
289     len = MIN(buffer->offset, len);
290     memmove(buffer->buffer, buffer->buffer + len, buffer->offset - len);
291     buffer->offset -= len;
292     return len;
293 }
294 
295 #ifdef SPICE_DEBUG_ALIGNMENT
spice_alignment_warning(const char * loc,void * p,unsigned sz)296 void spice_alignment_warning(const char *loc, void *p, unsigned sz)
297 {
298     static const char *last_loc = NULL;
299     if (loc != last_loc) {
300         last_loc = loc;
301         spice_log(G_LOG_LEVEL_WARNING, loc, __FUNCTION__,
302                   "Misaligned access at %p, alignment %u", p, sz);
303     }
304 }
305 
spice_alignment_debug(const char * loc,void * p,unsigned sz)306 void spice_alignment_debug(const char *loc, void *p, unsigned sz)
307 {
308     static const char *last_loc = NULL;
309     if (loc != last_loc) {
310         last_loc = loc;
311         spice_log(G_LOG_LEVEL_DEBUG, loc, __FUNCTION__,
312                   "Expected misaligned access at %p, alignment %u", p, sz);
313     }
314 }
315 #endif // SPICE_DEBUG_ALIGNMENT
316