Branch data Line data Source code
1 : : /*
2 : : * Copyright 2011 Collabora Ltd.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This program is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * See the included COPYING file for more information.
12 : : */
13 : :
14 : : #undef G_DISABLE_ASSERT
15 : :
16 : : #include <stdio.h>
17 : : #include <stdlib.h>
18 : : #include <string.h>
19 : : #include "glib.h"
20 : :
21 : : /* Keep in sync with glib/gbytes.c */
22 : : struct _GBytes
23 : : {
24 : : gconstpointer data;
25 : : gsize size;
26 : : gint ref_count;
27 : : GDestroyNotify free_func;
28 : : gpointer user_data;
29 : : };
30 : :
31 : : static const gchar *NYAN = "nyannyan";
32 : : static const gsize N_NYAN = 8;
33 : :
34 : : static void
35 : 1 : test_new (void)
36 : : {
37 : : const gchar *data;
38 : : GBytes *bytes;
39 : : gsize size;
40 : :
41 : 1 : data = "test";
42 : 1 : bytes = g_bytes_new (data, 4);
43 : 1 : g_assert_nonnull (bytes);
44 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) != data);
45 : 1 : g_assert_cmpuint (size, ==, 4);
46 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
47 : 1 : g_assert_cmpmem (data, 4, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
48 : :
49 : 1 : g_bytes_unref (bytes);
50 : 1 : }
51 : :
52 : : static void
53 : 1 : test_new_take (void)
54 : : {
55 : : gchar *data;
56 : : GBytes *bytes;
57 : : gsize size;
58 : :
59 : 1 : data = g_strdup ("test");
60 : 1 : bytes = g_bytes_new_take (data, 4);
61 : 1 : g_assert_nonnull (bytes);
62 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) == data);
63 : 1 : g_assert_cmpuint (size, ==, 4);
64 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
65 : :
66 : 1 : g_bytes_unref (bytes);
67 : 1 : }
68 : :
69 : : static void
70 : 1 : test_new_static (void)
71 : : {
72 : : const gchar *data;
73 : : GBytes *bytes;
74 : : gsize size;
75 : :
76 : 1 : data = "test";
77 : 1 : bytes = g_bytes_new_static (data, 4);
78 : 1 : g_assert_nonnull (bytes);
79 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) == data);
80 : 1 : g_assert_cmpuint (size, ==, 4);
81 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
82 : :
83 : 1 : g_bytes_unref (bytes);
84 : 1 : }
85 : :
86 : : static void
87 : 1 : test_new_from_bytes (void)
88 : : {
89 : 1 : const gchar *data = "smile and wave";
90 : : GBytes *bytes;
91 : : GBytes *sub;
92 : :
93 : 1 : bytes = g_bytes_new (data, 14);
94 : 1 : sub = g_bytes_new_from_bytes (bytes, 10, 4);
95 : :
96 : 1 : g_assert_nonnull (sub);
97 : 1 : g_assert_true (g_bytes_get_data (sub, NULL) == ((gchar *)g_bytes_get_data (bytes, NULL)) + 10);
98 : 1 : g_bytes_unref (bytes);
99 : :
100 : 1 : g_assert_cmpmem (g_bytes_get_data (sub, NULL), g_bytes_get_size (sub), "wave", 4);
101 : 1 : g_bytes_unref (sub);
102 : 1 : }
103 : :
104 : : /* Verify that creating slices of GBytes reference the top-most bytes
105 : : * at the correct offset. Ensure that intermediate GBytes are not referenced.
106 : : */
107 : : static void
108 : 1 : test_new_from_bytes_slice (void)
109 : : {
110 : 1 : GBytes *bytes = g_bytes_new_static ("Some stupid data", strlen ("Some stupid data") + 1);
111 : 1 : GBytes *bytes1 = g_bytes_new_from_bytes (bytes, 4, 13);
112 : 1 : GBytes *bytes2 = g_bytes_new_from_bytes (bytes1, 1, 12);
113 : 1 : GBytes *bytes3 = g_bytes_new_from_bytes (bytes2, 0, 6);
114 : :
115 : 1 : g_assert_cmpint (bytes->ref_count, ==, 4);
116 : 1 : g_assert_cmpint (bytes1->ref_count, ==, 1);
117 : 1 : g_assert_cmpint (bytes2->ref_count, ==, 1);
118 : 1 : g_assert_cmpint (bytes3->ref_count, ==, 1);
119 : :
120 : 1 : g_assert_null (bytes->user_data);
121 : 1 : g_assert_true (bytes1->user_data == bytes);
122 : 1 : g_assert_true (bytes2->user_data == bytes);
123 : 1 : g_assert_true (bytes3->user_data == bytes);
124 : :
125 : 1 : g_assert_cmpint (17, ==, g_bytes_get_size (bytes));
126 : 1 : g_assert_cmpint (13, ==, g_bytes_get_size (bytes1));
127 : 1 : g_assert_cmpint (12, ==, g_bytes_get_size (bytes2));
128 : 1 : g_assert_cmpint (6, ==, g_bytes_get_size (bytes3));
129 : :
130 : 1 : g_assert_cmpint (0, ==, strncmp ("Some stupid data", (gchar *)bytes->data, 17));
131 : 1 : g_assert_cmpint (0, ==, strncmp (" stupid data", (gchar *)bytes1->data, 13));
132 : 1 : g_assert_cmpint (0, ==, strncmp ("stupid data", (gchar *)bytes2->data, 12));
133 : 1 : g_assert_cmpint (0, ==, strncmp ("stupid", (gchar *)bytes3->data, 6));
134 : :
135 : 1 : g_bytes_unref (bytes);
136 : 1 : g_bytes_unref (bytes1);
137 : 1 : g_bytes_unref (bytes2);
138 : 1 : g_bytes_unref (bytes3);
139 : 1 : }
140 : :
141 : : /* Ensure that referencing an entire GBytes just returns the same bytes
142 : : * instance (with incremented reference count) instead of a new instance.
143 : : */
144 : : static void
145 : 1 : test_new_from_bytes_shared_ref (void)
146 : : {
147 : 1 : GBytes *bytes = g_bytes_new_static ("Some data", strlen ("Some data") + 1);
148 : 1 : GBytes *other = g_bytes_new_from_bytes (bytes, 0, g_bytes_get_size (bytes));
149 : :
150 : 1 : g_assert_true (bytes == other);
151 : 1 : g_assert_cmpint (bytes->ref_count, ==, 2);
152 : :
153 : 1 : g_bytes_unref (bytes);
154 : 1 : g_bytes_unref (other);
155 : 1 : }
156 : :
157 : : static void
158 : 1 : on_destroy_increment (gpointer data)
159 : : {
160 : 1 : gint *count = data;
161 : 1 : g_assert_nonnull (count);
162 : 1 : (*count)++;
163 : 1 : }
164 : :
165 : : static void
166 : 1 : test_new_with_free_func (void)
167 : : {
168 : : GBytes *bytes;
169 : : gchar *data;
170 : 1 : gint count = 0;
171 : : gsize size;
172 : :
173 : 1 : data = "test";
174 : 1 : bytes = g_bytes_new_with_free_func (data, 4, on_destroy_increment, &count);
175 : 1 : g_assert_nonnull (bytes);
176 : 1 : g_assert_cmpint (count, ==, 0);
177 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) == data);
178 : 1 : g_assert_cmpuint (size, ==, 4);
179 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
180 : :
181 : 1 : g_bytes_unref (bytes);
182 : 1 : g_assert_cmpuint (count, ==, 1);
183 : 1 : }
184 : :
185 : : static void
186 : 1 : test_hash (void)
187 : : {
188 : : GBytes *bytes1;
189 : : GBytes *bytes2;
190 : : guint hash1;
191 : : guint hash2;
192 : :
193 : 1 : bytes1 = g_bytes_new ("blah", 4);
194 : 1 : bytes2 = g_bytes_new ("blah", 4);
195 : :
196 : 1 : hash1 = g_bytes_hash (bytes1);
197 : 1 : hash2 = g_bytes_hash (bytes2);
198 : 1 : g_assert_cmpuint (hash1, ==, hash2);
199 : :
200 : 1 : g_bytes_unref (bytes1);
201 : 1 : g_bytes_unref (bytes2);
202 : 1 : }
203 : :
204 : : static void
205 : 1 : test_equal (void)
206 : : {
207 : : GBytes *bytes;
208 : : GBytes *bytes2;
209 : :
210 : 1 : bytes = g_bytes_new ("blah", 4);
211 : :
212 : 1 : bytes2 = g_bytes_new ("blah", 4);
213 : 1 : g_assert_true (g_bytes_equal (bytes, bytes2));
214 : 1 : g_assert_true (g_bytes_equal (bytes2, bytes));
215 : 1 : g_bytes_unref (bytes2);
216 : :
217 : 1 : bytes2 = g_bytes_new ("bla", 3);
218 : 1 : g_assert_false (g_bytes_equal (bytes, bytes2));
219 : 1 : g_assert_false (g_bytes_equal (bytes2, bytes));
220 : 1 : g_bytes_unref (bytes2);
221 : :
222 : 1 : bytes2 = g_bytes_new ("true", 4);
223 : 1 : g_assert_false (g_bytes_equal (bytes, bytes2));
224 : 1 : g_assert_false (g_bytes_equal (bytes2, bytes));
225 : 1 : g_bytes_unref (bytes2);
226 : :
227 : 1 : g_bytes_unref (bytes);
228 : 1 : }
229 : :
230 : : static void
231 : 1 : test_compare (void)
232 : : {
233 : : GBytes *bytes;
234 : : GBytes *bytes2;
235 : :
236 : 1 : bytes = g_bytes_new ("blah", 4);
237 : :
238 : 1 : bytes2 = g_bytes_new ("blah", 4);
239 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), ==, 0);
240 : 1 : g_bytes_unref (bytes2);
241 : :
242 : 1 : bytes2 = g_bytes_new ("bla", 3);
243 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0);
244 : 1 : g_bytes_unref (bytes2);
245 : :
246 : 1 : bytes2 = g_bytes_new ("abcd", 4);
247 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0);
248 : 1 : g_bytes_unref (bytes2);
249 : :
250 : 1 : bytes2 = g_bytes_new ("blahblah", 8);
251 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
252 : 1 : g_bytes_unref (bytes2);
253 : :
254 : 1 : bytes2 = g_bytes_new ("zyx", 3);
255 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
256 : 1 : g_bytes_unref (bytes2);
257 : :
258 : 1 : bytes2 = g_bytes_new ("zyxw", 4);
259 : 1 : g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
260 : 1 : g_bytes_unref (bytes2);
261 : :
262 : 1 : g_bytes_unref (bytes);
263 : 1 : }
264 : :
265 : : static void
266 : 1 : test_to_data_transferred (void)
267 : : {
268 : : gconstpointer memory;
269 : : gpointer data;
270 : : gsize size;
271 : : GBytes *bytes;
272 : :
273 : : /* Memory transferred: one reference, and allocated with g_malloc */
274 : 1 : bytes = g_bytes_new (NYAN, N_NYAN);
275 : 1 : memory = g_bytes_get_data (bytes, NULL);
276 : 1 : data = g_bytes_unref_to_data (bytes, &size);
277 : 1 : g_assert_true (data == memory);
278 : 1 : g_assert_cmpmem (data, size, NYAN, N_NYAN);
279 : 1 : g_free (data);
280 : 1 : }
281 : :
282 : : static void
283 : 1 : test_to_data_two_refs (void)
284 : : {
285 : : gconstpointer memory;
286 : : gpointer data;
287 : : gsize size;
288 : : GBytes *bytes;
289 : :
290 : : /* Memory copied: two references */
291 : 1 : bytes = g_bytes_new (NYAN, N_NYAN);
292 : 1 : bytes = g_bytes_ref (bytes);
293 : 1 : memory = g_bytes_get_data (bytes, NULL);
294 : 1 : data = g_bytes_unref_to_data (bytes, &size);
295 : 1 : g_assert_true (data != memory);
296 : 1 : g_assert_cmpmem (data, size, NYAN, N_NYAN);
297 : 1 : g_free (data);
298 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) == memory);
299 : 1 : g_assert_cmpuint (size, ==, N_NYAN);
300 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN);
301 : 1 : g_bytes_unref (bytes);
302 : 1 : }
303 : :
304 : : static void
305 : 1 : test_to_data_non_malloc (void)
306 : : {
307 : : gpointer data;
308 : : gsize size;
309 : : GBytes *bytes;
310 : :
311 : : /* Memory copied: non malloc memory */
312 : 1 : bytes = g_bytes_new_static (NYAN, N_NYAN);
313 : 1 : g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
314 : 1 : data = g_bytes_unref_to_data (bytes, &size);
315 : 1 : g_assert_true (data != (gpointer)NYAN);
316 : 1 : g_assert_cmpmem (data, size, NYAN, N_NYAN);
317 : 1 : g_free (data);
318 : 1 : }
319 : :
320 : : static void
321 : 1 : test_to_data_different_free_func (void)
322 : : {
323 : : gpointer data;
324 : : gsize size;
325 : : GBytes *bytes;
326 : 1 : gchar *sentinel = g_strdup ("hello");
327 : :
328 : : /* Memory copied: free func and user_data don’t point to the bytes data */
329 : 1 : bytes = g_bytes_new_with_free_func (NYAN, N_NYAN, g_free, sentinel);
330 : 1 : g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
331 : :
332 : 1 : data = g_bytes_unref_to_data (bytes, &size);
333 : 1 : g_assert_true (data != (gpointer)NYAN);
334 : 1 : g_assert_cmpmem (data, size, NYAN, N_NYAN);
335 : 1 : g_free (data);
336 : :
337 : : /* @sentinel should not be leaked; testing that requires this test to be run
338 : : * under valgrind. We can’t use a custom free func to check it isn’t leaked,
339 : : * as the point of this test is to hit a condition in `try_steal_and_unref()`
340 : : * which is short-circuited if the free func isn’t g_free().
341 : : * See discussion in https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2152 */
342 : 1 : }
343 : :
344 : : static void
345 : 1 : test_to_array_transferred (void)
346 : : {
347 : : gconstpointer memory;
348 : : GByteArray *array;
349 : : GBytes *bytes;
350 : :
351 : : /* Memory transferred: one reference, and allocated with g_malloc */
352 : 1 : bytes = g_bytes_new (NYAN, N_NYAN);
353 : 1 : memory = g_bytes_get_data (bytes, NULL);
354 : 1 : array = g_bytes_unref_to_array (bytes);
355 : 1 : g_assert_nonnull (array);
356 : 1 : g_assert_true (array->data == memory);
357 : 1 : g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
358 : 1 : g_byte_array_unref (array);
359 : 1 : }
360 : :
361 : : static void
362 : 1 : test_to_array_transferred_oversize (void)
363 : : {
364 : 1 : g_test_message ("g_bytes_unref_to_array() can only take GBytes up to "
365 : : "G_MAXUINT in length; test that longer ones are rejected");
366 : :
367 : : if (sizeof (guint) >= sizeof (gsize))
368 : : {
369 : : g_test_skip ("Skipping test as guint is not smaller than gsize");
370 : : }
371 [ + - ]: 1 : else if (g_test_undefined ())
372 : : {
373 : 1 : GByteArray *array = NULL;
374 : 1 : GBytes *bytes = NULL;
375 : 1 : gpointer data = g_memdup2 (NYAN, N_NYAN);
376 : 1 : gsize len = ((gsize) G_MAXUINT) + 1;
377 : :
378 : 1 : bytes = g_bytes_new_take (data, len);
379 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
380 : : "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed");
381 : 1 : array = g_bytes_unref_to_array (g_steal_pointer (&bytes));
382 : 1 : g_test_assert_expected_messages ();
383 : 1 : g_assert_null (array);
384 : :
385 : 1 : g_free (data);
386 : : }
387 : : else
388 : : {
389 : 0 : g_test_skip ("Skipping test as testing undefined behaviour is disabled");
390 : : }
391 : 1 : }
392 : :
393 : : static void
394 : 1 : test_to_array_two_refs (void)
395 : : {
396 : : gconstpointer memory;
397 : : GByteArray *array;
398 : : GBytes *bytes;
399 : : gsize size;
400 : :
401 : : /* Memory copied: two references */
402 : 1 : bytes = g_bytes_new (NYAN, N_NYAN);
403 : 1 : bytes = g_bytes_ref (bytes);
404 : 1 : memory = g_bytes_get_data (bytes, NULL);
405 : 1 : array = g_bytes_unref_to_array (bytes);
406 : 1 : g_assert_nonnull (array);
407 : 1 : g_assert_true (array->data != memory);
408 : 1 : g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
409 : 1 : g_byte_array_unref (array);
410 : 1 : g_assert_true (g_bytes_get_data (bytes, &size) == memory);
411 : 1 : g_assert_cmpuint (size, ==, N_NYAN);
412 : 1 : g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN);
413 : 1 : g_bytes_unref (bytes);
414 : 1 : }
415 : :
416 : : static void
417 : 1 : test_to_array_non_malloc (void)
418 : : {
419 : : GByteArray *array;
420 : : GBytes *bytes;
421 : :
422 : : /* Memory copied: non malloc memory */
423 : 1 : bytes = g_bytes_new_static (NYAN, N_NYAN);
424 : 1 : g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
425 : 1 : array = g_bytes_unref_to_array (bytes);
426 : 1 : g_assert_nonnull (array);
427 : 1 : g_assert_true (array->data != (gpointer)NYAN);
428 : 1 : g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
429 : 1 : g_byte_array_unref (array);
430 : 1 : }
431 : :
432 : : static void
433 : 1 : test_null (void)
434 : : {
435 : : GBytes *bytes;
436 : : gpointer data;
437 : : gsize size;
438 : :
439 : 1 : bytes = g_bytes_new (NULL, 0);
440 : :
441 : 1 : data = g_bytes_unref_to_data (bytes, &size);
442 : :
443 : 1 : g_assert_null (data);
444 : 1 : g_assert_cmpuint (size, ==, 0);
445 : 1 : }
446 : :
447 : : static void
448 : 1 : test_get_region (void)
449 : : {
450 : : GBytes *bytes;
451 : :
452 : 1 : bytes = g_bytes_new_static (NYAN, N_NYAN);
453 : :
454 : : /* simple valid gets at the start */
455 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, 0, 1) == NYAN);
456 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN) == NYAN);
457 : :
458 : : /* an invalid get because the range is too wide */
459 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN + 1) == NULL);
460 : :
461 : : /* an valid get, but of a zero-byte range at the end */
462 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 0) == NYAN + N_NYAN);
463 : :
464 : : /* not a valid get because it overlap ones byte */
465 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 1) == NULL);
466 : :
467 : : /* let's try some multiplication overflow now */
468 : 1 : g_assert_true (g_bytes_get_region (bytes, 32, 0, G_MAXSIZE / 32 + 1) == NULL);
469 : 1 : g_assert_true (g_bytes_get_region (bytes, G_MAXSIZE / 32 + 1, 0, 32) == NULL);
470 : :
471 : : /* and some addition overflow */
472 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, -G_MAXSIZE) == NULL);
473 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSSIZE, ((gsize) G_MAXSSIZE) + 1) == NULL);
474 : 1 : g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, 1) == NULL);
475 : :
476 : 1 : g_bytes_unref (bytes);
477 : 1 : }
478 : :
479 : : static void
480 : 1 : test_unref_null (void)
481 : : {
482 : 1 : g_test_summary ("Test that calling g_bytes_unref() on NULL is a no-op");
483 : 1 : g_bytes_unref (NULL);
484 : 1 : }
485 : :
486 : : int
487 : 1 : main (int argc, char *argv[])
488 : : {
489 : 1 : g_test_init (&argc, &argv, NULL);
490 : :
491 : 1 : g_test_add_func ("/bytes/new", test_new);
492 : 1 : g_test_add_func ("/bytes/new-take", test_new_take);
493 : 1 : g_test_add_func ("/bytes/new-static", test_new_static);
494 : 1 : g_test_add_func ("/bytes/new-with-free-func", test_new_with_free_func);
495 : 1 : g_test_add_func ("/bytes/new-from-bytes", test_new_from_bytes);
496 : 1 : g_test_add_func ("/bytes/new-from-bytes-slice", test_new_from_bytes_slice);
497 : 1 : g_test_add_func ("/bytes/new-from-bytes-shared-ref", test_new_from_bytes_shared_ref);
498 : 1 : g_test_add_func ("/bytes/hash", test_hash);
499 : 1 : g_test_add_func ("/bytes/equal", test_equal);
500 : 1 : g_test_add_func ("/bytes/compare", test_compare);
501 : 1 : g_test_add_func ("/bytes/to-data/transferred", test_to_data_transferred);
502 : 1 : g_test_add_func ("/bytes/to-data/two-refs", test_to_data_two_refs);
503 : 1 : g_test_add_func ("/bytes/to-data/non-malloc", test_to_data_non_malloc);
504 : 1 : g_test_add_func ("/bytes/to-data/different-free-func", test_to_data_different_free_func);
505 : 1 : g_test_add_func ("/bytes/to-array/transferred", test_to_array_transferred);
506 : 1 : g_test_add_func ("/bytes/to-array/transferred/oversize", test_to_array_transferred_oversize);
507 : 1 : g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
508 : 1 : g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
509 : 1 : g_test_add_func ("/bytes/null", test_null);
510 : 1 : g_test_add_func ("/bytes/get-region", test_get_region);
511 : 1 : g_test_add_func ("/bytes/unref-null", test_unref_null);
512 : :
513 : 1 : return g_test_run ();
514 : : }
|