[pypy-commit] pypy sandbox-2: Try to add carefully logic in the GC that disables the most advanced
arigo
pypy.commits at gmail.com
Fri Aug 9 15:06:19 EDT 2019
Author: Armin Rigo <arigo at tunes.org>
Branch: sandbox-2
Changeset: r97131:23010c892cff
Date: 2019-08-09 21:05 +0200
http://bitbucket.org/pypy/pypy/changeset/23010c892cff/
Log: Try to add carefully logic in the GC that disables the most advanced
features, incrementality and pinning.
diff --git a/pypy/module/gc/moduledef.py b/pypy/module/gc/moduledef.py
--- a/pypy/module/gc/moduledef.py
+++ b/pypy/module/gc/moduledef.py
@@ -16,7 +16,11 @@
def __init__(self, space, w_name):
if (not space.config.translating or
- space.config.translation.gctransformer == "framework"):
+ (space.config.translation.gctransformer == "framework"
+ and not space.config.translation.sandbox)):
+ # some of these functions allow app-level code to do invalid
+ # things by trying hard enough. For safety, in sandbox mode
+ # we don't provide any of them.
self.appleveldefs.update({
'dump_rpy_heap': 'app_referents.dump_rpy_heap',
'get_stats': 'app_referents.get_stats',
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -519,10 +519,21 @@
bigobj = self.nonlarge_max + 1
self.max_number_of_pinned_objects = self.nursery_size / (bigobj * 2)
+ def safer_variant(self):
+ # When running in sandbox mode, turn off two features: incrementality
+ # and object pinning. This should be done in a way that cannot *add*
+ # any security bug, but it could in theory avoid bugs in this complex
+ # logic.
+ return self.config.sandbox
+
def enable(self):
self.enabled = True
def disable(self):
+ if self.safer_variant():
+ # gc.disable() is ignored in this mode. It should not be
+ # allowed to disable major collections.
+ return
self.enabled = False
def isenabled(self):
@@ -763,6 +774,16 @@
def collect(self, gen=2):
"""Do a minor (gen=0), start a major (gen=1), or do a full
major (gen>=2) collection."""
+ self.check_safe_gc_state()
+ if self.safer_variant():
+ # gen < 0 is dangerous, and gen == 1 leaves the GC in the
+ # middle of a major collection. We disable these two modes
+ # in the safer variant.
+ if gen <= 0:
+ gen = 0
+ else:
+ gen = 2
+ #
if gen < 0:
# Dangerous! this makes no progress on the major GC cycle.
# If called too often, the memory usage will keep increasing,
@@ -786,6 +807,7 @@
# This does a complete minor and major collection.
self.minor_and_major_collection()
self.rrc_invoke_callback()
+ self.check_safe_gc_state()
def collect_step(self):
"""
@@ -795,12 +817,26 @@
This is meant to be used together with gc.disable(), to have a
fine-grained control on when the GC runs.
"""
+ # This function should never be called in safer_variant() mode,
+ # because it leaves the GC in the middle of an incremental step.
+ # In PyPy the function gc.collect_step() is removed from --sandbox.
+ if self.safer_variant():
+ out_of_memory("sandbox: collect_step() has been disabled")
+ return False
+ #
old_state = self.gc_state
self._minor_collection()
self.major_collection_step()
self.rrc_invoke_callback()
return rgc._encode_states(old_state, self.gc_state)
+ def check_safe_gc_state(self):
+ if self.safer_variant():
+ # in this variant, gc_state should always be SCANNING when the
+ # mutator runs
+ if self.gc_state != STATE_SCANNING:
+ out_of_memory("sandbox: unexpected internal GC state")
+
def minor_collection_with_major_progress(self, extrasize=0,
force_enabled=False):
"""Do a minor collection. Then, if the GC is enabled and there
@@ -808,6 +844,7 @@
step. If there is no major GC but the threshold is reached, start a
major GC.
"""
+ self.check_safe_gc_state()
self._minor_collection()
if not self.enabled and not force_enabled:
return
@@ -826,6 +863,10 @@
if self.gc_state != STATE_SCANNING or self.threshold_reached(extrasize):
self.major_collection_step(extrasize)
+ if self.safer_variant():
+ # finish the just-started major collection immediately
+ self.gc_step_until(STATE_SCANNING)
+
# See documentation in major_collection_step() for target invariants
while self.gc_state != STATE_SCANNING: # target (A1)
threshold = self.threshold_objects_made_old
@@ -840,6 +881,7 @@
self.major_collection_step(extrasize)
self.rrc_invoke_callback()
+ self.check_safe_gc_state()
def collect_and_reserve(self, totalsize):
@@ -1098,6 +1140,8 @@
return self.is_in_nursery(obj)
def pin(self, obj):
+ if self.safer_variant(): # no pinning in the safer variant
+ return False
if self.pinned_objects_in_nursery >= self.max_number_of_pinned_objects:
return False
if not self.is_in_nursery(obj):
@@ -3074,6 +3118,9 @@
def rawrefcount_init(self, dealloc_trigger_callback):
# see pypy/doc/discussion/rawrefcount.rst
+ if self.safer_variant():
+ out_of_memory("sandbox: rawrefcount_init() not supported")
+ return
if not self.rrc_enabled:
self.rrc_p_list_young = self.AddressStack()
self.rrc_p_list_old = self.AddressStack()
More information about the pypy-commit
mailing list