1 /*
2  * Copyright (c) 2015-2020, 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 /** \file
30  * \brief Compiler front-end, including public API calls for compilation.
31  */
32 #include "allocator.h"
33 #include "ue2common.h"
34 #include "grey.h"
35 #include "hs_compile.h"
36 #include "hs_internal.h"
37 #include "database.h"
38 #include "compiler/compiler.h"
39 #include "compiler/error.h"
40 #include "nfagraph/ng.h"
41 #include "nfagraph/ng_expr_info.h"
42 #include "parser/Parser.h"
43 #include "parser/parse_error.h"
44 #include "parser/prefilter.h"
45 #include "parser/unsupported.h"
46 #include "util/compile_error.h"
47 #include "util/cpuid_flags.h"
48 #include "util/cpuid_inline.h"
49 #include "util/depth.h"
50 #include "util/popcount.h"
51 #include "util/target_info.h"
52 
53 #include <cassert>
54 #include <cstddef>
55 #include <cstring>
56 #include <limits.h>
57 #include <string>
58 #include <vector>
59 
60 using namespace std;
61 using namespace ue2;
62 
63 /** \brief Cheap check that no unexpected mode flags are on. */
64 static
validModeFlags(unsigned int mode)65 bool validModeFlags(unsigned int mode) {
66     static const unsigned allModeFlags = HS_MODE_BLOCK
67                                        | HS_MODE_STREAM
68                                        | HS_MODE_VECTORED
69                                        | HS_MODE_SOM_HORIZON_LARGE
70                                        | HS_MODE_SOM_HORIZON_MEDIUM
71                                        | HS_MODE_SOM_HORIZON_SMALL;
72 
73     return !(mode & ~allModeFlags);
74 }
75 
76 /** \brief Validate mode flags. */
77 static
checkMode(unsigned int mode,hs_compile_error ** comp_error)78 bool checkMode(unsigned int mode, hs_compile_error **comp_error) {
79     // First, check that only bits with meaning are on.
80     if (!validModeFlags(mode)) {
81         *comp_error = generateCompileError("Invalid parameter: "
82                 "unrecognised mode flags.", -1);
83         return false;
84     }
85 
86     // Our mode must be ONE of (block, streaming, vectored).
87     unsigned checkmode
88         = mode & (HS_MODE_STREAM | HS_MODE_BLOCK | HS_MODE_VECTORED);
89     if (popcount32(checkmode) != 1) {
90         *comp_error = generateCompileError(
91             "Invalid parameter: mode must have one "
92             "(and only one) of HS_MODE_BLOCK, HS_MODE_STREAM or "
93             "HS_MODE_VECTORED set.",
94             -1);
95         return false;
96     }
97 
98     // If you specify SOM precision, you must be in streaming mode and you only
99     // get to have one.
100     unsigned somMode = mode & (HS_MODE_SOM_HORIZON_LARGE |
101                                HS_MODE_SOM_HORIZON_MEDIUM |
102                                HS_MODE_SOM_HORIZON_SMALL);
103     if (somMode) {
104         if (!(mode & HS_MODE_STREAM)) {
105             *comp_error = generateCompileError("Invalid parameter: the "
106                     "HS_MODE_SOM_HORIZON_ mode flags may only be set in "
107                     "streaming mode.", -1);
108             return false;
109 
110         }
111         if ((somMode & (somMode - 1)) != 0) {
112             *comp_error = generateCompileError("Invalid parameter: only one "
113                     "HS_MODE_SOM_HORIZON_ mode flag can be set.", -1);
114             return false;
115         }
116     }
117 
118     return true;
119 }
120 
121 static
checkPlatform(const hs_platform_info * p,hs_compile_error ** comp_error)122 bool checkPlatform(const hs_platform_info *p, hs_compile_error **comp_error) {
123     static constexpr u32 HS_TUNE_LAST = HS_TUNE_FAMILY_ICX;
124     static constexpr u32 HS_CPU_FEATURES_ALL =
125         HS_CPU_FEATURES_AVX2 | HS_CPU_FEATURES_AVX512 |
126         HS_CPU_FEATURES_AVX512VBMI;
127 
128     if (!p) {
129         return true;
130     }
131 
132     if (p->cpu_features & ~HS_CPU_FEATURES_ALL) {
133         *comp_error = generateCompileError("Invalid cpu features specified in "
134                                            "the platform information.", -1);
135         return false;
136    }
137 
138     if (p->tune > HS_TUNE_LAST) {
139         *comp_error = generateCompileError("Invalid tuning value specified in "
140                                            "the platform information.", -1);
141         return false;
142     }
143 
144     return true;
145 }
146 
147 /** \brief Convert from SOM mode to bytes of precision. */
148 static
getSomPrecision(unsigned mode)149 unsigned getSomPrecision(unsigned mode) {
150     if (mode & HS_MODE_VECTORED) {
151         /* always assume full precision for vectoring */
152         return 8;
153     }
154 
155     if (mode & HS_MODE_SOM_HORIZON_LARGE) {
156         return 8;
157     } else if (mode & HS_MODE_SOM_HORIZON_MEDIUM) {
158         return 4;
159     } else if (mode & HS_MODE_SOM_HORIZON_SMALL) {
160         return 2;
161     }
162     return 0;
163 }
164 
165 namespace ue2 {
166 
167 hs_error_t
hs_compile_multi_int(const char * const * expressions,const unsigned * flags,const unsigned * ids,const hs_expr_ext * const * ext,unsigned elements,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** comp_error,const Grey & g)168 hs_compile_multi_int(const char *const *expressions, const unsigned *flags,
169                      const unsigned *ids, const hs_expr_ext *const *ext,
170                      unsigned elements, unsigned mode,
171                      const hs_platform_info_t *platform, hs_database_t **db,
172                      hs_compile_error_t **comp_error, const Grey &g) {
173     // Check the args: note that it's OK for flags, ids or ext to be null.
174     if (!comp_error) {
175         if (db) {
176             *db = nullptr;
177         }
178         // nowhere to write the string, but we can still report an error code
179         return HS_COMPILER_ERROR;
180     }
181     if (!db) {
182         *comp_error = generateCompileError("Invalid parameter: db is NULL", -1);
183         return HS_COMPILER_ERROR;
184     }
185     if (!expressions) {
186         *db = nullptr;
187         *comp_error
188             = generateCompileError("Invalid parameter: expressions is NULL",
189                                    -1);
190         return HS_COMPILER_ERROR;
191     }
192     if (elements == 0) {
193         *db = nullptr;
194         *comp_error = generateCompileError("Invalid parameter: elements is zero", -1);
195         return HS_COMPILER_ERROR;
196     }
197 
198 #if defined(FAT_RUNTIME)
199     if (!check_ssse3()) {
200         *db = nullptr;
201         *comp_error = generateCompileError("Unsupported architecture", -1);
202         return HS_ARCH_ERROR;
203     }
204 #endif
205 
206     if (!checkMode(mode, comp_error)) {
207         *db = nullptr;
208         assert(*comp_error); // set by checkMode.
209         return HS_COMPILER_ERROR;
210     }
211 
212     if (!checkPlatform(platform, comp_error)) {
213         *db = nullptr;
214         assert(*comp_error); // set by checkPlatform.
215         return HS_COMPILER_ERROR;
216     }
217 
218     if (elements > g.limitPatternCount) {
219         *db = nullptr;
220         *comp_error = generateCompileError("Number of patterns too large", -1);
221         return HS_COMPILER_ERROR;
222     }
223 
224     // This function is simply a wrapper around both the parser and compiler
225     bool isStreaming = mode & (HS_MODE_STREAM | HS_MODE_VECTORED);
226     bool isVectored = mode & HS_MODE_VECTORED;
227     unsigned somPrecision = getSomPrecision(mode);
228 
229     target_t target_info = platform ? target_t(*platform)
230                                     : get_current_target();
231 
232     try {
233         CompileContext cc(isStreaming, isVectored, target_info, g);
234         NG ng(cc, elements, somPrecision);
235 
236         for (unsigned int i = 0; i < elements; i++) {
237             // Add this expression to the compiler
238             try {
239                 addExpression(ng, i, expressions[i], flags ? flags[i] : 0,
240                               ext ? ext[i] : nullptr, ids ? ids[i] : 0);
241             } catch (CompileError &e) {
242                 /* Caught a parse error:
243                  * throw it upstream as a CompileError with a specific index */
244                 e.setExpressionIndex(i);
245                 throw; /* do not slice */
246             }
247         }
248 
249         // Check sub-expression ids
250         ng.rm.pl.validateSubIDs(ids, expressions, flags, elements);
251         // Renumber and assign lkey to reports
252         ng.rm.logicalKeyRenumber();
253 
254         unsigned length = 0;
255         struct hs_database *out = build(ng, &length, 0);
256 
257         assert(out);    // should have thrown exception on error
258         assert(length);
259 
260         *db = out;
261         *comp_error = nullptr;
262 
263         return HS_SUCCESS;
264     }
265     catch (const CompileError &e) {
266         // Compiler error occurred
267         *db = nullptr;
268         *comp_error = generateCompileError(e.reason,
269                                            e.hasIndex ? (int)e.index : -1);
270         return HS_COMPILER_ERROR;
271     }
272     catch (const std::bad_alloc &) {
273         *db = nullptr;
274         *comp_error = const_cast<hs_compile_error_t *>(&hs_enomem);
275         return HS_COMPILER_ERROR;
276     }
277     catch (...) {
278         assert(!"Internal error, unexpected exception");
279         *db = nullptr;
280         *comp_error = const_cast<hs_compile_error_t *>(&hs_einternal);
281         return HS_COMPILER_ERROR;
282     }
283 }
284 
285 hs_error_t
hs_compile_lit_multi_int(const char * const * expressions,const unsigned * flags,const unsigned * ids,const hs_expr_ext * const * ext,const size_t * lens,unsigned elements,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** comp_error,const Grey & g)286 hs_compile_lit_multi_int(const char *const *expressions, const unsigned *flags,
287                          const unsigned *ids, const hs_expr_ext *const *ext,
288                          const size_t *lens, unsigned elements, unsigned mode,
289                          const hs_platform_info_t *platform, hs_database_t **db,
290                          hs_compile_error_t **comp_error, const Grey &g) {
291     // Check the args: note that it's OK for flags, ids or ext to be null.
292     if (!comp_error) {
293         if (db) {
294             *db = nullptr;
295         }
296         // nowhere to write the string, but we can still report an error code
297         return HS_COMPILER_ERROR;
298     }
299     if (!db) {
300         *comp_error = generateCompileError("Invalid parameter: db is NULL", -1);
301         return HS_COMPILER_ERROR;
302     }
303     if (!expressions) {
304         *db = nullptr;
305         *comp_error
306             = generateCompileError("Invalid parameter: expressions is NULL",
307                                    -1);
308         return HS_COMPILER_ERROR;
309     }
310     if (!lens) {
311         *db = nullptr;
312         *comp_error = generateCompileError("Invalid parameter: len is NULL", -1);
313         return HS_COMPILER_ERROR;
314     }
315     if (elements == 0) {
316         *db = nullptr;
317         *comp_error = generateCompileError("Invalid parameter: elements is zero", -1);
318         return HS_COMPILER_ERROR;
319     }
320 
321 #if defined(FAT_RUNTIME)
322     if (!check_ssse3()) {
323         *db = nullptr;
324         *comp_error = generateCompileError("Unsupported architecture", -1);
325         return HS_ARCH_ERROR;
326     }
327 #endif
328 
329     if (!checkMode(mode, comp_error)) {
330         *db = nullptr;
331         assert(*comp_error); // set by checkMode.
332         return HS_COMPILER_ERROR;
333     }
334 
335     if (!checkPlatform(platform, comp_error)) {
336         *db = nullptr;
337         assert(*comp_error); // set by checkPlattform.
338         return HS_COMPILER_ERROR;
339     }
340 
341     if (elements > g.limitPatternCount) {
342         *db = nullptr;
343         *comp_error = generateCompileError("Number of patterns too large", -1);
344         return HS_COMPILER_ERROR;
345     }
346 
347     // This function is simply a wrapper around both the parser and compiler
348     bool isStreaming = mode & (HS_MODE_STREAM | HS_MODE_VECTORED);
349     bool isVectored = mode & HS_MODE_VECTORED;
350     unsigned somPrecision = getSomPrecision(mode);
351 
352     target_t target_info = platform ? target_t(*platform)
353                                     : get_current_target();
354 
355     try {
356         CompileContext cc(isStreaming, isVectored, target_info, g);
357         NG ng(cc, elements, somPrecision);
358 
359         for (unsigned int i = 0; i < elements; i++) {
360             // Add this expression to the compiler
361             try {
362                 addLitExpression(ng, i, expressions[i], flags ? flags[i] : 0,
363                                  ext ? ext[i] : nullptr, ids ? ids[i] : 0,
364                                  lens[i]);
365             } catch (CompileError &e) {
366                 /* Caught a parse error;
367                  * throw it upstream as a CompileError with a specific index */
368                 e.setExpressionIndex(i);
369                 throw; /* do not slice */
370             }
371         }
372 
373         // Check sub-expression ids
374         ng.rm.pl.validateSubIDs(ids, expressions, flags, elements);
375         // Renumber and assign lkey to reports
376         ng.rm.logicalKeyRenumber();
377 
378         unsigned length = 0;
379         struct hs_database *out = build(ng, &length, 1);
380 
381         assert(out);    //should have thrown exception on error
382         assert(length);
383 
384         *db = out;
385         *comp_error = nullptr;
386 
387         return HS_SUCCESS;
388     }
389     catch (const CompileError &e) {
390         // Compiler error occurred
391         *db = nullptr;
392         *comp_error = generateCompileError(e.reason,
393                                            e.hasIndex ? (int)e.index : -1);
394         return HS_COMPILER_ERROR;
395     }
396     catch (const std::bad_alloc &) {
397         *db = nullptr;
398         *comp_error = const_cast<hs_compile_error_t *>(&hs_enomem);
399         return HS_COMPILER_ERROR;
400     }
401     catch (...) {
402         assert(!"Internal errror, unexpected exception");
403         *db = nullptr;
404         *comp_error = const_cast<hs_compile_error_t *>(&hs_einternal);
405         return HS_COMPILER_ERROR;
406     }
407 }
408 
409 } // namespace ue2
410 
411 extern "C" HS_PUBLIC_API
hs_compile(const char * expression,unsigned flags,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** error)412 hs_error_t HS_CDECL hs_compile(const char *expression, unsigned flags,
413                                unsigned mode,
414                                const hs_platform_info_t *platform,
415                                hs_database_t **db, hs_compile_error_t **error) {
416     if (expression == nullptr) {
417         *db = nullptr;
418         *error = generateCompileError("Invalid parameter: expression is NULL",
419                                       -1);
420         return HS_COMPILER_ERROR;
421     }
422 
423     unsigned id = 0; // single expressions get zero as an ID
424     const hs_expr_ext * const *ext = nullptr; // unused for this call.
425 
426     return hs_compile_multi_int(&expression, &flags, &id, ext, 1, mode,
427                                 platform, db, error, Grey());
428 }
429 
430 extern "C" HS_PUBLIC_API
hs_compile_multi(const char * const * expressions,const unsigned * flags,const unsigned * ids,unsigned elements,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** error)431 hs_error_t HS_CDECL hs_compile_multi(const char *const *expressions,
432                                      const unsigned *flags, const unsigned *ids,
433                                      unsigned elements, unsigned mode,
434                                      const hs_platform_info_t *platform,
435                                      hs_database_t **db,
436                                      hs_compile_error_t **error) {
437     const hs_expr_ext * const *ext = nullptr; // unused for this call.
438     return hs_compile_multi_int(expressions, flags, ids, ext, elements, mode,
439                                 platform, db, error, Grey());
440 }
441 
442 extern "C" HS_PUBLIC_API
hs_compile_ext_multi(const char * const * expressions,const unsigned * flags,const unsigned * ids,const hs_expr_ext * const * ext,unsigned elements,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** error)443 hs_error_t HS_CDECL hs_compile_ext_multi(const char * const *expressions,
444                                      const unsigned *flags, const unsigned *ids,
445                                      const hs_expr_ext * const *ext,
446                                      unsigned elements, unsigned mode,
447                                      const hs_platform_info_t *platform,
448                                      hs_database_t **db,
449                                      hs_compile_error_t **error) {
450     return hs_compile_multi_int(expressions, flags, ids, ext, elements, mode,
451                                 platform, db, error, Grey());
452 }
453 
454 extern "C" HS_PUBLIC_API
hs_compile_lit(const char * expression,unsigned flags,const size_t len,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** error)455 hs_error_t HS_CDECL hs_compile_lit(const char *expression, unsigned flags,
456                                    const size_t len, unsigned mode,
457                                    const hs_platform_info_t *platform,
458                                    hs_database_t **db,
459                                    hs_compile_error_t **error) {
460     if (expression == nullptr) {
461         *db = nullptr;
462         *error = generateCompileError("Invalid parameter: expression is NULL",
463                                       -1);
464         return HS_COMPILER_ERROR;
465     }
466 
467     unsigned id = 0; // single expressions get zero as an ID
468     const hs_expr_ext * const *ext = nullptr; // unused for this call.
469 
470     return hs_compile_lit_multi_int(&expression, &flags, &id, ext, &len, 1,
471                                     mode, platform, db, error, Grey());
472 }
473 
474 extern "C" HS_PUBLIC_API
hs_compile_lit_multi(const char * const * expressions,const unsigned * flags,const unsigned * ids,const size_t * lens,unsigned elements,unsigned mode,const hs_platform_info_t * platform,hs_database_t ** db,hs_compile_error_t ** error)475 hs_error_t HS_CDECL hs_compile_lit_multi(const char * const *expressions,
476                                          const unsigned *flags,
477                                          const unsigned *ids,
478                                          const size_t *lens,
479                                          unsigned elements, unsigned mode,
480                                          const hs_platform_info_t *platform,
481                                          hs_database_t **db,
482                                          hs_compile_error_t **error) {
483     const hs_expr_ext * const *ext = nullptr; // unused for this call.
484     return hs_compile_lit_multi_int(expressions, flags, ids, ext, lens,
485                                     elements, mode, platform, db, error,
486                                     Grey());
487 }
488 
489 static
hs_expression_info_int(const char * expression,unsigned int flags,const hs_expr_ext_t * ext,unsigned int mode,hs_expr_info_t ** info,hs_compile_error_t ** error)490 hs_error_t hs_expression_info_int(const char *expression, unsigned int flags,
491                                   const hs_expr_ext_t *ext, unsigned int mode,
492                                   hs_expr_info_t **info,
493                                   hs_compile_error_t **error) {
494     if (!error) {
495         // nowhere to write an error, but we can still return an error code.
496         return HS_COMPILER_ERROR;
497     }
498 
499 #if defined(FAT_RUNTIME)
500     if (!check_ssse3()) {
501         *error = generateCompileError("Unsupported architecture", -1);
502         return HS_ARCH_ERROR;
503     }
504 #endif
505 
506     if (!info) {
507         *error = generateCompileError("Invalid parameter: info is NULL", -1);
508         return HS_COMPILER_ERROR;
509     }
510 
511     if (!expression) {
512         *error = generateCompileError("Invalid parameter: expression is NULL",
513                                       -1);
514         return HS_COMPILER_ERROR;
515     }
516 
517     *info = nullptr;
518     *error = nullptr;
519 
520     hs_expr_info local_info;
521     memset(&local_info, 0, sizeof(local_info));
522 
523     try {
524         bool isStreaming = mode & (HS_MODE_STREAM | HS_MODE_VECTORED);
525         bool isVectored = mode & HS_MODE_VECTORED;
526 
527         CompileContext cc(isStreaming, isVectored, get_current_target(),
528                           Grey());
529 
530         // Ensure that our pattern isn't too long (in characters).
531         if (strlen(expression) > cc.grey.limitPatternLength) {
532             throw ParseError("Pattern length exceeds limit.");
533         }
534 
535         ReportManager rm(cc.grey);
536         ParsedExpression pe(0, expression, flags, 0, ext);
537         assert(pe.component);
538 
539         // Apply prefiltering transformations if desired.
540         if (pe.expr.prefilter) {
541             prefilterTree(pe.component, ParseMode(flags));
542         }
543 
544         // Expressions containing zero-width assertions and other extended pcre
545         // types aren't supported yet. This call will throw a ParseError
546         // exception if the component tree contains such a construct.
547         checkUnsupported(*pe.component);
548 
549         pe.component->checkEmbeddedStartAnchor(true);
550         pe.component->checkEmbeddedEndAnchor(true);
551 
552         auto built_expr = buildGraph(rm, cc, pe);
553         unique_ptr<NGHolder> &g = built_expr.g;
554         ExpressionInfo &expr = built_expr.expr;
555 
556         if (!g) {
557             DEBUG_PRINTF("NFA build failed, but no exception was thrown.\n");
558             throw ParseError("Internal error.");
559         }
560 
561         fillExpressionInfo(rm, cc, *g, expr, &local_info);
562     }
563     catch (const CompileError &e) {
564         // Compiler error occurred
565         *error = generateCompileError(e);
566         return HS_COMPILER_ERROR;
567     }
568     catch (std::bad_alloc &) {
569         *error = const_cast<hs_compile_error_t *>(&hs_enomem);
570         return HS_COMPILER_ERROR;
571     }
572     catch (...) {
573         assert(!"Internal error, unexpected exception");
574         *error = const_cast<hs_compile_error_t *>(&hs_einternal);
575         return HS_COMPILER_ERROR;
576     }
577 
578     hs_expr_info *rv = (hs_expr_info *)hs_misc_alloc(sizeof(*rv));
579     if (!rv) {
580         *error = const_cast<hs_compile_error_t *>(&hs_enomem);
581         return HS_COMPILER_ERROR;
582     }
583 
584     *rv = local_info;
585     *info = rv;
586     return HS_SUCCESS;
587 }
588 
589 extern "C" HS_PUBLIC_API
hs_expression_info(const char * expression,unsigned int flags,hs_expr_info_t ** info,hs_compile_error_t ** error)590 hs_error_t HS_CDECL hs_expression_info(const char *expression,
591                                        unsigned int flags,
592                                        hs_expr_info_t **info,
593                                        hs_compile_error_t **error) {
594     return hs_expression_info_int(expression, flags, nullptr, HS_MODE_BLOCK,
595                                   info, error);
596 }
597 
598 extern "C" HS_PUBLIC_API
hs_expression_ext_info(const char * expression,unsigned int flags,const hs_expr_ext_t * ext,hs_expr_info_t ** info,hs_compile_error_t ** error)599 hs_error_t HS_CDECL hs_expression_ext_info(const char *expression,
600                                            unsigned int flags,
601                                            const hs_expr_ext_t *ext,
602                                            hs_expr_info_t **info,
603                                            hs_compile_error_t **error) {
604     return hs_expression_info_int(expression, flags, ext, HS_MODE_BLOCK, info,
605                                   error);
606 }
607 
608 extern "C" HS_PUBLIC_API
hs_populate_platform(hs_platform_info_t * platform)609 hs_error_t HS_CDECL hs_populate_platform(hs_platform_info_t *platform) {
610     if (!platform) {
611         return HS_INVALID;
612     }
613 
614     memset(platform, 0, sizeof(*platform));
615 
616     platform->cpu_features = cpuid_flags();
617     platform->tune = cpuid_tune();
618 
619     return HS_SUCCESS;
620 }
621 
622 extern "C" HS_PUBLIC_API
hs_free_compile_error(hs_compile_error_t * error)623 hs_error_t HS_CDECL hs_free_compile_error(hs_compile_error_t *error) {
624 #if defined(FAT_RUNTIME)
625     if (!check_ssse3()) {
626         return HS_ARCH_ERROR;
627     }
628 #endif
629     freeCompileError(error);
630     return HS_SUCCESS;
631 }
632