diff options
| author | Paul Eggert | 2017-12-09 13:57:38 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-12-12 15:17:12 -0800 |
| commit | 881abfc7fb55db2d00adf352100cc58a6a86c176 (patch) | |
| tree | 4bb07ccaf020ea861ce95ff4fd57bb6d2c562810 /src | |
| parent | 244346c744a6700d320a0a0fe8c796be3b3ff023 (diff) | |
| download | emacs-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.c | 37 | ||||
| -rw-r--r-- | src/gmalloc.c | 6 | ||||
| -rw-r--r-- | src/lisp.h | 34 | ||||
| -rw-r--r-- | src/ptr-bounds.h | 52 |
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 * | |||
| 900 | INLINE Lisp_Object | 915 | INLINE Lisp_Object |
| 901 | make_lisp_symbol (struct Lisp_Symbol *sym) | 916 | make_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 | |||
| 3 | Copyright 2017 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along 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 */ | ||