Generalize fix for crash due to non-contiguous EMACS_INT (Bug#10780).
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 25 Feb 2012 19:39:42 +0000 (11:39 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 25 Feb 2012 19:39:42 +0000 (11:39 -0800)
Suggested by Stefan Monnier in
<http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00692.html>.
* alloc.c (widen_to_Lisp_Object): New static function.
(mark_memory): Also mark Lisp_Objects by fetching pointer words
and widening them to Lisp_Objects.  This would work even if
USE_LSB_TAG is defined and wide integers are used, which might
happen in a future version of Emacs.

src/ChangeLog
src/alloc.c
src/lisp.h

index 1566d62..9221041 100644 (file)
@@ -1,3 +1,14 @@
+2012-02-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Generalize fix for crash due to non-contiguous EMACS_INT (Bug#10780).
+       Suggested by Stefan Monnier in
+       <http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00692.html>.
+       * alloc.c (widen_to_Lisp_Object): New static function.
+       (mark_memory): Also mark Lisp_Objects by fetching pointer words
+       and widening them to Lisp_Objects.  This would work even if
+       USE_LSB_TAG is defined and wide integers are used, which might
+       happen in a future version of Emacs.
+
 2012-02-25  Chong Yidong  <cyd@gnu.org>
 
        * fileio.c (Ffile_selinux_context, Fset_file_selinux_context):
index 044e750..21c4db4 100644 (file)
@@ -1582,6 +1582,21 @@ make_number (EMACS_INT n)
 }
 #endif
 \f
+/* Convert the pointer-sized word P to EMACS_INT while preserving its
+   type and ptr fields.  */
+static Lisp_Object
+widen_to_Lisp_Object (void *p)
+{
+  intptr_t i = (intptr_t) p;
+#ifdef USE_LISP_UNION_TYPE
+  Lisp_Object obj;
+  obj.i = i;
+  return obj;
+#else
+  return i;
+#endif
+}
+\f
 /***********************************************************************
                          String Allocation
  ***********************************************************************/
@@ -4293,7 +4308,17 @@ mark_memory (void *start, void *end)
 
   for (pp = start; (void *) pp < end; pp++)
     for (i = 0; i < sizeof *pp; i += GC_POINTER_ALIGNMENT)
-      mark_maybe_pointer (*(void **) ((char *) pp + i));
+      {
+       void *w = *(void **) ((char *) pp + i);
+       mark_maybe_pointer (w);
+
+       /* A host where a Lisp_Object is wider than a pointer might
+          allocate a Lisp_Object in non-adjacent halves.  If
+          USE_LSB_TAG, the bottom half is not a valid pointer, so
+          widen it to to a Lisp_Object and check it that way.  */
+       if (sizeof w < sizeof (Lisp_Object))
+         mark_maybe_object (widen_to_Lisp_Object (w));
+      }
 }
 
 /* setjmp will work with GCC unless NON_SAVING_SETJMP is defined in
index 375d376..36f58d0 100644 (file)
@@ -197,22 +197,8 @@ extern int suppress_checking EXTERNALLY_VISIBLE;
 # if defined DECL_ALIGN
 /* On hosts where VALBITS is greater than the pointer width in bits,
    USE_LSB_TAG is:
-
-    a. unnecessary, because the top bits of an EMACS_INT are unused,
-
-    b. slower, because it typically requires extra masking, and
-
-    c. harmful, because it can create Lisp_Object values that are so scrambled
-       that mark_maybe_object cannot decipher them.  mark_maybe_object assumes
-       that EMACS_INT values are contiguous, but a host where EMACS_INT is
-       wider than a pointer might allocate the top half of an EMACS_INT in
-       (say) a 32-bit word on the stack, putting the bottom half in a 32-bit
-       register that is saved elsewhere in a jmp_buf.  When this happens,
-       since USE_LSB_TAG is not defined the bottom half alone is a valid
-       pointer that mark_maybe_pointer can follow; but if USE_LSB_TAG were
-       defined, the bottom half would not be a valid pointer and neither
-       mark_maybe_object nor mark_maybe_pointer would follow it.
-
+    a. unnecessary, because the top bits of an EMACS_INT are unused, and
+    b. slower, because it typically requires extra masking.
    So, define USE_LSB_TAG only on hosts where it might be useful.  */
 #  if UINTPTR_MAX >> VALBITS != 0
 #   define USE_LSB_TAG