Author: Armin Rigo <[email protected]>
Branch: shadowstack-issue2722
Changeset: r96574:0f76d02c2314
Date: 2019-05-08 12:27 +0200
http://bitbucket.org/pypy/pypy/changeset/0f76d02c2314/

Log:    Link 'increase_root_stack_depth' through RPython and test it

diff --git a/rpython/memory/gctransform/framework.py 
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -236,6 +236,9 @@
         if root_walker.stacklet_support:
             root_walker.need_stacklet_support(self, getfn)
 
+        if hasattr(root_walker, 'build_increase_root_stack_depth_ptr'):
+            root_walker.build_increase_root_stack_depth_ptr(getfn)
+
         self.layoutbuilder.encode_type_shapes_now()
         self.create_custom_trace_funcs(gcdata.gc, translator.rtyper)
 
@@ -1652,6 +1655,10 @@
         else:
             hop.rename("same_as")
 
+    def gct_gc_increase_root_stack_depth(self, hop):
+        hop.genop("direct_call",
+                  [self.root_walker.gc_increase_root_stack_depth_ptr,
+                   hop.spaceop.args[0]])
 
 
 class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
diff --git a/rpython/memory/gctransform/shadowstack.py 
b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -95,7 +95,7 @@
         self.shadow_stack_pool = ShadowStackPool(gcdata)
         rsd = gctransformer.root_stack_depth
         if rsd is not None:
-            self.shadow_stack_pool.root_stack_size = sizeofaddr * rsd
+            self.shadow_stack_pool.root_stack_depth = rsd
 
     def push_stack(self, addr):
         top = self.incr_stack(1)
@@ -253,6 +253,15 @@
         self.gc_modified_shadowstack_ptr = getfn(gc_modified_shadowstack,
                                                  [], annmodel.s_None)
 
+    def build_increase_root_stack_depth_ptr(self, getfn):
+        shadow_stack_pool = self.shadow_stack_pool
+        def gc_increase_root_stack_depth(new_size):
+            shadow_stack_pool.increase_root_stack_depth(new_size)
+
+        self.gc_increase_root_stack_depth_ptr = getfn(
+                gc_increase_root_stack_depth, [annmodel.SomeInteger()],
+                annmodel.s_None)
+
     def postprocess_graph(self, gct, graph, any_inlining):
         from rpython.memory.gctransform import shadowcolor
         if any_inlining:
@@ -269,7 +278,7 @@
     """Manages a pool of shadowstacks.
     """
     _alloc_flavor_ = "raw"
-    root_stack_size = sizeofaddr * 163840
+    root_stack_depth = 163840
     has_threads = False
 
     def __init__(self, gcdata):
@@ -334,36 +343,38 @@
 
     def _prepare_unused_stack(self):
         if self.unused_full_stack == llmemory.NULL:
-            self.unused_full_stack = llmemory.raw_malloc(self.root_stack_size)
+            root_stack_size = sizeofaddr * self.root_stack_depth
+            self.unused_full_stack = llmemory.raw_malloc(root_stack_size)
             if self.unused_full_stack == llmemory.NULL:
                 raise MemoryError
 
-    def increase_root_stack_size(self, new_size):
-        if new_size <= self.root_stack_size:
+    def increase_root_stack_depth(self, new_depth):
+        if new_depth <= self.root_stack_depth:
             return     # can't easily decrease the size
         if self.unused_full_stack:
             llmemory.raw_free(self.unused_full_stack)
             self.unused_full_stack = llmemory.NULL
         used = self.gcdata.root_stack_top - self.gcdata.root_stack_base
-        addr = self._resize(self.gcdata.root_stack_base, used, new_size)
+        addr = self._resize(self.gcdata.root_stack_base, used, new_depth)
         self.gcdata.root_stack_base = addr
         self.gcdata.root_stack_top  = addr + used
         # no gc operations above: we just switched shadowstacks
         if self.has_threads:
-            self._resize_thread_shadowstacks(new_size)
-        self.root_stack_size = new_size
+            self._resize_thread_shadowstacks(new_depth)
+        self.root_stack_depth = new_depth
 
-    def _resize_thread_shadowstacks(self, new_size):
+    def _resize_thread_shadowstacks(self, new_depth):
         if self.gcdata.thread_stacks is not None:
             for ssref in self.gcdata.thread_stacks.values():
                 if ssref.base:
                     used = ssref.top - ssref.base
-                    addr = self._resize(base, used, new_size)
+                    addr = self._resize(base, used, new_depth)
                     ssref.base = addr
                     ssref.top = addr + used
     _resize_thread_shadowstacks._dont_inline_ = True
 
-    def _resize(self, base, used, new_size):
+    def _resize(self, base, used, new_depth):
+        new_size = sizeofaddr * new_depth
         ll_assert(used <= new_size, "shadowstack resize: overflow detected")
         addr = llmemory.raw_malloc(new_size)
         if addr == llmemory.NULL:
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -690,6 +690,13 @@
         hop.exception_cannot_occur()
         return hop.genop('gc_move_out_of_nursery', hop.args_v, 
resulttype=hop.r_result)
 
[email protected]_look_inside
+def increase_root_stack_depth(new_depth):
+    """Shadowstack: make sure the size of the shadowstack is at least
+    'new_depth' pointers."""
+    from rpython.rtyper.lltypesystem.lloperation import llop
+    llop.gc_increase_root_stack_depth(lltype.Void, new_depth)
+
 # ____________________________________________________________
 
 
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -1226,6 +1226,9 @@
     def op_gc_move_out_of_nursery(self, obj):
         raise NotImplementedError("gc_move_out_of_nursery")
 
+    def op_gc_increase_root_stack_depth(self, new_depth):
+        raise NotImplementedError("gc_increase_root_stack_depth")
+
     def op_revdb_stop_point(self, *args):
         pass
     def op_revdb_send_answer(self, *args):
diff --git a/rpython/rtyper/lltypesystem/lloperation.py 
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -530,6 +530,7 @@
     'gc_rawrefcount_next_dead':         LLOp(),
 
     'gc_move_out_of_nursery':           LLOp(),
+    'gc_increase_root_stack_depth':     LLOp(),
 
     'gc_push_roots'        : LLOp(),  # temporary: list of roots to save
     'gc_pop_roots'         : LLOp(),  # temporary: list of roots to restore
diff --git a/rpython/rtyper/lltypesystem/opimpl.py 
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -776,6 +776,9 @@
 def op_gc_move_out_of_nursery(obj):
     return obj
 
+def op_gc_increase_root_stack_depth(new_depth):
+    pass
+
 def op_revdb_do_next_call():
     pass
 
diff --git a/rpython/translator/c/test/test_newgc.py 
b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -1912,6 +1912,45 @@
     def test_total_gc_time(self):
         res = self.run("total_gc_time")
         assert res > 0 # should take a few microseconds
+
+    def define_increase_root_stack_depth(cls):
+        class X:
+            pass
+        def g(n):
+            if n <= 0:
+                return None
+            x = X()
+            x.n = n
+            x.next = g(n - 1)
+            return x
+        def f(depth):
+            from rpython.rlib.rstack import _stack_set_length_fraction
+            _stack_set_length_fraction(50.0)
+            # ^^^ the default is enough for at least 10'000 (but less than
+            # 100'000) recursions of the simple function g().  We multiply
+            # it by 50.0 to make sure that 200'000 works.  The default
+            # shadowstack depth is 163'840 entries, so 200'000 overflows
+            # that default shadowstack depth, and gives a segfault unless
+            # the following line works too.
+            from rpython.rlib.rgc import increase_root_stack_depth
+            increase_root_stack_depth(depth + 100)
+            #
+            g(depth)
+            return 42
+        return f
+
+    def test_increase_root_stack_depth(self):
+        if not sys.platform.startswith('linux'):
+            py.test.skip("linux only")
+        #
+        def myrunner(args):
+            args1 = ['/bin/bash', '-c', 'ulimit -s unlimited && %s' %
+                     (' '.join(args),)]
+            return subprocess.check_output(args1)
+        res = self.run("increase_root_stack_depth", 200000, runner=myrunner)
+        assert res == 42
+
+
 # ____________________________________________________________________
 
 class TaggedPointersTest(object):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to