1 /*
2  * Copyright (c) 2015-2017, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 
31 #include "gtest/gtest.h"
32 #include "nfa/truffle.h"
33 #include "nfa/trufflecompile.h"
34 #include "util/charreach.h"
35 #include "util/simd_utils.h"
36 
37 using namespace ue2;
38 
TEST(Truffle,CompileDot)39 TEST(Truffle, CompileDot) {
40     m128 mask1, mask2;
41     memset(&mask1, 0, sizeof(mask1));
42     memset(&mask2, 0, sizeof(mask2));
43 
44     CharReach chars;
45 
46     chars.setall();
47 
48     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
49 
50     CharReach out = truffle2cr((u8 *)&mask1, (u8 *)&mask2);
51 
52     ASSERT_EQ(out, chars);
53 
54 }
55 
TEST(Truffle,CompileChars)56 TEST(Truffle, CompileChars) {
57     m128 mask1, mask2;
58 
59     CharReach chars;
60 
61     // test one char at a time
62     for (u32 c = 0; c < 256; ++c) {
63         mask1 = zeroes128();
64         mask2 = zeroes128();
65         chars.clear();
66         chars.set((u8)c);
67         truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
68         CharReach out = truffle2cr((u8 *)&mask1, (u8 *)&mask2);
69         ASSERT_EQ(out, chars);
70     }
71 
72     // set all chars up to dot
73     for (u32 c = 0; c < 256; ++c) {
74         mask1 = zeroes128();
75         mask2 = zeroes128();
76         chars.set((u8)c);
77         truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
78         CharReach out = truffle2cr((u8 *)&mask1, (u8 *)&mask2);
79         ASSERT_EQ(out, chars);
80     }
81 
82     // unset all chars from dot
83     for (u32 c = 0; c < 256; ++c) {
84         mask1 = zeroes128();
85         mask2 = zeroes128();
86         chars.clear((u8)c);
87         truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
88         CharReach out = truffle2cr((u8 *)&mask1, (u8 *)&mask2);
89         ASSERT_EQ(out, chars);
90     }
91 
92 }
93 
TEST(Truffle,ExecNoMatch1)94 TEST(Truffle, ExecNoMatch1) {
95     m128 mask1, mask2;
96     memset(&mask1, 0, sizeof(mask1));
97     memset(&mask2, 0, sizeof(mask2));
98 
99     CharReach chars;
100 
101     chars.set('a');
102 
103     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
104 
105     char t1[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\xff";
106 
107     for (size_t i = 0; i < 16; i++) {
108         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
109 
110         ASSERT_EQ((size_t)t1 + strlen(t1), (size_t)rv);
111     }
112 }
113 
TEST(Truffle,ExecNoMatch2)114 TEST(Truffle, ExecNoMatch2) {
115     m128 mask1, mask2;
116 
117     CharReach chars;
118 
119     chars.set('a');
120     chars.set('B');
121 
122     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
123 
124     char t1[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
125 
126     for (size_t i = 0; i < 16; i++) {
127         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
128 
129         ASSERT_EQ((size_t)t1 + strlen(t1), (size_t)rv);
130     }
131 }
132 
TEST(Truffle,ExecNoMatch3)133 TEST(Truffle, ExecNoMatch3) {
134     m128 mask1, mask2;
135 
136     CharReach chars;
137 
138     chars.set('V'); /* V = 0x56, e = 0x65 */
139 
140     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
141 
142     char t1[] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
143 
144     for (size_t i = 0; i < 16; i++) {
145         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
146 
147         ASSERT_EQ((size_t)t1 + strlen(t1), (size_t)rv);
148     }
149 }
150 
TEST(Truffle,ExecMiniMatch0)151 TEST(Truffle, ExecMiniMatch0) {
152     m128 lo, hi;
153 
154     CharReach chars;
155     chars.set('a');
156 
157     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
158 
159     char t1[] = "a";
160 
161     const u8 *rv = truffleExec(lo, hi, (u8 *)t1, (u8 *)t1 + strlen(t1));
162 
163     ASSERT_EQ((size_t)t1, (size_t)rv);
164 }
165 
TEST(Truffle,ExecMiniMatch1)166 TEST(Truffle, ExecMiniMatch1) {
167     m128 lo, hi;
168 
169     CharReach chars;
170     chars.set('a');
171 
172     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
173 
174     char t1[] = "bbbbbbbabbb";
175 
176     const u8 *rv = truffleExec(lo, hi, (u8 *)t1, (u8 *)t1 + strlen(t1));
177 
178     ASSERT_EQ((size_t)t1 + 7, (size_t)rv);
179 }
180 
TEST(Truffle,ExecMiniMatch2)181 TEST(Truffle, ExecMiniMatch2) {
182     m128 lo, hi;
183 
184     CharReach chars;
185     chars.set(0);
186 
187     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
188 
189     char t1[] = "bbbbbbb\0bbb";
190 
191     const u8 *rv = truffleExec(lo, hi, (u8 *)t1, (u8 *)t1 + 11);
192 
193     ASSERT_EQ((size_t)t1 + 7, (size_t)rv);
194 }
195 
TEST(Truffle,ExecMiniMatch3)196 TEST(Truffle, ExecMiniMatch3) {
197     m128 lo, hi;
198 
199     CharReach chars;
200     chars.set('a');
201 
202     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
203 
204     char t1[] = "\0\0\0\0\0\0\0a\0\0\0";
205 
206     const u8 *rv = truffleExec(lo, hi, (u8 *)t1, (u8 *)t1 + 11);
207 
208     ASSERT_EQ((size_t)t1 + 7, (size_t)rv);
209 }
210 
TEST(Truffle,ExecMatchBig)211 TEST(Truffle, ExecMatchBig) {
212     m128 lo, hi;
213 
214     CharReach chars;
215     chars.set('a');
216 
217     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
218 
219     std::array<u8, 400> t1;
220     t1.fill('b');
221     t1[120] = 'a';
222 
223     for (size_t i = 0; i < 16; i++) {
224         const u8 *rv = truffleExec(lo, hi, (u8 *)t1.data() + i, (u8 *)t1.data() + 399);
225 
226         ASSERT_LE(((size_t)t1.data() + 120) & ~0xf, (size_t)rv);
227     }
228 }
229 
TEST(Truffle,ExecMatch1)230 TEST(Truffle, ExecMatch1) {
231     m128 mask1, mask2;
232 
233     CharReach chars;
234 
235     chars.set('a');
236 
237     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
238 
239     /*          0123456789012345678901234567890 */
240     char t1[] = "bbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbb";
241 
242     for (size_t i = 0; i < 16; i++) {
243         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
244 
245         ASSERT_EQ((size_t)t1 + 17, (size_t)rv);
246     }
247 }
248 
TEST(Truffle,ExecMatch2)249 TEST(Truffle, ExecMatch2) {
250     m128 mask1, mask2;
251 
252     CharReach chars;
253 
254     chars.set('a');
255 
256     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
257 
258     /*          0123456789012345678901234567890 */
259     char t1[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
260 
261     for (size_t i = 0; i < 16; i++) {
262         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
263 
264         ASSERT_EQ((size_t)t1 + 17, (size_t)rv);
265     }
266 }
267 
TEST(Truffle,ExecMatch3)268 TEST(Truffle, ExecMatch3) {
269     m128 mask1, mask2;
270 
271     CharReach chars;
272 
273     chars.set('a');
274     chars.set('B');
275 
276     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
277 
278     /*          0123456789012345678901234567890 */
279     char t1[] = "bbbbbbbbbbbbbbbbbBaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
280 
281     for (size_t i = 0; i < 16; i++) {
282         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
283 
284         ASSERT_EQ((size_t)t1 + 17, (size_t)rv);
285     }
286 }
287 
TEST(Truffle,ExecMatch4)288 TEST(Truffle, ExecMatch4) {
289     m128 mask1, mask2;
290 
291     CharReach chars;
292 
293     chars.set('a');
294     chars.set('C');
295     chars.set('A');
296     chars.set('c');
297 
298     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
299 
300     /*          0123456789012345678901234567890 */
301     char t1[] = "bbbbbbbbbbbbbbbbbAaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
302     char t2[] = "bbbbbbbbbbbbbbbbbCaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
303     char t3[] = "bbbbbbbbbbbbbbbbbcaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
304     char t4[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbabbbbbbbbbbbb";
305 
306     for (size_t i = 0; i < 16; i++) {
307         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1 + i, (u8 *)t1 + strlen(t1));
308 
309         ASSERT_EQ((size_t)t1 + 17, (size_t)rv);
310 
311         rv = truffleExec(mask1, mask2, (u8 *)t2 + i, (u8 *)t2 + strlen(t1));
312 
313         ASSERT_EQ((size_t)t2 + 17, (size_t)rv);
314 
315         rv = truffleExec(mask1, mask2, (u8 *)t3 + i, (u8 *)t3 + strlen(t3));
316 
317         ASSERT_EQ((size_t)t3 + 17, (size_t)rv);
318 
319         rv = truffleExec(mask1, mask2, (u8 *)t4 + i, (u8 *)t4 + strlen(t4));
320 
321         ASSERT_EQ((size_t)t4 + 17, (size_t)rv);
322     }
323 }
324 
TEST(Truffle,ExecMatch5)325 TEST(Truffle, ExecMatch5) {
326     m128 mask1, mask2;
327 
328     CharReach chars;
329 
330     chars.set('a');
331 
332     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
333 
334     char t1[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
335 
336     for (size_t i = 0; i < 31; i++) {
337         t1[48 - i] = 'a';
338         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + strlen(t1));
339 
340         ASSERT_EQ((size_t)&t1[48 - i], (size_t)rv);
341     }
342 }
343 
TEST(Truffle,ExecMatch6)344 TEST(Truffle, ExecMatch6) {
345     m128 mask1, mask2;
346 
347     CharReach chars;
348 
349     // [0-Z] - includes some graph chars
350     chars.setRange('0', 'Z');
351 
352     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
353 
354     std::array<u8, 128> t1;
355     t1.fill('*'); // it's full of stars!
356 
357     for (u8 c = '0'; c <= 'Z'; c++) {
358         t1[17] = c;
359         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1.data(), (u8 *)t1.data() + 128);
360 
361         ASSERT_EQ((size_t)t1.data() + 17, (size_t)rv);
362     }
363 }
364 
TEST(Truffle,ExecMatch7)365 TEST(Truffle, ExecMatch7) {
366     m128 mask1, mask2;
367 
368     CharReach chars;
369 
370     // hi bits
371     chars.setRange(127, 255);
372 
373     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
374 
375     std::array<u8, 128> t1;
376     t1.fill('*'); // it's full of stars!
377 
378     for (unsigned int c = 127; c <= 255; c++) {
379         t1[40] = (u8)c;
380         const u8 *rv = truffleExec(mask1, mask2, (u8 *)t1.data(), (u8 *)t1.data() + 128);
381 
382         ASSERT_EQ((size_t)t1.data() + 40, (size_t)rv);
383     }
384 }
385 
TEST(ReverseTruffle,ExecNoMatch1)386 TEST(ReverseTruffle, ExecNoMatch1) {
387     m128 mask1, mask2;
388 
389     CharReach chars;
390     chars.set('a');
391 
392     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
393 
394     char t[] = " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
395     char *t1 = t + 1;
396     size_t len = strlen(t1);
397 
398     for (size_t i = 0; i < 16; i++) {
399         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
400         ASSERT_EQ((const u8 *)t, rv);
401     }
402 }
403 
TEST(ReverseTruffle,ExecNoMatch2)404 TEST(ReverseTruffle, ExecNoMatch2) {
405     m128 mask1, mask2;
406 
407     CharReach chars;
408 
409     chars.set('a');
410     chars.set('B');
411 
412     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
413 
414     char t[] = " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
415     char *t1 = t + 1;
416     size_t len = strlen(t1);
417 
418     for (size_t i = 0; i < 16; i++) {
419         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
420         ASSERT_EQ((const u8 *)t, rv);
421     }
422 }
423 
TEST(ReverseTruffle,ExecNoMatch3)424 TEST(ReverseTruffle, ExecNoMatch3) {
425     m128 mask1, mask2;
426 
427     CharReach chars;
428     chars.set('V'); /* V = 0x56, e = 0x65 */
429 
430     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
431 
432     char t[] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
433     char *t1 = t + 1;
434     size_t len = strlen(t1);
435 
436     for (size_t i = 0; i < 16; i++) {
437         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
438         ASSERT_EQ((const u8 *)t, rv);
439     }
440 }
441 
TEST(ReverseTruffle,ExecMiniMatch0)442 TEST(ReverseTruffle, ExecMiniMatch0) {
443     m128 lo, hi;
444 
445     CharReach chars;
446     chars.set('a');
447 
448     truffleBuildMasks(chars, (u8 *)&lo, (u8 *)&hi);
449 
450     char t1[] = "a";
451 
452     const u8 *rv = rtruffleExec(lo, hi, (u8 *)t1, (u8 *)t1 + strlen(t1));
453 
454     ASSERT_EQ((size_t)t1, (size_t)rv);
455 }
456 
TEST(ReverseTruffle,ExecMiniMatch1)457 TEST(ReverseTruffle, ExecMiniMatch1) {
458     m128 mask1, mask2;
459 
460     CharReach chars;
461     chars.set('a');
462 
463     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
464 
465     /*          0123456789012345678901234567890 */
466     char t1[] = "bbbbbbbabbbb";
467     size_t len = strlen(t1);
468 
469     const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len);
470     ASSERT_NE((const u8 *)t1 - 1, rv); // not found
471     EXPECT_EQ('a', (char)*rv);
472     ASSERT_EQ((const u8 *)t1 + 7, rv);
473 }
474 
TEST(ReverseTruffle,ExecMiniMatch2)475 TEST(ReverseTruffle, ExecMiniMatch2) {
476     m128 mask1, mask2;
477 
478     CharReach chars;
479     chars.set('a');
480 
481     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
482 
483     /*          0123456789012345678901234567890 */
484     char t1[] = "babbbbbabbbb";
485     size_t len = strlen(t1);
486 
487     const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len);
488     ASSERT_NE((const u8 *)t1 - 1, rv); // not found
489     EXPECT_EQ('a', (char)*rv);
490     ASSERT_EQ((const u8 *)t1 + 7, rv);
491 }
492 
493 
TEST(ReverseTruffle,ExecMatch1)494 TEST(ReverseTruffle, ExecMatch1) {
495     m128 mask1, mask2;
496 
497     CharReach chars;
498     chars.set('a');
499 
500     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
501 
502     /*          0123456789012345678901234567890 */
503     char t1[] = "bbbbbbabbbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
504     size_t len = strlen(t1);
505 
506     for (size_t i = 0; i < 16; i++) {
507         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
508         ASSERT_NE((const u8 *)t1 - 1, rv); // not found
509         EXPECT_EQ('a', (char)*rv);
510         ASSERT_EQ((const u8 *)t1 + 17, rv);
511     }
512 }
513 
TEST(ReverseTruffle,ExecMatch2)514 TEST(ReverseTruffle, ExecMatch2) {
515     m128 mask1, mask2;
516 
517     CharReach chars;
518     chars.set('a');
519 
520     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
521 
522     /*          0123456789012345678901234567890 */
523     char t1[] = "bbbbabbbbbbbbbbbbaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbb";
524     size_t len = strlen(t1);
525 
526     for (size_t i = 0; i < 16; i++) {
527         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
528         ASSERT_NE((const u8 *)t1 - 1, rv); // not found
529         EXPECT_EQ('a', (char)*rv);
530         ASSERT_EQ((const u8 *)t1 + 32, rv);
531     }
532 }
533 
TEST(ReverseTruffle,ExecMatch3)534 TEST(ReverseTruffle, ExecMatch3) {
535     m128 mask1, mask2;
536 
537     CharReach chars;
538     chars.set('a');
539     chars.set('B');
540 
541     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
542 
543     /*          0123456789012345678901234567890 */
544     char t1[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaBbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
545     size_t len = strlen(t1);
546 
547     for (size_t i = 0; i < 16; i++) {
548         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
549         ASSERT_NE((const u8 *)t1 - 1, rv); // not found
550         EXPECT_EQ('B', (char)*rv);
551         ASSERT_EQ((const u8 *)t1 + 32, rv);
552     }
553 
554     // check that we match the 'a' bytes as well.
555     ASSERT_EQ('B', t1[32]);
556     t1[32] = 'b';
557     for (size_t i = 0; i < 16; i++) {
558         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
559         ASSERT_NE((const u8 *)t1 - 1, rv); // not found
560         EXPECT_EQ('a', (char)*rv);
561         ASSERT_EQ((const u8 *)t1 + 31, rv);
562     }
563 }
564 
TEST(ReverseTruffle,ExecMatch4)565 TEST(ReverseTruffle, ExecMatch4) {
566     m128 mask1, mask2;
567 
568     CharReach chars;
569     chars.set('a');
570     chars.set('C');
571     chars.set('A');
572     chars.set('c');
573 
574     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
575 
576     /*          0123456789012345678901234567890 */
577     char t1[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaAbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
578     char t2[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaCbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
579     char t3[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaacbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
580     char t4[] = "bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbb";
581     size_t len = strlen(t1);
582 
583     for (size_t i = 0; i < 16; i++) {
584         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len - i);
585         EXPECT_EQ('A', (char)*rv);
586         ASSERT_EQ((const u8 *)t1 + 32, rv);
587 
588         rv = rtruffleExec(mask1, mask2, (u8 *)t2, (u8 *)t2 + len - i);
589         EXPECT_EQ('C', (char)*rv);
590         ASSERT_EQ((const u8 *)t2 + 32, rv);
591 
592         rv = rtruffleExec(mask1, mask2, (u8 *)t3, (u8 *)t3 + len - i);
593         EXPECT_EQ('c', (char)*rv);
594         ASSERT_EQ((const u8 *)t3 + 32, rv);
595 
596         rv = rtruffleExec(mask1, mask2, (u8 *)t4, (u8 *)t4 + len - i);
597         EXPECT_EQ('a', (char)*rv);
598         ASSERT_EQ((const u8 *)t4 + 32, rv);
599     }
600 }
601 
TEST(ReverseTruffle,ExecMatch5)602 TEST(ReverseTruffle, ExecMatch5) {
603     m128 mask1, mask2;
604 
605     CharReach chars;
606     chars.set('a');
607 
608     truffleBuildMasks(chars, (u8 *)&mask1, (u8 *)&mask2);
609 
610     char t1[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
611     size_t len = strlen(t1);
612 
613     for (size_t i = 0; i < len; i++) {
614         t1[i] = 'a';
615         const u8 *rv = rtruffleExec(mask1, mask2, (u8 *)t1, (u8 *)t1 + len);
616 
617         ASSERT_EQ((const u8 *)t1 + i, rv);
618     }
619 }
620