]> git.eshelyaron.com Git - emacs.git/commitdiff
Re-port to 32-bit systems without alignment primitives
authorPo Lu <luangruo@yahoo.com>
Sun, 9 Mar 2025 15:02:21 +0000 (23:02 +0800)
committerEshel Yaron <me@eshelyaron.com>
Wed, 12 Mar 2025 18:46:41 +0000 (19:46 +0100)
* configure.ac (ALIGNOF_INT, ALIGNOF_LONG, ALIGNOF_LONG_LONG):
New variables.
(emacs_cv_alignas_unavailable): Define if alignas and structure
alignment primitives are unavailable.  In such an environment,
the MSB tagging scheme must be enabled, as must the GNU malloc.

* msdos/sed2v2.inp: Adjust correspondingly.

* src/alloc.c (union emacs_align_type): Remove types which
contain flexible array members.  The address of a field
subsequent to an aggregate with flexible array members cannot
validly be taken.
(mark_memory) [!USE_LSB_TAG && !WIDE_EMACS_INT]: Strip type bits
before scanning memory.

* src/emacs.c (main):

* src/eval.c (Fautoload_do_load):

* src/fns.c (Frequire): Rename a number of illogically named
fields.

* src/lisp.h (ALIGNOF_EMACS_INT): Define to the natural
alignment of EMACS_INT.
(IDEAL_GCALIGNMENT): New macro.
(USE_LSB_TAG): Disable if no alignment specifiers are available,
WIDE_EMACS_INT is undefined, and the natural alignment of
EMACS_INT falls short of LSB tagging's requirements.
(gflags): Rename illogically named fields and don't define them
as bitfields, which runs afoul of certain compiler issues.
(will_dump_p, will_bootstrap_p, will_dump_with_pdumper_p)
(dumped_with_pdumper_p): Adjust accordingly.

* src/pdumper.c (VM_SUPPORTED): Define to 0 when !USE_LSB_TAG.
It is better to read dump files into the heap by hand than to be
supplied with an address that is not representable.
(_dump_object_start_pseudovector): Rename to
dump_object_start_pseudovector, to avoid encroaching on reserved
names.
(START_DUMP_PVEC): Adjust correspondingly.
(dump_mmap_contiguous_vm): Preserve errno around failure
cleanup.
(dump_bitset_bit_set_p): Work around certain compiler issues.
(pdumper_load) [!USE_LSB_TAG]: Reject dump file allocations
that are not representable as Lisp_Objects.

Tested on i386-unknown-solaris2.10, sparc-sun-solaris2.10.

(cherry picked from commit a5f8ce9f1eae29f87fe13adb61bd4e15faa628a2)

configure.ac
msdos/sed2v2.inp
src/alloc.c
src/emacs.c
src/eval.c
src/fns.c
src/lisp.h
src/pdumper.c

index a13a7765e425beedbf1664a2de67f9c50cefb6ec..c487f4a48ad35615d7d4559e6a9671118adf643d 100644 (file)
@@ -3218,8 +3218,68 @@ AC_CACHE_CHECK(
    fi])
 doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
 
+AC_CHECK_ALIGNOF([int])
+AC_CHECK_ALIGNOF([long])
+AC_CHECK_ALIGNOF([long long])
+AC_CHECK_SIZEOF([long])
+
+AC_CACHE_CHECK([for struct alignment],
+  [emacs_cv_struct_alignment],
+  [AC_COMPILE_IFELSE(
+     [AC_LANG_PROGRAM([[#include <stddef.h>
+                       struct s { char c; } __attribute__ ((aligned (8)));
+                       struct t { char c; struct s s; };
+                       char verify[offsetof (struct t, s) == 8 ? 1 : -1];
+                     ]])],
+     [emacs_cv_struct_alignment=yes],
+     [emacs_cv_struct_alignment=no])])
+if test "$emacs_cv_struct_alignment" = yes; then
+  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], [1],
+    [Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
+     structure to an N-byte boundary.])
+fi
+
 system_malloc=yes
 
+# If it appears as if the system malloc can't be trusted to return
+# adequately positioned memory, enable the GNU malloc, which more
+# consistently provides allocations at low addresses, as is required for
+# the pdumper to load dump files at a representable location.
+AS_IF([test "$with_pdumper" = "yes" && test "$with_wide_int" != "yes"],
+  AC_CHECK_HEADERS([stdalign.h])
+  [AC_CACHE_CHECK([whether alignas is required yet unavailable],
+    [emacs_cv_alignas_unavailable],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#endif
+      #include <limits.h>
+     ]], [[
+#define IDEAL_GCALIGNMENT 8
+#if INTPTR_MAX <= INT_MAX && !defined WIDE_EMACS_INT
+#  define ALIGNOF_EMACS_INT ALIGNOF_INT
+# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
+#  define ALIGNOF_EMACS_INT ALIGNOF_LONG
+# elif INTPTR_MAX <= LLONG_MAX
+#  define ALIGNOF_EMACS_INT ALIGNOF_LONG_LONG
+# else
+# error "INTPTR_MAX too large"
+#endif
+
+#if (ALIGNOF_EMACS_INT < IDEAL_GCALIGNMENT && !defined alignas \
+     && !defined HAVE_STRUCT_ATTRIBUTE_ALIGNED                 \
+     && !defined __alignas_is_defined                          \
+     && __STDC_VERSION__ < 202311 && __cplusplus < 201103)
+#error "!USE_LSB_TAG required"
+#endif
+   ]])], [emacs_cv_alignas_unavailable=no],
+        [emacs_cv_alignas_unavailable=yes])])
+   AS_IF([test "$emacs_cv_alignas_unavailable" = "yes"],
+     [system_malloc=no
+       AC_MSG_WARN([The GNU memory manager will be enabled as your system
+does not guarantee that the portable dumper can allocate memory at a suitably
+low address.])])])
+
 dnl This must be before the test of $ac_cv_func_sbrk below.
 AC_CHECK_FUNCS_ONCE([sbrk])
 
@@ -5856,7 +5916,6 @@ AC_SUBST([HAVE_LIBSECCOMP])
 AC_SUBST([LIBSECCOMP_LIBS])
 AC_SUBST([LIBSECCOMP_CFLAGS])
 
-AC_CHECK_SIZEOF([long])
 SIZEOF_LONG="$ac_cv_sizeof_long"
 AC_SUBST([SIZEOF_LONG])
 
@@ -7219,22 +7278,6 @@ else
 fi
 AC_SUBST([LIBXMENU])
 
-AC_CACHE_CHECK([for struct alignment],
-  [emacs_cv_struct_alignment],
-  [AC_COMPILE_IFELSE(
-     [AC_LANG_PROGRAM([[#include <stddef.h>
-                       struct s { char c; } __attribute__ ((aligned (8)));
-                       struct t { char c; struct s s; };
-                       char verify[offsetof (struct t, s) == 8 ? 1 : -1];
-                     ]])],
-     [emacs_cv_struct_alignment=yes],
-     [emacs_cv_struct_alignment=no])])
-if test "$emacs_cv_struct_alignment" = yes; then
-  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], [1],
-    [Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
-     structure to an N-byte boundary.])
-fi
-
 AC_C_RESTRICT
 AC_C_TYPEOF
 
index ff6eca0f6253c36b4e4079e09c661efd4b402fca..6a6a3c2d9a89413e9206a72c36fce25bbe7db054 100644 (file)
@@ -140,6 +140,9 @@ s/^#undef HAVE_DECL_STRTOIMAX *$/#define HAVE_DECL_STRTOIMAX 1/
 s/^#undef HAVE_PDUMPER *$/#define HAVE_PDUMPER 1/
 s/^#undef HAVE_STRTOLL *$/#define HAVE_STRTOLL 1/
 s/^#undef HAVE_STRTOULL *$/#define HAVE_STRTOULL 1/
+s/^#undef ALIGNOF_INT *$/s/^.*$/#define ALIGNOF_INT 4/
+s/^#undef ALIGNOF_LONG *$/s/^.*$/#define ALIGNOF_LONG 4/
+s/^#undef ALIGNOF_LONG_LONG *$/s/^.*$/#define ALIGNOF_LONG_LONG 4/
 /^#undef HAVE_STRUCT_DIRENT_D_TYPE *$/c\
 #if __DJGPP__ + (__DJGPP_MINOR__ >= 5) >= 3\
 #define HAVE_STRUCT_DIRENT_D_TYPE 1/\
index 7fa05e54202bf83c1264934c9b4ed2daf5a58b50..c0d68e6c9643666db132595b0cf8b2fef6ecad05 100644 (file)
@@ -150,8 +150,6 @@ union emacs_align_type
 {
   struct frame frame;
   struct Lisp_Bignum Lisp_Bignum;
-  struct Lisp_Bool_Vector Lisp_Bool_Vector;
-  struct Lisp_Char_Table Lisp_Char_Table;
   struct Lisp_CondVar Lisp_CondVar;
   struct Lisp_Finalizer Lisp_Finalizer;
   struct Lisp_Float Lisp_Float;
@@ -160,21 +158,25 @@ union emacs_align_type
   struct Lisp_Misc_Ptr Lisp_Misc_Ptr;
   struct Lisp_Mutex Lisp_Mutex;
   struct Lisp_Overlay Lisp_Overlay;
-  struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table;
   struct Lisp_Subr Lisp_Subr;
   struct Lisp_Sqlite Lisp_Sqlite;
   struct Lisp_User_Ptr Lisp_User_Ptr;
-  struct Lisp_Vector Lisp_Vector;
   struct terminal terminal;
   struct thread_state thread_state;
   struct window window;
 
   /* Omit the following since they would require including process.h
-     etc.  In practice their alignments never exceed that of the
-     structs already listed.  */
+     etc, or because they are defined with flexible array members, which
+     are rejected by some C99 compilers when this union subsequently
+     appears in an `alignof' expression.  In practice their alignments
+     never exceed that of the structs already listed.  */
 #if 0
+  struct Lisp_Bool_Vector Lisp_Bool_Vector;
+  struct Lisp_Char_Table Lisp_Char_Table;
+  struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table;
   struct Lisp_Module_Function Lisp_Module_Function;
   struct Lisp_Process Lisp_Process;
+  struct Lisp_Vector Lisp_Vector;
   struct save_window_data save_window_data;
   struct scroll_bar scroll_bar;
   struct xwidget_view xwidget_view;
@@ -5167,14 +5169,20 @@ mark_memory (void const *start, void const *end)
   for (pp = start; (void const *) pp < end; pp += GC_POINTER_ALIGNMENT)
     {
       void *p = *(void *const *) pp;
+      intptr_t ip;
+
+#if !USE_LSB_TAG && !defined WIDE_EMACS_INT
+      ip = (intptr_t) p;
+      mark_maybe_pointer ((void *) (ip & VALMASK), false);
+#else /* USE_LSB_TAG || WIDE_EMACS_INT */
       mark_maybe_pointer (p, false);
+#endif /* USE_LSB_TAG || WIDE_EMACS_INT */
 
       /* Unmask any struct Lisp_Symbol pointer that make_lisp_symbol
         previously disguised by adding the address of 'lispsym'.
         On a host with 32-bit pointers and 64-bit Lisp_Objects,
         a Lisp_Object might be split into registers saved into
         non-adjacent words and P might be the low-order word's value.  */
-      intptr_t ip;
       ckd_add (&ip, (intptr_t) p, (intptr_t) lispsym);
       mark_maybe_pointer ((void *) ip, true);
     }
index dc7041c23382ca1e30c689e6abc5d96e7b19bc52..6ff7b632c0faa6a479435c051ad0870f02bc7a76 100644 (file)
@@ -1311,13 +1311,11 @@ android_emacs_init (int argc, char **argv, char *dump_file)
   if (!initialized && temacs)
     {
 #ifdef HAVE_PDUMPER
-      if (strcmp (temacs, "pdump") == 0 ||
-          strcmp (temacs, "pbootstrap") == 0)
-        gflags.will_dump_with_pdumper_ = true;
-      if (strcmp (temacs, "pbootstrap") == 0)
-        gflags.will_bootstrap_ = true;
-      gflags.will_dump_ =
-        will_dump_with_pdumper_p ();
+      if (!strcmp (temacs, "pdump") || !strcmp (temacs, "pbootstrap"))
+        gflags.will_dump_with_pdumper = true;
+      if (!strcmp (temacs, "pbootstrap"))
+       gflags.will_bootstrap = true;
+      gflags.will_dump = will_dump_with_pdumper_p ();
       if (will_dump_p ())
         dump_mode = temacs;
 #endif
index 5985786fdc557116e1a6d24c3fb8f25ae4bbf106..ef1db469f904021756b4ac8514f22839afe7c2fb 100644 (file)
@@ -2390,7 +2390,7 @@ it defines a macro.  */)
     {
       /* Avoid landing here recursively while outputting the
         backtrace from the error.  */
-      gflags.will_dump_ = false;
+      gflags.will_dump = false;
       error ("Attempt to autoload %s while preparing to dump",
             SDATA (SYMBOL_NAME (funname)));
     }
index 46addee831295e1f80269c824ded939ac58e9c1e..7903f91ec68340833380aec13e03998d34e4a4d7 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -3777,7 +3777,7 @@ FILENAME are suppressed.  */)
        {
          /* Avoid landing here recursively while outputting the
             backtrace from the error.  */
-         gflags.will_dump_ = false;
+         gflags.will_dump = false;
          error ("(require %s) while preparing to dump",
                 SDATA (SYMBOL_NAME (feature)));
        }
index e013ee7e419abb0e7cce820a8ce4673049bab950..4506f8613a8a81bd2448837228d670ff467e3ab5 100644 (file)
@@ -89,18 +89,21 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS)
 typedef int EMACS_INT;
 typedef unsigned int EMACS_UINT;
 enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH };
+#  define ALIGNOF_EMACS_INT ALIGNOF_INT
 #  define EMACS_INT_MAX INT_MAX
 #  define pI ""
 # elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
 typedef long int EMACS_INT;
 typedef unsigned long EMACS_UINT;
 enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH };
+#  define ALIGNOF_EMACS_INT ALIGNOF_LONG
 #  define EMACS_INT_MAX LONG_MAX
 #  define pI "l"
 # elif INTPTR_MAX <= LLONG_MAX
 typedef long long int EMACS_INT;
 typedef unsigned long long int EMACS_UINT;
 enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH };
+#  define ALIGNOF_EMACS_INT ALIGNOF_LONG_LONG
 #  define EMACS_INT_MAX LLONG_MAX
 /* MinGW supports %lld only if __USE_MINGW_ANSI_STDIO is non-zero,
    which is arranged by config.h, and (for mingw.org) if GCC is 6.0 or
@@ -237,13 +240,26 @@ DEFINE_GDB_SYMBOL_END (INTTYPEBITS)
    expression involving VAL_MAX.  */
 #define VAL_MAX (EMACS_INT_MAX >> (GCTYPEBITS - 1))
 
+/* The alignment ideally required of objects subject to garbage
+   collection.  (In the sense that it would be ideal for such an
+   alignment to be available to enable LSB tagging.)  */
+#define IDEAL_GCALIGNMENT 8
+
 /* Whether the least-significant bits of an EMACS_INT contain the tag.
    On hosts where pointers-as-ints do not exceed VAL_MAX / 2, USE_LSB_TAG is:
     a. unnecessary, because the top bits of an EMACS_INT are unused, and
     b. slower, because it typically requires extra masking.
    So, USE_LSB_TAG is true only on hosts where it might be useful.  */
 DEFINE_GDB_SYMBOL_BEGIN (bool, USE_LSB_TAG)
+#if (ALIGNOF_EMACS_INT < IDEAL_GCALIGNMENT && !defined alignas \
+     && !defined WIDE_EMACS_INT                                        \
+     && !defined HAVE_STRUCT_ATTRIBUTE_ALIGNED                 \
+     && !defined __alignas_is_defined                          \
+     && __STDC_VERSION__ < 202311 && __cplusplus < 201103)
+#define USE_LSB_TAG 0
+#else /* EMACS_INT_WIDTH >= GCALIGNMENT || defined alignas ... */
 #define USE_LSB_TAG (VAL_MAX / 2 < INTPTR_MAX)
+#endif /* EMACS_INT_WIDTH >= GCALIGNMENT || defined alignas ... */
 DEFINE_GDB_SYMBOL_END (USE_LSB_TAG)
 
 /* Mask for the value (as opposed to the type bits) of a Lisp object.  */
@@ -262,7 +278,7 @@ DEFINE_GDB_SYMBOL_END (VALMASK)
    USE_LSB_TAG, 1 otherwise.  It must be a literal integer constant,
    for older versions of GCC (through at least 4.9).  */
 #if USE_LSB_TAG
-# define GCALIGNMENT 8
+# define GCALIGNMENT IDEAL_GCALIGNMENT
 # if GCALIGNMENT != 1 << GCTYPEBITS
 #  error "GCALIGNMENT and GCTYPEBITS are inconsistent"
 # endif
@@ -629,15 +645,15 @@ extern bool initialized;
 extern struct gflags
 {
   /* True means this Emacs instance was born to dump.  */
-  bool will_dump_ : 1;
-  bool will_bootstrap_ : 1;
+  bool will_dump;
+  bool will_bootstrap;
 #ifdef HAVE_PDUMPER
   /* Set in an Emacs process that will likely dump with pdumper; all
      Emacs processes may dump with pdumper, however.  */
-  bool will_dump_with_pdumper_ : 1;
+  bool will_dump_with_pdumper;
   /* Set in an Emacs process that has been restored from a portable
      dump.  */
-  bool dumped_with_pdumper_ : 1;
+  bool dumped_with_pdumper;
 #endif
 } gflags;
 
@@ -645,7 +661,7 @@ INLINE bool
 will_dump_p (void)
 {
 #if HAVE_PDUMPER
-  return gflags.will_dump_;
+  return gflags.will_dump;
 #else
   return false;
 #endif
@@ -655,7 +671,7 @@ INLINE bool
 will_bootstrap_p (void)
 {
 #if HAVE_PDUMPER
-  return gflags.will_bootstrap_;
+  return gflags.will_bootstrap;
 #else
   return false;
 #endif
@@ -665,7 +681,7 @@ INLINE bool
 will_dump_with_pdumper_p (void)
 {
 #if HAVE_PDUMPER
-  return gflags.will_dump_with_pdumper_;
+  return gflags.will_dump_with_pdumper;
 #else
   return false;
 #endif
@@ -675,7 +691,7 @@ INLINE bool
 dumped_with_pdumper_p (void)
 {
 #if HAVE_PDUMPER
-  return gflags.dumped_with_pdumper_;
+  return gflags.dumped_with_pdumper;
 #else
   return false;
 #endif
index 342c37b5e620d3c6a60981b069ac0d9e4b51f02a..8e10e561bcf77fb1bfefe6637e5ab34f40d55de5 100644 (file)
@@ -77,7 +77,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #define VM_POSIX 1
 #define VM_MS_WINDOWS 2
 
-#if defined (HAVE_MMAP) && defined (MAP_FIXED)
+#if !USE_LSB_TAG
+# define VM_SUPPORTED 0
+#elif defined (HAVE_MMAP) && defined (MAP_FIXED)
 # define VM_SUPPORTED VM_POSIX
 # if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ)
 #  define MAP_POPULATE MAP_PREFAULT_READ
@@ -1964,9 +1966,9 @@ dump_field_emacs_ptr (struct dump_context *ctx,
 }
 
 static void
-_dump_object_start_pseudovector (struct dump_context *ctx,
-                                union vectorlike_header *out_hdr,
-                                const union vectorlike_header *in_hdr)
+dump_object_start_pseudovector (struct dump_context *ctx,
+                               union vectorlike_header *out_hdr,
+                               const union vectorlike_header *in_hdr)
 {
   eassert (in_hdr->size & PSEUDOVECTOR_FLAG);
   ptrdiff_t vec_size = vectorlike_nbytes (in_hdr);
@@ -1976,9 +1978,9 @@ _dump_object_start_pseudovector (struct dump_context *ctx,
 
 /* Need a macro for alloca.  */
 #define START_DUMP_PVEC(ctx, hdr, type, out)                  \
-  const union vectorlike_header *_in_hdr = (hdr);             \
-  type *out = alloca (vectorlike_nbytes (_in_hdr));           \
-  _dump_object_start_pseudovector (ctx, &out->header, _in_hdr)
+  const union vectorlike_header *in_hdr = (hdr);             \
+  type *out = alloca (vectorlike_nbytes (in_hdr));           \
+  dump_object_start_pseudovector (ctx, &out->header, in_hdr)
 
 static dump_off
 finish_dump_pvec (struct dump_context *ctx,
@@ -3994,14 +3996,14 @@ dump_do_fixup (struct dump_context *ctx,
                Lisp_Object fixup,
                Lisp_Object prev_fixup)
 {
-  enum dump_fixup_type type =
-    (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup));
+  enum dump_fixup_type type
+    (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup));
   dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup));
 #ifdef ENABLE_CHECKING
   if (!NILP (prev_fixup))
     {
-      dump_off prev_dump_fixup_offset =
-        dump_off_from_lisp (XCAR (XCDR (prev_fixup)));
+      dump_off prev_dump_fixup_offset
+       = dump_off_from_lisp (XCAR (XCDR (prev_fixup)));
       eassert (dump_fixup_offset - prev_dump_fixup_offset
               >= sizeof (void *));
     }
@@ -4618,23 +4620,8 @@ dump_anonymous_allocate_posix (void *base,
 }
 #endif
 
-/* Perform anonymous memory allocation.  */
-static void *
-dump_anonymous_allocate (void *base,
-                         const size_t size,
-                         enum dump_memory_protection protection)
-{
-#if VM_SUPPORTED == VM_POSIX
-  return dump_anonymous_allocate_posix (base, size, protection);
-#elif VM_SUPPORTED == VM_MS_WINDOWS
-  return dump_anonymous_allocate_w32 (base, size, protection);
-#else
-  errno = ENOSYS;
-  return NULL;
-#endif
-}
+/* Undo the effect of `dump_reserve_address_space'.  */
 
-/* Undo the effect of dump_reserve_address_space().  */
 static void
 dump_anonymous_release (void *addr, size_t size)
 {
@@ -4653,6 +4640,26 @@ dump_anonymous_release (void *addr, size_t size)
 #endif
 }
 
+/* Perform anonymous memory allocation.  */
+static void *
+dump_anonymous_allocate (void *base,
+                         const size_t size,
+                         enum dump_memory_protection protection)
+{
+  void *val;
+
+#if VM_SUPPORTED == VM_POSIX
+  val = dump_anonymous_allocate_posix (base, size, protection);
+#elif VM_SUPPORTED == VM_MS_WINDOWS
+  val = dump_anonymous_allocate_w32 (base, size, protection);
+#else
+  errno = ENOSYS;
+  val = NULL;
+#endif
+
+  return val;
+}
+
 #if VM_SUPPORTED == VM_MS_WINDOWS
 static void *
 dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
@@ -4824,20 +4831,20 @@ static void
 dump_discard_mem (void *mem, size_t size)
 {
 #if VM_SUPPORTED == VM_MS_WINDOWS
-      /* Discard COWed pages.  */
-      (void) VirtualFree (mem, size, MEM_DECOMMIT);
-      /* Release the commit charge for the mapping.  */
-      DWORD old_prot;
-      (void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot);
+  /* Discard COWed pages.  */
+  (void) VirtualFree (mem, size, MEM_DECOMMIT);
+  /* Release the commit charge for the mapping.  */
+  DWORD old_prot;
+  (void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot);
 #elif VM_SUPPORTED == VM_POSIX
 # ifdef HAVE_POSIX_MADVISE
-      /* Discard COWed pages.  */
-      (void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
+  /* Discard COWed pages.  */
+  (void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
 # elif defined HAVE_MADVISE
-      (void) madvise (mem, size, MADV_DONTNEED);
+  (void) madvise (mem, size, MADV_DONTNEED);
 #endif
-      /* Release the commit charge for the mapping.  */
-      (void) mprotect (mem, size, PROT_NONE);
+  /* Release the commit charge for the mapping.  */
+  (void) mprotect (mem, size, PROT_NONE);
 #endif
 }
 
@@ -4959,21 +4966,23 @@ dump_mmap_release_vm (struct dump_memory_map *map)
 static bool
 needs_mmap_retry_p (void)
 {
-#if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS || defined _AIX
+#if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS \
+  || defined _AIX
   return true;
-#else
+#else /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */
   return false;
-#endif
+#endif /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */
 }
 
 static bool
 dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
                         size_t total_size)
 {
+  int save_errno;
   bool ret = false;
   void *resv = NULL;
   bool retry = false;
-  const bool need_retry = needs_mmap_retry_p ();
+  bool need_retry = needs_mmap_retry_p ();
 
   do
     {
@@ -4986,11 +4995,10 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
         }
 
       eassert (resv == NULL);
-      resv = dump_anonymous_allocate (NULL,
-                                      total_size,
+      resv = dump_anonymous_allocate (NULL, total_size,
                                       DUMP_MEMORY_ACCESS_NONE);
       if (!resv)
-        goto out;
+       goto out;
 
       char *mem = resv;
 
@@ -5039,6 +5047,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
   ret = true;
   resv = NULL;
  out:
+  save_errno = errno;
   if (resv)
     dump_anonymous_release (resv, total_size);
   if (!ret)
@@ -5051,6 +5060,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
            dump_mmap_release (&maps[i]);
        }
     }
+  errno = save_errno;
   return ret;
 }
 
@@ -5058,8 +5068,8 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
 
    Each dump_memory_map structure describes how to fill the
    corresponding range of memory. On input, all members except MAPPING
-   are valid. On output, MAPPING contains the location of the given
-   chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping +
+   are valid.  On output, MAPPING contains the location of the given
+   chunk of memory.  The MAPPING for MAPS[N] is MAPS[N-1].mapping +
    MAPS[N-1].size.
 
    Each mapping SIZE must be a multiple of the system page size except
@@ -5085,8 +5095,10 @@ dump_mmap_contiguous (struct dump_memory_map *maps, int nr_maps)
       total_size += maps[i].spec.size;
     }
 
-  return (VM_SUPPORTED ? dump_mmap_contiguous_vm : dump_mmap_contiguous_heap)
-    (maps, nr_maps, total_size);
+  if (VM_SUPPORTED)
+    return dump_mmap_contiguous_vm (maps, nr_maps, total_size);
+  else
+    return dump_mmap_contiguous_heap (maps, nr_maps, total_size);
 }
 
 typedef uint_fast32_t dump_bitset_word;
@@ -5129,7 +5141,7 @@ dump_bitset_bit_set_p (const struct dump_bitset *bitset,
 {
   dump_bitset_word bit = 1;
   bit <<= bit_number % DUMP_BITSET_WORD_WIDTH;
-  return *dump_bitset__bit_slot (bitset, bit_number) & bit;
+  return (*dump_bitset__bit_slot (bitset, bit_number) & bit) != 0;
 }
 
 static void
@@ -5548,8 +5560,8 @@ dump_do_dump_relocation (const uintptr_t dump_base,
         struct bignum_reload_info reload_info;
        static_assert (sizeof (reload_info) <= sizeof (*bignum_val (bignum)));
         memcpy (&reload_info, bignum_val (bignum), sizeof (reload_info));
-        const mp_limb_t *limbs =
-          dump_ptr (dump_base, reload_info.data_location);
+        const mp_limb_t *limbs = dump_ptr (dump_base,
+                                          reload_info.data_location);
         mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
         break;
       }
@@ -5790,15 +5802,29 @@ pdumper_load (const char *dump_filename, char *argv0)
     goto out;
 
   err = PDUMPER_LOAD_ERROR;
-  mark_bits_needed =
-    divide_round_up (header->discardable_start, DUMP_ALIGNMENT);
+  dump_base = (uintptr_t) sections[DS_HOT].mapping;
+
+#if !USE_LSB_TAG
+  /* The dump may have been mapped at a location that does not admit of
+     representation as Lisp_Objects.  Abort in this case.  */
+  if ((dump_base + dump_size) & ~VALMASK)
+    {
+      fprintf (stderr,
+              "Failed to load dump file: 0x%p+0x%p & 0x%p != 0\n",
+              (void *) dump_base, (void *) dump_size,
+              (void *) (uintptr_t) VALMASK);
+      goto out;
+    }
+#endif /* !USE_LSB_TAG */
+
+  mark_bits_needed
+    = divide_round_up (header->discardable_start, DUMP_ALIGNMENT);
   if (!dump_bitsets_init (mark_bits, mark_bits_needed))
     goto out;
 
   /* Point of no return.  */
   err = PDUMPER_LOAD_SUCCESS;
-  dump_base = (uintptr_t) sections[DS_HOT].mapping;
-  gflags.dumped_with_pdumper_ = true;
+  gflags.dumped_with_pdumper = true;
   dump_private.header = *header;
   dump_private.mark_bits = mark_bits[0];
   dump_private.last_mark_bits = mark_bits[1];
@@ -5815,8 +5841,8 @@ pdumper_load (const char *dump_filename, char *argv0)
   Lisp_Object hashes = zero_vector;
   if (header->hash_list)
     {
-      struct Lisp_Vector *hash_tables =
-       (struct Lisp_Vector *) (dump_base + header->hash_list);
+      struct Lisp_Vector *hash_tables
+       (struct Lisp_Vector *) (dump_base + header->hash_list);
       hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike);
     }
 
@@ -5852,7 +5878,6 @@ pdumper_load (const char *dump_filename, char *argv0)
     dump_mmap_release (&sections[i]);
   if (dump_fd >= 0)
     emacs_close (dump_fd);
-
   return err;
 }