vfprintf-internal: Get rid of alloca.
[glibc.git] / misc / tst-allocate_once.c
blobbd9df516a33bb516dbff6359bdbba07c6d4270b5
1 /* Test the allocate_once function.
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C 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.
10 The GNU C 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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <allocate_once.h>
20 #include <mcheck.h>
21 #include <string.h>
22 #include <support/check.h>
23 #include <support/support.h>
25 /* Allocate a new string. */
26 static void *
27 allocate_string (void *closure)
29 return xstrdup (closure);
32 /* Allocation and deallocation functions which are not expected to be
33 called. */
35 static void *
36 allocate_not_called (void *closure)
38 FAIL_EXIT1 ("allocation function called unexpectedly (%p)", closure);
41 static void
42 deallocate_not_called (void *closure, void *ptr)
44 FAIL_EXIT1 ("deallocate function called unexpectedly (%p, %p)",
45 closure, ptr);
48 /* Counter for various function calls. */
49 static int function_called;
51 /* An allocation function which returns NULL and records that it has
52 been called. */
53 static void *
54 allocate_return_null (void *closure)
56 /* The function should only be called once. */
57 TEST_COMPARE (function_called, 0);
58 ++function_called;
59 return NULL;
63 /* The following is used to check the retry logic, by causing a fake
64 race condition. */
65 static void *fake_race_place;
66 static char fake_race_region[3]; /* To obtain unique addresses. */
68 static void *
69 fake_race_allocate (void *closure)
71 TEST_VERIFY (closure == &fake_race_region[0]);
72 TEST_COMPARE (function_called, 0);
73 ++function_called;
74 /* Fake allocation by another thread. */
75 fake_race_place = &fake_race_region[1];
76 return &fake_race_region[2];
79 static void
80 fake_race_deallocate (void *closure, void *ptr)
82 /* Check that the pointer returned from fake_race_allocate is
83 deallocated (and not the one stored in fake_race_place). */
84 TEST_VERIFY (ptr == &fake_race_region[2]);
86 TEST_VERIFY (fake_race_place == &fake_race_region[1]);
87 TEST_VERIFY (closure == &fake_race_region[0]);
88 TEST_COMPARE (function_called, 1);
89 ++function_called;
92 /* Similar to fake_race_allocate, but expects to be paired with free
93 as the deallocation function. */
94 static void *
95 fake_race_allocate_for_free (void *closure)
97 TEST_VERIFY (closure == &fake_race_region[0]);
98 TEST_COMPARE (function_called, 0);
99 ++function_called;
100 /* Fake allocation by another thread. */
101 fake_race_place = &fake_race_region[1];
102 return xstrdup ("to be freed");
105 static int
106 do_test (void)
108 mtrace ();
110 /* Simple allocation. */
111 void *place1 = NULL;
112 char *string1 = allocate_once (&place1, allocate_string,
113 deallocate_not_called,
114 (char *) "test string 1");
115 TEST_VERIFY_EXIT (string1 != NULL);
116 TEST_VERIFY (strcmp ("test string 1", string1) == 0);
117 /* Second call returns the first pointer, without calling any
118 callbacks. */
119 TEST_VERIFY (string1
120 == allocate_once (&place1, allocate_not_called,
121 deallocate_not_called,
122 (char *) "test string 1a"));
124 /* Different place should result in another call. */
125 void *place2 = NULL;
126 char *string2 = allocate_once (&place2, allocate_string,
127 deallocate_not_called,
128 (char *) "test string 2");
129 TEST_VERIFY_EXIT (string2 != NULL);
130 TEST_VERIFY (strcmp ("test string 2", string2) == 0);
131 TEST_VERIFY (string1 != string2);
133 /* Check error reporting (NULL return value from the allocation
134 function). */
135 void *place3 = NULL;
136 char *string3 = allocate_once (&place3, allocate_return_null,
137 deallocate_not_called, NULL);
138 TEST_VERIFY (string3 == NULL);
139 TEST_COMPARE (function_called, 1);
141 /* Check that the deallocation function is called if the race is
142 lost. */
143 function_called = 0;
144 TEST_VERIFY (allocate_once (&fake_race_place,
145 fake_race_allocate,
146 fake_race_deallocate,
147 &fake_race_region[0])
148 == &fake_race_region[1]);
149 TEST_COMPARE (function_called, 2);
150 function_called = 3;
151 TEST_VERIFY (allocate_once (&fake_race_place,
152 fake_race_allocate,
153 fake_race_deallocate,
154 &fake_race_region[0])
155 == &fake_race_region[1]);
156 TEST_COMPARE (function_called, 3);
158 /* Similar, but this time rely on that free is called. */
159 function_called = 0;
160 fake_race_place = NULL;
161 TEST_VERIFY (allocate_once (&fake_race_place,
162 fake_race_allocate_for_free,
163 NULL,
164 &fake_race_region[0])
165 == &fake_race_region[1]);
166 TEST_COMPARE (function_called, 1);
167 function_called = 3;
168 TEST_VERIFY (allocate_once (&fake_race_place,
169 fake_race_allocate_for_free,
170 NULL,
171 &fake_race_region[0])
172 == &fake_race_region[1]);
173 TEST_COMPARE (function_called, 3);
175 free (place2);
176 free (place1);
178 return 0;
181 #include <support/test-driver.c>