You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/util-mpm-wumanber.c

1340 lines
38 KiB
C

/* Implementation of the Wu-Manber pattern matching algorithm.
*
* Copyright (c) 2008 Victor Julien <victor@inliniac.net>
*
* Ideas:
* - the hash contains a list of patterns. Maybe we can 'train' the hash
* so the most common patterns always appear first in this list.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "util-mpm.h"
#include "util-mpm-wumanber.h"
#include "util-unittest.h"
void WmInitCtx (MpmCtx *mpm_ctx);
void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int32_t);
void WmDestroyCtx(MpmCtx *mpm_ctx);
void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx);
int WmAddPatternCI(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, u_int32_t id);
int WmAddPatternCS(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, u_int32_t id);
int WmPreparePatterns(MpmCtx *mpm_ctx);
u_int32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int8_t *buf, u_int16_t buflen);
u_int32_t WmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int8_t *buf, u_int16_t buflen);
void WmPrintInfo(MpmCtx *mpm_ctx);
void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
void WmRegisterTests(void);
/* uppercase to lowercase conversion lookup table */
static u_int8_t lowercasetable[256];
/* marco to do the actual lookup */
#define wm_tolower(c) lowercasetable[(c)]
void MpmWuManberRegister (void) {
mpm_table[MPM_WUMANBER].name = "wumanber";
mpm_table[MPM_WUMANBER].InitCtx = WmInitCtx;
mpm_table[MPM_WUMANBER].InitThreadCtx = WmThreadInitCtx;
mpm_table[MPM_WUMANBER].DestroyCtx = WmDestroyCtx;
mpm_table[MPM_WUMANBER].DestroyThreadCtx = WmThreadDestroyCtx;
mpm_table[MPM_WUMANBER].AddPattern = WmAddPatternCS;
mpm_table[MPM_WUMANBER].AddPatternNocase = WmAddPatternCI;
mpm_table[MPM_WUMANBER].Prepare = WmPreparePatterns;
mpm_table[MPM_WUMANBER].Search = WmSearch2; /* default to WmSearch2. We may fall back to 1 */
mpm_table[MPM_WUMANBER].Cleanup = MpmMatchCleanup;
mpm_table[MPM_WUMANBER].PrintCtx = WmPrintInfo;
mpm_table[MPM_WUMANBER].PrintThreadCtx = WmPrintSearchStats;
mpm_table[MPM_WUMANBER].RegisterUnittests = WmRegisterTests;
/* create table for O(1) lowercase conversion lookup */
u_int8_t c = 0;
for ( ; c < 255; c++) {
if (c >= 'A' && c <= 'Z')
lowercasetable[c] = (c + ('a' - 'A'));
else
lowercasetable[c] = c;
}
}
/* append an endmatch to a pattern
*
* Only used in the initialization phase */
static void WmEndMatchAppend(MpmCtx *mpm_ctx, WmPattern *p, u_int32_t id)
{
MpmEndMatch *em = MpmAllocEndMatch(mpm_ctx);
if (em == NULL) {
printf("ERROR: WmAllocEndMatch failed\n");
return;
}
em->id = id;
if (p->em == NULL) {
p->em = em;
return;
}
MpmEndMatch *m = p->em;
while (m->next) {
m = m->next;
}
m->next = em;
}
void prt (u_int8_t *buf, u_int16_t buflen) {
u_int16_t i;
for (i = 0; i < buflen; i++) {
if (isprint(buf[i])) printf("%c", buf[i]);
else printf("\\x%X", buf[i]);
}
//printf("\n");
}
void WmPrintInfo(MpmCtx *mpm_ctx) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
printf("MPM WuManber Information:\n");
printf("Memory allocs: %u\n", mpm_ctx->memory_cnt);
printf("Memory alloced: %u\n", mpm_ctx->memory_size);
printf("Unique Patterns: %u\n", mpm_ctx->pattern_cnt);
printf("Total Patterns: %u\n", mpm_ctx->total_pattern_cnt);
printf("Smallest: %u\n", mpm_ctx->minlen);
printf("Largest: %u\n", mpm_ctx->maxlen);
printf("Max shiftlen: %u\n", wm_ctx->shiftlen);
printf("Search function: ");
if (mpm_ctx->Search == WmSearch1) printf("WmSearch1 (allows single byte patterns)\n");
else if (mpm_ctx->Search == WmSearch2) printf("WmSearch2 (only for multibyte patterns)\n");
else printf("ERROR\n");
printf("\n");
}
WmPattern *WmAllocPattern(MpmCtx *mpm_ctx) {
WmPattern *p = malloc(sizeof(WmPattern));
if (p == NULL) {
printf("ERROR: WmAllocPattern: malloc failed\n");
}
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += sizeof(WmPattern);
p->cs = NULL;
p->ci = NULL;
p->len = 0;
p->next = NULL;
p->flags = 0;
p->prefix_ci = 0;
p->prefix_cs = 0;
p->em = NULL;
return p;
}
static WmHashItem *
WmAllocHashItem(MpmCtx *mpm_ctx) {
WmHashItem *hi = malloc(sizeof(WmHashItem));
if (hi == NULL) {
printf("ERROR: WmAllocHashItem: malloc failed\n");
}
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += sizeof(WmHashItem);
hi->flags = 0;
hi->nxt = NULL;
hi->idx = 0;
return hi;
}
static void memcpy_tolower(u_int8_t *d, u_int8_t *s, u_int16_t len) {
u_int16_t i;
for (i = 0; i < len; i++) {
d[i] = wm_tolower(s[i]);
}
}
static int WmCmpPattern(WmPattern *p, u_int8_t *pat, u_int16_t patlen, char nocase) {
if (p->len != patlen)
return 0;
if (!((nocase && p->flags & NOCASE) || (!nocase && !(p->flags & NOCASE))))
return 0;
if (memcmp(p->cs, pat, patlen) != 0)
return 0;
return 1;
}
/* See if a pattern is already included. Used when adding a pattern,
* NOT at search runtime! */
static WmPattern *
WmSearchPattern(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, char nocase) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
WmPattern *p = wm_ctx->head;
while (p) {
if (WmCmpPattern(p, pat, patlen, nocase) == 1) {
//printf("WmSearchPattern: pattern found\n");
return p;
}
p = p->next;
}
return NULL;
}
void WmFreePattern(MpmCtx *mpm_ctx, WmPattern *p) {
if (p && p->em) {
MpmEndMatchFreeAll(mpm_ctx, p->em);
}
if (p && p->cs) {
free(p->cs);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= p->len;
}
if (p && p->ci) {
free(p->ci);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= p->len;
}
if (p) {
free(p);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(WmPattern);
}
}
int WmAddPattern(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, char nocase, u_int32_t id) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
//printf("WmAddPattern: ctx %p \"", mpm_ctx); prt(pat, patlen); printf("\" id %u\n", id);
if (patlen == 0)
return 0;
/* get a memory piece */
WmPattern *p = WmSearchPattern(mpm_ctx, pat, patlen, nocase);
if (p == NULL) {
//printf("WmAddPattern: allocing new pattern\n");
p = WmAllocPattern(mpm_ctx);
if (p == NULL)
goto error;
p->len = patlen;
/* setup the case sensitive part of the pattern */
p->cs = malloc(patlen);
if (p->cs == NULL) goto error;
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += patlen;
memcpy(p->cs, pat, patlen);
/* setup the case insensitive part of the pattern */
p->ci = malloc(patlen);
if (p->ci == NULL) goto error;
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += patlen;
if (nocase) memcpy_tolower(p->ci, pat, patlen);
else memcpy(p->ci, pat, patlen);
if (p->len > 1) {
p->prefix_cs = (u_int16_t)(*(p->cs)+*(p->cs+1));
p->prefix_ci = (u_int16_t)(*(p->ci)+*(p->ci+1));
}
if (nocase) p->flags |= NOCASE;
//printf("WmAddPattern: ci \""); prt(p->ci,p->len);
//printf("\" cs \""); prt(p->cs,p->len);
//printf("\" prefix_ci %u, prefix_cs %u\n", p->prefix_ci, p->prefix_cs);
/* put in the pattern list */
if (wm_ctx->head == NULL) wm_ctx->head = p;
if (wm_ctx->tail) wm_ctx->tail->next = p;
wm_ctx->tail = p;
if (mpm_ctx->pattern_cnt == 65535) {
printf("Max search words reached\n");
exit(1);
}
mpm_ctx->pattern_cnt++;
if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen;
if (mpm_ctx->pattern_cnt == 1) mpm_ctx->minlen = patlen;
else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen;
}
/* we need a match */
WmEndMatchAppend(mpm_ctx, p, id);
/* keep track of highest pattern id */
if (id > mpm_ctx->max_pattern_id)
mpm_ctx->max_pattern_id = id;
mpm_ctx->total_pattern_cnt++;
return 0;
error:
WmFreePattern(mpm_ctx, p);
return -1;
}
int WmAddPatternCI(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, u_int32_t id) {
return WmAddPattern(mpm_ctx, pat, patlen, 0, id);
}
int WmAddPatternCS(MpmCtx *mpm_ctx, u_int8_t *pat, u_int16_t patlen, u_int32_t id) {
return WmAddPattern(mpm_ctx, pat, patlen, 1, id);
}
#define HASH_SIZE 65536
#define HASH(b) (((*(b))<<8) | *((b)+1))
static void WmPrepareHash(MpmCtx *mpm_ctx) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
u_int16_t i;
u_int16_t idx = 0;
u_int8_t idx8 = 0;
wm_ctx->hash = (WmHashItem *)malloc(sizeof(WmHashItem) * HASH_SIZE);
if (wm_ctx->hash == NULL) goto error;
memset(wm_ctx->hash, 0, sizeof(WmHashItem) * HASH_SIZE);
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += (sizeof(WmHashItem) * HASH_SIZE);
for (i = 0; i < mpm_ctx->pattern_cnt; i++)
{
if(wm_ctx->parray[i].len == 1) {
idx8 = (u_int8_t)wm_ctx->parray[i].ci[0];
if (wm_ctx->hash1[idx8].flags == 0) {
wm_ctx->hash1[idx8].idx = i;
wm_ctx->hash1[idx8].flags |= 0x01;
} else {
WmHashItem *hi = WmAllocHashItem(mpm_ctx);
hi->idx = i;
hi->flags |= 0x01;
/* Append this HashItem to the list */
WmHashItem *thi = &wm_ctx->hash1[idx8];
while (thi->nxt) thi = thi->nxt;
thi->nxt = hi;
}
} else {
u_int16_t patlen = wm_ctx->shiftlen;
idx = ((wm_ctx->parray[i].ci[patlen-1]<<8) + (wm_ctx->parray[i].ci[patlen-2]));
if (wm_ctx->hash[idx].flags == 0) {
wm_ctx->hash[idx].idx = i;
wm_ctx->hash[idx].flags |= 0x01;
} else {
WmHashItem *hi = WmAllocHashItem(mpm_ctx);
hi->idx = i;
hi->flags |= 0x01;
/* Append this HashItem to the list */
WmHashItem *thi = &wm_ctx->hash[idx];
while (thi->nxt) thi = thi->nxt;
thi->nxt = hi;
}
}
}
return;
error:
return;
}
/*
static int WmCmpSort(const void *a, const void *b) {
WmPattern *p1 = (WmPattern *)a;
WmPattern *p2 = (WmPattern *)b;
int r = 0;
if (p1->len == p2->len)
return memcmp(p1->ci, p2->ci, p1->len);
else if(p1->len < p2->len ) {
if ((r = memcmp(p1->ci, p2->ci, p1->len)) != 0)
return r;
return -1;
} else {
if ((r = memcmp(p1->ci, p2->ci, p2->len)) != 0)
return r;
return 1;
}
}
*/
static void WmPrepareShiftTable(MpmCtx *mpm_ctx)
{
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
u_int16_t shift = 0, k = 0, idx = 0;
u_int32_t i = 0;
u_int16_t smallest = mpm_ctx->minlen;
if (smallest > 255) smallest = 255;
if (smallest < 2) smallest = 2;
wm_ctx->shiftlen = smallest;
/* default shift table is set to minimal shift */
for (i = 0; i < 65536; i++)
wm_ctx->shifttable[i] = wm_ctx->shiftlen - 1;
for (i = 0; i < mpm_ctx->pattern_cnt; i++)
{
/* ignore one byte patterns */
if (wm_ctx->parray[i].len == 1)
continue;
//printf("WmPrepareShiftTable: i = %u ", i);
//prt(wm_ctx->parray[i].ci, wm_ctx->parray[i].len);
for (k = 0; k < wm_ctx->shiftlen-1; k++)
{
shift = (wm_ctx->shiftlen - 2 - k);
if (shift > 255) shift = 255;
idx = ((wm_ctx->parray[i].ci[k]) | (wm_ctx->parray[i].ci[k+1]<<8));
if (shift < wm_ctx->shifttable[idx]) {
wm_ctx->shifttable[idx] = shift;
}
//printf("WmPrepareShiftTable: i %u, k %u, idx %u, shift set to %u: \"%c%c\"\n",
// i, k, idx, shift, wm_ctx->parray[i].ci[k], wm_ctx->parray[i].ci[k+1]);
}
}
}
int WmPreparePatterns(MpmCtx *mpm_ctx) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
/* alloc the pattern array */
wm_ctx->parray = malloc(mpm_ctx->pattern_cnt * sizeof(WmPattern));
if (wm_ctx->parray == NULL) goto error;
memset(wm_ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(WmPattern));
//printf("mpm_ctx %p, parray %p\n", mpm_ctx,wm_ctx->parray);
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(WmPattern));
/* populate it */
u_int16_t i = 0;
WmPattern *node = wm_ctx->head;
while (node != NULL) {
//printf("i %u: node->ci %s\n", i, node->ci);
memcpy(&wm_ctx->parray[i], node, sizeof(WmPattern));
node = node->next; i++;
}
/* Sort the patterns as Wu-Manber wants a sorted list */
//qsort(wm_ctx->parray, mpm_ctx->pattern_cnt, sizeof(WmPattern), WmCmpSort);
WmPrepareShiftTable(mpm_ctx);
WmPrepareHash(mpm_ctx);
if (mpm_ctx->minlen == 1)
mpm_ctx->Search = WmSearch1;
return 0;
error:
return -1;
}
void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) {
WmThreadCtx *wm_thread_ctx = (WmThreadCtx *)mpm_thread_ctx->ctx;
printf("Shift 0: %u\n", wm_thread_ctx->stat_shift_null);
printf("Loop match: %u\n", wm_thread_ctx->stat_loop_match);
printf("Loop no match: %u\n", wm_thread_ctx->stat_loop_no_match);
printf("Num shifts: %u\n", wm_thread_ctx->stat_num_shift);
printf("Total shifts: %u\n", wm_thread_ctx->stat_total_shift);
}
static inline int
memcmp_lowercase(u_int8_t *s1, u_int8_t *s2, u_int16_t n) {
size_t i;
/* check backwards because we already tested the first
* 2 to 4 chars. This way we are more likely to detect
* a miss and thus speed up a little... */
for (i = n - 1; i; i--) {
if (wm_tolower(*(s2+i)) != s1[i])
return 1;
}
return 0;
}
u_int32_t WmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int8_t *buf, u_int16_t buflen) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
WmThreadCtx *wm_thread_ctx = (WmThreadCtx *)mpm_thread_ctx->ctx;
u_int32_t cnt = 0;
u_int8_t *bufmin = buf;
u_int8_t *bufend = buf + buflen - 1;
u_int16_t sl = wm_ctx->shiftlen;
u_int16_t h;
u_int8_t shift;
WmHashItem *thi, *hi;
WmPattern *p;
u_int16_t prefixci_buf;
u_int16_t prefixcs_buf;
if (buflen == 0)
return 0;
//printf("BUF(%u) ", buflen); prt(buf,buflen); printf("\n");
buf++;
while (buf <= bufend) {
h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1)));
shift = wm_ctx->shifttable[h];
if (shift == 0) {
wm_thread_ctx->stat_shift_null++;
/* get our hash item */
hi = &wm_ctx->hash[h];
prefixci_buf = (u_int16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2)));
prefixcs_buf = (u_int16_t)(*(buf-sl+1) + *(buf-sl+2));
//printf("WmSearch2: prefixci_buf %u, prefixcs_buf %u\n", prefixci_buf, prefixcs_buf);
for (thi = hi; thi != NULL; thi = thi->nxt) {
p = &wm_ctx->parray[thi->idx];
//printf("WmSearch2: p->prefix_ci %u, p->prefix_cs %u\n",
// p->prefix_ci, p->prefix_cs);
if (p->flags & NOCASE) {
if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl)))
continue;
if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) {
cnt++;
//printf("CI Exact match: "); prt(p->ci, p->len); printf("\n");
wm_thread_ctx->stat_loop_match++;
MpmEndMatch *em;
for (em = p->em; em; em = em->next) {
//printf("em %p id %u\n", em, em->id);
MpmMatchAppend(mpm_thread_ctx, em, &mpm_thread_ctx->match[em->id],(buf-sl+1 - bufmin));
}
} else {
wm_thread_ctx->stat_loop_no_match++;
}
} else {
if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl)))
continue;
if (memcmp(p->cs, buf-sl+1, p->len) == 0) {
cnt++;
//printf("CS Exact match: "); prt(p->cs, p->len); printf("\n");
wm_thread_ctx->stat_loop_match++;
MpmEndMatch *em;
for (em = p->em; em; em = em->next) {
//printf("em %p id %u\n", em, em->id);
MpmMatchAppend(mpm_thread_ctx, em, &mpm_thread_ctx->match[em->id],(buf-sl+1 - bufmin));
}
} else {
wm_thread_ctx->stat_loop_no_match++;
}
}
}
shift = 1;
} else {
wm_thread_ctx->stat_total_shift += shift;
wm_thread_ctx->stat_num_shift++;
}
buf += shift;
}
return cnt;
}
u_int32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int8_t *buf, u_int16_t buflen) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
//WmThreadCtx *wm_thread_ctx = (WmThreadCtx *)mpm_thread_ctx->ctx;
u_int8_t *bufmin = buf;
u_int8_t *bufend = buf + buflen - 1;
u_int32_t cnt = 0;
WmPattern *p;
MpmEndMatch *em;
WmHashItem *thi, *hi;
if (buflen == 0)
return 0;
//printf("BUF "); prt(buf,buflen); printf("\n");
if (mpm_ctx->minlen == 1) {
while (buf <= bufend) {
u_int8_t h = wm_tolower(*buf);
hi = &wm_ctx->hash1[h];
if (hi->flags & 0x01) {
for (thi = hi; thi != NULL; thi = thi->nxt) {
p = &wm_ctx->parray[thi->idx];
if (p->len != 1)
continue;
if (p->flags & NOCASE) {
if (wm_tolower(*buf) == p->ci[0]) {
//printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (WmSearch1)\n");
for (em = p->em; em; em = em->next) {
MpmMatchAppend(mpm_thread_ctx, em, &mpm_thread_ctx->match[em->id],(buf+1 - bufmin));
}
cnt++;
}
} else {
if (*buf == p->cs[0]) {
//printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (WmSearch1)\n");
for (em = p->em; em; em = em->next) {
MpmMatchAppend(mpm_thread_ctx, em, &mpm_thread_ctx->match[em->id],(buf+1 - bufmin));
}
cnt++;
}
}
}
}
buf += 1;
}
}
//printf("WmSearch1: after 1byte cnt %u\n", cnt);
if (mpm_ctx->maxlen > 1) {
/* Pass bufmin on because buf no longer points to the
* start of the buffer. */
cnt += WmSearch2(mpm_ctx, mpm_thread_ctx, bufmin, buflen);
//printf("WmSearch1: after 2+byte cnt %u\n", cnt);
}
return cnt;
}
void WmInitCtx (MpmCtx *mpm_ctx) {
//printf("WmInitCtx: mpm_ctx %p\n", mpm_ctx);
memset(mpm_ctx, 0, sizeof(MpmCtx));
mpm_ctx->ctx = malloc(sizeof(WmCtx));
if (mpm_ctx->ctx == NULL)
return;
memset(mpm_ctx->ctx, 0, sizeof(WmCtx));
}
void WmDestroyCtx(MpmCtx *mpm_ctx) {
WmCtx *wm_ctx = (WmCtx *)mpm_ctx->ctx;
if (wm_ctx != NULL) {
WmPattern *p = wm_ctx->head, *tp;
while (p) {
tp = p->next;
WmFreePattern(mpm_ctx,p);
p = tp;
}
if (wm_ctx->parray) {
free(wm_ctx->parray);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(mpm_ctx->pattern_cnt * sizeof(WmPattern));
}
if (wm_ctx->hash) {
free(wm_ctx->hash);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(sizeof(WmHashItem) * HASH_SIZE);
}
free(mpm_ctx->ctx);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(WmCtx);
}
}
void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, u_int32_t matchsize) {
memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
mpm_thread_ctx->ctx = malloc(sizeof(WmThreadCtx));
if (mpm_thread_ctx->ctx == NULL)
return;
memset(mpm_thread_ctx->ctx, 0, sizeof(WmThreadCtx));
mpm_thread_ctx->memory_cnt++;
mpm_thread_ctx->memory_size += sizeof(WmThreadCtx);
/* alloc an array with the size of _all_ keys in all instances.
* this is done so the detect engine won't have to care about
* what instance it's looking up in. The matches all have a
* unique id and is the array lookup key at the same time */
//u_int32_t keys = mpm_ctx->max_pattern_id + 1;
u_int32_t keys = matchsize + 1;
if (keys) {
mpm_thread_ctx->match = malloc(keys * sizeof(MpmMatchBucket));
if (mpm_thread_ctx->match == NULL) {
printf("ERROR: could not setup memory for pattern matcher: %s\n", strerror(errno));
exit(1);
}
memset(mpm_thread_ctx->match, 0, keys * sizeof(MpmMatchBucket));
mpm_thread_ctx->memory_cnt++;
mpm_thread_ctx->memory_size += (keys * sizeof(MpmMatchBucket));
}
}
void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) {
WmThreadCtx *wm_ctx = (WmThreadCtx *)mpm_thread_ctx->ctx;
if (wm_ctx) {
if (mpm_thread_ctx->match != NULL) {
mpm_thread_ctx->memory_cnt--;
mpm_thread_ctx->memory_size -= ((mpm_ctx->max_pattern_id + 1) * sizeof(MpmMatchBucket));
free(mpm_thread_ctx->match);
}
mpm_thread_ctx->memory_cnt--;
mpm_thread_ctx->memory_size -= sizeof(WmThreadCtx);
free(mpm_thread_ctx->ctx);
}
MpmMatchFreeSpares(mpm_thread_ctx, mpm_thread_ctx->sparelist);
MpmMatchFreeSpares(mpm_thread_ctx, mpm_thread_ctx->qlist);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
int WmTestInitCtx01 (void) {
int result = 0;
MpmCtx mpm_ctx;
WmInitCtx(&mpm_ctx);
if (mpm_ctx.ctx != NULL)
result = 1;
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitCtx02 (void) {
int result = 0;
MpmCtx mpm_ctx;
WmInitCtx(&mpm_ctx);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
if (wm_ctx->head == NULL)
result = 1;
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitCtx03 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
if (mpm_ctx.Search == WmSearch2)
result = 1;
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestThreadInitCtx01 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
if (mpm_thread_ctx.memory_cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestThreadInitCtx02 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmThreadCtx *wm_thread_ctx = (WmThreadCtx *)mpm_thread_ctx.ctx;
if (wm_thread_ctx->stat_shift_null == 0)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern01 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
int ret = WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
if (ret == 0)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern02 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
if (wm_ctx->head != NULL)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern03 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
WmPattern *pat = wm_ctx->head;
if (pat->len == 4)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern04 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
WmPattern *pat = wm_ctx->head;
if (pat->flags & NOCASE)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern05 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 0, 1234);
WmPattern *pat = wm_ctx->head;
if (!(pat->flags & NOCASE))
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern06 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmCtx *wm_ctx = (WmCtx *)mpm_ctx.ctx;
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
WmPattern *pat = wm_ctx->head;
if (memcmp(pat->cs, "abcd", 4) == 0)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestInitAddPattern07 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 1234);
if (mpm_ctx.max_pattern_id == 1234)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestPrepare01 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"a", 1, 1, 0);
WmPreparePatterns(&mpm_ctx);
if (mpm_ctx.Search == WmSearch1)
result = 1;
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch01 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcd", 4);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch02 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abce", 4);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 0)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch03 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch04 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"bcde", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch05 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"efgh", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch06 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"eFgH", 4, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdEfGh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch07 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcd", 4, 0, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"eFgH", 4, 1, 1);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdEfGh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch08 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"abcde", 5, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"bcde", 4, 1, 1);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch09 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"ab", 2, 1, 0);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"ab", 2);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch10 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"bc", 2, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"gh", 2, 1, 1);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2);
u_int32_t cnt = WmSearch2(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch11 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"a", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"d", 1, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"h", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
u_int32_t cnt = WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 3)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch12 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"A", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"d", 1, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"Z", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
u_int32_t cnt = WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch13 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"a", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"de",2, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"h", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
u_int32_t cnt = WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 3)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch14 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"A", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"de",2, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"Z", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
u_int32_t cnt = WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
MpmMatchCleanup(&mpm_thread_ctx);
if (cnt == 2)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch15 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"A", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"de",2, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"Z", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
u_int32_t len = mpm_thread_ctx.match[1].len;
MpmMatchCleanup(&mpm_thread_ctx);
if (len == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
int WmTestSearch16 (void) {
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
MpmInitCtx(&mpm_ctx, MPM_WUMANBER);
WmAddPattern(&mpm_ctx, (u_int8_t *)"A", 1, 1, 0);
WmAddPattern(&mpm_ctx, (u_int8_t *)"de",2, 1, 1);
WmAddPattern(&mpm_ctx, (u_int8_t *)"Z", 1, 1, 2);
WmPreparePatterns(&mpm_ctx);
WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3);
WmSearch1(&mpm_ctx, &mpm_thread_ctx, (u_int8_t *)"abcdefgh", 8);
u_int32_t len = mpm_thread_ctx.match[0].len;
MpmMatchCleanup(&mpm_thread_ctx);
if (len == 1)
result = 1;
WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx);
WmDestroyCtx(&mpm_ctx);
return result;
}
void WmRegisterTests(void) {
UtRegisterTest("WmTestInitCtx01", WmTestInitCtx01, 1);
UtRegisterTest("WmTestInitCtx02", WmTestInitCtx02, 1);
UtRegisterTest("WmTestInitCtx03", WmTestInitCtx03, 1);
UtRegisterTest("WmTestThreadInitCtx01", WmTestThreadInitCtx01, 1);
UtRegisterTest("WmTestThreadInitCtx02", WmTestThreadInitCtx02, 1);
UtRegisterTest("WmTestInitAddPattern01", WmTestInitAddPattern01, 1);
UtRegisterTest("WmTestInitAddPattern02", WmTestInitAddPattern02, 1);
UtRegisterTest("WmTestInitAddPattern03", WmTestInitAddPattern03, 1);
UtRegisterTest("WmTestInitAddPattern04", WmTestInitAddPattern04, 1);
UtRegisterTest("WmTestInitAddPattern05", WmTestInitAddPattern05, 1);
UtRegisterTest("WmTestInitAddPattern06", WmTestInitAddPattern06, 1);
UtRegisterTest("WmTestInitAddPattern07", WmTestInitAddPattern07, 1);
UtRegisterTest("WmTestPrepare01", WmTestPrepare01, 1);
UtRegisterTest("WmTestSearch01", WmTestSearch01, 1);
UtRegisterTest("WmTestSearch02", WmTestSearch02, 1);
UtRegisterTest("WmTestSearch03", WmTestSearch03, 1);
UtRegisterTest("WmTestSearch04", WmTestSearch04, 1);
UtRegisterTest("WmTestSearch05", WmTestSearch05, 1);
UtRegisterTest("WmTestSearch06", WmTestSearch06, 1);
UtRegisterTest("WmTestSearch07", WmTestSearch07, 1);
UtRegisterTest("WmTestSearch08", WmTestSearch08, 1);
UtRegisterTest("WmTestSearch09", WmTestSearch09, 1);
UtRegisterTest("WmTestSearch10", WmTestSearch10, 1);
UtRegisterTest("WmTestSearch11", WmTestSearch11, 1);
UtRegisterTest("WmTestSearch12", WmTestSearch12, 1);
UtRegisterTest("WmTestSearch13", WmTestSearch13, 1);
UtRegisterTest("WmTestSearch14", WmTestSearch14, 1);
UtRegisterTest("WmTestSearch15", WmTestSearch15, 1);
UtRegisterTest("WmTestSearch16", WmTestSearch16, 1);
}