xref: /netbsd-src/tests/lib/libc/regex/t_exhaust.c (revision 381ab8c9c7f533c53a0242b33a0e7650b86c5737)
1 /*	$NetBSD: t_exhaust.c,v 1.14 2021/06/09 21:09:20 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __RCSID("$NetBSD: t_exhaust.c,v 1.14 2021/06/09 21:09:20 christos Exp $");
41 
42 #include <sys/resource.h>
43 #include <err.h>
44 
45 #ifdef TEST
46 # include <assert.h>
47 # define ATF_REQUIRE(a) assert(a)
48 # define ATF_REQUIRE_MSG(a, fmt, ...) \
49     if (!(a)) err(EXIT_FAILURE, fmt, __VA_ARGS__)
50 #else
51 # include <atf-c.h>
52 #endif
53 
54 #include <regex.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 
59 #ifndef REGEX_MAXSIZE
60 #define REGEX_MAXSIZE	9999
61 #endif
62 
63 #ifdef TRACE
64 
65 #include <dlfcn.h>
66 void *
malloc(size_t l)67 malloc(size_t l)
68 {
69 	static void *(*m)(size_t);
70 	static int q;
71 	if (m == NULL) m = dlsym(RTLD_NEXT, "malloc");
72 	void *p = (*m)(l);
73 	if (q)
74 		return p;
75 	q = 1;
76 	printf("%p m %zu\n", p, l);
77 	q = 0;
78 	return p;
79 }
80 
81 void
free(void * p)82 free(void *p)
83 {
84 	static void (*f)(void *);
85 	if (f == NULL) f = dlsym(RTLD_NEXT, "malloc");
86 	printf("%p f\n", p);
87 	(*f)(p);
88 }
89 #endif
90 
91 static char *
mkstr(const char * str,size_t len)92 mkstr(const char *str, size_t len)
93 {
94 	size_t slen = strlen(str);
95 	char *p = malloc(slen * len + 1);
96 	ATF_REQUIRE_MSG(p != NULL, "slen=%zu, len=%zu", slen, len);
97 	for (size_t i = 0; i < len; i++)
98 		strcpy(&p[i * slen], str);
99 	return p;
100 }
101 
102 static char *
concat(const char * d,const char * s)103 concat(const char *d, const char *s)
104 {
105 	size_t dlen = strlen(d);
106 	size_t slen = strlen(s);
107 	char *p = malloc(dlen + slen + 1);
108 
109 	ATF_REQUIRE_MSG(p != NULL, "slen=%zu, dlen=%zu", slen, dlen);
110 	strcpy(p, d);
111 	strcpy(p + dlen, s);
112 	return p;
113 }
114 
115 static char *
p0(size_t len)116 p0(size_t len)
117 {
118 	char *d, *s1, *s2;
119 	s1 = mkstr("\\(", len);
120 	s2 = concat(s1, ")");
121 	free(s1);
122 	d = concat("(", s2);
123 	free(s2);
124 	return d;
125 }
126 
127 static char *
p1(size_t len)128 p1(size_t len)
129 {
130 	char *d, *s1, *s2, *s3;
131 	s1 = mkstr("\\(", 60);
132 	s2 = mkstr("(.*)", len);
133 	s3 = concat(s1, s2);
134 	free(s2);
135 	free(s1);
136 	s1 = concat(s3, ")");
137 	free(s3);
138 	d = concat("(", s1);
139 	free(s1);
140 	return d;
141 }
142 
143 static char *
ps(const char * m,const char * s,size_t len)144 ps(const char *m, const char *s, size_t len)
145 {
146 	char *d, *s1, *s2, *s3;
147 	s1 = mkstr(m, len);
148 	s2 = mkstr(s, len);
149 	s3 = concat(s1, s2);
150 	free(s2);
151 	free(s1);
152 	d = concat("(.?)", s3);
153 	free(s3);
154 	return d;
155 }
156 
157 static char *
p2(size_t len)158 p2(size_t len)
159 {
160 	return ps("((.*){0,255}", ")", len);
161 }
162 
163 static char *
p3(size_t len)164 p3(size_t len)
165 {
166 	return ps("(.\\{0,}", ")", len);
167 }
168 
169 static char *
p4(size_t len)170 p4(size_t len)
171 {
172 	return ps("((.*){1,255}", ")", len);
173 }
174 
175 static char *
p5(size_t len)176 p5(size_t len)
177 {
178 	return ps("(", "){1,100}", len);
179 }
180 
181 static char *
p6(size_t len)182 p6(size_t len)
183 {
184 	char *d, *s1, *s2;
185 	s1 = mkstr("(?:(.*)|", len);
186 	s2 = concat(s1, "(.*)");
187 	free(s1);
188 	s1 = mkstr(")", len);
189 	d = concat(s2, s1);
190 	free(s1);
191 	free(s2);
192 	return d;
193 }
194 
195 static const struct {
196 	char *(*pattern)(size_t);
197 	int type;
198 } tests[] = {
199 	{ p0, REG_EXTENDED },
200 	{ p1, REG_EXTENDED },
201 	{ p2, REG_EXTENDED },
202 	{ p3, REG_EXTENDED },
203 	{ p4, REG_EXTENDED },
204 	{ p5, REG_EXTENDED },
205 	{ p6, REG_BASIC },
206 };
207 
208 static void
run(void)209 run(void)
210 {
211 	regex_t re;
212 	int e;
213 	struct rlimit limit;
214 	char *patterns[__arraycount(tests)];
215 
216 	for (size_t i = 0; i < __arraycount(patterns); i++) {
217 		patterns[i] = (*tests[i].pattern)(REGEX_MAXSIZE);
218 	}
219 
220 	limit.rlim_cur = limit.rlim_max = 256 * 1024 * 1024;
221 	ATF_REQUIRE(setrlimit(RLIMIT_VMEM, &limit) != -1);
222 
223 	for (size_t i = 0; i < __arraycount(tests); i++) {
224 		e = regcomp(&re, patterns[i], tests[i].type);
225 		if (e) {
226 			char ebuf[1024];
227 			(void)regerror(e, &re, ebuf, sizeof(ebuf));
228 			ATF_REQUIRE_MSG(e == REG_ESPACE,
229 			    "regcomp returned %d (%s) for pattern %zu [%s]", e,
230 			    ebuf, i, patterns[i]);
231 			continue;
232 		}
233 		(void)regexec(&re, "aaaaaaaaaaa", 0, NULL, 0);
234 		regfree(&re);
235 	}
236 	for (size_t i = 0; i < __arraycount(patterns); i++) {
237 		free(patterns[i]);
238 	}
239 }
240 
241 #ifndef TEST
242 
243 ATF_TC(regcomp_too_big);
244 
ATF_TC_HEAD(regcomp_too_big,tc)245 ATF_TC_HEAD(regcomp_too_big, tc)
246 {
247 
248 	atf_tc_set_md_var(tc, "descr", "Check that large patterns don't"
249 	    " crash, but return a proper error code");
250 	// libtre needs it.
251 	atf_tc_set_md_var(tc, "timeout", "600");
252 	atf_tc_set_md_var(tc, "require.memory", "256M");
253 }
254 
ATF_TC_BODY(regcomp_too_big,tc)255 ATF_TC_BODY(regcomp_too_big, tc)
256 {
257 	run();
258 }
259 
ATF_TP_ADD_TCS(tp)260 ATF_TP_ADD_TCS(tp)
261 {
262 
263 	ATF_TP_ADD_TC(tp, regcomp_too_big);
264 	return atf_no_error();
265 }
266 #else
267 int
main(void)268 main(void)
269 {
270 	run();
271 	return 0;
272 }
273 #endif
274