aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2017-12-09 13:57:38 -0800
committerPaul Eggert2017-12-12 15:17:12 -0800
commit881abfc7fb55db2d00adf352100cc58a6a86c176 (patch)
tree4bb07ccaf020ea861ce95ff4fd57bb6d2c562810 /src
parent244346c744a6700d320a0a0fe8c796be3b3ff023 (diff)
downloademacs-881abfc7fb55db2d00adf352100cc58a6a86c176.tar.gz
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/>. */
33#include "lisp.h" 33#include "lisp.h"
34#include "dispextern.h" 34#include "dispextern.h"
35#include "intervals.h" 35#include "intervals.h"
36#include "ptr-bounds.h"
36#include "puresize.h" 37#include "puresize.h"
37#include "sheap.h" 38#include "sheap.h"
38#include "systime.h" 39#include "systime.h"
@@ -4564,6 +4565,7 @@ live_string_holding (struct mem_node *m, void *p)
4564 must not be on the free-list. */ 4565 must not be on the free-list. */
4565 if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0]) 4566 if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0])
4566 { 4567 {
4568 cp = ptr_bounds_copy (cp, b);
4567 struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0]; 4569 struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0];
4568 if (s->u.s.data) 4570 if (s->u.s.data)
4569 return make_lisp_ptr (s, Lisp_String); 4571 return make_lisp_ptr (s, Lisp_String);
@@ -4598,6 +4600,7 @@ live_cons_holding (struct mem_node *m, void *p)
4598 && (b != cons_block 4600 && (b != cons_block
4599 || offset / sizeof b->conses[0] < cons_block_index)) 4601 || offset / sizeof b->conses[0] < cons_block_index))
4600 { 4602 {
4603 cp = ptr_bounds_copy (cp, b);
4601 struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0]; 4604 struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0];
4602 if (!EQ (s->u.s.car, Vdead)) 4605 if (!EQ (s->u.s.car, Vdead))
4603 return make_lisp_ptr (s, Lisp_Cons); 4606 return make_lisp_ptr (s, Lisp_Cons);
@@ -4633,6 +4636,7 @@ live_symbol_holding (struct mem_node *m, void *p)
4633 && (b != symbol_block 4636 && (b != symbol_block
4634 || offset / sizeof b->symbols[0] < symbol_block_index)) 4637 || offset / sizeof b->symbols[0] < symbol_block_index))
4635 { 4638 {
4639 cp = ptr_bounds_copy (cp, b);
4636 struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0]; 4640 struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0];
4637 if (!EQ (s->u.s.function, Vdead)) 4641 if (!EQ (s->u.s.function, Vdead))
4638 return make_lisp_symbol (s); 4642 return make_lisp_symbol (s);
@@ -4692,6 +4696,7 @@ live_misc_holding (struct mem_node *m, void *p)
4692 && (b != marker_block 4696 && (b != marker_block
4693 || offset / sizeof b->markers[0] < marker_block_index)) 4697 || offset / sizeof b->markers[0] < marker_block_index))
4694 { 4698 {
4699 cp = ptr_bounds_copy (cp, b);
4695 union Lisp_Misc *s = p = cp -= offset % sizeof b->markers[0]; 4700 union Lisp_Misc *s = p = cp -= offset % sizeof b->markers[0];
4696 if (s->u_any.type != Lisp_Misc_Free) 4701 if (s->u_any.type != Lisp_Misc_Free)
4697 return make_lisp_ptr (s, Lisp_Misc); 4702 return make_lisp_ptr (s, Lisp_Misc);
@@ -5955,6 +5960,7 @@ garbage_collect_1 (void *end)
5955 stack_copy = xrealloc (stack_copy, stack_size); 5960 stack_copy = xrealloc (stack_copy, stack_size);
5956 stack_copy_size = stack_size; 5961 stack_copy_size = stack_size;
5957 } 5962 }
5963 stack = ptr_bounds_set (stack, stack_size);
5958 no_sanitize_memcpy (stack_copy, stack, stack_size); 5964 no_sanitize_memcpy (stack_copy, stack, stack_size);
5959 } 5965 }
5960 } 5966 }
@@ -6848,7 +6854,9 @@ sweep_conses (void)
6848 6854
6849 for (pos = start; pos < stop; pos++) 6855 for (pos = start; pos < stop; pos++)
6850 { 6856 {
6851 if (!CONS_MARKED_P (&cblk->conses[pos])) 6857 struct Lisp_Cons *acons
6858 = ptr_bounds_copy (&cblk->conses[pos], cblk);
6859 if (!CONS_MARKED_P (acons))
6852 { 6860 {
6853 this_free++; 6861 this_free++;
6854 cblk->conses[pos].u.s.u.chain = cons_free_list; 6862 cblk->conses[pos].u.s.u.chain = cons_free_list;
@@ -6858,7 +6866,7 @@ sweep_conses (void)
6858 else 6866 else
6859 { 6867 {
6860 num_used++; 6868 num_used++;
6861 CONS_UNMARK (&cblk->conses[pos]); 6869 CONS_UNMARK (acons);
6862 } 6870 }
6863 } 6871 }
6864 } 6872 }
@@ -6901,17 +6909,20 @@ sweep_floats (void)
6901 register int i; 6909 register int i;
6902 int this_free = 0; 6910 int this_free = 0;
6903 for (i = 0; i < lim; i++) 6911 for (i = 0; i < lim; i++)
6904 if (!FLOAT_MARKED_P (&fblk->floats[i])) 6912 {
6905 { 6913 struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk);
6906 this_free++; 6914 if (!FLOAT_MARKED_P (afloat))
6907 fblk->floats[i].u.chain = float_free_list; 6915 {
6908 float_free_list = &fblk->floats[i]; 6916 this_free++;
6909 } 6917 fblk->floats[i].u.chain = float_free_list;
6910 else 6918 float_free_list = &fblk->floats[i];
6911 { 6919 }
6912 num_used++; 6920 else
6913 FLOAT_UNMARK (&fblk->floats[i]); 6921 {
6914 } 6922 num_used++;
6923 FLOAT_UNMARK (afloat);
6924 }
6925 }
6915 lim = FLOAT_BLOCK_SIZE; 6926 lim = FLOAT_BLOCK_SIZE;
6916 /* If this block contains only free floats and we have already 6927 /* If this block contains only free floats and we have already
6917 seen more than two blocks worth of free floats then deallocate 6928 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/>.
40# include "lisp.h" 40# include "lisp.h"
41#endif 41#endif
42 42
43#include "ptr-bounds.h"
44
43#ifdef HAVE_MALLOC_H 45#ifdef HAVE_MALLOC_H
44# if GNUC_PREREQ (4, 2, 0) 46# if GNUC_PREREQ (4, 2, 0)
45# pragma GCC diagnostic ignored "-Wdeprecated-declarations" 47# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -558,7 +560,7 @@ malloc_initialize_1 (void)
558 _heapinfo[0].free.size = 0; 560 _heapinfo[0].free.size = 0;
559 _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; 561 _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
560 _heapindex = 0; 562 _heapindex = 0;
561 _heapbase = (char *) _heapinfo; 563 _heapbase = (char *) ptr_bounds_init (_heapinfo);
562 _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); 564 _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info));
563 565
564 register_heapinfo (); 566 register_heapinfo ();
@@ -997,6 +999,7 @@ _free_internal_nolock (void *ptr)
997 999
998 if (ptr == NULL) 1000 if (ptr == NULL)
999 return; 1001 return;
1002 ptr = ptr_bounds_init (ptr);
1000 1003
1001 PROTECT_MALLOC_STATE (0); 1004 PROTECT_MALLOC_STATE (0);
1002 1005
@@ -1308,6 +1311,7 @@ _realloc_internal_nolock (void *ptr, size_t size)
1308 else if (ptr == NULL) 1311 else if (ptr == NULL)
1309 return _malloc_internal_nolock (size); 1312 return _malloc_internal_nolock (size);
1310 1313
1314 ptr = ptr_bounds_init (ptr);
1311 block = BLOCK (ptr); 1315 block = BLOCK (ptr);
1312 1316
1313 PROTECT_MALLOC_STATE (0); 1317 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;
379 XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0)) 379 XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0))
380# define lisp_h_XFASTINT(a) XINT (a) 380# define lisp_h_XFASTINT(a) XINT (a)
381# define lisp_h_XINT(a) (XLI (a) >> INTTYPEBITS) 381# define lisp_h_XINT(a) (XLI (a) >> INTTYPEBITS)
382# define lisp_h_XSYMBOL(a) \ 382# ifdef __CHKP__
383# define lisp_h_XSYMBOL(a) \
384 (eassert (SYMBOLP (a)), \
385 (struct Lisp_Symbol *) ((char *) XUNTAG (a, Lisp_Symbol) \
386 + (intptr_t) lispsym))
387# else
388 /* If !__CHKP__ this is equivalent, and is a bit faster as of GCC 7. */
389# define lisp_h_XSYMBOL(a) \
383 (eassert (SYMBOLP (a)), \ 390 (eassert (SYMBOLP (a)), \
384 (struct Lisp_Symbol *) ((intptr_t) XLI (a) - Lisp_Symbol \ 391 (struct Lisp_Symbol *) ((intptr_t) XLI (a) - Lisp_Symbol \
385 + (char *) lispsym)) 392 + (char *) lispsym))
393# endif
386# define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK)) 394# define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK))
387# define lisp_h_XUNTAG(a, type) \ 395# define lisp_h_XUNTAG(a, type) \
388 __builtin_assume_aligned ((char *) XLP (a) - (type), GCALIGNMENT) 396 __builtin_assume_aligned ((char *) XLP (a) - (type), GCALIGNMENT)
@@ -826,10 +834,15 @@ typedef EMACS_UINT Lisp_Word_tag;
826 834
827/* Declare extern constants for Lisp symbols. These can be helpful 835/* Declare extern constants for Lisp symbols. These can be helpful
828 when using a debugger like GDB, on older platforms where the debug 836 when using a debugger like GDB, on older platforms where the debug
829 format does not represent C macros. */ 837 format does not represent C macros. However, they are unbounded
830#define DEFINE_LISP_SYMBOL(name) \ 838 and would just be asking for trouble if checking pointer bounds. */
831 DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \ 839#ifdef __CHKP__
832 DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name)) 840# define DEFINE_LISP_SYMBOL(name)
841#else
842# define DEFINE_LISP_SYMBOL(name) \
843 DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \
844 DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name))
845#endif
833 846
834/* The index of the C-defined Lisp symbol SYM. 847/* The index of the C-defined Lisp symbol SYM.
835 This can be used in a static initializer. */ 848 This can be used in a static initializer. */
@@ -889,6 +902,8 @@ INLINE struct Lisp_Symbol *
889{ 902{
890#if USE_LSB_TAG 903#if USE_LSB_TAG
891 return lisp_h_XSYMBOL (a); 904 return lisp_h_XSYMBOL (a);
905#elif defined __CHKP__
906# error "pointer-checking not supported with wide integers"
892#else 907#else
893 eassert (SYMBOLP (a)); 908 eassert (SYMBOLP (a));
894 intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol); 909 intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
@@ -900,8 +915,13 @@ INLINE struct Lisp_Symbol *
900INLINE Lisp_Object 915INLINE Lisp_Object
901make_lisp_symbol (struct Lisp_Symbol *sym) 916make_lisp_symbol (struct Lisp_Symbol *sym)
902{ 917{
903 intptr_t symoffset = (char *) sym - (char *) lispsym; 918#ifdef __CHKP__
904 Lisp_Object a = TAG_PTR (Lisp_Symbol, (char *) symoffset); 919 char *symoffset = (char *) sym - (intptr_t) lispsym;
920#else
921 /* If !__CHKP__ this is equivalent, and is a bit faster as of GCC 7. */
922 char *symoffset = (char *) ((char *) sym - (char *) lispsym);
923#endif
924 Lisp_Object a = TAG_PTR (Lisp_Symbol, symoffset);
905 eassert (XSYMBOL (a) == sym); 925 eassert (XSYMBOL (a) == sym);
906 return a; 926 return a;
907} 927}
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 @@
1/* Pointer bounds checking for GNU Emacs
2
3Copyright 2017 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#ifndef PTR_BOUNDS_H
21#define PTR_BOUNDS_H
22
23#include <stddef.h>
24
25/* When not checking pointer bounds, the following macros simply
26 return their first argument. These macros return either void *, or
27 the same type as their first argument. */
28
29/* Return a copy of P, but with the bounds of Q. */
30#ifdef __CHKP__
31# define ptr_bounds_copy(p, q) __builtin___bnd_copy_ptr_bounds (p, q)
32#else
33# define ptr_bounds_copy(p, q) ((void) (void const *) {q}, p)
34#endif
35
36/* Return a copy of P, but with infinite bounds.
37 This is a loophole in pointer bounds checking. */
38#ifdef __CHKP__
39# define ptr_bounds_init(p) __builtin___bnd_init_ptr_bounds (p)
40#else
41# define ptr_bounds_init(p) (p)
42#endif
43
44/* Return a copy of P, but with bounds [P, P + N).
45 This is a loophole in pointer bounds checking. */
46#ifdef __CHKP__
47# define ptr_bounds_set(p, n) __builtin___bnd_set_ptr_bounds (p, n)
48#else
49# define ptr_bounds_set(p, n) ((void) (size_t) {n}, p)
50#endif
51
52#endif /* PTR_BOUNDS_H */