emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 881abfc 2/5: Port to gcc -fcheck-pointer-bounds


From: Paul Eggert
Subject: [Emacs-diffs] master 881abfc 2/5: Port to gcc -fcheck-pointer-bounds
Date: Tue, 12 Dec 2017 18:17:19 -0500 (EST)

branch: master
commit 881abfc7fb55db2d00adf352100cc58a6a86c176
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Port to gcc -fcheck-pointer-bounds
    
    This is a minimal port, just to get Emacs running;
    it does not attempt to make the pointer bounds at all tight.
    * src/ptr-bounds.h: New file.
    * src/alloc.c, src/gmalloc.c: Include it.
    * src/alloc.c (live_string_holding, live_cons_holding)
    (live_symbol_holding, live_misc_holding, garbage_collect_1)
    (sweep_conses, sweep_floats):
    * src/gmalloc.c (malloc_initialize_1, _free_internal_nolock)
    (_realloc_internal_nolock):
    Widen pointer bounds as necessary.
    We're in a memory allocator so this is OK.
    * src/lisp.h (lisp_h_XSYMBOL, make_lisp_symbol) [__CHKP__]:
    Do not convert from pointer to integer and back again, so
    that GCC does not lose track of pointer bounds.
    (XSYMBOL) [__CHKP__ && !USE_LSB_TAG]: Now a compile-time error.
    Although it's possible to support both -fcheck-pointer-bounds and
    --with-wide-int, it's more work; keep things simple for now.
    (DEFINE_LISP_SYMBOL) [__CHKP__]: Now a no-op, to avoid
    trouble with unbounded pointers.
---
 etc/NEWS         |  7 +++++++
 src/alloc.c      | 37 ++++++++++++++++++++++++-------------
 src/gmalloc.c    |  6 +++++-
 src/lisp.h       | 34 +++++++++++++++++++++++++++-------
 src/ptr-bounds.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 115 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index c0d0d42..7376fc4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -31,6 +31,13 @@ functions 'json-serialize', 'json-insert', 
'json-parse-string', and
 'json-parse-buffer' are typically much faster than their Lisp
 counterparts from json.el.
 
+** Emacs has been ported to the -fcheck-pointer-bounds option of GCC.
+This causes Emacs to check bounds of some arrays addressed by its
+internal pointers, which can be helpful when debugging the Emacs
+interpreter or modules that it uses.  If your platform supports it you
+can enable it when configuring, e.g., './configure CFLAGS="-g3 -O2
+-mmpx -fcheck-pointer-bounds"' on Intel MPX platforms.
+
 
 * Startup Changes in Emacs 27.1
 
diff --git a/src/alloc.c b/src/alloc.c
index 38daee0..96b9aaa 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -33,6 +33,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "dispextern.h"
 #include "intervals.h"
+#include "ptr-bounds.h"
 #include "puresize.h"
 #include "sheap.h"
 #include "systime.h"
@@ -4564,6 +4565,7 @@ live_string_holding (struct mem_node *m, void *p)
         must not be on the free-list.  */
       if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0])
        {
+         cp = ptr_bounds_copy (cp, b);
          struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0];
          if (s->u.s.data)
            return make_lisp_ptr (s, Lisp_String);
@@ -4598,6 +4600,7 @@ live_cons_holding (struct mem_node *m, void *p)
          && (b != cons_block
              || offset / sizeof b->conses[0] < cons_block_index))
        {
+         cp = ptr_bounds_copy (cp, b);
          struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0];
          if (!EQ (s->u.s.car, Vdead))
            return make_lisp_ptr (s, Lisp_Cons);
@@ -4633,6 +4636,7 @@ live_symbol_holding (struct mem_node *m, void *p)
          && (b != symbol_block
              || offset / sizeof b->symbols[0] < symbol_block_index))
        {
+         cp = ptr_bounds_copy (cp, b);
          struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0];
          if (!EQ (s->u.s.function, Vdead))
            return make_lisp_symbol (s);
@@ -4692,6 +4696,7 @@ live_misc_holding (struct mem_node *m, void *p)
          && (b != marker_block
              || offset / sizeof b->markers[0] < marker_block_index))
        {
+         cp = ptr_bounds_copy (cp, b);
          union Lisp_Misc *s = p = cp -= offset % sizeof b->markers[0];
          if (s->u_any.type != Lisp_Misc_Free)
            return make_lisp_ptr (s, Lisp_Misc);
@@ -5955,6 +5960,7 @@ garbage_collect_1 (void *end)
              stack_copy = xrealloc (stack_copy, stack_size);
              stack_copy_size = stack_size;
            }
+         stack = ptr_bounds_set (stack, stack_size);
          no_sanitize_memcpy (stack_copy, stack, stack_size);
        }
     }
@@ -6848,7 +6854,9 @@ sweep_conses (void)
 
               for (pos = start; pos < stop; pos++)
                 {
-                  if (!CONS_MARKED_P (&cblk->conses[pos]))
+                 struct Lisp_Cons *acons
+                   = ptr_bounds_copy (&cblk->conses[pos], cblk);
+                 if (!CONS_MARKED_P (acons))
                     {
                       this_free++;
                       cblk->conses[pos].u.s.u.chain = cons_free_list;
@@ -6858,7 +6866,7 @@ sweep_conses (void)
                   else
                     {
                       num_used++;
-                      CONS_UNMARK (&cblk->conses[pos]);
+                     CONS_UNMARK (acons);
                     }
                 }
             }
@@ -6901,17 +6909,20 @@ sweep_floats (void)
       register int i;
       int this_free = 0;
       for (i = 0; i < lim; i++)
-        if (!FLOAT_MARKED_P (&fblk->floats[i]))
-          {
-            this_free++;
-            fblk->floats[i].u.chain = float_free_list;
-            float_free_list = &fblk->floats[i];
-          }
-        else
-          {
-            num_used++;
-            FLOAT_UNMARK (&fblk->floats[i]);
-          }
+       {
+         struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk);
+         if (!FLOAT_MARKED_P (afloat))
+           {
+             this_free++;
+             fblk->floats[i].u.chain = float_free_list;
+             float_free_list = &fblk->floats[i];
+           }
+         else
+           {
+             num_used++;
+             FLOAT_UNMARK (afloat);
+           }
+       }
       lim = FLOAT_BLOCK_SIZE;
       /* If this block contains only free floats and we have already
          seen more than two blocks worth of free floats then deallocate
diff --git a/src/gmalloc.c b/src/gmalloc.c
index a17d39c..97ab765 100644
--- a/src/gmalloc.c
+++ b/src/gmalloc.c
@@ -40,6 +40,8 @@ License along with this library.  If not, see 
<https://www.gnu.org/licenses/>.
 # include "lisp.h"
 #endif
 
+#include "ptr-bounds.h"
+
 #ifdef HAVE_MALLOC_H
 # if GNUC_PREREQ (4, 2, 0)
 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -558,7 +560,7 @@ malloc_initialize_1 (void)
   _heapinfo[0].free.size = 0;
   _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
   _heapindex = 0;
-  _heapbase = (char *) _heapinfo;
+  _heapbase = (char *) ptr_bounds_init (_heapinfo);
   _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info));
 
   register_heapinfo ();
@@ -997,6 +999,7 @@ _free_internal_nolock (void *ptr)
 
   if (ptr == NULL)
     return;
+  ptr = ptr_bounds_init (ptr);
 
   PROTECT_MALLOC_STATE (0);
 
@@ -1308,6 +1311,7 @@ _realloc_internal_nolock (void *ptr, size_t size)
   else if (ptr == NULL)
     return _malloc_internal_nolock (size);
 
+  ptr = ptr_bounds_init (ptr);
   block = BLOCK (ptr);
 
   PROTECT_MALLOC_STATE (0);
diff --git a/src/lisp.h b/src/lisp.h
index 54103d4..8947c59 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -379,10 +379,18 @@ typedef EMACS_INT Lisp_Word;
     XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0))
 # define lisp_h_XFASTINT(a) XINT (a)
 # define lisp_h_XINT(a) (XLI (a) >> INTTYPEBITS)
-# define lisp_h_XSYMBOL(a) \
+# ifdef __CHKP__
+#  define lisp_h_XSYMBOL(a) \
+    (eassert (SYMBOLP (a)), \
+     (struct Lisp_Symbol *) ((char *) XUNTAG (a, Lisp_Symbol) \
+                            + (intptr_t) lispsym))
+# else
+   /* If !__CHKP__ this is equivalent, and is a bit faster as of GCC 7.  */
+#  define lisp_h_XSYMBOL(a) \
     (eassert (SYMBOLP (a)), \
      (struct Lisp_Symbol *) ((intptr_t) XLI (a) - Lisp_Symbol \
                             + (char *) lispsym))
+# endif
 # define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK))
 # define lisp_h_XUNTAG(a, type) \
     __builtin_assume_aligned ((char *) XLP (a) - (type), GCALIGNMENT)
@@ -826,10 +834,15 @@ typedef EMACS_UINT Lisp_Word_tag;
 
 /* Declare extern constants for Lisp symbols.  These can be helpful
    when using a debugger like GDB, on older platforms where the debug
-   format does not represent C macros.  */
-#define DEFINE_LISP_SYMBOL(name) \
-  DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \
-  DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name))
+   format does not represent C macros.  However, they are unbounded
+   and would just be asking for trouble if checking pointer bounds.  */
+#ifdef __CHKP__
+# define DEFINE_LISP_SYMBOL(name)
+#else
+# define DEFINE_LISP_SYMBOL(name) \
+   DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \
+   DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name))
+#endif
 
 /* The index of the C-defined Lisp symbol SYM.
    This can be used in a static initializer.  */
@@ -889,6 +902,8 @@ INLINE struct Lisp_Symbol *
 {
 #if USE_LSB_TAG
   return lisp_h_XSYMBOL (a);
+#elif defined __CHKP__
+# error "pointer-checking not supported with wide integers"
 #else
   eassert (SYMBOLP (a));
   intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
@@ -900,8 +915,13 @@ INLINE struct Lisp_Symbol *
 INLINE Lisp_Object
 make_lisp_symbol (struct Lisp_Symbol *sym)
 {
-  intptr_t symoffset = (char *) sym - (char *) lispsym;
-  Lisp_Object a = TAG_PTR (Lisp_Symbol, (char *) symoffset);
+#ifdef __CHKP__
+  char *symoffset = (char *) sym - (intptr_t) lispsym;
+#else
+  /* If !__CHKP__ this is equivalent, and is a bit faster as of GCC 7.  */
+  char *symoffset = (char *) ((char *) sym - (char *) lispsym);
+#endif
+  Lisp_Object a = TAG_PTR (Lisp_Symbol, symoffset);
   eassert (XSYMBOL (a) == sym);
   return a;
 }
diff --git a/src/ptr-bounds.h b/src/ptr-bounds.h
new file mode 100644
index 0000000..5497982
--- /dev/null
+++ b/src/ptr-bounds.h
@@ -0,0 +1,52 @@
+/* Pointer bounds checking for GNU Emacs
+
+Copyright 2017 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef PTR_BOUNDS_H
+#define PTR_BOUNDS_H
+
+#include <stddef.h>
+
+/* When not checking pointer bounds, the following macros simply
+   return their first argument.  These macros return either void *, or
+   the same type as their first argument.  */
+
+/* Return a copy of P, but with the bounds of Q.  */
+#ifdef __CHKP__
+# define ptr_bounds_copy(p, q) __builtin___bnd_copy_ptr_bounds (p, q)
+#else
+# define ptr_bounds_copy(p, q) ((void) (void const *) {q}, p)
+#endif
+
+/* Return a copy of P, but with infinite bounds.
+   This is a loophole in pointer bounds checking.  */
+#ifdef __CHKP__
+# define ptr_bounds_init(p) __builtin___bnd_init_ptr_bounds (p)
+#else
+# define ptr_bounds_init(p) (p)
+#endif
+
+/* Return a copy of P, but with bounds [P, P + N).
+   This is a loophole in pointer bounds checking.  */
+#ifdef __CHKP__
+# define ptr_bounds_set(p, n) __builtin___bnd_set_ptr_bounds (p, n)
+#else
+# define ptr_bounds_set(p, n) ((void) (size_t) {n}, p)
+#endif
+
+#endif /* PTR_BOUNDS_H */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]