Merge pull request #3679 from fonttools/cff2-specializer-maxStack

[CFF2] specializer fix stack overflow
This commit is contained in:
Behdad Esfahbod 2024-11-08 10:51:04 -07:00 committed by GitHub
commit dafb6d26a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 610 additions and 971 deletions

View File

@ -446,9 +446,9 @@ def _convertToBlendCmds(args):
i = 0
while i < num_args:
arg = args[i]
i += 1
if not isinstance(arg, list):
new_args.append(arg)
i += 1
stack_use += 1
else:
prev_stack_use = stack_use
@ -458,13 +458,8 @@ def _convertToBlendCmds(args):
# up to the max stack limit.
num_sources = len(arg) - 1
blendlist = [arg]
i += 1
stack_use += 1 + num_sources # 1 for the num_blends arg
while (i < num_args) and isinstance(args[i], list):
blendlist.append(args[i])
i += 1
stack_use += num_sources
if stack_use + num_sources > maxStackLimit:
# if we are here, max stack is the CFF2 max stack.
# I use the CFF2 max stack limit here rather than
# the 'maxstack' chosen by the client, as the default
@ -472,7 +467,17 @@ def _convertToBlendCmds(args):
# the other operators, this just produces a little less
# optimization, but here it puts a hard (and low) limit
# on the number of source fonts that can be used.
break
#
# Make sure the stack depth does not exceed (maxstack - 1), so
# that subroutinizer can insert subroutine calls at any point.
while (
(i < num_args)
and isinstance(args[i], list)
and stack_use + num_sources < maxStackLimit
):
blendlist.append(args[i])
i += 1
stack_use += num_sources
# blendList now contains as many single blend tuples as can be
# combined without exceeding the CFF2 stack limit.
num_blends = len(blendlist)
@ -504,6 +509,19 @@ def _addArgs(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(
commands,
ignoreErrors=False,
@ -746,7 +764,7 @@ def specializeCommands(
# Make sure the stack depth does not exceed (maxstack - 1), so
# 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)
del commands[i]

File diff suppressed because it is too large Load Diff