Skip to content

Commit eb21c63

Browse files
committed
test: Add test for 'memmem' function
This function was untested. Signed-off-by: Keith Packard <[email protected]>
1 parent 2c0a358 commit eb21c63

File tree

3 files changed

+342
-0
lines changed

3 files changed

+342
-0
lines changed

test/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ endif
742742

743743
subdir('libc-testsuite')
744744
subdir('test-math')
745+
subdir('test-string')
745746

746747
if has_arm_semihost
747748
subdir('semihost')

test/test-string/meson.build

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
tests_mem = [
37+
'test-memmem',
38+
]
39+
40+
tests_string = tests_mem
41+
42+
foreach params : targets
43+
target = params['name']
44+
target_dir = params['dir']
45+
target_c_args = params['c_args']
46+
target_lib_prefix = params['lib_prefix']
47+
48+
_libs = [get_variable('lib_c' + target)]
49+
if is_variable('lib_semihost' + target)
50+
_libs += [get_variable('lib_semihost' + target)]
51+
endif
52+
53+
_lib_files=[]
54+
foreach _lib : _libs
55+
_lib_files += _lib.full_path()
56+
endforeach
57+
58+
if is_variable(crt0_test + target)
59+
_objs = [get_variable(crt0_test + target)]
60+
else
61+
_objs = []
62+
endif
63+
64+
_c_args = target_c_args + get_variable('test_c_args' + target, test_c_args)
65+
_link_args = target_c_args + _lib_files + get_variable('test_link_args' + target, test_link_args)
66+
_link_depends = get_variable('test_link_depends' + target, test_link_depends) + _libs
67+
foreach t1 : tests_string
68+
t1_src = t1 + '.c'
69+
test_file_name_arg=['-DTEST_FILE_NAME="' + t1 + target + '.txt"']
70+
71+
test(t1 + target,
72+
executable(t1 + target, [t1_src],
73+
c_args: printf_compile_args_d + test_file_name_arg + _c_args,
74+
link_args: printf_link_args_d + _link_args,
75+
objects: _objs,
76+
link_depends: _link_depends,
77+
include_directories: inc),
78+
depends: bios_bin,
79+
timeout: 60,
80+
suite: 'test-string',
81+
env: test_env)
82+
endforeach
83+
84+
endforeach
85+
86+
if enable_native_tests
87+
88+
foreach t1 : tests_string
89+
t1_src = t1 + '.c'
90+
t1_name = t1 + '-native'
91+
test_file_name_arg=['-DTEST_FILE_NAME="' + t1_name + '.txt"']
92+
93+
test(t1_name,
94+
executable(t1_name, t1_src,
95+
c_args: native_c_args + ctype_c_args,
96+
link_args: native_c_args),
97+
suite: 'test-string'
98+
)
99+
endforeach
100+
101+
endif

test/test-string/test-memmem.c

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
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+
#ifdef __MSP430__
43+
#define HAY_MAX 256
44+
#define NEEDLE_MAX 16
45+
#else
46+
#define HAY_MAX 2048
47+
#define NEEDLE_MAX 256
48+
#endif
49+
50+
#define SEED 42
51+
52+
static uint8_t hay[HAY_MAX];
53+
static uint8_t needle[NEEDLE_MAX];
54+
55+
/* Generate random uint8_t */
56+
static uint8_t
57+
rand_byte(void)
58+
{
59+
return rand() & 0xff;
60+
}
61+
62+
/* Generate random size_t */
63+
static size_t
64+
rand_size_t(void)
65+
{
66+
size_t r = 0;
67+
size_t i;
68+
69+
for (i = 0; i < SIZE_WIDTH; i += 8) {
70+
r |= (size_t) rand_byte() << i;
71+
}
72+
return r;
73+
}
74+
75+
/* Generate random number between 0 and max inclusive */
76+
static size_t
77+
rand_range(size_t max)
78+
{
79+
size_t mask = ~(size_t)0;
80+
size_t ret;
81+
82+
if (max == 0)
83+
return 0;
84+
while (mask >> 1 > max)
85+
mask >>= 1;
86+
for (;;) {
87+
ret = rand_size_t() & mask;
88+
if (ret <= max)
89+
return ret;
90+
}
91+
}
92+
93+
static size_t
94+
rand_size(size_t max)
95+
{
96+
for (;;) {
97+
size_t ret = rand_range(max);
98+
if (ret)
99+
return ret;
100+
}
101+
}
102+
103+
static size_t
104+
rand_pos(size_t max)
105+
{
106+
return rand_range(max);
107+
}
108+
109+
static size_t
110+
rand_elt(size_t max)
111+
{
112+
return rand_range(max-1);
113+
}
114+
115+
#ifdef __MSP430__
116+
/* MSP430 emulator is rather slow */
117+
#define LOOPS 4
118+
#else
119+
#define LOOPS 10
120+
#endif
121+
122+
static void
123+
generate_hay(uint8_t *dst, size_t size)
124+
{
125+
while (size) {
126+
*dst++ = rand_byte();
127+
size--;
128+
}
129+
}
130+
131+
static void
132+
fixup_hay(uint8_t *hay, size_t hay_size, uint8_t *needle, size_t needle_size)
133+
{
134+
uint8_t *fix_pos = &needle[rand_elt(needle_size)];
135+
uint8_t fix = *fix_pos;
136+
137+
while (hay_size) {
138+
if (*hay == fix)
139+
*hay ^= 0x55;
140+
hay++;
141+
hay_size--;
142+
}
143+
144+
while (needle_size) {
145+
if (needle != fix_pos && *needle == fix)
146+
*needle ^= 0xaa;
147+
needle++;
148+
needle_size--;
149+
}
150+
}
151+
152+
int main(void)
153+
{
154+
static size_t hay_start, hay_size;
155+
static size_t needle_start, needle_size;
156+
static size_t needle_pos;
157+
int ret = 0;
158+
int hay_size_loop, needle_size_loop;
159+
int needle_pos_loop;
160+
161+
srand(SEED);
162+
163+
/* Check long alignments for hay and needle */
164+
for (hay_start = 0; hay_start < sizeof(long); hay_start++) {
165+
printf("loop %zd of %zd\n", hay_start, sizeof(long));
166+
167+
for (needle_start = 0; needle_start < sizeof(long); needle_start++) {
168+
169+
/* Generate LOOPS random hay sizes */
170+
for (hay_size_loop = 0; hay_size_loop < LOOPS; hay_size_loop++) {
171+
hay_size = rand_size(HAY_MAX - hay_start);
172+
size_t needle_max = NEEDLE_MAX - needle_start;
173+
if (needle_max > hay_size)
174+
needle_max = hay_size;
175+
176+
/* Generate LOOPS random needle sizes */
177+
for (needle_size_loop = 0; needle_size_loop < LOOPS; needle_size_loop++) {
178+
needle_size = rand_size(needle_max);
179+
180+
/* Generate LOOPS random needle locations */
181+
for (needle_pos_loop = 0; needle_pos_loop < LOOPS; needle_pos_loop++) {
182+
needle_pos = rand_pos(hay_size - needle_size);
183+
184+
uint8_t *hay_cur = &hay[hay_start];
185+
uint8_t *needle_cur = &needle[needle_start];
186+
187+
#if 0
188+
printf("hay_start %zu hay_size %zu needle_start %zu needle_size %zu needle_pos %zu\n",
189+
hay_start, hay_size, needle_start, needle_size, needle_pos);
190+
#endif
191+
192+
/* Set up the data */
193+
memset(hay, 0, HAY_MAX);
194+
memset(needle, 0, NEEDLE_MAX);
195+
generate_hay(hay_cur, hay_size);
196+
generate_hay(needle_cur, needle_size);
197+
198+
/*
199+
* Make sure the needle doesn't already exist in hay by
200+
* adjusting both
201+
*/
202+
fixup_hay(hay_cur, hay_size, needle_cur, needle_size);
203+
204+
/* Place the needle in the haystack */
205+
memcpy(&hay_cur[needle_pos], needle_cur, needle_size);
206+
207+
uint8_t *result;
208+
209+
result = memmem(hay_cur, hay_size, needle_cur, needle_size);
210+
211+
if (result != hay_cur + needle_pos) {
212+
printf("expected needle at %zu got %zu\n",
213+
needle_pos, result - hay_cur);
214+
printf("hay_start %zu hay_size %zu needle_start %zu needle_size %zu needle_pos %zu\n",
215+
hay_start, hay_size, needle_start, needle_size, needle_pos);
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+
size_t damage_pos = rand_elt(needle_size);
224+
hay_cur[needle_pos + damage_pos] ^= 1;
225+
226+
result = memmem(hay_cur, hay_size, needle_cur, needle_size);
227+
228+
if (result != NULL) {
229+
printf("expected no needle, got %zu\n", result - hay_cur);
230+
printf("hay_start %zu hay_size %zu needle_start %zu needle_size %zu needle_pos %zu\n",
231+
hay_start, hay_size, needle_start, needle_size, needle_pos);
232+
ret = 1;
233+
}
234+
}
235+
}
236+
}
237+
}
238+
}
239+
return ret;
240+
}

0 commit comments

Comments
 (0)