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