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