From ebabebad34a3811230b7bfe351eface7f5efc8a9 Mon Sep 17 00:00:00 2001
From: Ken Sharp <ken.sharp@artifex.com>
Date: Wed, 8 Apr 2020 16:06:44 +0100
Subject: [PATCH] PostScript interpreter - don't leave A85Decode pdf_rules
 uninitialised

Bug #702319 "Read of uninitialized value according to valgrind..."

There are a number of other bugs which relate to this particular problem:
690976, 692983 and 693485. The problem has come about as a cumulative
result of working on these bugs.

Starting with commit :
http://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=e0ecca32ecd12dae3310fac4b65dc224031c85a2
for bug 690976 a new flag 'pdf_rules' was added to the Ascii85Decode
state. This is initialised from the dictionary operand in PostScript
by zA85D() in zfdecode.c. When this flag is true the ASCII85Decode
filter will silently accept just '~' as a valid termination for a string
(should be '~>').

However this is not the only way to initialise an Ascii85Decode filter,
the PostScript token scanner can also use s_A85D_init_inline() which
does not initialise the flag. From this point we have the potential
for testing an unitialised variable in s_A85D_process(), if we get an
encoded string which terminates with a '~' and the filter was
instantiated from PostScript.

When fixing bug 692983, this commit:
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=d561224d1495321d40012230abbcf835b298f557

Alex specifically added a comment that pdf_rules must not be initialised
in s_A85D_init_inline() but didn't say why! The reason is that the
regular stream initialisation code (s_A85D-init) also uses this inline
function, so if it altered pdf_rules it would overwrite the value
previously set by zA85D().

Since the initialisation is done in two places, the only way to fix this
is to initialise pdf_rules in gs_scan_token() which this commit duly
does. I've also added comments in s_A85D_init_inline to explain more
clearly *why* pdf_rules must not be initialised here.
---
 base/sa85d.h | 9 ++++++++-
 psi/iscan.c  | 4 ++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/base/sa85d.h b/base/sa85d.h
index 6e74622..8685af7 100644
--- a/base/sa85d.h
+++ b/base/sa85d.h
@@ -41,7 +41,14 @@ typedef struct stream_A85D_state_s {
   (ss)->min_left = 1; \
   (ss)->word = 0; \
   (ss)->odd = 0; \
-  /* pdf_rules should not be initialized here */ \
+  /* pdf_rules should not be initialized here. This flag is initialised in\
+   * zA85D to either true or false, and this inline function is called *after*\
+   * that in s_A85D_init to do the remaining initialisation. However, this\
+   * inline function is also called from gs_scan_token to handle inline\
+   * ASCII85 strings. These are not to be interpreted using PDF rules\
+   * and so we must not set the flag here, but in the relevant calling\
+   * functions.\
+   */ \
   (ss)->require_eod=false; \
   END
 extern const stream_template s_A85D_template;
diff --git a/psi/iscan.c b/psi/iscan.c
index e5956e1..9b7151a 100644
--- a/psi/iscan.c
+++ b/psi/iscan.c
@@ -581,6 +581,10 @@ gs_scan_token(i_ctx_t *i_ctx_p, ref * pref, scanner_state * pstate)
                         s_A85D_init_inline(&sstate.s_ss.a85d);
                         sstate.s_ss.st.templat = &s_A85D_template;
                         sstate.s_ss.a85d.require_eod = true;
+                        /* If this is an inline ASCII string, interpret it normally, throw an error
+                         * if it fails rather than ignoring it as PDF (Acrobat) does.
+                         */
+                        sstate.s_ss.a85d.pdf_rules = false;
                         goto str;
                 }
                 sputback_inline(s, sptr, endptr);
-- 
1.8.3.1

