On Tue, Dec 10, 2013 at 06:38:51AM -0800, John Johansen wrote:
>     This is a slightly updated (to apply against current dev) version of the
>     differential compression patch.
> 
>     Differential state compression encodes a state's transitions as the
>     difference between the state and its default state (the state it is
>     relative too).
> [...]
>     Signed-off-by: John Johansen <[email protected]>


Impressive; I think I understood very nearly all of it, thanks for the
copius documentation, comments, and above-all, clear code, though I'm
afraid I haven't yet figured out if this requires kernel modifications to
support the differential compression.

I have some questions inline.

With the caveat that I haven't looked at how well the _other_ code
will handle this, only the code in this patch:

Acked-by: Seth Arnold <[email protected]>

> === modified file 'parser/libapparmor_re/aare_rules.cc'
> --- parser/libapparmor_re/aare_rules.cc       2013-10-14 21:36:05 +0000
> +++ parser/libapparmor_re/aare_rules.cc       2013-12-10 13:24:18 +0000
> @@ -315,6 +315,13 @@
>               } else if (flags & DFA_DUMP_EQUIV)
>                       cerr << "\nDFA did not generate an equivalence class\n";
>  
> +             if (flags & DFA_CONTROL_DIFF_ENCODE) {
> +                     dfa.diff_encode(flags);
> +
> +                     if (flags & DFA_DUMP_DIFF_ENCODE)
> +                             dfa.dump_diff_encode(cerr);
> +             }
> +
>               CHFA chfa(dfa, eq, flags);
>               if (flags & DFA_DUMP_TRANS_TABLE)
>                       chfa.dump(cerr);
> 
> === modified file 'parser/libapparmor_re/apparmor_re.h'
> --- parser/libapparmor_re/apparmor_re.h       2013-09-27 23:13:22 +0000
> +++ parser/libapparmor_re/apparmor_re.h       2013-12-10 13:27:08 +0000
> @@ -31,7 +31,11 @@
>  #define DFA_CONTROL_FILTER_DENY      (1 << 6)
>  #define DFA_CONTROL_REMOVE_UNREACHABLE  (1 << 7)
>  #define DFA_CONTROL_TRANS_HIGH               (1 << 8)
> +#define DFA_CONTROL_DIFF_ENCODE              (1 << 9)
>  
> +#define DFA_DUMP_DIFF_PROGRESS               (1 << 10)
> +#define DFA_DUMP_DIFF_ENCODE         (1 << 11)
> +#define DFA_DUMP_DIFF_STATS          (1 << 12)
>  #define DFA_DUMP_MIN_PARTS           (1 << 13)
>  #define DFA_DUMP_UNIQ_PERMS          (1 << 14)
>  #define DFA_DUMP_MIN_UNIQ_PERMS      (1 << 15)
> 
> === modified file 'parser/libapparmor_re/chfa.cc'
> --- parser/libapparmor_re/chfa.cc     2012-02-24 12:21:59 +0000
> +++ parser/libapparmor_re/chfa.cc     2013-12-10 14:26:52 +0000
> @@ -32,6 +32,7 @@
>  #include "hfa.h"
>  #include "chfa.h"
>  #include "../immunix.h"
> +#include "flex-tables.h"
>  
>  void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
>                                    size_t prev, size_t start)
> @@ -53,6 +54,11 @@
>       if (flags & DFA_DUMP_TRANS_PROGRESS)
>               fprintf(stderr, "Compressing HFA:\r");
>  
> +     if (dfa.diffcount)
> +             flags = YYTH_FLAG_DIFF_ENCODE;
> +     else
> +             flags = 0;
> +
>       if (eq.empty())
>               max_eq = 255;
>       else {
> @@ -242,6 +248,8 @@
>       }
>  
>  do_insert:
> +     if (from->flags & DiffEncodeFlag)
> +             base |= DiffEncodeBit32;
>       default_base.push_back(make_pair(default_state, base));
>  }
>  
> @@ -279,7 +287,7 @@
>                          << *next_check[i].second << " -> "
>                          << *next_check[i].first << ": ";
>  
> -                     size_t offs = i - 
> default_base[num[next_check[i].second]].second;
> +                     size_t offs = i - 
> base_mask_size(default_base[num[next_check[i].second]].second);
>                       if (eq.size())
>                               os << offs;
>                       else
> @@ -296,7 +304,6 @@
>   * (Only the -Cf and -Ce formats are currently supported.)
>   */
>  
> -#include "flex-tables.h"
>  #define YYTH_REGEX_MAGIC 0x1B5E783D
>  
>  static inline size_t pad64(size_t i)
> @@ -395,6 +402,7 @@
>  
>       size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 
> 1);
>       th.th_magic = htonl(YYTH_REGEX_MAGIC);
> +     th.th_flags = htonl(flags);
>       th.th_hsize = htonl(hsize);
>       th.th_ssize = htonl(hsize +
>                           flex_table_size(accept.begin(), accept.end()) +
> 
> === modified file 'parser/libapparmor_re/chfa.h'
> --- parser/libapparmor_re/chfa.h      2012-02-24 12:21:59 +0000
> +++ parser/libapparmor_re/chfa.h      2013-12-10 14:19:05 +0000
> @@ -26,6 +26,10 @@
>  
>  #include "hfa.h"
>  
> +#define BASE32_FLAGS 0xff000000
> +#define DiffEncodeBit32 0x80000000
> +#define base_mask_size(X) ((X) & ~BASE32_FLAGS)
> +

I know with only one use it's not a big deal, but I do prefer macros in
upper-case.

>  using namespace std;
>  
>  class CHFA {
> @@ -51,6 +55,7 @@
>       map<uchar, uchar> &eq;
>       uchar max_eq;
>       size_t first_free;
> +     unsigned int flags;
>  };
>  
>  #endif /* __LIBAA_RE_CHFA_H */
> 
> === modified file 'parser/libapparmor_re/flex-tables.h'
> --- parser/libapparmor_re/flex-tables.h       2010-11-09 21:39:18 +0000
> +++ parser/libapparmor_re/flex-tables.h       2013-12-10 14:17:09 +0000
> @@ -5,6 +5,7 @@
>  #include <stdint.h>
>  
>  #define YYTH_MAGIC   0xF13C57B1
> +#define YYTH_FLAG_DIFF_ENCODE 1
>  
>  struct table_set_header {
>       uint32_t        th_magic;       /* TH_MAGIC */
> 
> === modified file 'parser/libapparmor_re/hfa.cc'
> --- parser/libapparmor_re/hfa.cc      2012-05-30 21:31:41 +0000
> +++ parser/libapparmor_re/hfa.cc      2013-12-10 14:06:00 +0000
> @@ -73,6 +73,194 @@
>       return os;
>  }
>  
> +/**
> + * diff_weight - Find differential compression distance between @rel and 
> @this
> + * @rel: State to compare too
> + * Returns: An integer indicating how good rel is as a base, larger == better
> + *
> + * Find the relative weighted difference for differential state compression
> + * with queried state being compressed against @rel
> + *
> + * +1 for each transition that matches (char and dest - saves a transition)
> + * 0 for each transition that doesn't match and exists in both states
> + * 0  for transition that self has and @other doesn't (no extra required)
> + * -1 for each transition that is in @rel and not in @this (have to override)
> + *
> + * @rel should not be a state that has already been made differential or it 
> may
> + * introduce extra transitions as it does not recurse to find all transitions
> + *
> + * Should be applied after state minimization 
> +*/
> +int State::diff_weight(State *rel)
> +{
> +     int weight = 0;
> +
> +     if (this == rel)
> +             return 0;
> +
> +     if (rel->diff->rel) {
> +             /* Can only be diff encoded against states that are relative
> +              * to a state of a lower depth. ie, at most one sibling in
> +              * the chain
> +              */
> +             if (rel->diff->rel->diff->depth >= this->diff->depth)
> +                     return 0;
> +     } else if (rel->diff->depth >= this->diff->depth)
> +             return 0;
> +
> +     if (rel->flags & DiffEncodeFlag) {
> +             for (uchar i = 0; i < 256; i++) {

I think I'd rather see this as a standard 'int' or 'unsigned int'; '256'
isn't expressible as an unsigned char, so every i < 256 will involve the
usual integer promotion rules. Might as well just make 'i' an integer and
avoid the whole thing. :)

> +                     State *state = rel->next(i);
> +                     StateTrans::iterator j = trans.find(i);
> +                     if (j != trans.end()) {
> +                             if (state == j->second)
> +                                     weight++;
> +                             /* else
> +                                0 - keep transition to mask
> +                             */
> +                     } else if (state == otherwise) {
> +                             /* 0 - match of default against @rel
> +                              * We don't save a transition but don't have
> +                              * to mask either
> +                              */
> +                     } else {
> +                             /* @rel has transition not covered by @this.
> +                              * Need to add a transition to mask it
> +                              */
> +                             weight--;
> +                     }
> +             }
> +             return weight;
> +     }
> +
> +     unsigned int count = 0;
> +     for (StateTrans::iterator i = rel->trans.begin(); i != rel->trans.end();
> + i++) {
> +             StateTrans::iterator j = trans.find(i->first);
> +             if (j != trans.end()) {
> +                     if (i->second == j->second)
> +                             weight++;
> +                     /* } else {
> +                             0 - keep transition to mask
> +                     */
> +                     count++;
> +             } else if (i->second == otherwise) {
> +                     /* 0 - match of default against @rel
> +                      * We don't save a transition but don't have to
> +                      * mask either
> +                      */
> +             } else {
> +                     /* rel has transition not covered by @this.  Need to
> +                      * add a transition to mask
> +                      */
> +                     weight--;
> +             }
> +     }
> +
> +     /* cover transitions in @this but not in @rel */
> +     unsigned int this_count = 0;
> +     if (count < trans.size()) {
> +             for (StateTrans::iterator i = trans.begin(); i != trans.end(); 
> i++) {
> +                     StateTrans::iterator j = rel->trans.find(i->first);
> +                     if (j == rel->trans.end()) {
> +                             this_count++;
> +                             if (i->second == rel->otherwise)
> +                                     /* replaced by rel->cases.otherwise */
> +                                     weight++;
> +                     }
> +             }
> +     }

The previous two loops look like they are an O(M*log(N) + N*log(M)) operation
(assuming trans.find() is O(log(N)) operation) -- while in the long run,
this would be obviously better than an O(N^2) nested loops, I wonder if
the smaller amounts of data that I suspect will be involved here if the
simplicity of nested loops would go more quickly.


> +     if (rel->otherwise != otherwise) {
> +             /* rel default transitions have to be masked with transitions
> +              * This covers all transitions not covered above
> +              */
> +             weight -= 256 - (rel->trans.size() + this_count);
> +     }
> +
> +     return weight;
> +}
> +
> +/**
> + * make_relative - Make this state relative to @rel
> + * @rel: state to make this state relative too
> + *
> + * @rel can be a relative (differentially compressed state)
> + */
> +int State::make_relative(State *rel)
> +{
> +     int weight = 0;
> +
> +     if (this == rel || !rel)
> +             return 0;
> +
> +     if (flags & DiffEncodeFlag)
> +             return 0;
> +
> +     flags |= DiffEncodeFlag;
> +
> +     for (int i = 0; i < 256 ; i++) {
> +             State *next = rel->next(i);
> +
> +             StateTrans::iterator j = trans.find(i);
> +             if (j != trans.end()) {
> +                     if (j->second == next) {
> +                             trans.erase(j);
> +                             weight++;
> +                     }
> +                     /* else keep transition to mask */
> +             } else if (otherwise == next) {
> +                     /* do nothing, otherwise transition disappears when
> +                      * reassigned
> +                      */
> +             } else {
> +                     /* need a new transition to mask those in lower state */
> +                     trans[i] = otherwise;
> +                     weight--;
> +             }
> +     }
> +
> +     otherwise = rel;
> +
> +     return weight;
> +}
> +
> +/**
> + * flatten_differential - remove differential encode from this state
> + */
> +void State::flatten_relative(void)
> +{
> +     if (!(flags & DiffEncodeFlag))
> +             return;
> +
> +     map<State *, int> count;
> +
> +     for (int i = 0; i < 256; i++)
> +             count[next(i)] += 1;
> +
> +     int j = 0;
> +     State *def = next(0);
> +     for (int i = 1; i < 256; i++) {
> +             if (count[next(i)] > count[next(j)]) {
> +                     j = i;
> +                     def = next(i);
> +             }
> +     }
> +
> +     for (int i = 0; i < 256; i++) {
> +             if (trans.find(i) != trans.end()) {
> +                     if (trans[i] == def)
> +                             trans.erase(i);
> +             } else {
> +                     if (trans[i] != def)
> +                             trans[i] = next(i);
> +             }
> +     }
> +
> +     otherwise = def;
> +     flags = flags & ~DiffEncodeFlag;
> +}
> +
>  static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet 
> **nnodes
>  )
>  {
> @@ -175,6 +363,7 @@
>  DFA::DFA(Node *root, dfaflags_t flags): root(root)
>  {
>       int i = 0;
> +     diffcount = 0;          /* set by diff_encode */
>  
>       if (flags & DFA_DUMP_PROGRESS)
>               fprintf(stderr, "Creating dfa:\r");
> @@ -606,6 +795,239 @@
>       }
>  }
>  
> +
> +/* diff_encode helper functions */
> +static unsigned int add_to_dag(DiffDag *dag, State *state,
> +                            State *parent)
> +{
> +     unsigned int rc = 0;
> +     if (!state->diff) {
> +             dag->rel = NULL;
> +             if (parent)
> +                     dag->depth = parent->diff->depth + 1;
> +             else
> +                     dag->depth = 1;
> +             dag->state = state;
> +             state->diff = dag;
> +             rc = 1;
> +     }
> +     if (parent && parent->diff->depth < state->diff->depth)
> +             state->diff->parents.push_back(parent);
> +     return rc;
> +}
> +
> +static int diff_partition(State *state, Partition &part, State **candidate)
> +{
> +     int weight = 0;
> +     *candidate = NULL;
> +
> +     for (Partition::iterator i = part.begin(); i != part.end(); i++) {
> +             if (*i == state)
> +                     continue;
> +
> +             int tmp = state->diff_weight(*i);
> +             if (tmp > weight) {
> +                     weight = tmp;
> +                     *candidate = *i;
> +             }
> +     }
> +     return weight;
> +}
> +
> +/**
> + * diff_encode - compress dfa by differentially encoding state transitions
> + * @dfa_flags: flags controling dfa creation
> + *
> + * This function reduces the number of transitions that need to be stored
> + * by encoding transitions as the difference between the state and a
> + * another transitions that is set as the states default.
> + *
> + * For performance reasons this function does not try to compute the
> + * absolute best encoding (maximal spanning tree) but instead computes
> + * a very good encoding within the following limitations.
> + *   - Not all states have to be differentially encoded.  This allows for
> + *     multiple states to be used as a terminating basis.
> + *   - The number of state transitions needed to match an input of length
> + *     m will be 2m
> + *
> + * To guarentee this the ordering and distance calculation is done in the
> + * following manner.
> + * - A DAG of the DFA is created starting with the start state(s).
> + * - A state can only be relative (have a differential encoding) to
> + *   another state if that state has
> + *   - a lower depth in the DAG
> + *   - is a sibling (same depth) that is not relative
> + *   - is a sibling that is relative to a state with lower depth in the DAG
> + *
> + * The run time constraints are maintained by the DAG ordering + relative
> + * state constraints.  For any input character C when at state S with S being
> + * at level N in the DAG then at most 2N states must be traversed to find the
> + * transition for C.  However on the maximal number of transitions is not 
> m*m,
> + * because  when a character is matched and forward movement is made through
> + * the DFA any relative transition search will move back through the DAG 
> order.
> + * So say for character C we start matching on a state S that is at depth 10
> + * in the DAG.  The transition for C is not found in S and we recurse 
> backwards
> + * to a depth of 6.  A transition is found and it steps to the next state, 
> but
> + * the state transition at most will only move 1 deeper into the DAG so for
> + * the next state the maximum number of states traversed is 2*7.
> + */
> +void DFA::diff_encode(dfaflags_t flags)
> +{
> +     DiffDag *dag;
> +     unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
> +
> +     /* clear the depth flag */
> +     for (Partition::iterator i = states.begin(); i != states.end(); i++) {
> +             (*i)->diff = NULL;
> +             transitions += (*i)->trans.size();
> +     }
> +
> +     /* Prealloc structures we need.  We know the exact number of elements,
> +      * and once setup they don't change so we don't need the flexibility
> +      * or overhead of stl, just allocate the needed data as an array
> +      */
> +     dag = new DiffDag [states.size()];
> +
> +     /* Generate DAG ordering and parent sets */
> +     add_to_dag(&dag[0], nonmatching, NULL);
> +     add_to_dag(&dag[1], start, NULL);
> +
> +     unsigned int tail = 2;
> +     for (unsigned int i = 1; i < tail; i++) {
> +             State *state = dag[i].state;
> +             State *child = dag[i].state->otherwise;
> +             if (child)
> +                     tail += add_to_dag(&dag[tail], child, state);
> +
> +             for (StateTrans::iterator j = state->trans.begin(); j != 
> state->trans.end(); j++) {
> +                     child = j->second;
> +                     tail += add_to_dag(&dag[tail], child, state);
> +             }
> +     }
> +     depth = dag[tail - 1].depth;
> +
> +     /* calculate which state to make a transitions relative too */
> +     for (unsigned int i = 2; i < tail; i++) {
> +             State *state = dag[i].state;
> +             State *candidate = NULL;
> +
> +             int weight = diff_partition(state,
> +                                         state->otherwise->diff->parents,
> +                                         &candidate);
> +
> +             for (StateTrans::iterator j = state->trans.begin(); j != 
> state->trans.end(); j++) {
> +                     State *tmp_candidate;
> +                     int tmp = diff_partition(state,
> +                                              j->second->diff->parents,
> +                                              &tmp_candidate);
> +                     if (tmp > weight) {
> +                             weight = tmp;
> +                             candidate = tmp_candidate;
> +                     }
> +             }
> +
> +             if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
> +                     cerr << "\033[2KDiff Encode: " << i << " of "
> +                          << tail << ".  Diff states " << xcount
> +                          << " Savings " << xweight << "\r";
> +
> +             state->diff->rel = candidate;
> +             if (candidate) {
> +                     xcount++;
> +                     xweight += weight;
> +             }
> +     }
> +
> +     /* now make transitions relative, start at the back of the list so
> +      * as to start with the last transitions and work backwards to avoid
> +      * having to traverse multiple previous states (that have been made
> +      * relative already) to reconstruct previous state transition table
> +      */
> +     unsigned int aweight = 0;
> +     diffcount = 0;
> +     for (int i = tail - 1; i > 1; i--) {
> +             if (dag[i].rel) {
> +                     int weight = dag[i].state->make_relative(dag[i].rel);
> +                     aweight += weight;
> +                     diffcount++;
> +             }
> +     }
> +
> +     if (flags & DFA_DUMP_DIFF_STATS)
> +             cerr << "Diff encode  states: " << diffcount << " of "
> +                     << tail << " reached @ depth "  << depth << ". "
> +                  <<  aweight << " trans removed\n";
> +
> +     if (xweight != aweight)
> +             cerr << "Diff encode error: actual savings " << aweight
> +                  << " != expected " << xweight << "\n";
> +
> +     if (xcount != diffcount)
> +             cerr << "Diff encode error: actual count " << diffcount
> +                  << " != expected " << xcount << " \n";
> +
> +     /* cleanup */
> +     for (unsigned int i = 0; i < tail; i++)
> +             dag[i].parents.clear();
> +     delete [] dag;

Something about the dag[i].parents.clear() seems out of place; will it
leak the 'shells' of the data structures? Can these be fiddled with so
they'll be properly cleaned up when they go out of scope?

> +}
> +
> +/**
> + * flatten_differential - remove differential state encoding
> + *
> + * Flatten the dfa back into a flat encoding.
> + */
> +void DFA::undiff_encode(void)
> +{
> +     for (Partition::iterator i = states.begin(); i != states.end(); i++)
> +             (*i)->flatten_relative();
> +     diffcount = 0;
> +}
> +
> +void DFA::dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
> +                       Partition &chain, State *state, unsigned int &count,
> +                       unsigned int &total, unsigned int &max)
> +{
> +     if (relmap[state].size() == 0) {
> +             for (Partition::iterator i = chain.begin(); i != chain.end(); 
> i++)
> +                     os << **i << " <- ";
> +             os << *state << "\n";
> +
> +             count++;
> +             total += chain.size() + 1;
> +             if (chain.size() + 1 > max)
> +                     max = chain.size() + 1;
> +     }
> +
> +     chain.push_back(state);
> +     for (Partition::iterator i = relmap[state].begin(); i != 
> relmap[state].end(); i++)
> +             dump_diff_chain(os, relmap, chain, *i, count, total, max);
> +     chain.pop_back();
> +}
> +
> +/* Dump the DFA diff_encoding chains */
> +void DFA::dump_diff_encode(ostream &os)
> +{
> +     map<State *, Partition> rel;
> +     Partition base, chain;
> +
> +     for (Partition::iterator i = states.begin(); i != states.end(); i++) {
> +             if ((*i)->flags & DiffEncodeFlag)
> +                     rel[(*i)->otherwise].push_back(*i);
> +             else
> +                     base.push_back(*i);
> +     }
> +
> +     unsigned int count = 0, total = 0, max = 0;
> +     for (Partition::iterator i = base.begin(); i != base.end(); i++)
> +             dump_diff_chain(os, rel, chain, *i, count, total, max);
> +
> +     os << base.size() << " non-differentially encoded states\n";
> +     os << "chains: " << count - base.size() << "\n";
> +     os << "average chain size: " << (double) (total - base.size()) / 
> (double) (count - base.size()) << "\n";
> +     os << "longest chain: " << max << "\n";
> +}
> +
>  /**
>   * text-dump the DFA (for debugging).
>   */
> 
> === modified file 'parser/libapparmor_re/hfa.h'
> --- parser/libapparmor_re/hfa.h       2012-05-30 21:31:41 +0000
> +++ parser/libapparmor_re/hfa.h       2013-12-10 14:10:29 +0000
> @@ -28,10 +28,13 @@
>  #include <map>
>  #include <vector>
>  
> +#include <assert.h>
>  #include <stdint.h>
>  
>  #include "expr-tree.h"
>  
> +#define DiffEncodeFlag 1
> +
>  class State;
>  
>  typedef map<uchar, State *> StateTrans;
> @@ -334,6 +337,19 @@
>       }
>  };
>  
> +/* Temporary state structure used when building differential encoding
> + * @parents - set of states that have transitions to this state
> + * @depth - level in the DAG
> + * @state - back reference to state this DAG entry belongs
> + * @rel - state that this state is relative to for differential encoding
> + */
> +struct DiffDag {
> +     Partition parents;
> +     int depth;
> +     State *state;
> +     State *rel;
> +};
> +
>  /*
>   * State - DFA individual state information
>   * label: a unique label to identify the state used for pretty printing
> @@ -352,7 +368,7 @@
>  class State {
>  public:
>       State(int l, ProtoState &n, State *other) throw(int):
> -     label(l), perms(), trans()
> +             label(l), flags(0), perms(), trans()
>       {
>               int error;
>  
> @@ -372,15 +388,30 @@
>       };
>  
>       State *next(uchar c) {
> -             StateTrans::iterator i = trans.find(c);
> -             if (i != trans.end())
> -                     return i->second;
> -             return otherwise;
> -     };
> +             State *state = this;
> +             do {
> +                     StateTrans::iterator i = state->trans.find(c);
> +                     if (i != state->trans.end())
> +                             return i->second;
> +
> +                     if (!(state->flags & DiffEncodeFlag))
> +                             return state->otherwise;
> +                     state = state->otherwise;
> +             } while (state);
> +
> +             /* never reached */
> +             assert(0);
> +             return NULL;
> +     }
> +
> +     int diff_weight(State *rel);
> +     int make_relative(State *rel);
> +     void flatten_relative(void);
>  
>       int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
>  
>       int label;
> +     int flags;
>       perms_t perms;
>       StateTrans trans;
>       State *otherwise;
> @@ -389,6 +420,7 @@
>       union {
>               Partition *partition;   /* used during minimization */
>               ProtoState proto;       /* used during creation */
> +             DiffDag *diff;          /* used during diff encoding */
>       };
>  };
>  
> @@ -429,12 +461,16 @@
>       }
>  };
>  
> +
>  /* Transitions in the DFA. */
> -
>  class DFA {
>       void dump_node_to_dfa(void);
>       State *add_new_state(NodeSet *nodes, State *other);
>       void update_state_transitions(State *state);
> +     void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
> +                          Partition &chain, State *state,
> +                          unsigned int &count, unsigned int &total,
> +                          unsigned int &max);
>  
>       /* temporary values used during computations */
>       NodeCache anodes_cache;
> @@ -455,11 +491,19 @@
>       size_t hash_trans(State *s);
>       void minimize(dfaflags_t flags);
>       int apply_and_clear_deny(void);
> +
> +     void diff_encode(dfaflags_t flags);
> +     void undiff_encode(void);
> +     void dump_diff_encode(ostream &os);
> +
>       void dump(ostream &os);
>       void dump_dot_graph(ostream &os);
>       void dump_uniq_perms(const char *s);
> +
>       map<uchar, uchar> equivalence_classes(dfaflags_t flags);
>       void apply_equivalence_classes(map<uchar, uchar> &eq);
> +
> +     unsigned int diffcount;
>       Node *root;
>       State *nonmatching, *start;
>       Partition states;
> 
> === modified file 'parser/parser_main.c'
> --- parser/parser_main.c      2013-10-30 00:03:23 +0000
> +++ parser/parser_main.c      2013-12-10 14:34:13 +0000
> @@ -194,10 +194,10 @@
>         DFA_DUMP_SIMPLE_TREE },
>       { 1, "stats", "Dump all compile stats",
>         DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
> -       DFA_DUMP_EQUIV_STATS },
> +       DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
>       { 1, "progress", "Dump progress for all compile phases",
>         DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
> -       DFA_DUMP_TRANS_STATS },
> +       DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
>       { 1, "dfa-progress", "Dump dfa creation as in progress",
>         DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
>       { 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
> @@ -222,6 +222,12 @@
>       { 1, "equiv-stats", "Dump equivance class stats",
>         DFA_DUMP_EQUIV_STATS },
>       { 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
> +     { 1, "diff-encode", "Dump differential encoding",
> +       DFA_DUMP_DIFF_ENCODE },
> +     { 1, "diff-stats", "Dump differential encoding stats",
> +       DFA_DUMP_DIFF_STATS },
> +     { 1, "diff-progress", "Dump progress of differential encoding",
> +       DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
>       { 0, NULL, NULL, 0 },
>  };
>  
> @@ -251,6 +257,8 @@
>         DFA_CONTROL_TRANS_HIGH },
>       { 2, "compress-fast", "do faster dfa transition table compression",
>         DFA_CONTROL_TRANS_HIGH },
> +     { 1, "diff-encode", "Differentially encode transitions",
> +       DFA_CONTROL_DIFF_ENCODE },
>       { 0, NULL, NULL, 0 },
>  };
>  


Thanks!

Attachment: signature.asc
Description: Digital signature

-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to