xref: /llvm-project/compiler-rt/test/sanitizer_common/TestCases/Posix/regex_startend.cpp (revision 3b8b5d1f22f2c5d8ae55709a92d02011dea056ca)
1 // RUN: %clangxx -O0 -g %s -o %t && %run %t
2 /// Check that REG_STARTEND is handled correctly.
3 /// This is a regression test for https://github.com/google/sanitizers/issues/1371
4 /// Previously, on GLibc systems, the interceptor was calling __compat_regexec
5 /// (regexec@GLIBC_2.2.5) insead of the newer __regexec (regexec@GLIBC_2.3.4).
6 /// The __compat_regexec strips the REG_STARTEND flag but does not report an error
7 /// if other flags are present. This can result in infinite loops for programs that
8 /// use REG_STARTEND to find all matches inside a buffer (since ignoring REG_STARTEND
9 /// means that the search always starts from the first character).
10 
11 #include <assert.h>
12 #include <regex.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 /// REG_STARTEND is a BSD extension not supported everywhere.
18 #ifdef REG_STARTEND
test_matched(const regex_t * preg,const char * string,size_t start,size_t end,const char * expected)19 void test_matched(const regex_t *preg, const char *string, size_t start,
20                   size_t end, const char *expected) {
21   regmatch_t match[1];
22   match[0].rm_so = start;
23   match[0].rm_eo = end;
24   int rv = regexec(preg, string, 1, match, REG_STARTEND);
25   int matchlen = (int)(match[0].rm_eo - match[0].rm_so);
26   const char *matchstart = string + match[0].rm_so;
27   if (rv == 0) {
28     if (expected == nullptr) {
29       fprintf(stderr, "ERROR: expected no match but got '%.*s'\n",
30               matchlen, matchstart);
31       abort();
32     } else if ((size_t)matchlen != strlen(expected) ||
33                memcmp(matchstart, expected, strlen(expected)) != 0) {
34       fprintf(stderr, "ERROR: expected '%s' match but got '%.*s'\n",
35               expected, matchlen, matchstart);
36       abort();
37     }
38   } else if (rv == REG_NOMATCH) {
39     if (expected != nullptr) {
40       fprintf(stderr, "ERROR: expected '%s' match but got no match\n", expected);
41       abort();
42     }
43   } else {
44     printf("ERROR: unexpected regexec return value %d\n", rv);
45     abort();
46   }
47 }
48 
main(void)49 int main(void) {
50   regex_t regex;
51   int rv = regcomp(&regex, "[A-Z][A-Z]", 0);
52   assert(!rv);
53   test_matched(&regex, "ABCD", 0, 4, "AB");
54   test_matched(&regex, "ABCD", 0, 1, nullptr); // Not long enough
55   test_matched(&regex, "ABCD", 1, 4, "BC");
56   test_matched(&regex, "ABCD", 1, 2, nullptr); // Not long enough
57   test_matched(&regex, "ABCD", 2, 4, "CD");
58   test_matched(&regex, "ABCD", 2, 3, nullptr); // Not long enough
59   test_matched(&regex, "ABCD", 3, 4, nullptr); // Not long enough
60   regfree(&regex);
61   printf("Successful test\n");
62   return 0;
63 }
64 #else
main(void)65 int main(void) {
66   return 0;
67 }
68 #endif
69