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:
parent
ee5303c8a0
commit
5aab543a3b
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user