aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-08-15 02:18:06 -0700
committerPaul Eggert2019-08-15 02:18:44 -0700
commit3548fd8a53869ce6b42c47f690660cb8eddb8aab (patch)
tree4da084bfab97e61c649abb3332254d0ea898188f
parent6cbf73b5f9f51b5e25b855bf9f521c1ef070dd4a (diff)
downloademacs-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.ac13
-rw-r--r--src/fns.c8
-rw-r--r--src/lisp.h47
-rw-r--r--src/profiler.c2
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.])
5372fi 5372fi
5373 5373
5374AC_C_TYPEOF
5375
5376AC_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])])
5382if test "$emacs_cv_statement_expressions" = yes; then
5383 AC_DEFINE([HAVE_STATEMENT_EXPRESSIONS], 1,
5384 [Define to 1 if statement expressions work.])
5385fi
5386
5374if test "${GNU_MALLOC}" = "yes" ; then 5387if 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.])
diff --git a/src/fns.c b/src/fns.c
index acc6d46db85..920addeaf13 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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,
3994static Lisp_Object 3994static Lisp_Object
3995hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) 3995hashfn_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)
4003Lisp_Object 4003Lisp_Object
4004hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h) 4004hashfn_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
4029struct hash_table_test const 4029struct 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
1130INLINE Lisp_Object 1143INLINE 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
1136INLINE EMACS_INT 1150INLINE 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
1156INLINE Lisp_Object
1157make_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
1149INLINE Lisp_Object 1170INLINE Lisp_Object
1150make_fixnum (EMACS_INT n) 1171make_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
1204INLINE Lisp_Object
1205make_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
1184INLINE bool 1222INLINE 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
1240INLINE intmax_t 1273INLINE intmax_t
1241clip_to_bounds (intmax_t lower, intmax_t num, intmax_t upper) 1274clip_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
572static void syms_of_profiler_for_pdumper (void); 572static void syms_of_profiler_for_pdumper (void);