From 2cf7d307639eab6a44ae8e355c68294a02532614 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 14 Jul 2026 14:31:26 +0200 Subject: [PATCH] Skip setFillColorN/setStrokeColorN operators without valid arguments (issue 21570) The PDF document in question is corrupt, and note that even Adobe Reader (i.e. the PDF reference implementation) cannot render it correctly. Also, guard all other set fill/stroke color operators similarly. --- src/core/evaluator.js | 36 ++++++++++++++++++++++++++++++++++++ test/pdfs/.gitignore | 1 + test/pdfs/issue21570.pdf | Bin 0 -> 5319 bytes test/test_manifest.json | 7 +++++++ test/unit/evaluator_spec.js | 28 ++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+) create mode 100644 test/pdfs/issue21570.pdf diff --git a/src/core/evaluator.js b/src/core/evaluator.js index e0cb73d01..41a83644c 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -1991,40 +1991,64 @@ class PartialEvaluator { return; } case OPS.setFillColor: + if (!isNumberArray(args, null)) { + continue; + } cs = stateManager.state.fillColorSpace; args = [cs.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeColor: + if (!isNumberArray(args, null)) { + continue; + } cs = stateManager.state.strokeColorSpace; args = [cs.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillGray: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.gray; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeGray: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.gray; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillCMYKColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.cmyk; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeCMYKColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.cmyk; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillRGBColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.rgb; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; break; case OPS.setStrokeRGBColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.rgb; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; break; @@ -2041,6 +2065,9 @@ class PartialEvaluator { break; } if (cs.name === "Pattern") { + if (!Array.isArray(args)) { + continue; + } next( self.handleColorN( operatorList, @@ -2058,6 +2085,9 @@ class PartialEvaluator { ); return; } + if (!isNumberArray(args, null)) { + continue; + } args = [cs.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; @@ -2074,6 +2104,9 @@ class PartialEvaluator { break; } if (cs.name === "Pattern") { + if (!Array.isArray(args)) { + continue; + } next( self.handleColorN( operatorList, @@ -2091,6 +2124,9 @@ class PartialEvaluator { ); return; } + if (!isNumberArray(args, null)) { + continue; + } args = [cs.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 54d04c8cf..7cd2904ed 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -103,6 +103,7 @@ !issue9713.pdf !xfa_filled_imm1344e.pdf !issue8424.pdf +!issue21570.pdf !issue8480.pdf !bug1650302_reduced.pdf !issue18816.pdf diff --git a/test/pdfs/issue21570.pdf b/test/pdfs/issue21570.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6c1179975a08f81e888cab7ab29964e9ca6b5d04 GIT binary patch literal 5319 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