policyrep: Change caches to be per-policy, with weak references.

Make SELinuxPolicy weak-referenceable.

Implement a WeakKeyDefaultDict class which has the behaviors of a
combination of both WeakKeyDictionary and defaultdict.
This commit is contained in:
Chris PeBenito 2018-09-28 16:30:46 -04:00
parent 58bda1a40a
commit 76c64b6374
8 changed files with 61 additions and 27 deletions

View File

@ -32,6 +32,7 @@ import itertools
import ipaddress
import collections
import enum
import weakref
cimport sepol
cimport selinux

View File

@ -20,7 +20,7 @@
truth_table_row = collections.namedtuple("truth_table_row", ["values", "result"])
cdef dict _cond_cache = {}
cdef object _cond_cache = WeakKeyDefaultDict(dict)
#
# Classes
@ -62,10 +62,10 @@ cdef class Conditional(PolicyObject):
list booleans
try:
return _cond_cache[<uintptr_t>symbol]
return _cond_cache[policy][<uintptr_t>symbol]
except KeyError:
c = Conditional.__new__(Conditional)
_cond_cache[<uintptr_t>symbol] = c
_cond_cache[policy][<uintptr_t>symbol] = c
c.policy = policy
c.key = <uintptr_t>symbol
c._postfix_expression = []

View File

@ -19,9 +19,9 @@
#
# pylint: disable=protected-access
cdef dict _cat_cache = {}
cdef dict _sens_cache = {}
cdef dict _leveldecl_cache = {}
cdef object _cat_cache = WeakKeyDefaultDict(dict)
cdef object _sens_cache = WeakKeyDefaultDict(dict)
cdef object _leveldecl_cache = WeakKeyDefaultDict(dict)
#
@ -58,14 +58,14 @@ cdef class Category(PolicySymbol):
raise MLSDisabled
try:
return _cat_cache[<uintptr_t>symbol]
return _cat_cache[policy][<uintptr_t>symbol]
except KeyError:
c = Category.__new__(Category)
c.policy = policy
c.key = <uintptr_t>symbol
c.name = policy.category_value_to_name(symbol.s.value - 1)
c._value = symbol.s.value
_cat_cache[<uintptr_t>symbol] = c
_cat_cache[policy][<uintptr_t>symbol] = c
return c
def __hash__(self):
@ -119,10 +119,10 @@ cdef class Sensitivity(PolicySymbol):
raise MLSDisabled
try:
return _sens_cache[<uintptr_t>symbol]
return _sens_cache[policy][<uintptr_t>symbol]
except KeyError:
s = Sensitivity.__new__(Sensitivity)
_sens_cache[<uintptr_t>symbol] = s
_sens_cache[policy][<uintptr_t>symbol] = s
s.policy = policy
s.key = <uintptr_t>symbol
s.name = policy.level_value_to_name(symbol.level.sens - 1)
@ -233,10 +233,10 @@ cdef class LevelDecl(BaseMLSLevel):
raise MLSDisabled
try:
return _leveldecl_cache[<uintptr_t>symbol]
return _leveldecl_cache[policy][<uintptr_t>symbol]
except KeyError:
l = LevelDecl.__new__(LevelDecl)
_leveldecl_cache[<uintptr_t>symbol] = l
_leveldecl_cache[policy][<uintptr_t>symbol] = l
l.policy = policy
l._categories = set(CategoryEbitmapIterator.factory(policy, &symbol.level.cat))
# the datum for levels is also used for Sensitivity objects

View File

@ -18,8 +18,8 @@
# <http://www.gnu.org/licenses/>.
#
cdef dict _common_cache = {}
cdef dict _objclass_cache = {}
cdef object _common_cache = WeakKeyDefaultDict(dict)
cdef object _objclass_cache = WeakKeyDefaultDict(dict)
#
@ -45,7 +45,7 @@ cdef class Common(PolicySymbol):
dict perm_table
try:
return _common_cache[<uintptr_t>symbol]
return _common_cache[policy][<uintptr_t>symbol]
except KeyError:
c = Common.__new__(Common)
c.policy = policy
@ -68,7 +68,7 @@ cdef class Common(PolicySymbol):
c.perms = frozenset(c._perm_table.values())
_common_cache[<uintptr_t>symbol] = c
_common_cache[policy][<uintptr_t>symbol] = c
return c
def __contains__(self, other):
@ -106,13 +106,13 @@ cdef class ObjClass(PolicySymbol):
ObjClass c
try:
return _objclass_cache[<uintptr_t>symbol]
return _objclass_cache[policy][<uintptr_t>symbol]
except KeyError:
#
# Instantiate object class
#
c = ObjClass.__new__(ObjClass)
_objclass_cache[<uintptr_t>symbol] = c
_objclass_cache[policy][<uintptr_t>symbol] = c
c.policy = policy
c.key = <uintptr_t>symbol
c.nprim = symbol.permissions.nprim

View File

@ -46,6 +46,7 @@ cdef class SELinuxPolicy:
object log
object constraint_counts
object terule_counts
object __weakref__
# Public attributes:
readonly str path

View File

@ -21,8 +21,8 @@
#
# Cache objects
#
cdef dict _type_cache = {}
cdef dict _typeattr_cache = {}
cdef object _type_cache = WeakKeyDefaultDict(dict)
cdef object _typeattr_cache = WeakKeyDefaultDict(dict)
#
@ -77,10 +77,10 @@ cdef class Type(BaseType):
policy.type_value_to_name(symbol.s.value - 1)))
try:
return _type_cache[<uintptr_t>symbol]
return _type_cache[policy][<uintptr_t>symbol]
except KeyError:
t = Type.__new__(Type)
_type_cache[<uintptr_t>symbol] = t
_type_cache[policy][<uintptr_t>symbol] = t
t.policy = policy
t.key = <uintptr_t>symbol
t.value = symbol.s.value
@ -148,10 +148,10 @@ cdef class TypeAttribute(BaseType):
policy.type_value_to_name(symbol.s.value - 1)))
try:
return _typeattr_cache[<uintptr_t>symbol]
return _typeattr_cache[policy][<uintptr_t>symbol]
except KeyError:
a = TypeAttribute.__new__(TypeAttribute)
_typeattr_cache[<uintptr_t>symbol] = a
_typeattr_cache[policy][<uintptr_t>symbol] = a
a.policy = policy
a.key = <uintptr_t>symbol
a.name = policy.type_value_to_name(symbol.s.value - 1)

View File

@ -18,7 +18,7 @@
# <http://www.gnu.org/licenses/>.
#
cdef dict _user_cache = {}
cdef object _user_cache = WeakKeyDefaultDict(dict)
cdef class User(PolicySymbol):
@ -35,10 +35,10 @@ cdef class User(PolicySymbol):
"""Factory function for constructing User objects."""
cdef User u
try:
return _user_cache[<uintptr_t>symbol]
return _user_cache[policy][<uintptr_t>symbol]
except KeyError:
u = User.__new__(User)
_user_cache[<uintptr_t>symbol] = u
_user_cache[policy][<uintptr_t>symbol] = u
u.policy = policy
u.key = <uintptr_t>symbol
u.name = policy.user_value_to_name(symbol.s.value - 1)

View File

@ -60,6 +60,38 @@ class PolicyEnum(enum.Enum):
except ValueError:
return cls[value]
class WeakKeyDefaultDict(weakref.WeakKeyDictionary):
"""
A dictionary with a weak-referenced key and a default value.
This is a combination of WeakKeyDictionary and defaultdict
classes and has the interfaces of both, with the exception
of the constructor.
WeakKeyDefaultDict(default_factory, [dict])
"""
def __init__(self, default_factory, *args):
self.default_factory = default_factory
super().__init__(args)
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
return self.__missing__(key)
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
defaultvalue = self.default_factory()
self.__setitem__(key, defaultvalue)
return defaultvalue
#
# Functions
#