1 /*
2 * Copyright (c) 2026 Faraz Vahedi <kfv@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 /*
8 * Test for bsearch_s() routine.
9 */
10
11 #include <stdint.h>
12 #include <stdlib.h>
13
14 #define THUNK 42
15
16 #include "test-search.h"
17
18 static errno_t error_code;
19 static int compar_calls;
20
21 static int
searchhelp_s(const void * a,const void * b,void * thunk)22 searchhelp_s(const void *a, const void *b, void *thunk)
23 {
24 compar_calls++;
25 if (thunk != NULL)
26 ATF_REQUIRE_EQ(*(int *)thunk, THUNK);
27 return (searchhelp(a, b));
28 }
29
30 static void
constraint_handler(const char * restrict msg __unused,void * restrict ptr __unused,errno_t error)31 constraint_handler(const char * restrict msg __unused,
32 void * restrict ptr __unused, errno_t error)
33 {
34 error_code = error;
35 }
36
37 static void
expect_viol(const void * key,const void * base,rsize_t nmemb,rsize_t size,int (* compar)(const void *,const void *,void *),void * thunk)38 expect_viol(const void *key, const void *base, rsize_t nmemb, rsize_t size,
39 int (*compar)(const void *, const void *, void *), void *thunk)
40 {
41 error_code = 0;
42 compar_calls = 0;
43 ATF_CHECK(bsearch_s(key, base, nmemb, size, compar, thunk) == NULL);
44 ATF_CHECK(error_code > 0);
45 ATF_CHECK_EQ(compar_calls, 0);
46 }
47
48 static void *
do_bsearch_s(const int * key,const int * base,size_t n,void * ctx)49 do_bsearch_s(const int *key, const int *base, size_t n, void *ctx)
50 {
51 return (bsearch_s(key, base, n, sizeof(int), searchhelp_s, ctx));
52 }
53
54 ATF_TC_WITHOUT_HEAD(bsearch_s_constraints);
ATF_TC_BODY(bsearch_s_constraints,tc)55 ATF_TC_BODY(bsearch_s_constraints, tc)
56 {
57 int thunk = THUNK;
58 int key = 4;
59 int b[] = { 4, 7, 81 };
60
61 set_constraint_handler_s(constraint_handler);
62 expect_viol(&key, b, -1, sizeof(int), searchhelp_s, &thunk);
63 expect_viol(&key, b, RSIZE_MAX + 1, sizeof(int), searchhelp_s, &thunk);
64 expect_viol(&key, b, nitems(b), -1, searchhelp_s, &thunk);
65 expect_viol(&key, b, nitems(b), RSIZE_MAX + 1, searchhelp_s, &thunk);
66 expect_viol(NULL, b, nitems(b), sizeof(int), searchhelp_s, &thunk);
67 expect_viol(&key, NULL, 1, sizeof(int), searchhelp_s, &thunk);
68 expect_viol(&key, b, nitems(b), sizeof(int), NULL, &thunk);
69 /* size > RSIZE_MAX is a violation even when nmemb is zero. */
70 expect_viol(&key, b, 0, RSIZE_MAX + 1, searchhelp_s, &thunk);
71 }
72
73 ATF_TC_WITHOUT_HEAD(bsearch_s_nmemb_zero);
ATF_TC_BODY(bsearch_s_nmemb_zero,tc)74 ATF_TC_BODY(bsearch_s_nmemb_zero, tc)
75 {
76 int thunk = THUNK;
77 int key = 4;
78 int b[] = { 4, 7, 81 };
79
80 error_code = 0;
81 compar_calls = 0;
82 set_constraint_handler_s(constraint_handler);
83 ATF_CHECK(bsearch_s(&key, b, 0, sizeof(int), searchhelp_s,
84 &thunk) == NULL);
85 ATF_CHECK(error_code == 0);
86 ATF_CHECK_EQ(compar_calls, 0);
87 ATF_CHECK(bsearch_s(NULL, NULL, 0, 0, NULL, NULL) == NULL);
88 ATF_CHECK(error_code == 0);
89 }
90
91 ATF_TC_WITHOUT_HEAD(bsearch_s_h);
ATF_TC_BODY(bsearch_s_h,tc)92 ATF_TC_BODY(bsearch_s_h, tc)
93 {
94 int thunk = THUNK;
95 int b[] = { 4, 7, 81 };
96 int key = 7;
97 int *found;
98
99 error_code = 0;
100 compar_calls = 0;
101 set_constraint_handler_s(constraint_handler);
102 found = bsearch_s(&key, b, nitems(b), sizeof(int), searchhelp_s,
103 &thunk);
104 ATF_CHECK(error_code == 0);
105 ATF_CHECK(compar_calls > 0);
106 ATF_CHECK(found == &b[1]);
107
108 compar_calls = 0;
109 found = bsearch_s(&key, b, nitems(b), sizeof(int), searchhelp_s, NULL);
110 ATF_CHECK(found == &b[1]);
111 ATF_CHECK(compar_calls > 0);
112 }
113
114 ATF_TC_WITHOUT_HEAD(bsearch_s_test);
ATF_TC_BODY(bsearch_s_test,tc)115 ATF_TC_BODY(bsearch_s_test, tc)
116 {
117 int testvector[SVEC_LEN];
118 int thunk = THUNK;
119 int j;
120
121 for (j = 1; j <= SVEC_LEN; j++)
122 check_sorted_search(do_bsearch_s, &thunk, testvector,
123 (size_t)j);
124 }
125
ATF_TP_ADD_TCS(tp)126 ATF_TP_ADD_TCS(tp)
127 {
128 ATF_TP_ADD_TC(tp, bsearch_s_constraints);
129 ATF_TP_ADD_TC(tp, bsearch_s_nmemb_zero);
130 ATF_TP_ADD_TC(tp, bsearch_s_h);
131 ATF_TP_ADD_TC(tp, bsearch_s_test);
132
133 return (atf_no_error());
134 }
135