summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2017-12-09 13:57:38 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2017-12-12 15:17:12 -0800
commit881abfc7fb55db2d00adf352100cc58a6a86c176 (patch)
tree4bb07ccaf020ea861ce95ff4fd57bb6d2c562810 /src
parent244346c744a6700d320a0a0fe8c796be3b3ff023 (diff)
downloademacs-881abfc7fb55db2d00adf352100cc58a6a86c176.tar.gz
emacs-881abfc7fb55db2d00adf352100cc58a6a86c176.tar.bz2
emacs-881abfc7fb55db2d00adf352100cc58a6a86c176.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c37
-rw-r--r--src/gmalloc.c6
-rw-r--r--src/lisp.h34
-rw-r--r--src/ptr-bounds.h52
4 files changed, 108 insertions, 21 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 38daee065ae..96b9aaa0d2d 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 a17d39c1eeb..97ab76561f9 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 54103d4bebc..8947c59077e 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 00000000000..54979824c05
--- /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 */