From dc926ffc0f22a588e4e6a6808d69d3c02c958233 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 14 Sep 2017 15:38:57 +0200 Subject: [PATCH] Check `isEvalSupported`, and test that `eval` is actually supported, before attempting to use the `PostScriptCompiler` (issue 5573) Currently `PDFFunction` is implemented (basically) like a class with only `static` methods. Since it's used directly in a number of different `src/core/` files, attempting to pass in `isEvalSupported` would result in code that's *very* messy, not to mention difficult to maintain (since *every* single `PDFFunction` method call would need to include a `isEvalSupported` argument). Rather than having to wait for a possible re-factoring of `PDFFunction` that would avoid the above problems by design, it probably makes sense to at least set `isEvalSupported` globally for `PDFFunction`. Please note that there's one caveat with this solution: If `PDFJS.getDocument` is used to open multiple files simultaneously, with *different* `PDFJS.isEvalSupported` values set before each call, then the last one will always win. However, that seems like enough of an edge-case that we shouldn't have to worry about it. Besides, since we'll also test that `eval` is actually supported, it should be fine. Fixes 5573. --- src/core/document.js | 4 ++++ src/core/evaluator.js | 1 + src/core/function.js | 34 +++++++++++++++++++++++++--------- src/core/worker.js | 1 + src/display/api.js | 1 + 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index 1294b22d1..4d8b066fe 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -24,6 +24,7 @@ import { OperatorList, PartialEvaluator } from './evaluator'; import { AnnotationFactory } from './annotation'; import { calculateMD5 } from './crypto'; import { Linearization } from './parser'; +import { PDFFunction } from './function'; var Page = (function PageClosure() { @@ -532,6 +533,9 @@ var PDFDocument = (function PDFDocumentClosure() { }, }; this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory); + + let evaluatorOptions = this.pdfManager.evaluatorOptions; + PDFFunction.setIsEvalSupported(evaluatorOptions.isEvalSupported); }, get numPages() { var linearization = this.linearization; diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 4719107ef..796a33258 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -54,6 +54,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { disableFontFace: false, nativeImageDecoderSupport: NativeImageDecoding.DECODE, ignoreErrors: false, + isEvalSupported: true, }; function NativeImageDecoder(xref, resources, handler, forceDataSchema) { diff --git a/src/core/function.js b/src/core/function.js index 86f5b424e..a07f4c27a 100644 --- a/src/core/function.js +++ b/src/core/function.js @@ -13,17 +13,31 @@ * limitations under the License. */ -import { FormatError, info, isBool } from '../shared/util'; +import { + FormatError, info, isBool, isEvalSupported, shadow +} from '../shared/util'; import { isDict, isStream } from './primitives'; import { PostScriptLexer, PostScriptParser } from './ps_parser'; +let IsEvalSupportedCached = { + get value() { + return shadow(this, 'value', isEvalSupported()); + }, +}; + var PDFFunction = (function PDFFunctionClosure() { var CONSTRUCT_SAMPLED = 0; var CONSTRUCT_INTERPOLATED = 2; var CONSTRUCT_STICHED = 3; var CONSTRUCT_POSTSCRIPT = 4; + let isEvalSupported = true; + return { + setIsEvalSupported(support = true) { + isEvalSupported = support !== false; + }, + getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) { var i, ii; @@ -399,15 +413,17 @@ var PDFFunction = (function PDFFunctionClosure() { var range = IR[2]; var code = IR[3]; - var compiled = (new PostScriptCompiler()).compile(code, domain, range); - if (compiled) { - // Compiled function consists of simple expressions such as addition, - // subtraction, Math.max, and also contains 'var' and 'return' - // statements. See the generation in the PostScriptCompiler below. - // eslint-disable-next-line no-new-func - return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled); + if (isEvalSupported && IsEvalSupportedCached.value) { + let compiled = (new PostScriptCompiler()).compile(code, domain, range); + if (compiled) { + // Compiled function consists of simple expressions such as addition, + // subtraction, Math.max, and also contains 'var' and 'return' + // statements. See the generation in the PostScriptCompiler below. + // eslint-disable-next-line no-new-func + return new Function('src', 'srcOffset', 'dest', 'destOffset', + compiled); + } } - info('Unable to compile PS function'); var numOutputs = range.length >> 1; diff --git a/src/core/worker.js b/src/core/worker.js index 4156e4813..262a29048 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -602,6 +602,7 @@ var WorkerMessageHandler = { disableFontFace: data.disableFontFace, nativeImageDecoderSupport: data.nativeImageDecoderSupport, ignoreErrors: data.ignoreErrors, + isEvalSupported: data.isEvalSupported, }; getPdfManager(data, evaluatorOptions).then(function (newPdfManager) { diff --git a/src/display/api.js b/src/display/api.js index ddd764d5f..ec08f8204 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -357,6 +357,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { docBaseUrl: source.docBaseUrl, nativeImageDecoderSupport: source.nativeImageDecoderSupport, ignoreErrors: source.ignoreErrors, + isEvalSupported: getDefaultSetting('isEvalSupported'), }).then(function (workerId) { if (worker.destroyed) { throw new Error('Worker was destroyed');