diff options
| author | Paul Eggert | 2019-08-15 02:18:06 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-08-15 02:18:44 -0700 |
| commit | 3548fd8a53869ce6b42c47f690660cb8eddb8aab (patch) | |
| tree | 4da084bfab97e61c649abb3332254d0ea898188f | |
| parent | 6cbf73b5f9f51b5e25b855bf9f521c1ef070dd4a (diff) | |
| download | emacs-3548fd8a53869ce6b42c47f690660cb8eddb8aab.tar.gz emacs-3548fd8a53869ce6b42c47f690660cb8eddb8aab.zip | |
Debug out-of-range make_fixnum args
With --enable-checking, make_fixnum (N) now checks that N is
in fixnum range. Suggested by Pip Cet in:
https://lists.gnu.org/r/emacs-devel/2019-07/msg00548.html
A new function make_ufixnum (N) is for the rare cases where N
is intended to be unsigned and is in the range 0..INTMASK.
* configure.ac (AC_C_TYPEOF): Add.
(HAVE_STATEMENT_EXPRESSIONS): Resurrect this macro.
* src/fns.c (Frandom, hashfn_eq, hashfn_equal, hashfn_user_defined):
* src/profiler.c (hashfn_profiler):
Use make_ufixnum rather than make_fixum, since the argument is
an unsigned integer in the range 0..INTMASK rather than a signed
integer in the range MOST_NEGATIVE_FIXNUM..MOST_POSITIVE_FIXNUM.
Typically this is for hashes.
* src/lisp.h (lisp_h_make_fixnum_wrap) [USE_LSB_TAG]:
Rename from lisp_h_make_fixnum.
(lisp_h_make_fixnum): Redefine in terms of lisp_h_make_fixnum_wrap.
Check for fixnum overflow on compilers like GCC that
have statement expressions and typeof.
(FIXNUM_OVERFLOW_P): Move up.
(make_fixnum): Check for fixnum overflow.
(make_ufixnum): New function, which checks that the arg
fits into 0..INTMASK range.
| -rw-r--r-- | configure.ac | 13 | ||||
| -rw-r--r-- | src/fns.c | 8 | ||||
| -rw-r--r-- | src/lisp.h | 47 | ||||
| -rw-r--r-- | src/profiler.c | 2 |
4 files changed, 58 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac index c093d8650da..1400fcb5bc7 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -5371,6 +5371,19 @@ if test "$emacs_cv_struct_alignment" = yes; then | |||
| 5371 | structure to an N-byte boundary.]) | 5371 | structure to an N-byte boundary.]) |
| 5372 | fi | 5372 | fi |
| 5373 | 5373 | ||
| 5374 | AC_C_TYPEOF | ||
| 5375 | |||
| 5376 | AC_CACHE_CHECK([for statement expressions], | ||
| 5377 | [emacs_cv_statement_expressions], | ||
| 5378 | [AC_COMPILE_IFELSE( | ||
| 5379 | [AC_LANG_PROGRAM([], [[return ({ int x = 5; x-x; });]])], | ||
| 5380 | [emacs_cv_statement_expressions=yes], | ||
| 5381 | [emacs_cv_statement_expressions=no])]) | ||
| 5382 | if test "$emacs_cv_statement_expressions" = yes; then | ||
| 5383 | AC_DEFINE([HAVE_STATEMENT_EXPRESSIONS], 1, | ||
| 5384 | [Define to 1 if statement expressions work.]) | ||
| 5385 | fi | ||
| 5386 | |||
| 5374 | if test "${GNU_MALLOC}" = "yes" ; then | 5387 | if test "${GNU_MALLOC}" = "yes" ; then |
| 5375 | AC_DEFINE(GNU_MALLOC, 1, | 5388 | AC_DEFINE(GNU_MALLOC, 1, |
| 5376 | [Define to 1 if you want to use the GNU memory allocator.]) | 5389 | [Define to 1 if you want to use the GNU memory allocator.]) |
| @@ -87,7 +87,7 @@ See Info node `(elisp)Random Numbers' for more details. */) | |||
| 87 | return make_fixnum (remainder); | 87 | return make_fixnum (remainder); |
| 88 | val = get_random (); | 88 | val = get_random (); |
| 89 | } | 89 | } |
| 90 | return make_fixnum (val); | 90 | return make_ufixnum (val); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | /* Random data-structure functions. */ | 93 | /* Random data-structure functions. */ |
| @@ -3994,7 +3994,7 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2, | |||
| 3994 | static Lisp_Object | 3994 | static Lisp_Object |
| 3995 | hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) | 3995 | hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 3996 | { | 3996 | { |
| 3997 | return make_fixnum (XHASH (key) ^ XTYPE (key)); | 3997 | return make_ufixnum (XHASH (key) ^ XTYPE (key)); |
| 3998 | } | 3998 | } |
| 3999 | 3999 | ||
| 4000 | /* Ignore HT and return a hash code for KEY which uses 'equal' to compare keys. | 4000 | /* Ignore HT and return a hash code for KEY which uses 'equal' to compare keys. |
| @@ -4003,7 +4003,7 @@ hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) | |||
| 4003 | Lisp_Object | 4003 | Lisp_Object |
| 4004 | hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h) | 4004 | hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 4005 | { | 4005 | { |
| 4006 | return make_fixnum (sxhash (key, 0)); | 4006 | return make_ufixnum (sxhash (key, 0)); |
| 4007 | } | 4007 | } |
| 4008 | 4008 | ||
| 4009 | /* Ignore HT and return a hash code for KEY which uses 'eql' to compare keys. | 4009 | /* Ignore HT and return a hash code for KEY which uses 'eql' to compare keys. |
| @@ -4023,7 +4023,7 @@ hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) | |||
| 4023 | { | 4023 | { |
| 4024 | Lisp_Object args[] = { h->test.user_hash_function, key }; | 4024 | Lisp_Object args[] = { h->test.user_hash_function, key }; |
| 4025 | Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); | 4025 | Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); |
| 4026 | return FIXNUMP (hash) ? hash : make_fixnum (sxhash (hash, 0)); | 4026 | return FIXNUMP (hash) ? hash : make_ufixnum (sxhash (hash, 0)); |
| 4027 | } | 4027 | } |
| 4028 | 4028 | ||
| 4029 | struct hash_table_test const | 4029 | struct hash_table_test const |
diff --git a/src/lisp.h b/src/lisp.h index 0370c52fad6..1c98925fa8d 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -397,8 +397,16 @@ typedef EMACS_INT Lisp_Word; | |||
| 397 | (eassert (CONSP (a)), XUNTAG (a, Lisp_Cons, struct Lisp_Cons)) | 397 | (eassert (CONSP (a)), XUNTAG (a, Lisp_Cons, struct Lisp_Cons)) |
| 398 | #define lisp_h_XHASH(a) XUFIXNUM_RAW (a) | 398 | #define lisp_h_XHASH(a) XUFIXNUM_RAW (a) |
| 399 | #if USE_LSB_TAG | 399 | #if USE_LSB_TAG |
| 400 | # define lisp_h_make_fixnum(n) \ | 400 | # define lisp_h_make_fixnum_wrap(n) \ |
| 401 | XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0)) | 401 | XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0)) |
| 402 | # if defined HAVE_STATEMENT_EXPRESSIONS && defined HAVE_TYPEOF | ||
| 403 | # define lisp_h_make_fixnum(n) \ | ||
| 404 | ({ typeof (n) lisp_h_make_fixnum_n = n; \ | ||
| 405 | eassert (!FIXNUM_OVERFLOW_P (lisp_h_make_fixnum_n)); \ | ||
| 406 | lisp_h_make_fixnum_wrap (lisp_h_make_fixnum_n); }) | ||
| 407 | # else | ||
| 408 | # define lisp_h_make_fixnum(n) lisp_h_make_fixnum_wrap (n) | ||
| 409 | # endif | ||
| 402 | # define lisp_h_XFIXNUM_RAW(a) (XLI (a) >> INTTYPEBITS) | 410 | # define lisp_h_XFIXNUM_RAW(a) (XLI (a) >> INTTYPEBITS) |
| 403 | # define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK)) | 411 | # define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK)) |
| 404 | #endif | 412 | #endif |
| @@ -1125,12 +1133,18 @@ enum More_Lisp_Bits | |||
| 1125 | #define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS) | 1133 | #define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS) |
| 1126 | #define MOST_NEGATIVE_FIXNUM (-1 - MOST_POSITIVE_FIXNUM) | 1134 | #define MOST_NEGATIVE_FIXNUM (-1 - MOST_POSITIVE_FIXNUM) |
| 1127 | 1135 | ||
| 1136 | /* True if the possibly-unsigned integer I doesn't fit in a fixnum. */ | ||
| 1137 | |||
| 1138 | #define FIXNUM_OVERFLOW_P(i) \ | ||
| 1139 | (! ((0 <= (i) || MOST_NEGATIVE_FIXNUM <= (i)) && (i) <= MOST_POSITIVE_FIXNUM)) | ||
| 1140 | |||
| 1128 | #if USE_LSB_TAG | 1141 | #if USE_LSB_TAG |
| 1129 | 1142 | ||
| 1130 | INLINE Lisp_Object | 1143 | INLINE Lisp_Object |
| 1131 | (make_fixnum) (EMACS_INT n) | 1144 | (make_fixnum) (EMACS_INT n) |
| 1132 | { | 1145 | { |
| 1133 | return lisp_h_make_fixnum (n); | 1146 | eassert (!FIXNUM_OVERFLOW_P (n)); |
| 1147 | return lisp_h_make_fixnum_wrap (n); | ||
| 1134 | } | 1148 | } |
| 1135 | 1149 | ||
| 1136 | INLINE EMACS_INT | 1150 | INLINE EMACS_INT |
| @@ -1139,6 +1153,13 @@ INLINE EMACS_INT | |||
| 1139 | return lisp_h_XFIXNUM_RAW (a); | 1153 | return lisp_h_XFIXNUM_RAW (a); |
| 1140 | } | 1154 | } |
| 1141 | 1155 | ||
| 1156 | INLINE Lisp_Object | ||
| 1157 | make_ufixnum (EMACS_INT n) | ||
| 1158 | { | ||
| 1159 | eassert (0 <= n && n <= INTMASK); | ||
| 1160 | return lisp_h_make_fixnum_wrap (n); | ||
| 1161 | } | ||
| 1162 | |||
| 1142 | #else /* ! USE_LSB_TAG */ | 1163 | #else /* ! USE_LSB_TAG */ |
| 1143 | 1164 | ||
| 1144 | /* Although compiled only if ! USE_LSB_TAG, the following functions | 1165 | /* Although compiled only if ! USE_LSB_TAG, the following functions |
| @@ -1149,6 +1170,7 @@ INLINE EMACS_INT | |||
| 1149 | INLINE Lisp_Object | 1170 | INLINE Lisp_Object |
| 1150 | make_fixnum (EMACS_INT n) | 1171 | make_fixnum (EMACS_INT n) |
| 1151 | { | 1172 | { |
| 1173 | eassert (! FIXNUM_OVERFLOW_P (n)); | ||
| 1152 | EMACS_INT int0 = Lisp_Int0; | 1174 | EMACS_INT int0 = Lisp_Int0; |
| 1153 | if (USE_LSB_TAG) | 1175 | if (USE_LSB_TAG) |
| 1154 | { | 1176 | { |
| @@ -1179,6 +1201,22 @@ XFIXNUM_RAW (Lisp_Object a) | |||
| 1179 | return i >> INTTYPEBITS; | 1201 | return i >> INTTYPEBITS; |
| 1180 | } | 1202 | } |
| 1181 | 1203 | ||
| 1204 | INLINE Lisp_Object | ||
| 1205 | make_ufixnum (EMACS_INT n) | ||
| 1206 | { | ||
| 1207 | eassert (0 <= n && n <= INTMASK); | ||
| 1208 | EMACS_INT int0 = Lisp_Int0; | ||
| 1209 | if (USE_LSB_TAG) | ||
| 1210 | { | ||
| 1211 | EMACS_UINT u = n; | ||
| 1212 | n = u << INTTYPEBITS; | ||
| 1213 | n += int0; | ||
| 1214 | } | ||
| 1215 | else | ||
| 1216 | n += int0 << VALBITS; | ||
| 1217 | return XIL (n); | ||
| 1218 | } | ||
| 1219 | |||
| 1182 | #endif /* ! USE_LSB_TAG */ | 1220 | #endif /* ! USE_LSB_TAG */ |
| 1183 | 1221 | ||
| 1184 | INLINE bool | 1222 | INLINE bool |
| @@ -1232,11 +1270,6 @@ INLINE bool | |||
| 1232 | return lisp_h_EQ (x, y); | 1270 | return lisp_h_EQ (x, y); |
| 1233 | } | 1271 | } |
| 1234 | 1272 | ||
| 1235 | /* True if the possibly-unsigned integer I doesn't fit in a fixnum. */ | ||
| 1236 | |||
| 1237 | #define FIXNUM_OVERFLOW_P(i) \ | ||
| 1238 | (! ((0 <= (i) || MOST_NEGATIVE_FIXNUM <= (i)) && (i) <= MOST_POSITIVE_FIXNUM)) | ||
| 1239 | |||
| 1240 | INLINE intmax_t | 1273 | INLINE intmax_t |
| 1241 | clip_to_bounds (intmax_t lower, intmax_t num, intmax_t upper) | 1274 | clip_to_bounds (intmax_t lower, intmax_t num, intmax_t upper) |
| 1242 | { | 1275 | { |
diff --git a/src/profiler.c b/src/profiler.c index 6b482abf335..6943905062c 100644 --- a/src/profiler.c +++ b/src/profiler.c | |||
| @@ -566,7 +566,7 @@ hashfn_profiler (Lisp_Object bt, struct Lisp_Hash_Table *h) | |||
| 566 | } | 566 | } |
| 567 | else | 567 | else |
| 568 | hash = XHASH (bt); | 568 | hash = XHASH (bt); |
| 569 | return make_fixnum (SXHASH_REDUCE (hash)); | 569 | return make_ufixnum (SXHASH_REDUCE (hash)); |
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | static void syms_of_profiler_for_pdumper (void); | 572 | static void syms_of_profiler_for_pdumper (void); |