[cffLib.specializer] Fix more stack-overflow opportunity

I think it's solid now.
This commit is contained in:
Behdad Esfahbod 2024-11-06 18:44:22 -05:00
parent 2e96d81b05
commit bb7a29e81a
2 changed files with 20 additions and 5 deletions

View File

@ -509,6 +509,19 @@ def _addArgs(a, b):
return a + b return a + b
def _argsStackUse(args):
stackLen = 0
maxLen = 0
for arg in args:
if type(arg) is list:
# Blended arg
maxLen = max(maxLen, stackLen + _argsStackUse(arg))
stackLen += arg[-1]
else:
stackLen += 1
return max(stackLen, maxLen)
def specializeCommands( def specializeCommands(
commands, commands,
ignoreErrors=False, ignoreErrors=False,
@ -751,7 +764,7 @@ def specializeCommands(
# Make sure the stack depth does not exceed (maxstack - 1), so # Make sure the stack depth does not exceed (maxstack - 1), so
# that subroutinizer can insert subroutine calls at any point. # that subroutinizer can insert subroutine calls at any point.
if new_op and len(args1) + len(args2) < maxstack: if new_op and _argsStackUse(args1) + _argsStackUse(args2) < maxstack:
commands[i - 1] = (new_op, args1 + args2) commands[i - 1] = (new_op, args1 + args2)
del commands[i] del commands[i]

View File

@ -585,17 +585,19 @@ class CFFSpecializeProgramTest:
# maxstack CFF2=513, specializer uses up to 512 # maxstack CFF2=513, specializer uses up to 512
def test_maxstack_blends(self): def test_maxstack_blends(self):
getNumRegions = lambda iv: 15 numRegions = 15
blend_one = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 blend" numOps = 2000
getNumRegions = lambda iv: numRegions
blend_one = " ".join([str(i) for i in range(1 + numRegions)] + ["1", "blend"])
operands = " ".join([blend_one] * 6) operands = " ".join([blend_one] * 6)
operator = "rrcurveto" operator = "rrcurveto"
charstr = " ".join([operands, operator] * 10) charstr = " ".join([operands, operator] * numOps)
expected = charstr expected = charstr
specialized = charstr_specialize( specialized = charstr_specialize(
charstr, getNumRegions=getNumRegions, maxstack=maxStack charstr, getNumRegions=getNumRegions, maxstack=maxStack
) )
stack_use = charstr_stack_use(specialized, getNumRegions=getNumRegions) stack_use = charstr_stack_use(specialized, getNumRegions=getNumRegions)
assert stack_use < maxStack assert maxStack - numRegions < stack_use < maxStack
class CFF2VFTestSpecialize(DataFilesHandler): class CFF2VFTestSpecialize(DataFilesHandler):