Commit 718fb741 authored by Evan Simpson's avatar Evan Simpson

Fix RestrictedPython.compiler stacksize computations, which could cause...

Fix RestrictedPython.compiler stacksize computations, which could cause segmentation faults when incorrect.  Incremented PythonScripts magic number to force recompilation of Scripts.
parent a44a6e19
...@@ -17,7 +17,7 @@ This product provides support for Script objects containing restricted ...@@ -17,7 +17,7 @@ This product provides support for Script objects containing restricted
Python code. Python code.
""" """
__version__='$Revision: 1.37 $'[11:-2] __version__='$Revision: 1.38 $'[11:-2]
import sys, os, traceback, re, marshal import sys, os, traceback, re, marshal
from Globals import DTMLFile, MessageDialog, package_home from Globals import DTMLFile, MessageDialog, package_home
...@@ -41,7 +41,7 @@ Python_magic = imp.get_magic() ...@@ -41,7 +41,7 @@ Python_magic = imp.get_magic()
del imp del imp
# This should only be incremented to force recompilation. # This should only be incremented to force recompilation.
Script_magic = 2 Script_magic = 3
manage_addPythonScriptForm = DTMLFile('www/pyScriptAdd', globals()) manage_addPythonScriptForm = DTMLFile('www/pyScriptAdd', globals())
_default_file = os.path.join(package_home(globals()), _default_file = os.path.join(package_home(globals()),
......
"""A flow graph representation for Python bytecode""" """A flow graph representation for Python bytecode"""
from __future__ import nested_scopes
import dis import dis
import new import new
import string import string
...@@ -372,6 +373,7 @@ class PyFlowGraph(FlowGraph): ...@@ -372,6 +373,7 @@ class PyFlowGraph(FlowGraph):
def getCode(self): def getCode(self):
"""Get a Python code object""" """Get a Python code object"""
if self.stage == RAW: if self.stage == RAW:
self.computeStackDepth()
self.flattenGraph() self.flattenGraph()
if self.stage == FLAT: if self.stage == FLAT:
self.convertArgs() self.convertArgs()
...@@ -399,6 +401,36 @@ class PyFlowGraph(FlowGraph): ...@@ -399,6 +401,36 @@ class PyFlowGraph(FlowGraph):
if io: if io:
sys.stdout = save sys.stdout = save
def computeStackDepth(self):
"""Compute the max stack depth.
Approach is to compute the stack effect of each basic block.
Then find the path through the code with the largest total
effect.
"""
depth = {}
exit = None
for b in self.getBlocks():
depth[b] = findDepth(b.getInstructions())
seen = {}
def max_depth(b, d):
if seen.has_key(b):
return d
seen[b] = 1
d = d + depth[b]
children = b.get_children()
if children:
return max([max_depth(c, d) for c in children])
else:
if not b.label == "exit":
return max_depth(self.exit, d)
else:
return d
self.stacksize = max_depth(self.entry, 0)
def flattenGraph(self): def flattenGraph(self):
"""Arrange the blocks in order and resolve jumps""" """Arrange the blocks in order and resolve jumps"""
assert self.stage == RAW assert self.stage == RAW
...@@ -685,16 +717,10 @@ class StackDepthTracker: ...@@ -685,16 +717,10 @@ class StackDepthTracker:
maxDepth = 0 maxDepth = 0
for i in insts: for i in insts:
opname = i[0] opname = i[0]
delta = self.effect.get(opname, 0) delta = self.effect.get(opname)
if delta > 1: if delta is not None:
depth = depth + delta
elif delta < 0:
if depth > maxDepth:
maxDepth = depth
depth = depth + delta depth = depth + delta
else: else:
if depth > maxDepth:
maxDepth = depth
# now check patterns # now check patterns
for pat, pat_delta in self.patterns: for pat, pat_delta in self.patterns:
if opname[:len(pat)] == pat: if opname[:len(pat)] == pat:
...@@ -702,12 +728,14 @@ class StackDepthTracker: ...@@ -702,12 +728,14 @@ class StackDepthTracker:
depth = depth + delta depth = depth + delta
break break
# if we still haven't found a match # if we still haven't found a match
if delta == 0: if delta is None:
meth = getattr(self, opname, None) meth = getattr(self, opname, None)
if meth is not None: if meth is not None:
depth = depth + meth(i[1]) depth = depth + meth(i[1])
if depth < 0: if depth < 0:
depth = 0 depth = 0
if depth > maxDepth:
maxDepth = depth
return maxDepth return maxDepth
effect = { effect = {
...@@ -742,6 +770,11 @@ class StackDepthTracker: ...@@ -742,6 +770,11 @@ class StackDepthTracker:
'IMPORT_STAR': -1, 'IMPORT_STAR': -1,
'IMPORT_NAME': 0, 'IMPORT_NAME': 0,
'IMPORT_FROM': 1, 'IMPORT_FROM': 1,
'LOAD_ATTR': 0, # unlike other loads
# close enough...
'SETUP_EXCEPT': 3,
'SETUP_FINALLY': 3,
'FOR_ITER': 1,
} }
# use pattern match # use pattern match
patterns = [ patterns = [
...@@ -753,20 +786,20 @@ class StackDepthTracker: ...@@ -753,20 +786,20 @@ class StackDepthTracker:
# UNPACK_SEQUENCE, BUILD_TUPLE, # UNPACK_SEQUENCE, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE # BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
def UNPACK_SEQUENCE(self, count): def UNPACK_SEQUENCE(self, count):
return count return count-1
def BUILD_TUPLE(self, count): def BUILD_TUPLE(self, count):
return -count return 1-count
def BUILD_LIST(self, count): def BUILD_LIST(self, count):
return -count return 1-count
def CALL_FUNCTION(self, argc): def CALL_FUNCTION(self, argc):
hi, lo = divmod(argc, 256) hi, lo = divmod(argc, 256)
return lo + hi * 2 return -(lo + hi * 2)
def CALL_FUNCTION_VAR(self, argc): def CALL_FUNCTION_VAR(self, argc):
return self.CALL_FUNCTION(argc)+1 return self.CALL_FUNCTION(argc)-1
def CALL_FUNCTION_KW(self, argc): def CALL_FUNCTION_KW(self, argc):
return self.CALL_FUNCTION(argc)+1 return self.CALL_FUNCTION(argc)-1
def CALL_FUNCTION_VAR_KW(self, argc): def CALL_FUNCTION_VAR_KW(self, argc):
return self.CALL_FUNCTION(argc)+2 return self.CALL_FUNCTION(argc)-2
def MAKE_FUNCTION(self, argc): def MAKE_FUNCTION(self, argc):
return -argc return -argc
def BUILD_SLICE(self, argc): def BUILD_SLICE(self, argc):
...@@ -774,5 +807,7 @@ class StackDepthTracker: ...@@ -774,5 +807,7 @@ class StackDepthTracker:
return -1 return -1
elif argc == 3: elif argc == 3:
return -2 return -2
def DUP_TOPX(self, argc):
return argc
findDepth = StackDepthTracker().findDepth findDepth = StackDepthTracker().findDepth
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment