1 /* $NetBSD: t_strchrnul.c,v 1.1 2023/01/30 19:49:49 christos Exp $ */
2 
3 /*
4  * Written by J.T. Conklin <jtc@acorntoolworks.com>
5  * Public domain.
6  */
7 
8 #include <atf-c.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <dlfcn.h>
14 
15 static char	*slow_strchrnul(char *, int);
16 static void	 verify_strchrnul(char *, int, unsigned int, unsigned int);
17 
18 char * (*volatile strchrnul_fn)(const char *, int);
19 
20 static char *
21 slow_strchrnul(char *buf, int ch)
22 {
23 	unsigned char c = 1;
24 
25 	ch &= 0xff;
26 
27 	for (; ; buf++) {
28 		c = *buf;
29 		if (c == ch || c == 0)
30 			return buf;
31 	}
32 }
33 
34 static void
35 verify_strchrnul(char *buf, int ch, unsigned int t, unsigned int a)
36 {
37 	const char *off, *ok_off;
38 
39 	off = strchrnul_fn(buf, ch);
40 	ok_off = slow_strchrnul(buf, ch);
41 	if (off == ok_off)
42 		return;
43 
44 	fprintf(stderr, "test_strchrnul(\"%s\", %#x) gave %zd not %zd (test %d, "
45 	    "alignment %d)\n",
46 	    buf, ch, off ? off - buf : -1, ok_off ? ok_off - buf : -1, t, a);
47 
48 	atf_tc_fail("Check stderr for details");
49 }
50 
51 ATF_TC(strchrnul_basic);
52 ATF_TC_HEAD(strchrnul_basic, tc)
53 {
54 
55         atf_tc_set_md_var(tc, "descr", "Test strchrnul(3) results");
56 }
57 
58 ATF_TC_BODY(strchrnul_basic, tc)
59 {
60 	void *dl_handle;
61 	char *off;
62 	char buf[32];
63 	unsigned int t, a;
64 
65 	const char *tab[] = {
66 		"",
67 		"a",
68 		"aa",
69 		"abc",
70 		"abcd",
71 		"abcde",
72 		"abcdef",
73 		"abcdefg",
74 		"abcdefgh",
75 
76 		"/",
77 		"//",
78 		"/a",
79 		"/a/",
80 		"/ab",
81 		"/ab/",
82 		"/abc",
83 		"/abc/",
84 		"/abcd",
85 		"/abcd/",
86 		"/abcde",
87 		"/abcde/",
88 		"/abcdef",
89 		"/abcdef/",
90 		"/abcdefg",
91 		"/abcdefg/",
92 		"/abcdefgh",
93 		"/abcdefgh/",
94 
95 		"a/",
96 		"a//",
97 		"a/a",
98 		"a/a/",
99 		"a/ab",
100 		"a/ab/",
101 		"a/abc",
102 		"a/abc/",
103 		"a/abcd",
104 		"a/abcd/",
105 		"a/abcde",
106 		"a/abcde/",
107 		"a/abcdef",
108 		"a/abcdef/",
109 		"a/abcdefg",
110 		"a/abcdefg/",
111 		"a/abcdefgh",
112 		"a/abcdefgh/",
113 
114 		"ab/",
115 		"ab//",
116 		"ab/a",
117 		"ab/a/",
118 		"ab/ab",
119 		"ab/ab/",
120 		"ab/abc",
121 		"ab/abc/",
122 		"ab/abcd",
123 		"ab/abcd/",
124 		"ab/abcde",
125 		"ab/abcde/",
126 		"ab/abcdef",
127 		"ab/abcdef/",
128 		"ab/abcdefg",
129 		"ab/abcdefg/",
130 		"ab/abcdefgh",
131 		"ab/abcdefgh/",
132 
133 		"abc/",
134 		"abc//",
135 		"abc/a",
136 		"abc/a/",
137 		"abc/ab",
138 		"abc/ab/",
139 		"abc/abc",
140 		"abc/abc/",
141 		"abc/abcd",
142 		"abc/abcd/",
143 		"abc/abcde",
144 		"abc/abcde/",
145 		"abc/abcdef",
146 		"abc/abcdef/",
147 		"abc/abcdefg",
148 		"abc/abcdefg/",
149 		"abc/abcdefgh",
150 		"abc/abcdefgh/",
151 
152 		"abcd/",
153 		"abcd//",
154 		"abcd/a",
155 		"abcd/a/",
156 		"abcd/ab",
157 		"abcd/ab/",
158 		"abcd/abc",
159 		"abcd/abc/",
160 		"abcd/abcd",
161 		"abcd/abcd/",
162 		"abcd/abcde",
163 		"abcd/abcde/",
164 		"abcd/abcdef",
165 		"abcd/abcdef/",
166 		"abcd/abcdefg",
167 		"abcd/abcdefg/",
168 		"abcd/abcdefgh",
169 		"abcd/abcdefgh/",
170 
171 		"abcde/",
172 		"abcde//",
173 		"abcde/a",
174 		"abcde/a/",
175 		"abcde/ab",
176 		"abcde/ab/",
177 		"abcde/abc",
178 		"abcde/abc/",
179 		"abcde/abcd",
180 		"abcde/abcd/",
181 		"abcde/abcde",
182 		"abcde/abcde/",
183 		"abcde/abcdef",
184 		"abcde/abcdef/",
185 		"abcde/abcdefg",
186 		"abcde/abcdefg/",
187 		"abcde/abcdefgh",
188 		"abcde/abcdefgh/",
189 
190 		"abcdef/",
191 		"abcdef//",
192 		"abcdef/a",
193 		"abcdef/a/",
194 		"abcdef/ab",
195 		"abcdef/ab/",
196 		"abcdef/abc",
197 		"abcdef/abc/",
198 		"abcdef/abcd",
199 		"abcdef/abcd/",
200 		"abcdef/abcde",
201 		"abcdef/abcde/",
202 		"abcdef/abcdef",
203 		"abcdef/abcdef/",
204 		"abcdef/abcdefg",
205 		"abcdef/abcdefg/",
206 		"abcdef/abcdefgh",
207 		"abcdef/abcdefgh/",
208 
209 		"abcdefg/",
210 		"abcdefg//",
211 		"abcdefg/a",
212 		"abcdefg/a/",
213 		"abcdefg/ab",
214 		"abcdefg/ab/",
215 		"abcdefg/abc",
216 		"abcdefg/abc/",
217 		"abcdefg/abcd",
218 		"abcdefg/abcd/",
219 		"abcdefg/abcde",
220 		"abcdefg/abcde/",
221 		"abcdefg/abcdef",
222 		"abcdefg/abcdef/",
223 		"abcdefg/abcdefg",
224 		"abcdefg/abcdefg/",
225 		"abcdefg/abcdefgh",
226 		"abcdefg/abcdefgh/",
227 
228 		"abcdefgh/",
229 		"abcdefgh//",
230 		"abcdefgh/a",
231 		"abcdefgh/a/",
232 		"abcdefgh/ab",
233 		"abcdefgh/ab/",
234 		"abcdefgh/abc",
235 		"abcdefgh/abc/",
236 		"abcdefgh/abcd",
237 		"abcdefgh/abcd/",
238 		"abcdefgh/abcde",
239 		"abcdefgh/abcde/",
240 		"abcdefgh/abcdef",
241 		"abcdefgh/abcdef/",
242 		"abcdefgh/abcdefg",
243 		"abcdefgh/abcdefg/",
244 		"abcdefgh/abcdefgh",
245 		"abcdefgh/abcdefgh/",
246 	};
247 
248 	dl_handle = dlopen(NULL, RTLD_LAZY);
249 	strchrnul_fn = dlsym(dl_handle, "test_strchrnul");
250 	if (!strchrnul_fn)
251 		strchrnul_fn = strchrnul;
252 
253 	for (a = 3; a < 3 + sizeof(long); ++a) {
254 		/* Put char and a \0 before the buffer */
255 		buf[a-1] = '/';
256 		buf[a-2] = '0';
257 		buf[a-3] = 0xff;
258 		for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
259 			int len = strlen(tab[t]) + 1;
260 			memcpy(&buf[a], tab[t], len);
261 
262 			/* Put the char we are looking for after the \0 */
263 			buf[a + len] = '/';
264 
265 			/* Check search for NUL at end of string */
266 			verify_strchrnul(buf + a, 0, t, a);
267 
268 			/* Then for the '/' in the strings */
269 			verify_strchrnul(buf + a, '/', t, a);
270 
271 			/* check zero extension of char arg */
272 			verify_strchrnul(buf + a, 0xffffff00 | '/', t, a);
273 
274 			/* Replace all the '/' with 0xff */
275 			while (*(off = slow_strchrnul(buf + a, '/')) != '\0')
276 				*off = 0xff;
277 
278 			buf[a + len] = 0xff;
279 
280 			/* Check we can search for 0xff as well as '/' */
281 			verify_strchrnul(buf + a, 0xff, t, a);
282 		}
283 	}
284 	(void)dlclose(dl_handle);
285 }
286 
287 ATF_TP_ADD_TCS(tp)
288 {
289 
290 	ATF_TP_ADD_TC(tp, strchrnul_basic);
291 
292 	return atf_no_error();
293 }
294