From 4612d1eab721a1010312382d1048c8b3a67b18fa Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun, 7 Sep 2014 15:27:59 -0700
Subject: [PATCH] Fix bug uncovered by changing alloca to auto buffer.

* coding.c (growable_destination): New function.
(produce_chars): Use it for sanity checks.  Do not fiddle with
dst_end if the source and destination are both nil, as it's
the caller's responsibility to avoid overlap.
* keyboard.c (read_decoded_event_from_main_queue):
The destination must be MAX_MULTIBYTE_LENGTH times the max source
length, not 4 times, to prevent decode_coding_c_string from trying
to reallocate a destination.  This removes the need for the FIXME.

Fixes: debbugs:18410
---
 src/ChangeLog  | 10 ++++++++++
 src/coding.c   | 20 ++++++++++++++++++--
 src/keyboard.c | 13 +++----------
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 88ab1eedca8..2654abd32d4 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,15 @@
 2014-09-07  Paul Eggert  <eggert@cs.ucla.edu>
 
+	Fix bug uncovered by changing alloca to auto buffer (Bug#18410).
+	* coding.c (growable_destination): New function.
+	(produce_chars): Use it for sanity checks.  Do not fiddle with
+	dst_end if the source and destination are both nil, as it's
+	the caller's responsibility to avoid overlap.
+	* keyboard.c (read_decoded_event_from_main_queue):
+	The destination must be MAX_MULTIBYTE_LENGTH times the max source
+	length, not 4 times, to prevent decode_coding_c_string from trying
+	to reallocate a destination.  This removes the need for the FIXME.
+
 	* callproc.c (exec_failed) [DOS_NT]: Define a dummy.
 	All callers simplified.  Add a comment about exec_failed, vfork,
 	and alloca.
diff --git a/src/coding.c b/src/coding.c
index 84b774b4355..ed107a297ba 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -690,6 +690,14 @@ CHECK_NATNUM_CDR (Lisp_Object x)
   XSETCDR (x, tmp);
 }
 
+/* True if CODING's destination can be grown.  */
+
+static bool
+growable_destination (struct coding_system *coding)
+{
+  return STRINGP (coding->dst_object) || BUFFERP (coding->dst_object);
+}
+
 
 /* Safely get one byte from the source text pointed by SRC which ends
    at SRC_END, and set C to that byte.  If there are not enough bytes
@@ -7019,8 +7027,10 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table,
       int *buf = coding->charbuf;
       int *buf_end = buf + coding->charbuf_used;
 
-      if (EQ (coding->src_object, coding->dst_object))
+      if (EQ (coding->src_object, coding->dst_object)
+	  && ! NILP (coding->dst_object))
 	{
+	  eassert (growable_destination (coding));
 	  coding_set_source (coding);
 	  dst_end = ((unsigned char *) coding->source) + coding->consumed;
 	}
@@ -7059,6 +7069,7 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table,
 
 	      if ((dst_end - dst) / MAX_MULTIBYTE_LENGTH < to_nchars)
 		{
+		  eassert (growable_destination (coding));
 		  if (((min (PTRDIFF_MAX, SIZE_MAX) - (buf_end - buf))
 		       / MAX_MULTIBYTE_LENGTH)
 		      < to_nchars)
@@ -7103,7 +7114,10 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table,
       const unsigned char *src_end = src + coding->consumed;
 
       if (EQ (coding->dst_object, coding->src_object))
-	dst_end = (unsigned char *) src;
+	{
+	  eassert (growable_destination (coding));
+	  dst_end = (unsigned char *) src;
+	}
       if (coding->src_multibyte != coding->dst_multibyte)
 	{
 	  if (coding->src_multibyte)
@@ -7119,6 +7133,7 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table,
 		  ONE_MORE_BYTE (c);
 		  if (dst == dst_end)
 		    {
+		      eassert (growable_destination (coding));
 		      if (EQ (coding->src_object, coding->dst_object))
 			dst_end = (unsigned char *) src;
 		      if (dst == dst_end)
@@ -7149,6 +7164,7 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table,
 
 		if (dst >= dst_end - 1)
 		  {
+		    eassert (growable_destination (coding));
 		    if (EQ (coding->src_object, coding->dst_object))
 		      dst_end = (unsigned char *) src;
 		    if (dst >= dst_end - 1)
diff --git a/src/keyboard.c b/src/keyboard.c
index eef0770684e..c435ba74faa 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -2355,22 +2355,15 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
 	      struct coding_system *coding
 		= TERMINAL_KEYBOARD_CODING (terminal);
 	      unsigned char src[MAX_ENCODED_BYTES];
-	      unsigned char dest[4 * sizeof src];
+	      unsigned char dest[MAX_ENCODED_BYTES * MAX_MULTIBYTE_LENGTH];
 	      int i;
 	      for (i = 0; i < n; i++)
 		src[i] = XINT (events[i]);
 	      if (meta_key != 2)
 		for (i = 0; i < n; i++)
 		  src[i] &= ~0x80;
-
-	      /* FIXME: For some reason decode_coding_c_string requires a
-		 fresh output buffer each time, and reusing the old buffer can
-		 make Emacs dump core.  Avoid triggering the problem for now
-		 by allocating a new buffer each time through the loop.  */
-	      bool please_fixme = true;
-	      coding->destination = please_fixme ? alloca (n * 4) : dest;
-
-	      coding->dst_bytes = n * 4;
+	      coding->destination = dest;
+	      coding->dst_bytes = sizeof dest;
 	      decode_coding_c_string (coding, src, n, Qnil);
 	      eassert (coding->produced_char <= n);
 	      if (coding->produced_char == 0)
-- 
2.39.5