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

View File

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