Reject oversized step-repeat expansions

This commit is contained in:
Flavien Solt 2026-04-21 11:10:50 +08:00 committed by jaseg
parent e3674de08d
commit 736107f7a4
2 changed files with 31 additions and 7 deletions

View file

@ -599,6 +599,8 @@ class GerberParser:
NUMBER = r"[\+-]?\d+"
DECIMAL = r"[\+-]?\d+([.]?\d+)?"
NAME = r"[a-zA-Z_$\.][a-zA-Z_$\.0-9+\-]+"
MAX_STEP_REPEAT_INSTANCES = 100000
MAX_STEP_REPEAT_RESULT_OBJECTS = 100000
STATEMENT_REGEXES = {
'coord': fr"(G0?[123]|G74|G75|G54|G55)?\s*(?:X\+?(-?)({NUMBER}))?(?:Y\+?(-?)({NUMBER}))?" \
@ -1095,18 +1097,23 @@ class GerberParser:
i, j = float(match['I']), float(match['J'])
if x < 1 or y < 1:
raise SyntaxError('SR step-repeat X and Y values must be at least 1')
if x * y > self.MAX_STEP_REPEAT_INSTANCES:
raise SyntaxError('SR step-repeat expands to too many instances')
self.step_repeat_coords = [
(i*nx, j*ny)
for nx in range(x) for ny in range(y)] # the order matters here, cf. the spec
self.step_repeat_coords = (x, y, i, j)
self.step_repeat_objects = []
else:
x, y, i, j = self.step_repeat_coords
if len(self.step_repeat_objects) * x * y > self.MAX_STEP_REPEAT_RESULT_OBJECTS:
raise SyntaxError('SR step-repeat expands to too many objects')
for obj in self.step_repeat_objects:
for dx, dy in self.step_repeat_coords:
new_obj = copy.copy(obj)
new_obj.offset(dx, dy)
self.target.objects.append(new_obj)
for nx in range(x):
for ny in range(y):
new_obj = copy.copy(obj)
new_obj.offset(i * nx, j * ny)
self.target.objects.append(new_obj)
self.step_repeat_coords = None
self.step_repeat_objects = None

View file

@ -637,6 +637,23 @@ def test_syntax_error():
assert 'test_syntax_error.gbr' in exc_info.value.msg
assert '7' in exc_info.value.msg # lineno
@filter_syntax_warnings
def test_step_repeat_rejects_huge_instance_counts():
data = '\n'.join([
'G04 test*',
'%MOIN*%',
'%FSLAX24Y24*%',
'%ADD10C,0.0100*%',
'%SRX1000Y1000I1.0J1.0*%',
'D10*',
'X0000Y0000D03*',
'%SR*%',
'M02*',
])
with pytest.raises(SyntaxError, match='too many instances'):
GerberFile.from_string(data)
@filter_syntax_warnings
@pytest.mark.parametrize('reference', MIN_REFERENCE_FILES, indirect=True)
def test_invert_polarity(reference, tmpfile, img_support):