Exemple #1
0
int _yr_ac_optimize_failure_links(
    YR_AC_AUTOMATON* automaton)
{
  QUEUE queue = { NULL, NULL};

  // Push root's children.

  YR_AC_STATE* root_state = automaton->root;
  YR_AC_STATE* state = root_state->first_child;

  while (state != NULL)
  {
    FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state));
    state = state->siblings;
  }

  while (!_yr_ac_queue_is_empty(&queue))
  {
    YR_AC_STATE* current_state = _yr_ac_queue_pop(&queue);

    if (current_state->failure != root_state)
    {
      if (_yr_ac_transitions_subset(current_state, current_state->failure))
        current_state->failure = current_state->failure->failure;
    }

    // Push childrens of current_state
    state = current_state->first_child;

    while (state != NULL)
    {
      FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state));
      state = state->siblings;
    }
  }

  return ERROR_SUCCESS;
}
Exemple #2
0
void yr_ac_create_failure_links(
    YR_ARENA* arena,
    YR_AC_AUTOMATON* automaton)
{
  YR_AC_STATE_TRANSITION transition;

  YR_AC_STATE* current_state;
  YR_AC_STATE* failure_state;
  YR_AC_STATE* temp_state;
  YR_AC_STATE* state;
  YR_AC_STATE* transition_state;
  YR_AC_STATE* root_state;
  YR_AC_MATCH* match;

  QUEUE queue;

  queue.head = NULL;
  queue.tail = NULL;

  root_state = automaton->root;

  // Set the failure link of root state to itself.
  root_state->failure = root_state;

  // Push root's children and set their failure link to root.

  state = _yr_ac_first_transition(root_state, &transition);

  while (state != NULL)
  {
    _yr_ac_queue_push(&queue, state);
    state->failure = root_state;
    state = _yr_ac_next_transition(root_state, &transition);
  }

  // Traverse the trie in BFS order calculating the failure link
  // for each state.

  while (!_yr_ac_queue_is_empty(&queue))
  {
    current_state = _yr_ac_queue_pop(&queue);

    match = current_state->matches;

    if (match != NULL)
    {
      while (match->next != NULL)
        match = match->next;

      if (match->backtrack > 0)
        match->next = root_state->matches;
    }
    else
    {
      current_state->matches = root_state->matches;
    }

    transition_state = _yr_ac_first_transition(
        current_state,
        &transition);

    while (transition_state != NULL)
    {
      _yr_ac_queue_push(&queue, transition_state);
      failure_state = current_state->failure;

      while (1)
      {
        temp_state = yr_ac_next_state(
            failure_state,
            transition.input);

        if (temp_state != NULL)
        {
          transition_state->failure = temp_state;

          if (transition_state->matches == NULL)
          {
            transition_state->matches = temp_state->matches;
          }
          else
          {
            match = transition_state->matches;

            while (match != NULL && match->next != NULL)
              match = match->next;

            match->next = temp_state->matches;
          }

          break;
        }
        else
        {
          if (failure_state == root_state)
          {
            transition_state->failure = root_state;
            break;
          }
          else
          {
            failure_state = failure_state->failure;
          }
        }
      } // while(1)

      transition_state = _yr_ac_next_transition(
          current_state,
          &transition);
    }

  } // while(!__yr_ac_queue_is_empty(&queue))
}
Exemple #3
0
int _yr_ac_build_transition_table(
    YR_AC_AUTOMATON* automaton)
{
  YR_AC_STATE* state;
  YR_AC_STATE* child_state;
  YR_AC_STATE* root_state = automaton->root;

  uint32_t slot;

  QUEUE queue = { NULL, NULL};

  automaton->tables_size = 1024;

  automaton->t_table = (YR_AC_TRANSITION_TABLE) yr_malloc(
      automaton->tables_size * sizeof(YR_AC_TRANSITION));

  automaton->m_table = (YR_AC_MATCH_TABLE) yr_malloc(
      automaton->tables_size * sizeof(YR_AC_MATCH_TABLE_ENTRY));

  if (automaton->t_table == NULL || automaton->m_table == NULL)
  {
    yr_free(automaton->t_table);
    yr_free(automaton->m_table);

    return ERROR_INSUFFICIENT_MEMORY;
  }

  memset(automaton->t_table, 0,
      automaton->tables_size * sizeof(YR_AC_TRANSITION));

  memset(automaton->m_table, 0,
      automaton->tables_size * sizeof(YR_AC_MATCH_TABLE_ENTRY));

  automaton->t_table[0] = YR_AC_MAKE_TRANSITION(0, 0, YR_AC_USED_FLAG);
  automaton->m_table[0].match = root_state->matches;

  // Index 0 is for root node. Unused indexes start at 1.
  automaton->t_table_unused_candidate = 1;

  child_state = root_state->first_child;

  while (child_state != NULL)
  {
    child_state->t_table_slot = child_state->input + 1;
    automaton->t_table[child_state->input + 1] = YR_AC_MAKE_TRANSITION(
        0, child_state->input + 1, YR_AC_USED_FLAG);

    FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state));
    child_state = child_state->siblings;
  }

  while (!_yr_ac_queue_is_empty(&queue))
  {
    state = _yr_ac_queue_pop(&queue);

    FAIL_ON_ERROR(_yr_ac_find_suitable_transition_table_slot(
        automaton,
        state,
        &slot));

    automaton->t_table[state->t_table_slot] |= ((uint64_t) slot << 32);

    state->t_table_slot = slot;

    automaton->t_table[slot] = YR_AC_MAKE_TRANSITION(
        state->failure->t_table_slot, 0, YR_AC_USED_FLAG);

    automaton->m_table[slot].match = state->matches;

    // Push childrens of current_state

    child_state = state->first_child;

    while (child_state != NULL)
    {
      child_state->t_table_slot = slot + child_state->input + 1;
      automaton->t_table[child_state->t_table_slot] = YR_AC_MAKE_TRANSITION(
          0, child_state->input + 1, YR_AC_USED_FLAG);

      FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state));

      child_state = child_state->siblings;
    }
  }

  return ERROR_SUCCESS;
}