Esempio n. 1
0
// Saves out stream state for all our active suffix NFAs.
static rose_inline
void roseSaveNfaStreamState(const struct RoseEngine *t, char *state,
                            struct hs_scratch *scratch) {
    struct mq *queues = scratch->queues;
    u8 *aa = getActiveLeafArray(t, state);
    u32 aaCount = t->activeArrayCount;

    if (scratch->tctxt.mpv_inactive) {
        DEBUG_PRINTF("mpv is dead as a doornail\n");
        /* mpv if it exists is queue 0 */
        mmbit_unset(aa, aaCount, 0);
    }

    for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
         qi = mmbit_iterate(aa, aaCount, qi)) {
        DEBUG_PRINTF("saving stream state for qi=%u\n", qi);

        struct mq *q = queues + qi;

        // If it's active, it should have an active queue (as we should have
        // done some work!)
        assert(fatbit_isset(scratch->aqa, t->queueCount, qi));

        const struct NFA *nfa = getNfaByQueue(t, qi);
        saveStreamState(nfa, q, q_cur_loc(q));
    }
}
Esempio n. 2
0
static really_inline
int can_never_match(const struct RoseEngine *t, char *state,
                    struct hs_scratch *scratch, size_t length, u64a offset) {
    struct RoseContext *tctxt = &scratch->tctxt;

    if (tctxt->groups) {
        DEBUG_PRINTF("still has active groups\n");
        return 0;
    }

    if (offset + length <= t->anchoredDistance) { /* not < as may have eod */
        DEBUG_PRINTF("still in anchored region\n");
        return 0;
    }

    if (t->lastByteHistoryIterOffset) { /* last byte history is hard */
        DEBUG_PRINTF("last byte history\n");
        return 0;
    }

    if (mmbit_any(getActiveLeafArray(t, state), t->activeArrayCount)) {
        DEBUG_PRINTF("active leaf\n");
        return 0;
    }

    return 1;
}
Esempio n. 3
0
static really_inline
void roseEodExec_i(const struct RoseEngine *t, u8 *state, u64a offset,
                   struct hs_scratch *scratch, const char is_streaming) {
    assert(t);
    assert(scratch->core_info.buf || scratch->core_info.hbuf);
    assert(!scratch->core_info.buf || !scratch->core_info.hbuf);
    assert(!can_stop_matching(scratch));

    // Fire the special EOD event literal.
    if (t->hasEodEventLiteral) {
        DEBUG_PRINTF("firing eod event id %u at offset %llu\n",
                     t->eodLiteralId, offset);
        const struct core_info *ci = &scratch->core_info;
        size_t len = ci->buf ? ci->len : ci->hlen;
        assert(len || !ci->buf); /* len may be 0 if no history is required
                                  * (bounds checks only can lead to this) */

        roseRunEvent(len, t->eodLiteralId, &scratch->tctxt);
        if (can_stop_matching(scratch)) {
            DEBUG_PRINTF("user told us to stop\n");
            return;
        }
    }

    roseCheckNfaEod(t, state, scratch, offset, is_streaming);

    if (!t->eodIterOffset && !t->ematcherOffset) {
        DEBUG_PRINTF("no eod accepts\n");
        return;
    }

    // Handle pending EOD reports.
    int itrv = roseEodRunIterator(t, state, offset, scratch);
    if (itrv == MO_HALT_MATCHING) {
        return;
    }

    // Run the EOD anchored matcher if there is one.
    if (t->ematcherOffset) {
        assert(t->ematcherRegionSize);
        // Unset the reports we just fired so we don't fire them again below.
        mmbit_clear(getRoleState(state), t->rolesWithStateCount);
        mmbit_clear(getActiveLeafArray(t, state), t->activeArrayCount);
        sidecar_enabled_populate(t, scratch, state);

        hwlmcb_rv_t rv = roseEodRunMatcher(t, offset, scratch, is_streaming);
        if (rv == HWLM_TERMINATE_MATCHING) {
            return;
        }

        cleanupAfterEodMatcher(t, state, offset, scratch);

        // Fire any new EOD reports.
        roseEodRunIterator(t, state, offset, scratch);

        roseCheckEodSuffixes(t, state, offset, scratch);
    }
}
Esempio n. 4
0
static rose_inline
void roseCheckNfaEod(const struct RoseEngine *t, u8 *state,
                     struct hs_scratch *scratch, u64a offset,
                     const char is_streaming) {
    /* data, len is used for state decompress, should be full available data */
    const u8 *aa = getActiveLeafArray(t, state);
    const u32 aaCount = t->activeArrayCount;

    u8 key = 0;

    if (is_streaming) {
        const u8 *eod_data = scratch->core_info.hbuf;
        size_t eod_len = scratch->core_info.hlen;
        key = eod_len ? eod_data[eod_len - 1] : 0;
    }

    for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
         qi = mmbit_iterate(aa, aaCount, qi)) {
        const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
        const struct NFA *nfa = getNfaByInfo(t, info);

        if (!nfaAcceptsEod(nfa)) {
            DEBUG_PRINTF("nfa %u does not accept eod\n", qi);
            continue;
        }

        DEBUG_PRINTF("checking nfa %u\n", qi);

        char *fstate = scratch->fullState + info->fullStateOffset;
        const char *sstate = (const char *)state + info->stateOffset;

        if (is_streaming) {
            // Decompress stream state.
            nfaExpandState(nfa, fstate, sstate, offset, key);
        }

        nfaCheckFinalState(nfa, fstate, sstate, offset, scratch->tctxt.cb,
                           scratch->tctxt.cb_som, scratch->tctxt.userCtx);
    }
}
Esempio n. 5
0
static rose_inline
void roseCheckEodSuffixes(const struct RoseEngine *t, u8 *state, u64a offset,
                          struct hs_scratch *scratch) {
    const u8 *aa = getActiveLeafArray(t, state);
    const u32 aaCount = t->activeArrayCount;
    UNUSED u32 qCount = t->queueCount;

    for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
         qi = mmbit_iterate(aa, aaCount, qi)) {
        const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
        const struct NFA *nfa = getNfaByInfo(t, info);

        assert(nfaAcceptsEod(nfa));

        DEBUG_PRINTF("checking nfa %u\n", qi);

        assert(fatbit_isset(scratch->aqa, qCount, qi)); /* we have just been
                                                           triggered */

        char *fstate = scratch->fullState + info->fullStateOffset;
        const char *sstate = (const char *)state + info->stateOffset;

        struct mq *q = scratch->queues + qi;

        pushQueueNoMerge(q, MQE_END, scratch->core_info.len);

        q->context = NULL;
        /* rose exec is used as we don't want to / can't raise matches in the
         * history buffer. */
        char rv = nfaQueueExecRose(q->nfa, q, MO_INVALID_IDX);
        if (rv) { /* nfa is still alive */
            nfaCheckFinalState(nfa, fstate, sstate, offset, scratch->tctxt.cb,
                               scratch->tctxt.cb_som, scratch->tctxt.userCtx);
        }
    }
}
Esempio n. 6
0
hwlmcb_rv_t roseHandleChainMatch(const struct RoseEngine *t,
                                 struct hs_scratch *scratch, u32 event,
                                 u64a top_squash_distance, u64a end,
                                 char in_catchup) {
    assert(event == MQE_TOP || event >= MQE_TOP_FIRST);
    struct core_info *ci = &scratch->core_info;

    u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
    u32 aaCount = t->activeArrayCount;
    struct fatbit *activeQueues = scratch->aqa;
    u32 qCount = t->queueCount;

    const u32 qi = 0; /* MPV is always queue 0 if it exists */
    struct mq *q = &scratch->queues[qi];
    const struct NfaInfo *info = getNfaInfoByQueue(t, qi);

    s64a loc = (s64a)end - ci->buf_offset;
    assert(loc <= (s64a)ci->len && loc >= -(s64a)ci->hlen);

    if (!mmbit_set(aa, aaCount, qi)) {
        initQueue(q, qi, t, scratch);
        nfaQueueInitState(q->nfa, q);
        pushQueueAt(q, 0, MQE_START, loc);
        fatbit_set(activeQueues, qCount, qi);
    } else if (info->no_retrigger) {
        DEBUG_PRINTF("yawn\n");
        /* nfa only needs one top; we can go home now */
        return HWLM_CONTINUE_MATCHING;
    } else if (!fatbit_set(activeQueues, qCount, qi)) {
        initQueue(q, qi, t, scratch);
        loadStreamState(q->nfa, q, 0);
        pushQueueAt(q, 0, MQE_START, 0);
    } else if (isQueueFull(q)) {
        DEBUG_PRINTF("queue %u full -> catching up nfas\n", qi);
        /* we know it is a chained nfa and the suffixes/outfixes must already
         * be known to be consistent */
        if (ensureMpvQueueFlushed(t, scratch, qi, loc, in_catchup)
            == HWLM_TERMINATE_MATCHING) {
            DEBUG_PRINTF("terminating...\n");
            return HWLM_TERMINATE_MATCHING;
        }
    }

    if (top_squash_distance) {
        assert(q->cur != q->end);
        struct mq_item *last = &q->items[q->end - 1];
        if (last->type == event
            && last->location >= loc - (s64a)top_squash_distance) {
            last->location = loc;
            goto event_enqueued;
        }
    }

    pushQueue(q, event, loc);

event_enqueued:
    if (q_cur_loc(q) == (s64a)ci->len) {
        /* we may not run the nfa; need to ensure state is fine  */
        DEBUG_PRINTF("empty run\n");
        pushQueueNoMerge(q, MQE_END, loc);
        char alive = nfaQueueExec(q->nfa, q, loc);
        if (alive) {
            scratch->tctxt.mpv_inactive = 0;
            q->cur = q->end = 0;
            pushQueueAt(q, 0, MQE_START, loc);
        } else {
            mmbit_unset(aa, aaCount, qi);
            fatbit_unset(scratch->aqa, qCount, qi);
        }
    }

    DEBUG_PRINTF("added mpv event at %lld\n", loc);
    scratch->tctxt.next_mpv_offset = 0; /* the top event may result in matches
                                         * earlier than expected */
    return HWLM_CONTINUE_MATCHING;
}