Skip to content

Commit 4d35a31

Browse files
committed
test/test-string: Add test for memchr and memrchr
There wasn't one before. Signed-off-by: Keith Packard <[email protected]>
1 parent eb21c63 commit 4d35a31

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed

test/test-string/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
tests_mem = [
3737
'test-memmem',
38+
'test-memchr',
3839
]
3940

4041
tests_string = tests_mem

test/test-string/test-memchr.c

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* SPDX-License-Identifier: BSD-3-Clause
3+
*
4+
* Copyright © 2025 Keith Packard
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions
8+
* are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright
11+
* notice, this list of conditions and the following disclaimer.
12+
*
13+
* 2. Redistributions in binary form must reproduce the above
14+
* copyright notice, this list of conditions and the following
15+
* disclaimer in the documentation and/or other materials provided
16+
* with the distribution.
17+
*
18+
* 3. Neither the name of the copyright holder nor the names of its
19+
* contributors may be used to endorse or promote products derived
20+
* from this software without specific prior written permission.
21+
*
22+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33+
* OF THE POSSIBILITY OF SUCH DAMAGE.
34+
*/
35+
36+
#define _GNU_SOURCE
37+
#include <string.h>
38+
#include <stdio.h>
39+
#include <stdlib.h>
40+
#include <inttypes.h>
41+
42+
#define SEED 42
43+
#define HAY_MAX 2048
44+
45+
static uint8_t hay[HAY_MAX];
46+
47+
/* Generate random uint8_t */
48+
static uint8_t
49+
rand_byte(void)
50+
{
51+
return rand() & 0xff;
52+
}
53+
54+
static int
55+
rand_int(void)
56+
{
57+
int i;
58+
unsigned r = 0;
59+
60+
for (i = 0; i < __INT_WIDTH__; i += 8) {
61+
r |= (unsigned) rand_byte() << i;
62+
}
63+
return (int) r;
64+
}
65+
66+
/* Generate random size_t */
67+
static size_t
68+
rand_size_t(void)
69+
{
70+
size_t r = 0;
71+
size_t i;
72+
73+
for (i = 0; i < SIZE_WIDTH; i += 8) {
74+
r |= (size_t) rand_byte() << i;
75+
}
76+
return r;
77+
}
78+
79+
/* Generate random number between 0 and max inclusive */
80+
static size_t
81+
rand_range(size_t max)
82+
{
83+
size_t mask = ~(size_t)0;
84+
size_t ret;
85+
86+
if (max == 0)
87+
return 0;
88+
while (mask >> 1 > max)
89+
mask >>= 1;
90+
for (;;) {
91+
ret = rand_size_t() & mask;
92+
if (ret <= max)
93+
return ret;
94+
}
95+
}
96+
97+
static size_t
98+
rand_size(size_t max)
99+
{
100+
for (;;) {
101+
size_t ret = rand_range(max);
102+
if (ret)
103+
return ret;
104+
}
105+
}
106+
107+
static size_t
108+
rand_pos(size_t max)
109+
{
110+
return rand_range(max);
111+
}
112+
113+
#ifdef __MSP430__
114+
/* MSP430 emulator is rather slow */
115+
#define LOOPS 4
116+
#else
117+
#define LOOPS 32
118+
#endif
119+
120+
static void
121+
generate_hay(uint8_t *dst, size_t size)
122+
{
123+
while (size) {
124+
*dst++ = rand_byte();
125+
size--;
126+
}
127+
}
128+
129+
static void
130+
fixup_hay(uint8_t *hay, size_t hay_size, uint8_t needle)
131+
{
132+
while (hay_size) {
133+
if (*hay == needle)
134+
*hay ^= 0x55;
135+
hay++;
136+
hay_size--;
137+
}
138+
}
139+
140+
int main(void)
141+
{
142+
static size_t hay_start, hay_size;
143+
int ret = 0;
144+
int hay_size_loop;
145+
int needle_pos_loop;
146+
size_t needle_pos_1, needle_pos_2;
147+
148+
srand(SEED);
149+
150+
/* Check long alignments for hay */
151+
for (hay_start = 0; hay_start < sizeof(long); hay_start++) {
152+
printf("loop %zd of %zd\n", hay_start, sizeof(long));
153+
154+
/* Generate LOOPS random hay sizes */
155+
for (hay_size_loop = 0; hay_size_loop < LOOPS; hay_size_loop++) {
156+
hay_size = rand_size(HAY_MAX - hay_start - 1);
157+
158+
/* Generate LOOPS random needle locations */
159+
for (needle_pos_loop = 0; needle_pos_loop < LOOPS; needle_pos_loop++) {
160+
needle_pos_1 = rand_pos(hay_size - 1);
161+
needle_pos_2 = rand_pos(hay_size - 1);
162+
uint8_t *hay_cur = &hay[hay_start];
163+
int needle = rand_int();
164+
165+
if (needle_pos_2 < needle_pos_1) {
166+
size_t t = needle_pos_1;
167+
needle_pos_1 = needle_pos_2;
168+
needle_pos_2 = t;
169+
}
170+
#if 0
171+
printf("hay_start %zu hay_size %zu needle %d\n",
172+
hay_start, hay_size, needle);
173+
#endif
174+
175+
/* Set up the data */
176+
memset(hay, 0, HAY_MAX);
177+
generate_hay(hay_cur, hay_size);
178+
179+
/*
180+
* Make sure the needle doesn't already exist in hay by
181+
* adjusting both
182+
*/
183+
fixup_hay(hay_cur, hay_size, (uint8_t) needle);
184+
185+
/* Place the needle in the haystack */
186+
hay_cur[needle_pos_1] = (uint8_t) needle;
187+
hay_cur[needle_pos_2] = (uint8_t) needle;
188+
189+
uint8_t *result;
190+
191+
result = memchr(hay_cur, needle, hay_size);
192+
193+
if (result != hay_cur + needle_pos_1) {
194+
if (!result)
195+
printf("memchr expected needle at %zu got NULL\n",
196+
needle_pos_1);
197+
else
198+
printf("memchr expected needle at %zu got %zu\n",
199+
needle_pos_1, result - hay_cur);
200+
printf(" hay_start %zu hay_size %zu needle_pos_1 %zu needle_pos_2 %zu needle %d\n",
201+
hay_start, hay_size, needle_pos_1, needle_pos_2, needle);
202+
ret = 1;
203+
}
204+
205+
result = memrchr(hay_cur, needle, hay_size);
206+
207+
if (result != hay_cur + needle_pos_2) {
208+
if (!result)
209+
printf("memrchr expected needle at %zu got NULL\n",
210+
needle_pos_2);
211+
else
212+
printf("memrchr expected needle at %zu got %zu\n",
213+
needle_pos_2, result - hay_cur);
214+
printf(" hay_start %zu hay_size %zu needle_pos_1 %zu needle_pos_2 %zu needle %d\n",
215+
hay_start, hay_size, needle_pos_1, needle_pos_2, needle);
216+
ret = 1;
217+
}
218+
219+
/*
220+
* Introduce a single bit error in the hay
221+
* so that it no longer matches anywhere
222+
*/
223+
hay_cur[needle_pos_1] ^= 1;
224+
hay_cur[needle_pos_2] ^= 2;
225+
226+
result = memchr(hay_cur, needle, hay_size);
227+
228+
if (result != NULL) {
229+
printf("memchr expected no needle, got %zu\n", result - hay_cur);
230+
printf(" hay_start %zu hay_size %zu needle_pos_1 %zu needle_pos_2 %zu needle %d\n",
231+
hay_start, hay_size, needle_pos_1, needle_pos_2, needle);
232+
ret = 1;
233+
}
234+
235+
result = memrchr(hay_cur, needle, hay_size);
236+
237+
if (result != NULL) {
238+
printf("memrchr expected no needle, got %zu\n", result - hay_cur);
239+
printf(" hay_start %zu hay_size %zu needle_pos_1 %zu needle_pos_2 %zu needle %d\n",
240+
hay_start, hay_size, needle_pos_1, needle_pos_2, needle);
241+
ret = 1;
242+
}
243+
}
244+
}
245+
}
246+
return ret;
247+
}

0 commit comments

Comments
 (0)