xref: /freebsd/lib/libc/tests/string/strrchr_test.c (revision 8b5d77bbcbd98e684226950be1c779e108059d8d)
1*8b5d77bbSRobert Clausecker /*
2*8b5d77bbSRobert Clausecker  * SPDX-License-Identifier: BSD-2-Clause
3*8b5d77bbSRobert Clausecker  *
4*8b5d77bbSRobert Clausecker  * Copyright (c) 2023, 2026 Robert Clausecker <fuz@FreeBSD.org>
5*8b5d77bbSRobert Clausecker  *
6*8b5d77bbSRobert Clausecker  * Adapted from memrchr_test.c.
7*8b5d77bbSRobert Clausecker  */
8*8b5d77bbSRobert Clausecker 
9*8b5d77bbSRobert Clausecker #include <sys/cdefs.h>
10*8b5d77bbSRobert Clausecker 
11*8b5d77bbSRobert Clausecker #include <dlfcn.h>
12*8b5d77bbSRobert Clausecker #include <limits.h>
13*8b5d77bbSRobert Clausecker #include <stdio.h>
14*8b5d77bbSRobert Clausecker #include <string.h>
15*8b5d77bbSRobert Clausecker 
16*8b5d77bbSRobert Clausecker #include <atf-c.h>
17*8b5d77bbSRobert Clausecker 
18*8b5d77bbSRobert Clausecker static char *(*strrchr_fn)(const char *, int);
19*8b5d77bbSRobert Clausecker 
20*8b5d77bbSRobert Clausecker /*
21*8b5d77bbSRobert Clausecker  * Check that when looking for the character NUL, we find the
22*8b5d77bbSRobert Clausecker  * string terminator, and not some NUL character after it.
23*8b5d77bbSRobert Clausecker  */
24*8b5d77bbSRobert Clausecker ATF_TC_WITHOUT_HEAD(nul);
ATF_TC_BODY(nul,tc)25*8b5d77bbSRobert Clausecker ATF_TC_BODY(nul, tc)
26*8b5d77bbSRobert Clausecker {
27*8b5d77bbSRobert Clausecker 	size_t i, j, k;
28*8b5d77bbSRobert Clausecker 	char buf[1+15+64]; /* offset [0+15] + 64 buffer bytes + sentinels */
29*8b5d77bbSRobert Clausecker 
30*8b5d77bbSRobert Clausecker 	buf[0] = '\0';
31*8b5d77bbSRobert Clausecker 	memset(buf + 1, '-', sizeof(buf) - 1);
32*8b5d77bbSRobert Clausecker 
33*8b5d77bbSRobert Clausecker 	for (i = 0; i < 16; i++)
34*8b5d77bbSRobert Clausecker 		for (j = 0; j < 64; j++)
35*8b5d77bbSRobert Clausecker 			for (k = j; k < 64; k++) {
36*8b5d77bbSRobert Clausecker 				buf[i + j + 1] = '\0';
37*8b5d77bbSRobert Clausecker 				buf[i + k + 1] = '\0';
38*8b5d77bbSRobert Clausecker 				ATF_CHECK_EQ(strrchr_fn(buf + i + 1, '\0'), buf + i + j + 1);
39*8b5d77bbSRobert Clausecker 				buf[i + j + 1] = '-';
40*8b5d77bbSRobert Clausecker 				buf[i + k + 1] = '-';
41*8b5d77bbSRobert Clausecker 			}
42*8b5d77bbSRobert Clausecker }
43*8b5d77bbSRobert Clausecker 
44*8b5d77bbSRobert Clausecker /*
45*8b5d77bbSRobert Clausecker  * Check that if the character 'X' does not occur in the string
46*8b5d77bbSRobert Clausecker  * (but occurs before and after it), we correctly return NULL.
47*8b5d77bbSRobert Clausecker  */
48*8b5d77bbSRobert Clausecker ATF_TC_WITHOUT_HEAD(not_found);
ATF_TC_BODY(not_found,tc)49*8b5d77bbSRobert Clausecker ATF_TC_BODY(not_found, tc)
50*8b5d77bbSRobert Clausecker {
51*8b5d77bbSRobert Clausecker 	size_t i, j;
52*8b5d77bbSRobert Clausecker 	char buf[1+15+64+2]; /* offset [0..15] + 64 buffer bytes + sentinels */
53*8b5d77bbSRobert Clausecker 
54*8b5d77bbSRobert Clausecker 	buf[0] = 'X';
55*8b5d77bbSRobert Clausecker 	memset(buf + 1, '-', sizeof(buf) - 1);
56*8b5d77bbSRobert Clausecker 
57*8b5d77bbSRobert Clausecker 	for (i = 0; i < 16; i++)
58*8b5d77bbSRobert Clausecker 		for (j = 0; j < 64; j++) {
59*8b5d77bbSRobert Clausecker 			buf[i + j + 1] = '\0';
60*8b5d77bbSRobert Clausecker 			buf[i + j + 2] = 'X';
61*8b5d77bbSRobert Clausecker 			ATF_CHECK_EQ(strrchr_fn(buf + i + 1, 'X'), NULL);
62*8b5d77bbSRobert Clausecker 			buf[i + j + 1] = '-';
63*8b5d77bbSRobert Clausecker 			buf[i + j + 2] = '-';
64*8b5d77bbSRobert Clausecker 		}
65*8b5d77bbSRobert Clausecker }
66*8b5d77bbSRobert Clausecker 
67*8b5d77bbSRobert Clausecker static void
do_found_test(char buf[],size_t first,size_t second)68*8b5d77bbSRobert Clausecker do_found_test(char buf[], size_t first, size_t second)
69*8b5d77bbSRobert Clausecker {
70*8b5d77bbSRobert Clausecker 	/* invariant: first <= second */
71*8b5d77bbSRobert Clausecker 
72*8b5d77bbSRobert Clausecker 	buf[first] = 'X';
73*8b5d77bbSRobert Clausecker 	buf[second] = 'X';
74*8b5d77bbSRobert Clausecker 	ATF_CHECK_EQ(strrchr_fn(buf, 'X'), buf + second);
75*8b5d77bbSRobert Clausecker 	buf[first] = '-';
76*8b5d77bbSRobert Clausecker 	buf[second] = '-';
77*8b5d77bbSRobert Clausecker }
78*8b5d77bbSRobert Clausecker 
79*8b5d77bbSRobert Clausecker /*
80*8b5d77bbSRobert Clausecker  * Check that if the character 'X' occurs in the string multiple
81*8b5d77bbSRobert Clausecker  * times (i. e. twice), its last encounter is returned.
82*8b5d77bbSRobert Clausecker  */
83*8b5d77bbSRobert Clausecker ATF_TC_WITHOUT_HEAD(found);
ATF_TC_BODY(found,tc)84*8b5d77bbSRobert Clausecker ATF_TC_BODY(found, tc)
85*8b5d77bbSRobert Clausecker {
86*8b5d77bbSRobert Clausecker 	size_t i, j, k, l;
87*8b5d77bbSRobert Clausecker 	char buf[1+15+64+2];
88*8b5d77bbSRobert Clausecker 
89*8b5d77bbSRobert Clausecker 	buf[0] = 'X';
90*8b5d77bbSRobert Clausecker 	memset(buf + 1, '-', sizeof(buf) - 1);
91*8b5d77bbSRobert Clausecker 
92*8b5d77bbSRobert Clausecker 	for (i = 0; i < 16; i++)
93*8b5d77bbSRobert Clausecker 		for (j = 0; j < 64; j++)
94*8b5d77bbSRobert Clausecker 			for (k = 0; k < j; k++)
95*8b5d77bbSRobert Clausecker 				for (l = 0; l <= k; l++) {
96*8b5d77bbSRobert Clausecker 					buf[i + j + 1] = '\0';
97*8b5d77bbSRobert Clausecker 					buf[i + j + 2] = 'X';
98*8b5d77bbSRobert Clausecker 					do_found_test(buf + i + 1, l, k);
99*8b5d77bbSRobert Clausecker 					buf[i + j + 1] = '-';
100*8b5d77bbSRobert Clausecker 					buf[i + j + 2] = '-';
101*8b5d77bbSRobert Clausecker 				}
102*8b5d77bbSRobert Clausecker }
103*8b5d77bbSRobert Clausecker 
104*8b5d77bbSRobert Clausecker static void
do_values_test(char buf[],size_t len,size_t i,int c)105*8b5d77bbSRobert Clausecker do_values_test(char buf[], size_t len, size_t i, int c)
106*8b5d77bbSRobert Clausecker {
107*8b5d77bbSRobert Clausecker 	/* sentinels */
108*8b5d77bbSRobert Clausecker 	buf[-1] = c;
109*8b5d77bbSRobert Clausecker 	buf[len] = '\0';
110*8b5d77bbSRobert Clausecker 	buf[len + 1] = 'c';
111*8b5d77bbSRobert Clausecker 
112*8b5d77bbSRobert Clausecker 	/* fill the string with some other character, but not with NUL */
113*8b5d77bbSRobert Clausecker 	memset(buf, c == UCHAR_MAX ? c - 1 : c + 1, len);
114*8b5d77bbSRobert Clausecker 
115*8b5d77bbSRobert Clausecker 	if (i < len) {
116*8b5d77bbSRobert Clausecker 		buf[i] = c;
117*8b5d77bbSRobert Clausecker 		ATF_CHECK_EQ(strrchr_fn(buf, c), buf + i);
118*8b5d77bbSRobert Clausecker 	} else
119*8b5d77bbSRobert Clausecker 		ATF_CHECK_EQ(strrchr_fn(buf, c), c == 0 ? buf + len : NULL);
120*8b5d77bbSRobert Clausecker }
121*8b5d77bbSRobert Clausecker 
122*8b5d77bbSRobert Clausecker /*
123*8b5d77bbSRobert Clausecker  * Check that the character is found regardless of its value.
124*8b5d77bbSRobert Clausecker  * This catches arithmetic (overflow) errors in incorrect SWAR
125*8b5d77bbSRobert Clausecker  * implementations of byte-parallel character matching.
126*8b5d77bbSRobert Clausecker  */
127*8b5d77bbSRobert Clausecker ATF_TC_WITHOUT_HEAD(values);
ATF_TC_BODY(values,tc)128*8b5d77bbSRobert Clausecker ATF_TC_BODY(values, tc)
129*8b5d77bbSRobert Clausecker {
130*8b5d77bbSRobert Clausecker 	size_t i, j, k;
131*8b5d77bbSRobert Clausecker 	int c;
132*8b5d77bbSRobert Clausecker 	char buf[1+15+64+2];
133*8b5d77bbSRobert Clausecker 
134*8b5d77bbSRobert Clausecker 	for (i = 0; i < 16; i++)
135*8b5d77bbSRobert Clausecker 		for (j = 0; j < 64; j++)
136*8b5d77bbSRobert Clausecker 			for (k = 0; k <= j; k++)
137*8b5d77bbSRobert Clausecker 				for (c = 0; c <= UCHAR_MAX; c++)
138*8b5d77bbSRobert Clausecker 					do_values_test(buf + i + 1, j, k, c);
139*8b5d77bbSRobert Clausecker }
140*8b5d77bbSRobert Clausecker 
ATF_TP_ADD_TCS(tp)141*8b5d77bbSRobert Clausecker ATF_TP_ADD_TCS(tp)
142*8b5d77bbSRobert Clausecker {
143*8b5d77bbSRobert Clausecker 	void *dl_handle;
144*8b5d77bbSRobert Clausecker 
145*8b5d77bbSRobert Clausecker 	dl_handle = dlopen(NULL, RTLD_LAZY);
146*8b5d77bbSRobert Clausecker 	strrchr_fn = dlsym(dl_handle, "test_strrchr");
147*8b5d77bbSRobert Clausecker 	if (strrchr_fn == NULL)
148*8b5d77bbSRobert Clausecker 		strrchr_fn = strrchr;
149*8b5d77bbSRobert Clausecker 
150*8b5d77bbSRobert Clausecker 	ATF_TP_ADD_TC(tp, nul);
151*8b5d77bbSRobert Clausecker 	ATF_TP_ADD_TC(tp, not_found);
152*8b5d77bbSRobert Clausecker 	ATF_TP_ADD_TC(tp, found);
153*8b5d77bbSRobert Clausecker 	ATF_TP_ADD_TC(tp, values);
154*8b5d77bbSRobert Clausecker 
155*8b5d77bbSRobert Clausecker 	return (atf_no_error());
156*8b5d77bbSRobert Clausecker }
157