2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 01:57:43 +00:00

parser: replace dynamic_cast with is_type method

The dynamic_cast operator is slow as it needs to look at RTTI
information and even does some string comparisons, especially in deep
hierarchies like the one for Node. Profiling with callgrind showed
that dynamic_cast can eat a huge portion of the running time, as it
takes most of the time that is spent in the simplify_tree()
function. For some complex profiles, the number of calls to
dynamic_cast can be in the range of millions.

This commit replaces the use of dynamic_cast in the Node hierarchy
with a method called is_type(), which returns true if the pointer can
be casted to the specified type. It works by looking at a Node object
field that is an integer with bits set for each type up in the
hierarchy. Therefore, dynamic_cast is replaced by a simple bits
operation.

This change can reduce the compilation times for some profiles more
that 50%, especially in arm/arm64 arch. This opens the door to maybe
avoid "-O no-expr-simplify" in the snapd daemon, as now that option
would make the compilation slower in almost all cases.

This is the example profile used in some of my tests, with this change
the run-time is around 1/3 of what it was before on an x86 laptop:

profile "test" (attach_disconnected,mediate_deleted) {
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.fcitx.Fcitx.InputContext
    member="{Close,Destroy,Enable}IC"
    peer=(label=unconfined),
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.fcitx.Fcitx.InputContext
    member=Reset
    peer=(label=unconfined),
dbus receive
    bus=fcitx
    peer=(label=unconfined),
dbus receive
    bus=session
    interface=org.fcitx.Fcitx.*
    peer=(label=unconfined),
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.fcitx.Fcitx.InputContext
    member="Focus{In,Out}"
    peer=(label=unconfined),
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.fcitx.Fcitx.InputContext
    member="{CommitPreedit,Set*}"
    peer=(label=unconfined),
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.fcitx.Fcitx.InputContext
    member="{MouseEvent,ProcessKeyEvent}"
    peer=(label=unconfined),
dbus send
    bus={fcitx,session}
    path=/inputcontext_[0-9]*
    interface=org.freedesktop.DBus.Properties
    member=GetAll
    peer=(label=unconfined),
dbus (send)
    bus=session
    path=/org/a11y/bus
    interface=org.a11y.Bus
    member=GetAddress
    peer=(label=unconfined),
dbus (send)
    bus=session
    path=/org/a11y/bus
    interface=org.freedesktop.DBus.Properties
    member=Get{,All}
    peer=(label=unconfined),
dbus (receive, send)
    bus=accessibility
    path=/org/a11y/atspi/**
    peer=(label=unconfined),
dbus (send)
    bus=system
    path=/org/freedesktop/Accounts
    interface=org.freedesktop.DBus.Introspectable
    member=Introspect
    peer=(label=unconfined),
dbus (send)
    bus=system
    path=/org/freedesktop/Accounts
    interface=org.freedesktop.Accounts
    member=FindUserById
    peer=(label=unconfined),
dbus (receive, send)
    bus=system
    path=/org/freedesktop/Accounts/User[0-9]*
    interface=org.freedesktop.DBus.Properties
    member={Get,PropertiesChanged}
    peer=(label=unconfined),
dbus (send)
    bus=session
    interface=org.gtk.Actions
    member=Changed
    peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
    bus=session
    interface=org.gtk.Actions
    member={Activate,DescribeAll,SetState}
    peer=(label=unconfined),
dbus (receive)
    bus=session
    interface=org.gtk.Menus
    member={Start,End}
    peer=(label=unconfined),
dbus (send)
    bus=session
    interface=org.gtk.Menus
    member=Changed
    peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (send)
    bus=session
    path="/com/ubuntu/MenuRegistrar"
    interface="com.ubuntu.MenuRegistrar"
    member="{Register,Unregister}{App,Surface}Menu"
    peer=(label=unconfined),
}
This commit is contained in:
Alfonso Sánchez-Beato 2021-02-15 16:26:18 +01:00
parent ee5303c8a0
commit 5aab543a3b
4 changed files with 165 additions and 79 deletions

View File

@ -97,11 +97,11 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
*/
exact_match = 1;
for (depth_first_traversal i(tree); i && exact_match; i++) {
if (dynamic_cast<StarNode *>(*i) ||
dynamic_cast<PlusNode *>(*i) ||
dynamic_cast<AnyCharNode *>(*i) ||
dynamic_cast<CharSetNode *>(*i) ||
dynamic_cast<NotCharSetNode *>(*i))
if ((*i)->is_type(NODE_TYPE_STAR) ||
(*i)->is_type(NODE_TYPE_PLUS) ||
(*i)->is_type(NODE_TYPE_ANYCHAR) ||
(*i)->is_type(NODE_TYPE_CHARSET) ||
(*i)->is_type(NODE_TYPE_NOTCHARSET))
exact_match = 0;
}

View File

@ -210,7 +210,7 @@ int TwoChildNode::normalize_eps(int dir)
// Test for E | (E | E) and E . (E . E) which will
// result in an infinite loop
Node *c = child[!dir];
if (dynamic_cast<TwoChildNode *>(c) &&
if (c->is_type(NODE_TYPE_TWOCHILD) &&
&epsnode == c->child[dir] &&
&epsnode == c->child[!dir]) {
c->release();
@ -229,7 +229,7 @@ void CatNode::normalize(int dir)
for (;;) {
if (normalize_eps(dir)) {
continue;
} else if (dynamic_cast<CatNode *>(child[dir])) {
} else if (child[dir]->is_type(NODE_TYPE_CAT)) {
// (ab)c -> a(bc)
rotate_node(this, dir);
} else {
@ -248,11 +248,11 @@ void AltNode::normalize(int dir)
for (;;) {
if (normalize_eps(dir)) {
continue;
} else if (dynamic_cast<AltNode *>(child[dir])) {
} else if (child[dir]->is_type(NODE_TYPE_ALT)) {
// (a | b) | c -> a | (b | c)
rotate_node(this, dir);
} else if (dynamic_cast<CharSetNode *>(child[dir]) &&
dynamic_cast<CharNode *>(child[!dir])) {
} else if (child[dir]->is_type(NODE_TYPE_CHARSET) &&
child[!dir]->is_type(NODE_TYPE_CHAR)) {
// [a] | b -> b | [a]
Node *c = child[dir];
child[dir] = child[!dir];
@ -344,7 +344,7 @@ static Node *alt_to_charsets(Node *t, int dir)
static Node *basic_alt_factor(Node *t, int dir)
{
if (!dynamic_cast<AltNode *>(t))
if (!t->is_type(NODE_TYPE_ALT))
return t;
if (t->child[dir]->eq(t->child[!dir])) {
@ -355,8 +355,8 @@ static Node *basic_alt_factor(Node *t, int dir)
return tmp;
}
// (ab) | (ac) -> a(b|c)
if (dynamic_cast<CatNode *>(t->child[dir]) &&
dynamic_cast<CatNode *>(t->child[!dir]) &&
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
t->child[!dir]->is_type(NODE_TYPE_CAT) &&
t->child[dir]->child[dir]->eq(t->child[!dir]->child[dir])) {
// (ab) | (ac) -> a(b|c)
Node *left = t->child[dir];
@ -369,7 +369,7 @@ static Node *basic_alt_factor(Node *t, int dir)
return left;
}
// a | (ab) -> a (E | b) -> a (b | E)
if (dynamic_cast<CatNode *>(t->child[!dir]) &&
if (t->child[!dir]->is_type(NODE_TYPE_CAT) &&
t->child[dir]->eq(t->child[!dir]->child[dir])) {
Node *c = t->child[!dir];
t->child[dir]->release();
@ -379,7 +379,7 @@ static Node *basic_alt_factor(Node *t, int dir)
return c;
}
// ab | (a) -> a (b | E)
if (dynamic_cast<CatNode *>(t->child[dir]) &&
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
t->child[dir]->child[dir]->eq(t->child[!dir])) {
Node *c = t->child[dir];
t->child[!dir]->release();
@ -394,7 +394,7 @@ static Node *basic_alt_factor(Node *t, int dir)
static Node *basic_simplify(Node *t, int dir)
{
if (dynamic_cast<CatNode *>(t) && &epsnode == t->child[!dir]) {
if (t->is_type(NODE_TYPE_CAT) && &epsnode == t->child[!dir]) {
// aE -> a
Node *tmp = t->child[dir];
t->child[dir] = NULL;
@ -419,7 +419,7 @@ static Node *basic_simplify(Node *t, int dir)
*/
Node *simplify_tree_base(Node *t, int dir, bool &mod)
{
if (dynamic_cast<ImportantNode *>(t))
if (t->is_type(NODE_TYPE_IMPORTANT))
return t;
for (int i = 0; i < 2; i++) {
@ -442,15 +442,15 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
}
/* all tests after this must meet 2 alt node condition */
if (!dynamic_cast<AltNode *>(t) ||
!dynamic_cast<AltNode *>(t->child[!dir]))
if (!t->is_type(NODE_TYPE_ALT) ||
!t->child[!dir]->is_type(NODE_TYPE_ALT))
break;
// a | (a | b) -> (a | b)
// a | (b | (c | a)) -> (b | (c | a))
Node *p = t;
Node *i = t->child[!dir];
for (; dynamic_cast<AltNode *>(i); p = i, i = i->child[!dir]) {
for (; i->is_type(NODE_TYPE_ALT); p = i, i = i->child[!dir]) {
if (t->child[dir]->eq(i->child[dir])) {
Node *tmp = t->child[!dir];
t->child[!dir] = NULL;
@ -475,19 +475,19 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
int count = 0;
Node *subject = t->child[dir];
Node *a = subject;
if (dynamic_cast<CatNode *>(subject))
if (subject->is_type(NODE_TYPE_CAT))
a = subject->child[dir];
for (pp = p = t, i = t->child[!dir];
dynamic_cast<AltNode *>(i);) {
if ((dynamic_cast<CatNode *>(i->child[dir]) &&
i->is_type(NODE_TYPE_ALT);) {
if ((i->child[dir]->is_type(NODE_TYPE_CAT) &&
a->eq(i->child[dir]->child[dir])) ||
(a->eq(i->child[dir]))) {
// extract matching alt node
p->child[!dir] = i->child[!dir];
i->child[!dir] = subject;
subject = basic_simplify(i, dir);
if (dynamic_cast<CatNode *>(subject))
if (subject->is_type(NODE_TYPE_CAT))
a = subject->child[dir];
else
a = subject;
@ -502,7 +502,7 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
}
// last altnode in chain check other dir as well
if ((dynamic_cast<CatNode *>(i) &&
if ((i->is_type(NODE_TYPE_CAT) &&
a->eq(i->child[dir])) || (a->eq(i))) {
count++;
if (t == p) {
@ -528,7 +528,7 @@ int debug_tree(Node *t)
{
int nodes = 1;
if (!dynamic_cast<ImportantNode *>(t)) {
if (!t->is_type(NODE_TYPE_IMPORTANT)) {
if (t->child[0])
nodes += debug_tree(t->child[0]);
if (t->child[1])
@ -539,30 +539,30 @@ int debug_tree(Node *t)
static void count_tree_nodes(Node *t, struct node_counts *counts)
{
if (dynamic_cast<AltNode *>(t)) {
if (t->is_type(NODE_TYPE_ALT)) {
counts->alt++;
count_tree_nodes(t->child[0], counts);
count_tree_nodes(t->child[1], counts);
} else if (dynamic_cast<CatNode *>(t)) {
} else if (t->is_type(NODE_TYPE_CAT)) {
counts->cat++;
count_tree_nodes(t->child[0], counts);
count_tree_nodes(t->child[1], counts);
} else if (dynamic_cast<PlusNode *>(t)) {
} else if (t->is_type(NODE_TYPE_PLUS)) {
counts->plus++;
count_tree_nodes(t->child[0], counts);
} else if (dynamic_cast<StarNode *>(t)) {
} else if (t->is_type(NODE_TYPE_STAR)) {
counts->star++;
count_tree_nodes(t->child[0], counts);
} else if (dynamic_cast<OptionalNode *>(t)) {
} else if (t->is_type(NODE_TYPE_OPTIONAL)) {
counts->optional++;
count_tree_nodes(t->child[0], counts);
} else if (dynamic_cast<CharNode *>(t)) {
} else if (t->is_type(NODE_TYPE_CHAR)) {
counts->charnode++;
} else if (dynamic_cast<AnyCharNode *>(t)) {
} else if (t->is_type(NODE_TYPE_ANYCHAR)) {
counts->any++;
} else if (dynamic_cast<CharSetNode *>(t)) {
} else if (t->is_type(NODE_TYPE_CHARSET)) {
counts->charset++;
} else if (dynamic_cast<NotCharSetNode *>(t)) {
} else if (t->is_type(NODE_TYPE_NOTCHARSET)) {
counts->notcharset++;
}
}
@ -635,7 +635,8 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
void flip_tree(Node *node)
{
for (depth_first_traversal i(node); i; i++) {
if (CatNode *cat = dynamic_cast<CatNode *>(*i)) {
if ((*i)->is_type(NODE_TYPE_CAT)) {
CatNode *cat = static_cast<CatNode *>(*i);
swap(cat->child[0], cat->child[1]);
}
}

View File

@ -222,16 +222,43 @@ typedef struct Cases {
ostream &operator<<(ostream &os, Node &node);
#define NODE_TYPE_NODE 0
#define NODE_TYPE_INNER (1 << 0)
#define NODE_TYPE_ONECHILD (1 << 1)
#define NODE_TYPE_TWOCHILD (1 << 2)
#define NODE_TYPE_LEAF (1 << 3)
#define NODE_TYPE_EPS (1 << 4)
#define NODE_TYPE_IMPORTANT (1 << 5)
#define NODE_TYPE_C (1 << 6)
#define NODE_TYPE_CHAR (1 << 7)
#define NODE_TYPE_CHARSET (1 << 8)
#define NODE_TYPE_NOTCHARSET (1 << 9)
#define NODE_TYPE_ANYCHAR (1 << 10)
#define NODE_TYPE_STAR (1 << 11)
#define NODE_TYPE_OPTIONAL (1 << 12)
#define NODE_TYPE_PLUS (1 << 13)
#define NODE_TYPE_CAT (1 << 14)
#define NODE_TYPE_ALT (1 << 15)
#define NODE_TYPE_SHARED (1 << 16)
#define NODE_TYPE_ACCEPT (1 << 17)
#define NODE_TYPE_MATCHFLAG (1 << 18)
#define NODE_TYPE_EXACTMATCHFLAG (1 << 19)
#define NODE_TYPE_DENYMATCHFLAG (1 << 20)
/* An abstract node in the syntax tree. */
class Node {
public:
Node(): nullable(false), label(0) { child[0] = child[1] = 0; }
Node(Node *left): nullable(false), label(0)
Node(): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
{
child[0] = child[1] = 0;
}
Node(Node *left): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
{
child[0] = left;
child[1] = 0;
}
Node(Node *left, Node *right): nullable(false), label(0)
Node(Node *left, Node *right): nullable(false),
type_flags(NODE_TYPE_NODE), label(0)
{
child[0] = left;
child[1] = right;
@ -302,6 +329,13 @@ public:
NodeSet firstpos, lastpos, followpos;
/* child 0 is left, child 1 is right */
Node *child[2];
/*
* Bitmap that stores supported pointer casts for the Node, composed
* by the NODE_TYPE_* flags. This is used by is_type() as a substitute
* of costly dynamic_cast calls.
*/
unsigned type_flags;
bool is_type(unsigned type) { return type_flags & type; }
unsigned int label; /* unique number for debug etc */
/**
@ -315,25 +349,34 @@ public:
class InnerNode: public Node {
public:
InnerNode(): Node() { };
InnerNode(Node *left): Node(left) { };
InnerNode(Node *left, Node *right): Node(left, right) { };
InnerNode(): Node() { type_flags |= NODE_TYPE_INNER; };
InnerNode(Node *left): Node(left) { type_flags |= NODE_TYPE_INNER; };
InnerNode(Node *left, Node *right): Node(left, right)
{
type_flags |= NODE_TYPE_INNER;
};
};
class OneChildNode: public InnerNode {
public:
OneChildNode(Node *left): InnerNode(left) { };
OneChildNode(Node *left): InnerNode(left)
{
type_flags |= NODE_TYPE_ONECHILD;
};
};
class TwoChildNode: public InnerNode {
public:
TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
TwoChildNode(Node *left, Node *right): InnerNode(left, right)
{
type_flags |= NODE_TYPE_TWOCHILD;
};
virtual int normalize_eps(int dir);
};
class LeafNode: public Node {
public:
LeafNode(): Node() { };
LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; };
virtual void normalize(int dir __attribute__((unused))) { return; }
};
@ -342,6 +385,7 @@ class EpsNode: public LeafNode {
public:
EpsNode(): LeafNode()
{
type_flags |= NODE_TYPE_EPS;
nullable = true;
label = 0;
}
@ -356,7 +400,7 @@ public:
void compute_lastpos() { }
int eq(Node *other)
{
if (dynamic_cast<EpsNode *>(other))
if (other->is_type(NODE_TYPE_EPS))
return 1;
return 0;
}
@ -373,7 +417,7 @@ public:
*/
class ImportantNode: public LeafNode {
public:
ImportantNode(): LeafNode() { }
ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; }
void compute_firstpos() { firstpos.insert(this); }
void compute_lastpos() { lastpos.insert(this); }
virtual void follow(Cases &cases) = 0;
@ -386,7 +430,7 @@ public:
*/
class CNode: public ImportantNode {
public:
CNode(): ImportantNode() { }
CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; }
int is_accept(void) { return false; }
int is_postprocess(void) { return false; }
};
@ -394,7 +438,7 @@ public:
/* Match one specific character (/c/). */
class CharNode: public CNode {
public:
CharNode(transchar c): c(c) { }
CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; }
void follow(Cases &cases)
{
NodeSet **x = &cases.cases[c];
@ -408,8 +452,8 @@ public:
}
int eq(Node *other)
{
CharNode *o = dynamic_cast<CharNode *>(other);
if (o) {
if (other->is_type(NODE_TYPE_CHAR)) {
CharNode *o = static_cast<CharNode *>(other);
return c == o->c;
}
return 0;
@ -439,7 +483,10 @@ public:
/* Match a set of characters (/[abc]/). */
class CharSetNode: public CNode {
public:
CharSetNode(Chars &chars): chars(chars) { }
CharSetNode(Chars &chars): chars(chars)
{
type_flags |= NODE_TYPE_CHARSET;
}
void follow(Cases &cases)
{
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
@ -455,8 +502,11 @@ public:
}
int eq(Node *other)
{
CharSetNode *o = dynamic_cast<CharSetNode *>(other);
if (!o || chars.size() != o->chars.size())
if (!other->is_type(NODE_TYPE_CHARSET))
return 0;
CharSetNode *o = static_cast<CharSetNode *>(other);
if (chars.size() != o->chars.size())
return 0;
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
@ -498,7 +548,10 @@ public:
/* Match all except one character (/[^abc]/). */
class NotCharSetNode: public CNode {
public:
NotCharSetNode(Chars &chars): chars(chars) { }
NotCharSetNode(Chars &chars): chars(chars)
{
type_flags |= NODE_TYPE_NOTCHARSET;
}
void follow(Cases &cases)
{
if (!cases.otherwise)
@ -522,8 +575,11 @@ public:
}
int eq(Node *other)
{
NotCharSetNode *o = dynamic_cast<NotCharSetNode *>(other);
if (!o || chars.size() != o->chars.size())
if (!other->is_type(NODE_TYPE_NOTCHARSET))
return 0;
NotCharSetNode *o = static_cast<NotCharSetNode *>(other);
if (chars.size() != o->chars.size())
return 0;
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
@ -565,7 +621,7 @@ public:
/* Match any character (/./). */
class AnyCharNode: public CNode {
public:
AnyCharNode() { }
AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; }
void follow(Cases &cases)
{
if (!cases.otherwise)
@ -579,7 +635,7 @@ public:
}
int eq(Node *other)
{
if (dynamic_cast<AnyCharNode *>(other))
if (other->is_type(NODE_TYPE_ANYCHAR))
return 1;
return 0;
}
@ -589,7 +645,11 @@ public:
/* Match a node zero or more times. (This is a unary operator.) */
class StarNode: public OneChildNode {
public:
StarNode(Node *left): OneChildNode(left) { nullable = true; }
StarNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_STAR;
nullable = true;
}
void compute_firstpos() { firstpos = child[0]->firstpos; }
void compute_lastpos() { lastpos = child[0]->lastpos; }
void compute_followpos()
@ -601,7 +661,7 @@ public:
}
int eq(Node *other)
{
if (dynamic_cast<StarNode *>(other))
if (other->is_type(NODE_TYPE_STAR))
return child[0]->eq(other->child[0]);
return 0;
}
@ -618,12 +678,16 @@ public:
/* Match a node zero or one times. */
class OptionalNode: public OneChildNode {
public:
OptionalNode(Node *left): OneChildNode(left) { nullable = true; }
OptionalNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_OPTIONAL;
nullable = true;
}
void compute_firstpos() { firstpos = child[0]->firstpos; }
void compute_lastpos() { lastpos = child[0]->lastpos; }
int eq(Node *other)
{
if (dynamic_cast<OptionalNode *>(other))
if (other->is_type(NODE_TYPE_OPTIONAL))
return child[0]->eq(other->child[0]);
return 0;
}
@ -638,7 +702,9 @@ public:
/* Match a node one or more times. (This is a unary operator.) */
class PlusNode: public OneChildNode {
public:
PlusNode(Node *left): OneChildNode(left) {
PlusNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_PLUS;
}
void compute_nullable() { nullable = child[0]->nullable; }
void compute_firstpos() { firstpos = child[0]->firstpos; }
@ -651,7 +717,7 @@ public:
}
}
int eq(Node *other) {
if (dynamic_cast<PlusNode *>(other))
if (other->is_type(NODE_TYPE_PLUS))
return child[0]->eq(other->child[0]);
return 0;
}
@ -667,7 +733,10 @@ public:
/* Match a pair of consecutive nodes. */
class CatNode: public TwoChildNode {
public:
CatNode(Node *left, Node *right): TwoChildNode(left, right) { }
CatNode(Node *left, Node *right): TwoChildNode(left, right)
{
type_flags |= NODE_TYPE_CAT;
}
void compute_nullable()
{
nullable = child[0]->nullable && child[1]->nullable;
@ -695,7 +764,7 @@ public:
}
int eq(Node *other)
{
if (dynamic_cast<CatNode *>(other)) {
if (other->is_type(NODE_TYPE_CAT)) {
if (!child[0]->eq(other->child[0]))
return 0;
return child[1]->eq(other->child[1]);
@ -730,7 +799,10 @@ public:
/* Match one of two alternative nodes. */
class AltNode: public TwoChildNode {
public:
AltNode(Node *left, Node *right): TwoChildNode(left, right) { }
AltNode(Node *left, Node *right): TwoChildNode(left, right)
{
type_flags |= NODE_TYPE_ALT;
}
void compute_nullable()
{
nullable = child[0]->nullable || child[1]->nullable;
@ -745,7 +817,7 @@ public:
}
int eq(Node *other)
{
if (dynamic_cast<AltNode *>(other)) {
if (other->is_type(NODE_TYPE_ALT)) {
if (!child[0]->eq(other->child[0]))
return 0;
return child[1]->eq(other->child[1]);
@ -780,7 +852,10 @@ public:
class SharedNode: public ImportantNode {
public:
SharedNode() { }
SharedNode()
{
type_flags |= NODE_TYPE_SHARED;
}
void release(void)
{
/* don't delete SharedNodes via release as they are shared, and
@ -803,14 +878,17 @@ public:
*/
class AcceptNode: public SharedNode {
public:
AcceptNode() { }
AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; }
int is_accept(void) { return true; }
int is_postprocess(void) { return false; }
};
class MatchFlag: public AcceptNode {
public:
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit)
{
type_flags |= NODE_TYPE_MATCHFLAG;
}
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
uint32_t flag;
@ -819,12 +897,18 @@ public:
class ExactMatchFlag: public MatchFlag {
public:
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit)
{
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
}
};
class DenyMatchFlag: public MatchFlag {
public:
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet)
{
type_flags |= NODE_TYPE_DENYMATCHFLAG;
}
};
/* Traverse the syntax tree depth-first in an iterator-like manner. */
@ -833,7 +917,7 @@ class depth_first_traversal {
void push_left(Node *node) {
pos.push(node);
while (dynamic_cast<InnerNode *>(node)) {
while (node->is_type(NODE_TYPE_INNER)) {
pos.push(node->child[0]);
node = node->child[0];
}

View File

@ -1352,17 +1352,18 @@ int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
return error;
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
MatchFlag *match;
if (!(match = dynamic_cast<MatchFlag *>(*i)))
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
continue;
if (dynamic_cast<ExactMatchFlag *>(match)) {
MatchFlag *match = static_cast<MatchFlag *>(*i);
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
/* exact match only ever happens with x */
if (filedfa && !is_merged_x_consistent(exact_match_allow,
match->flag))
error = 1;;
exact_match_allow |= match->flag;
exact_audit |= match->audit;
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
perms.deny |= match->flag;
perms.quiet |= match->audit;
} else {