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 "ue2common.h"
32 #include "hwlm/noodle_build.h"
33 #include "hwlm/noodle_engine.h"
34 #include "hwlm/hwlm.h"
35 #include "hwlm/hwlm_literal.h"
36 #include "scratch.h"
37 #include "util/alloc.h"
38 #include "util/ue2string.h"
39 
40 #include <cstring>
41 #include <vector>
42 #include "gtest/gtest.h"
43 
44 using std::unique_ptr;
45 using std::vector;
46 using namespace ue2;
47 
48 struct hlmMatchEntry {
49     size_t to;
50     u32 id;
hlmMatchEntryhlmMatchEntry51     hlmMatchEntry(size_t end, u32 identifier) :
52             to(end), id(identifier) {}
53 };
54 
55 vector<hlmMatchEntry> ctxt;
56 
57 static
hlmSimpleCallback(size_t to,u32 id,UNUSED struct hs_scratch * scratch)58 hwlmcb_rv_t hlmSimpleCallback(size_t to, u32 id,
59                               UNUSED struct hs_scratch *scratch) {
60     DEBUG_PRINTF("match @%zu = %u\n", to, id);
61 
62     ctxt.push_back(hlmMatchEntry(to, id));
63 
64     return HWLM_CONTINUE_MATCHING;
65 }
66 
67 static
noodleMatch(const u8 * data,size_t data_len,const char * lit_str,size_t lit_len,char nocase,HWLMCallback cb)68 void noodleMatch(const u8 *data, size_t data_len, const char *lit_str,
69                  size_t lit_len, char nocase, HWLMCallback cb) {
70     u32 id = 1000;
71     hwlmLiteral lit(std::string(lit_str, lit_len), nocase, id);
72     auto n = noodBuildTable(lit);
73     ASSERT_TRUE(n != nullptr);
74 
75     hwlm_error_t rv;
76     struct hs_scratch scratch;
77     rv = noodExec(n.get(), data, data_len, 0, cb, &scratch);
78     ASSERT_EQ(HWLM_SUCCESS, rv);
79 }
80 
TEST(Noodle,nood1)81 TEST(Noodle, nood1) {
82     const size_t data_len = 1024;
83     unsigned int i, j;
84     u8 data[data_len];
85 
86     memset(data, 'a', data_len);
87 
88     noodleMatch(data, data_len, "a", 1, 0, hlmSimpleCallback);
89     ASSERT_EQ(1024U, ctxt.size());
90     for (i = 0; i < 1024; i++) {
91         ASSERT_EQ(i, ctxt[i].to);
92     }
93 
94     ctxt.clear();
95     noodleMatch(data, data_len, "A", 1, 0, hlmSimpleCallback);
96     ASSERT_EQ(0U, ctxt.size());
97 
98     ctxt.clear();
99     noodleMatch(data, data_len, "A", 1, 1, hlmSimpleCallback);
100     ASSERT_EQ(1024U, ctxt.size());
101     for (i = 0; i < 1024; i++) {
102         ASSERT_EQ(i, ctxt[i].to);
103     }
104 
105     for (j = 0; j < 16; j++) {
106         ctxt.clear();
107         noodleMatch(data + j, data_len - j, "A", 1, 1, hlmSimpleCallback);
108         ASSERT_EQ(1024 - j, ctxt.size());
109         for (i = 0; i < 1024 - j; i++) {
110             ASSERT_EQ(i, ctxt[i].to);
111         }
112 
113         ctxt.clear();
114         noodleMatch(data, data_len - j, "A", 1, 1, hlmSimpleCallback);
115         ASSERT_EQ(1024 - j, ctxt.size());
116         for (i = 0; i < 1024 - j; i++) {
117             ASSERT_EQ(i, ctxt[i].to);
118         }
119     }
120     ctxt.clear();
121 }
122 
TEST(Noodle,nood2)123 TEST(Noodle, nood2) {
124     const size_t data_len = 1024;
125     unsigned int i, j;
126     u8 data[data_len];
127 
128     memset(data, 'a', data_len);
129 
130     noodleMatch(data, data_len, "aa", 2, 0, hlmSimpleCallback);
131     ASSERT_EQ(1023U, ctxt.size());
132     for (i = 0; i < 1023; i++) {
133         ASSERT_EQ(i + 1, ctxt[i].to);
134     }
135 
136     ctxt.clear();
137     noodleMatch(data, data_len, "aA", 2, 0, hlmSimpleCallback);
138     ASSERT_EQ(0U, ctxt.size());
139 
140     ctxt.clear();
141     noodleMatch(data, data_len, "AA", 2, 0, hlmSimpleCallback);
142     ASSERT_EQ(0U, ctxt.size());
143 
144     ctxt.clear();
145     noodleMatch(data, data_len, "aa", 2, 1, hlmSimpleCallback);
146     ASSERT_EQ(1023U, ctxt.size());
147     for (i = 0; i < 1023; i++) {
148         ASSERT_EQ(i + 1, ctxt[i].to);
149     }
150 
151     ctxt.clear();
152     noodleMatch(data, data_len, "Aa", 2, 1, hlmSimpleCallback);
153     ASSERT_EQ(1023U, ctxt.size());
154     for (i = 0; i < 1023; i++) {
155         ASSERT_EQ(i + 1, ctxt[i].to);
156     }
157 
158     ctxt.clear();
159     noodleMatch(data, data_len, "AA", 2, 1, hlmSimpleCallback);
160     ASSERT_EQ(1023U, ctxt.size());
161     for (i = 0; i < 1023; i++) {
162         ASSERT_EQ(i + 1, ctxt[i].to);
163     }
164 
165     for (j = 0; j < 16; j++) {
166         ctxt.clear();
167         noodleMatch(data + j, data_len - j, "Aa", 2, 1, hlmSimpleCallback);
168         ASSERT_EQ(1023 - j, ctxt.size());
169         for (i = 0; i < 1023 - j; i++) {
170             ASSERT_EQ(i + 1, ctxt[i].to);
171         }
172 
173         ctxt.clear();
174         noodleMatch(data, data_len - j, "aA", 2, 1, hlmSimpleCallback);
175         ASSERT_EQ(1023 - j, ctxt.size());
176         for (i = 0; i < 1023 - j; i++) {
177             ASSERT_EQ(i + 1, ctxt[i].to);
178         }
179     }
180     ctxt.clear();
181 }
182 
TEST(Noodle,noodLong)183 TEST(Noodle, noodLong) {
184     const size_t data_len = 1024;
185     unsigned int i, j;
186     u8 data[data_len];
187 
188     memset(data, 'a', data_len);
189 
190     noodleMatch(data, data_len, "aaaa", 4, 0, hlmSimpleCallback);
191     ASSERT_EQ(1021U, ctxt.size());
192     for (i = 0; i < 1021; i++) {
193         ASSERT_EQ(i + 3, ctxt[i].to);
194     }
195 
196     ctxt.clear();
197     noodleMatch(data, data_len, "aaAA", 4, 0, hlmSimpleCallback);
198     ASSERT_EQ(0U, ctxt.size());
199 
200     ctxt.clear();
201     noodleMatch(data, data_len, "aaAA", 4, 1, hlmSimpleCallback);
202     ASSERT_EQ(1021U, ctxt.size());
203     for (i = 0; i < 1021; i++) {
204         ASSERT_EQ(i + 3, ctxt[i].to);
205     }
206 
207     for (j = 0; j < 16; j++) {
208         ctxt.clear();
209         noodleMatch(data + j, data_len - j, "AAaa", 4, 1, hlmSimpleCallback);
210         ASSERT_EQ(1021 - j, ctxt.size());
211         for (i = 0; i < 1021 - j; i++) {
212             ASSERT_EQ(i + 3, ctxt[i].to);
213         }
214 
215         ctxt.clear();
216         noodleMatch(data + j, data_len - j, "aaaA", 4, 1, hlmSimpleCallback);
217         ASSERT_EQ(1021 - j, ctxt.size());
218         for (i = 0; i < 1021 - j; i++) {
219             ASSERT_EQ(i + 3, ctxt[i].to);
220         }
221     }
222     ctxt.clear();
223 }
224 
TEST(Noodle,noodCutoverSingle)225 TEST(Noodle, noodCutoverSingle) {
226     const size_t max_data_len = 128;
227     u8 data[max_data_len + 15];
228 
229     memset(data, 'a', max_data_len + 15);
230 
231     for (u32 align = 0; align < 16; align++) {
232         for (u32 len = 0; len < max_data_len; len++) {
233             ctxt.clear();
234             noodleMatch(data + align, len, "a", 1, 0, hlmSimpleCallback);
235             EXPECT_EQ(len, ctxt.size());
236             for (u32 i = 0; i < ctxt.size(); i++) {
237                 ASSERT_EQ(i, ctxt[i].to);
238             }
239         }
240     }
241     ctxt.clear();
242 }
243 
TEST(Noodle,noodCutoverDouble)244 TEST(Noodle, noodCutoverDouble) {
245     const size_t max_data_len = 128;
246     u8 data[max_data_len + 15];
247 
248     memset(data, 'a', max_data_len + 15);
249 
250     for (u32 align = 0; align < 16; align++) {
251         for (u32 len = 0; len < max_data_len; len++) {
252             ctxt.clear();
253             noodleMatch(data + align, len, "aa", 2, 0, hlmSimpleCallback);
254             EXPECT_EQ(len ? len - 1 : 0U, ctxt.size());
255             for (u32 i = 0; i < ctxt.size(); i++) {
256                 ASSERT_EQ(i + 1, ctxt[i].to);
257             }
258         }
259     }
260     ctxt.clear();
261 }
262 
263