Subject: bug#11519: "Wrong type argument: characterp" building custom-deps while boostrapping

From: Eli Zaretskii <[email-masked]>
Date: Tue, 22 May 2012 22:00:46 +0300

> From: Stefan Monnier <[email-masked]>
> Cc: Andreas Schwab <[email-masked]>,  [email-masked],  [email-masked]
> Date: Mon, 21 May 2012 16:39:56 -0400
> 
> I suggest you let-bind some witness variable is re_search_2 and then in
> the buffer-relocation code, you test this var and abort if it's non-nil.
> That should let us catch the offender red-handed, after which we will
> know better how to fix the problem.

I did the equivalent of the above, but without changing the source (to
minimize the chances that the bug will disappear).

Is the evidence below conclusive enough?

  Breakpoint 3, search_buffer (string=272417249, pos=1, pos_byte=1, lim=48448,
      lim_byte=51025, n=1, RE=1, trt=61843973, inverse_trt=61841925, posix=0)
      at search.c:1206
  1206              val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
  $1771 = 272417249
  $1772 = (struct Lisp_String *) 0x103cc1e0
  "(provide[ 	\n]+\\('\\|(quote[ 	\n]\\)[ 	\n]*ethio-util[ 	\n)]"
  (gdb) p current_buffer->text->beg
  $1773 = (
      unsigned char *) 0x10757948 ";;; ethio-util.el --- utilities for Ethiopic -*- coding: utf-8-emacs; -*-\n\n;; Copyright (C) 1997-1998, 2002-2012  Free Software Foundation, Inc.\n;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 20"...
  (gdb) p *p1@20
  $1774 = ";;; ethio-util.el --"
  (gdb) p p1
  $1775 = (
      unsigned char *) 0x10757948 ";;; ethio-util.el --- utilities for Ethiopic -*- coding: utf-8-emacs; -*-\n\n;; Copyright (C) 1997-1998, 2002-2012  Free Software Foundation, Inc.\n;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 20"...

So at this point, before we call re_search_2, p1 and
current_buffer->text->beg point to the same memory.  Now:

  (gdb) watch current_buffer->text->beg
  Hardware watchpoint 4: current_buffer->text->beg
  (gdb) c
  Continuing.
  Hardware watchpoint 4: current_buffer->text->beg

  Old value =
      (unsigned char *) 0x10757948 ";;; ethio-util.el --- utilities for Ethiopic
  -*- coding: utf-8-emacs; -*-\n\n;; Copyright (C) 1997-1998, 2002-2012  Free Soft
  ware Foundation, Inc.\n;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 20".
  ..
  New value =
      (unsigned char *) 0x10826948 ";;; ethio-util.el --- utilities for Ethiopic
  -*- coding: utf-8-emacs; -*-\n\n;; Copyright (C) 1997-1998, 2002-2012  Free Soft
  ware Foundation, Inc.\n;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 20"...
  r_alloc_sbrk (size=847872) at ralloc.c:808
  808               for (b = last_bloc; b != NIL_BLOC; b = b->prev)

Note that the address of buffer text has changed from 0x10757948 to
0x10826948.  And the culprit is ...

  (gdb) bt
  #0  r_alloc_sbrk (size=847872) at ralloc.c:808
  #1  0x012e9dc0 in get_contiguous_space (size=847872, position=0x10748000)
      at gmalloc.c:447
  #2  0x012ea662 in _malloc_internal_nolock (size=786436) at gmalloc.c:821
  #3  0x012eaa4c in _malloc_internal (size=786436) at gmalloc.c:904
  #4  0x012eaa99 in e_malloc (size=786436) at gmalloc.c:927
  #5  0x0103a3b2 in emacs_blocked_malloc (size=786436, ptr=0x0) at alloc.c:1308
  #6  0x012eaa99 in e_malloc (size=786436) at gmalloc.c:927
  #7  0x010397fb in xmalloc (size=786436) at alloc.c:727
  #8  0x0120da2d in load_charset_map_from_file (charset=0x1944970,
      mapfile=57455953, control_flag=1) at charset.c:501
  #9  0x0120e480 in load_charset (charset=0x1944970, control_flag=1)
      at charset.c:646
  #10 0x01214cc9 in maybe_unify_char (c=1704385, val=57027682) at charset.c:1644
  #11 0x0128b4a0 in string_char (
      p=0x1075d630 "  2.÷áחג  3.÷áחד  4.÷áחה  5.÷áח\200\")\n  (cond\n   ((= arg ?1)\n    (insert \"÷áח\201\"))\n   ((= arg ?2)\n    (insert \"÷áחג\"))\n   ((= arg ?3)\n    (insert \"÷áחד\"))\n   ((= arg ?4)\n    (insert \"÷áחה\"))\n   ((= arg ?5"..., advanced=0x0, len=0x82dcec) at character.c:200
  #12 0x01142f65 in re_search_2 (bufp=0x1933c08,
      str1=0x10757948 ";;; ethio-util.el --- utilities for Ethiopic       -*- coding: utf-8-emacs; -*-\n\n;; Copyright (C) 1997-1998, 2002-2012  Free Software Foundation, Inc.\n;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 20"...,
      size1=51024, str2=0x1077fb17 "", size2=0, startpos=23749, range=27244,
      regs=0x19351f8, stop=51024) at regex.c:4421
  #13 0x010fbd78 in search_buffer (string=272417249, pos=1, pos_byte=1,
      lim=48448, lim_byte=51025, n=1, RE=1, trt=61843973, inverse_trt=61841925,
      posix=0) at search.c:1207
  #14 0x010fb578 in search_command (string=272417249, bound=56838170,
      noerror=56838194, count=56838170, direction=1, RE=1, posix=0)
      at search.c:997
  #15 0x010fefa4 in Fre_search_forward (regexp=272417249, bound=56838170,
      noerror=56838194, count=56838170) at search.c:2165

The fragment of regex.c that triggers this is as follows:

	      if (RE_TRANSLATE_P (translate))
		{
		  if (multibyte)
		    while (range > lim)
		      {
			int buf_charlen;

    >>>>>>>>>>>>>>>>>	buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
			buf_ch = RE_TRANSLATE (translate, buf_ch);
			if (fastmap[CHAR_LEADING_CODE (buf_ch)])
			  break;

			range -= buf_charlen;
			d += buf_charlen;
		      }

The marked line calls string_char, which calls maybe_unify_char, which
calls load_charset, which causes memory allocation and relocation of
buffer text.  The very next call to RE_TRANSLATE, which calls
char_table_translate, throws an error because buf_ch is garbage.

If you agree with the diagnosis, then how about the change below?  It
fixes the problem for me.  (Or is there a better way?)  If accepted, I
will add the necessary commentary to this code and a prototype for the
new function.  In any case, I suggest to install the fix on the
emacs-24 branch, because this issue is a disaster waiting to happen.

=== modified file 'src/ralloc.c'
--- src/ralloc.c	2012-04-16 01:18:13 +0000
+++ src/ralloc.c	2012-05-22 18:39:25 +0000
@@ -1143,6 +1143,12 @@ r_alloc_reset_variable (POINTER *old, PO
   bloc->variable = new;
 }
 
+void
+r_alloc_inhibit_buffer_relocation (int inhibit)
+{
+  use_relocatable_buffers = (inhibit ? 0 : 1);
+}
+
 
 /***********************************************************************
 			    Initialization

=== modified file 'src/search.c'
--- src/search.c	2012-05-17 00:03:49 +0000
+++ src/search.c	2012-05-22 18:41:23 +0000
@@ -1158,12 +1158,19 @@ search_buffer (Lisp_Object string, EMACS
       while (n < 0)
 	{
 	  EMACS_INT val;
+
+#ifdef REL_ALLOC
+	  r_alloc_inhibit_buffer_relocation (1);
+#endif
 	  val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
 			     pos_byte - BEGV_BYTE, lim_byte - pos_byte,
 			     (NILP (Vinhibit_changing_match_data)
 			      ? &search_regs : &search_regs_1),
 			     /* Don't allow match past current point */
 			     pos_byte - BEGV_BYTE);
+#ifdef REL_ALLOC
+	  r_alloc_inhibit_buffer_relocation (0);
+#endif
 	  if (val == -2)
 	    {
 	      matcher_overflow ();
@@ -1202,11 +1209,18 @@ search_buffer (Lisp_Object string, EMACS
       while (n > 0)
 	{
 	  EMACS_INT val;
+
+#ifdef REL_ALLOC
+	  r_alloc_inhibit_buffer_relocation (1);
+#endif
 	  val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
 			     pos_byte - BEGV_BYTE, lim_byte - pos_byte,
 			     (NILP (Vinhibit_changing_match_data)
 			      ? &search_regs : &search_regs_1),
 			     lim_byte - BEGV_BYTE);
+#ifdef REL_ALLOC
+	  r_alloc_inhibit_buffer_relocation (0);
+#endif
 	  if (val == -2)
 	    {
 	      matcher_overflow ();