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 test_new (void)
36 {
37 const gchar *data;
38 GBytes *bytes;
39 gsize size;
40
41 data = "test";
42 bytes = g_bytes_new (data, 4);
43 g_assert_nonnull (bytes);
44 g_assert_true (g_bytes_get_data (bytes, &size) != data);
45 g_assert_cmpuint (size, ==, 4);
46 g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
47 g_assert_cmpmem (data, 4, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
48
49 g_bytes_unref (bytes);
50 }
51
52 static void
53 test_new_take (void)
54 {
55 gchar *data;
56 GBytes *bytes;
57 gsize size;
58
59 data = g_strdup ("test");
60 bytes = g_bytes_new_take (data, 4);
61 g_assert_nonnull (bytes);
62 g_assert_true (g_bytes_get_data (bytes, &size) == data);
63 g_assert_cmpuint (size, ==, 4);
64 g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
65
66 g_bytes_unref (bytes);
67 }
68
69 static void
70 test_new_static (void)
71 {
72 const gchar *data;
73 GBytes *bytes;
74 gsize size;
75
76 data = "test";
77 bytes = g_bytes_new_static (data, 4);
78 g_assert_nonnull (bytes);
79 g_assert_true (g_bytes_get_data (bytes, &size) == data);
80 g_assert_cmpuint (size, ==, 4);
81 g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
82
83 g_bytes_unref (bytes);
84 }
85
86 static void
87 test_new_from_bytes (void)
88 {
89 const gchar *data = "smile and wave";
90 GBytes *bytes;
91 GBytes *sub;
92
93 bytes = g_bytes_new (data, 14);
94 sub = g_bytes_new_from_bytes (bytes, 10, 4);
95
96 g_assert_nonnull (sub);
97 g_assert_true (g_bytes_get_data (sub, NULL) == ((gchar *)g_bytes_get_data (bytes, NULL)) + 10);
98 g_bytes_unref (bytes);
99
100 g_assert_cmpmem (g_bytes_get_data (sub, NULL), g_bytes_get_size (sub), "wave", 4);
101 g_bytes_unref (sub);
102 }
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 test_new_from_bytes_slice (void)
109 {
110 GBytes *bytes = g_bytes_new_static ("Some stupid data", strlen ("Some stupid data") + 1);
111 GBytes *bytes1 = g_bytes_new_from_bytes (bytes, 4, 13);
112 GBytes *bytes2 = g_bytes_new_from_bytes (bytes1, 1, 12);
113 GBytes *bytes3 = g_bytes_new_from_bytes (bytes2, 0, 6);
114
115 g_assert_cmpint (bytes->ref_count, ==, 4);
116 g_assert_cmpint (bytes1->ref_count, ==, 1);
117 g_assert_cmpint (bytes2->ref_count, ==, 1);
118 g_assert_cmpint (bytes3->ref_count, ==, 1);
119
120 g_assert_null (bytes->user_data);
121 g_assert_true (bytes1->user_data == bytes);
122 g_assert_true (bytes2->user_data == bytes);
123 g_assert_true (bytes3->user_data == bytes);
124
125 g_assert_cmpint (17, ==, g_bytes_get_size (bytes));
126 g_assert_cmpint (13, ==, g_bytes_get_size (bytes1));
127 g_assert_cmpint (12, ==, g_bytes_get_size (bytes2));
128 g_assert_cmpint (6, ==, g_bytes_get_size (bytes3));
129
130 g_assert_cmpint (0, ==, strncmp ("Some stupid data", (gchar *)bytes->data, 17));
131 g_assert_cmpint (0, ==, strncmp (" stupid data", (gchar *)bytes1->data, 13));
132 g_assert_cmpint (0, ==, strncmp ("stupid data", (gchar *)bytes2->data, 12));
133 g_assert_cmpint (0, ==, strncmp ("stupid", (gchar *)bytes3->data, 6));
134
135 g_bytes_unref (bytes);
136 g_bytes_unref (bytes1);
137 g_bytes_unref (bytes2);
138 g_bytes_unref (bytes3);
139 }
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 test_new_from_bytes_shared_ref (void)
146 {
147 GBytes *bytes = g_bytes_new_static ("Some data", strlen ("Some data") + 1);
148 GBytes *other = g_bytes_new_from_bytes (bytes, 0, g_bytes_get_size (bytes));
149
150 g_assert_true (bytes == other);
151 g_assert_cmpint (bytes->ref_count, ==, 2);
152
153 g_bytes_unref (bytes);
154 g_bytes_unref (other);
155 }
156
157 static void
158 on_destroy_increment (gpointer data)
159 {
160 gint *count = data;
161 g_assert_nonnull (count);
162 (*count)++;
163 }
164
165 static void
166 test_new_with_free_func (void)
167 {
168 GBytes *bytes;
169 gchar *data;
170 gint count = 0;
171 gsize size;
172
173 data = "test";
174 bytes = g_bytes_new_with_free_func (data, 4, on_destroy_increment, &count);
175 g_assert_nonnull (bytes);
176 g_assert_cmpint (count, ==, 0);
177 g_assert_true (g_bytes_get_data (bytes, &size) == data);
178 g_assert_cmpuint (size, ==, 4);
179 g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4);
180
181 g_bytes_unref (bytes);
182 g_assert_cmpuint (count, ==, 1);
183 }
184
185 static void
186 test_hash (void)
187 {
188 GBytes *bytes1;
189 GBytes *bytes2;
190 guint hash1;
191 guint hash2;
192
193 bytes1 = g_bytes_new ("blah", 4);
194 bytes2 = g_bytes_new ("blah", 4);
195
196 hash1 = g_bytes_hash (bytes1);
197 hash2 = g_bytes_hash (bytes2);
198 g_assert_cmpuint (hash1, ==, hash2);
199
200 g_bytes_unref (bytes1);
201 g_bytes_unref (bytes2);
202 }
203
204 static void
205 test_equal (void)
206 {
207 GBytes *bytes;
208 GBytes *bytes2;
209
210 bytes = g_bytes_new ("blah", 4);
211
212 bytes2 = g_bytes_new ("blah", 4);
213 g_assert_true (g_bytes_equal (bytes, bytes2));
214 g_assert_true (g_bytes_equal (bytes2, bytes));
215 g_bytes_unref (bytes2);
216
217 bytes2 = g_bytes_new ("bla", 3);
218 g_assert_false (g_bytes_equal (bytes, bytes2));
219 g_assert_false (g_bytes_equal (bytes2, bytes));
220 g_bytes_unref (bytes2);
221
222 bytes2 = g_bytes_new ("true", 4);
223 g_assert_false (g_bytes_equal (bytes, bytes2));
224 g_assert_false (g_bytes_equal (bytes2, bytes));
225 g_bytes_unref (bytes2);
226
227 g_bytes_unref (bytes);
228 }
229
230 static void
231 test_compare (void)
232 {
233 GBytes *bytes;
234 GBytes *bytes2;
235
236 bytes = g_bytes_new ("blah", 4);
237
238 bytes2 = g_bytes_new ("blah", 4);
239 g_assert_cmpint (g_bytes_compare (bytes, bytes2), ==, 0);
240 g_bytes_unref (bytes2);
241
242 bytes2 = g_bytes_new ("bla", 3);
243 g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0);
244 g_bytes_unref (bytes2);
245
246 bytes2 = g_bytes_new ("abcd", 4);
247 g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0);
248 g_bytes_unref (bytes2);
249
250 bytes2 = g_bytes_new ("blahblah", 8);
251 g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
252 g_bytes_unref (bytes2);
253
254 bytes2 = g_bytes_new ("zyx", 3);
255 g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
256 g_bytes_unref (bytes2);
257
258 bytes2 = g_bytes_new ("zyxw", 4);
259 g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0);
260 g_bytes_unref (bytes2);
261
262 g_bytes_unref (bytes);
263 }
264
265 static void
266 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 bytes = g_bytes_new (NYAN, N_NYAN);
275 memory = g_bytes_get_data (bytes, NULL);
276 data = g_bytes_unref_to_data (bytes, &size);
277 g_assert_true (data == memory);
278 g_assert_cmpmem (data, size, NYAN, N_NYAN);
279 g_free (data);
280 }
281
282 static void
283 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 bytes = g_bytes_new (NYAN, N_NYAN);
292 bytes = g_bytes_ref (bytes);
293 memory = g_bytes_get_data (bytes, NULL);
294 data = g_bytes_unref_to_data (bytes, &size);
295 g_assert_true (data != memory);
296 g_assert_cmpmem (data, size, NYAN, N_NYAN);
297 g_free (data);
298 g_assert_true (g_bytes_get_data (bytes, &size) == memory);
299 g_assert_cmpuint (size, ==, N_NYAN);
300 g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN);
301 g_bytes_unref (bytes);
302 }
303
304 static void
305 test_to_data_non_malloc (void)
306 {
307 gpointer data;
308 gsize size;
309 GBytes *bytes;
310
311 /* Memory copied: non malloc memory */
312 bytes = g_bytes_new_static (NYAN, N_NYAN);
313 g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
314 data = g_bytes_unref_to_data (bytes, &size);
315 g_assert_true (data != (gpointer)NYAN);
316 g_assert_cmpmem (data, size, NYAN, N_NYAN);
317 g_free (data);
318 }
319
320 static void
321 test_to_data_different_free_func (void)
322 {
323 gpointer data;
324 gsize size;
325 GBytes *bytes;
326 gchar *sentinel = g_strdup ("hello");
327
328 /* Memory copied: free func and user_data don’t point to the bytes data */
329 bytes = g_bytes_new_with_free_func (NYAN, N_NYAN, g_free, sentinel);
330 g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
331
332 data = g_bytes_unref_to_data (bytes, &size);
333 g_assert_true (data != (gpointer)NYAN);
334 g_assert_cmpmem (data, size, NYAN, N_NYAN);
335 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 }
343
344 static void
345 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 bytes = g_bytes_new (NYAN, N_NYAN);
353 memory = g_bytes_get_data (bytes, NULL);
354 array = g_bytes_unref_to_array (bytes);
355 g_assert_nonnull (array);
356 g_assert_true (array->data == memory);
357 g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
358 g_byte_array_unref (array);
359 }
360
361 static void
362 test_to_array_transferred_oversize (void)
363 {
364 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 else if (g_test_undefined ())
372 {
373 GByteArray *array = NULL;
374 GBytes *bytes = NULL;
375 gpointer data = g_memdup2 (NYAN, N_NYAN);
376 gsize len = ((gsize) G_MAXUINT) + 1;
377
378 bytes = g_bytes_new_take (data, len);
379 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
380 "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed");
381 array = g_bytes_unref_to_array (g_steal_pointer (&bytes));
382 g_test_assert_expected_messages ();
383 g_assert_null (array);
384
385 g_free (data);
386 }
387 else
388 {
389 g_test_skip ("Skipping test as testing undefined behaviour is disabled");
390 }
391 }
392
393 static void
394 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 bytes = g_bytes_new (NYAN, N_NYAN);
403 bytes = g_bytes_ref (bytes);
404 memory = g_bytes_get_data (bytes, NULL);
405 array = g_bytes_unref_to_array (bytes);
406 g_assert_nonnull (array);
407 g_assert_true (array->data != memory);
408 g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
409 g_byte_array_unref (array);
410 g_assert_true (g_bytes_get_data (bytes, &size) == memory);
411 g_assert_cmpuint (size, ==, N_NYAN);
412 g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN);
413 g_bytes_unref (bytes);
414 }
415
416 static void
417 test_to_array_non_malloc (void)
418 {
419 GByteArray *array;
420 GBytes *bytes;
421
422 /* Memory copied: non malloc memory */
423 bytes = g_bytes_new_static (NYAN, N_NYAN);
424 g_assert_true (g_bytes_get_data (bytes, NULL) == NYAN);
425 array = g_bytes_unref_to_array (bytes);
426 g_assert_nonnull (array);
427 g_assert_true (array->data != (gpointer)NYAN);
428 g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
429 g_byte_array_unref (array);
430 }
431
432 static void
433 test_null (void)
434 {
435 GBytes *bytes;
436 gpointer data;
437 gsize size;
438
439 bytes = g_bytes_new (NULL, 0);
440
441 data = g_bytes_unref_to_data (bytes, &size);
442
443 g_assert_null (data);
444 g_assert_cmpuint (size, ==, 0);
445 }
446
447 static void
448 test_get_region (void)
449 {
450 GBytes *bytes;
451
452 bytes = g_bytes_new_static (NYAN, N_NYAN);
453
454 /* simple valid gets at the start */
455 g_assert_true (g_bytes_get_region (bytes, 1, 0, 1) == NYAN);
456 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 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 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 g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 1) == NULL);
466
467 /* let's try some multiplication overflow now */
468 g_assert_true (g_bytes_get_region (bytes, 32, 0, G_MAXSIZE / 32 + 1) == NULL);
469 g_assert_true (g_bytes_get_region (bytes, G_MAXSIZE / 32 + 1, 0, 32) == NULL);
470
471 /* and some addition overflow */
472 g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, -G_MAXSIZE) == NULL);
473 g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSSIZE, ((gsize) G_MAXSSIZE) + 1) == NULL);
474 g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, 1) == NULL);
475
476 g_bytes_unref (bytes);
477 }
478
479 static void
480 test_unref_null (void)
481 {
482 g_test_summary ("Test that calling g_bytes_unref() on NULL is a no-op");
483 g_bytes_unref (NULL);
484 }
485
486 int
487 main (int argc, char *argv[])
488 {
489 g_test_init (&argc, &argv, NULL);
490
491 g_test_add_func ("/bytes/new", test_new);
492 g_test_add_func ("/bytes/new-take", test_new_take);
493 g_test_add_func ("/bytes/new-static", test_new_static);
494 g_test_add_func ("/bytes/new-with-free-func", test_new_with_free_func);
495 g_test_add_func ("/bytes/new-from-bytes", test_new_from_bytes);
496 g_test_add_func ("/bytes/new-from-bytes-slice", test_new_from_bytes_slice);
497 g_test_add_func ("/bytes/new-from-bytes-shared-ref", test_new_from_bytes_shared_ref);
498 g_test_add_func ("/bytes/hash", test_hash);
499 g_test_add_func ("/bytes/equal", test_equal);
500 g_test_add_func ("/bytes/compare", test_compare);
501 g_test_add_func ("/bytes/to-data/transferred", test_to_data_transferred);
502 g_test_add_func ("/bytes/to-data/two-refs", test_to_data_two_refs);
503 g_test_add_func ("/bytes/to-data/non-malloc", test_to_data_non_malloc);
504 g_test_add_func ("/bytes/to-data/different-free-func", test_to_data_different_free_func);
505 g_test_add_func ("/bytes/to-array/transferred", test_to_array_transferred);
506 g_test_add_func ("/bytes/to-array/transferred/oversize", test_to_array_transferred_oversize);
507 g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
508 g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
509 g_test_add_func ("/bytes/null", test_null);
510 g_test_add_func ("/bytes/get-region", test_get_region);
511 g_test_add_func ("/bytes/unref-null", test_unref_null);
512
513 return g_test_run ();
514 }