diff options
| author | Paul Eggert | 2011-06-12 17:36:03 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-06-12 17:36:03 -0700 |
| commit | 13bdea59234b227bf8499a64352da3e5fd9e8c7b (patch) | |
| tree | deddcce496ffa4fdb6d5ffd45ec8c2c7c5c49d0c /src | |
| parent | d37ca62316e7526da7d75cc44c7a4cd8a6281bb5 (diff) | |
| download | emacs-13bdea59234b227bf8499a64352da3e5fd9e8c7b.tar.gz emacs-13bdea59234b227bf8499a64352da3e5fd9e8c7b.zip | |
Make sure a 64-bit char is never passed to CHAR_STRING.
Otherwise, CHAR_STRING would do the wrong thing on a 64-bit platform,
by silently ignoring the top 32 bits, allowing some values
that were far too large to be valid characters.
* character.h: Include <verify.h>.
(CHAR_STRING, CHAR_STRING_ADVANCE): Verify that the character
arguments are no wider than unsigned, as a compile-time check
to prevent future regressions in this area.
* data.c (Faset):
* editfns.c (Fchar_to_string, general_insert_function, Finsert_char):
(Fsubst_char_in_region):
* fns.c (concat):
* xdisp.c (decode_mode_spec_coding):
Adjust to CHAR_STRING's new requirement.
* editfns.c (Finsert_char, Fsubst_char_in_region):
* fns.c (concat): Check that character args are actually
characters. Without this test, these functions did the wrong
thing with wildly out-of-range values on 64-bit hosts.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 22 | ||||
| -rw-r--r-- | src/character.h | 9 | ||||
| -rw-r--r-- | src/data.c | 4 | ||||
| -rw-r--r-- | src/editfns.c | 38 | ||||
| -rw-r--r-- | src/fns.c | 9 | ||||
| -rw-r--r-- | src/xdisp.c | 3 |
6 files changed, 61 insertions, 24 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 921f976334a..f8a4abd9cce 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,25 @@ | |||
| 1 | 2011-06-13 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | |||
| 4 | Make sure a 64-bit char is never passed to CHAR_STRING. | ||
| 5 | Otherwise, CHAR_STRING would do the wrong thing on a 64-bit platform, | ||
| 6 | by silently ignoring the top 32 bits, allowing some values | ||
| 7 | that were far too large to be valid characters. | ||
| 8 | * character.h: Include <verify.h>. | ||
| 9 | (CHAR_STRING, CHAR_STRING_ADVANCE): Verify that the character | ||
| 10 | arguments are no wider than unsigned, as a compile-time check | ||
| 11 | to prevent future regressions in this area. | ||
| 12 | * data.c (Faset): | ||
| 13 | * editfns.c (Fchar_to_string, general_insert_function, Finsert_char): | ||
| 14 | (Fsubst_char_in_region): | ||
| 15 | * fns.c (concat): | ||
| 16 | * xdisp.c (decode_mode_spec_coding): | ||
| 17 | Adjust to CHAR_STRING's new requirement. | ||
| 18 | * editfns.c (Finsert_char, Fsubst_char_in_region): | ||
| 19 | * fns.c (concat): Check that character args are actually | ||
| 20 | characters. Without this test, these functions did the wrong | ||
| 21 | thing with wildly out-of-range values on 64-bit hosts. | ||
| 22 | |||
| 1 | 2011-06-12 Paul Eggert <eggert@cs.ucla.edu> | 23 | 2011-06-12 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 24 | ||
| 3 | Remove incorrect casts to 'unsigned' that lose info on 64-bit hosts. | 25 | Remove incorrect casts to 'unsigned' that lose info on 64-bit hosts. |
diff --git a/src/character.h b/src/character.h index 695a55be3fa..de97754cfc7 100644 --- a/src/character.h +++ b/src/character.h | |||
| @@ -23,6 +23,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 23 | #ifndef EMACS_CHARACTER_H | 23 | #ifndef EMACS_CHARACTER_H |
| 24 | #define EMACS_CHARACTER_H | 24 | #define EMACS_CHARACTER_H |
| 25 | 25 | ||
| 26 | #include <verify.h> | ||
| 27 | |||
| 26 | /* character code 1st byte byte sequence | 28 | /* character code 1st byte byte sequence |
| 27 | -------------- -------- ------------- | 29 | -------------- -------- ------------- |
| 28 | 0-7F 00..7F 0xxxxxxx | 30 | 0-7F 00..7F 0xxxxxxx |
| @@ -173,7 +175,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 173 | (p)[1] = (0x80 | (((c) >> 6) & 0x3F)), \ | 175 | (p)[1] = (0x80 | (((c) >> 6) & 0x3F)), \ |
| 174 | (p)[2] = (0x80 | ((c) & 0x3F)), \ | 176 | (p)[2] = (0x80 | ((c) & 0x3F)), \ |
| 175 | 3) \ | 177 | 3) \ |
| 176 | : char_string ((unsigned) c, p)) | 178 | : (char_string (c, p) + !verify_true (sizeof (c) <= sizeof (unsigned)))) |
| 177 | 179 | ||
| 178 | /* Store multibyte form of byte B in P. The caller should allocate at | 180 | /* Store multibyte form of byte B in P. The caller should allocate at |
| 179 | least MAX_MULTIBYTE_LENGTH bytes area at P in advance. Returns the | 181 | least MAX_MULTIBYTE_LENGTH bytes area at P in advance. Returns the |
| @@ -201,7 +203,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 201 | *(p)++ = (0x80 | (((c) >> 6) & 0x3F)), \ | 203 | *(p)++ = (0x80 | (((c) >> 6) & 0x3F)), \ |
| 202 | *(p)++ = (0x80 | ((c) & 0x3F)); \ | 204 | *(p)++ = (0x80 | ((c) & 0x3F)); \ |
| 203 | else \ | 205 | else \ |
| 204 | (p) += char_string ((c), (p)); \ | 206 | { \ |
| 207 | verify (sizeof (c) <= sizeof (unsigned)); \ | ||
| 208 | (p) += char_string (c, p); \ | ||
| 209 | } \ | ||
| 205 | } while (0) | 210 | } while (0) |
| 206 | 211 | ||
| 207 | 212 | ||
diff --git a/src/data.c b/src/data.c index 57d7753e393..3a08a7a8cd3 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2152,17 +2152,19 @@ bool-vector. IDX starts at 0. */) | |||
| 2152 | { | 2152 | { |
| 2153 | EMACS_INT idxval_byte, prev_bytes, new_bytes, nbytes; | 2153 | EMACS_INT idxval_byte, prev_bytes, new_bytes, nbytes; |
| 2154 | unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1; | 2154 | unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1; |
| 2155 | int c; | ||
| 2155 | 2156 | ||
| 2156 | if (idxval < 0 || idxval >= SCHARS (array)) | 2157 | if (idxval < 0 || idxval >= SCHARS (array)) |
| 2157 | args_out_of_range (array, idx); | 2158 | args_out_of_range (array, idx); |
| 2158 | CHECK_CHARACTER (newelt); | 2159 | CHECK_CHARACTER (newelt); |
| 2160 | c = XFASTINT (newelt); | ||
| 2159 | 2161 | ||
| 2160 | nbytes = SBYTES (array); | 2162 | nbytes = SBYTES (array); |
| 2161 | 2163 | ||
| 2162 | idxval_byte = string_char_to_byte (array, idxval); | 2164 | idxval_byte = string_char_to_byte (array, idxval); |
| 2163 | p1 = SDATA (array) + idxval_byte; | 2165 | p1 = SDATA (array) + idxval_byte; |
| 2164 | prev_bytes = BYTES_BY_CHAR_HEAD (*p1); | 2166 | prev_bytes = BYTES_BY_CHAR_HEAD (*p1); |
| 2165 | new_bytes = CHAR_STRING (XINT (newelt), p0); | 2167 | new_bytes = CHAR_STRING (c, p0); |
| 2166 | if (prev_bytes != new_bytes) | 2168 | if (prev_bytes != new_bytes) |
| 2167 | { | 2169 | { |
| 2168 | /* We must relocate the string data. */ | 2170 | /* We must relocate the string data. */ |
diff --git a/src/editfns.c b/src/editfns.c index 232af3595d0..81e5917a800 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -185,12 +185,13 @@ DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0, | |||
| 185 | usage: (char-to-string CHAR) */) | 185 | usage: (char-to-string CHAR) */) |
| 186 | (Lisp_Object character) | 186 | (Lisp_Object character) |
| 187 | { | 187 | { |
| 188 | int len; | 188 | int c, len; |
| 189 | unsigned char str[MAX_MULTIBYTE_LENGTH]; | 189 | unsigned char str[MAX_MULTIBYTE_LENGTH]; |
| 190 | 190 | ||
| 191 | CHECK_CHARACTER (character); | 191 | CHECK_CHARACTER (character); |
| 192 | c = XFASTINT (character); | ||
| 192 | 193 | ||
| 193 | len = CHAR_STRING (XFASTINT (character), str); | 194 | len = CHAR_STRING (c, str); |
| 194 | return make_string_from_bytes ((char *) str, 1, len); | 195 | return make_string_from_bytes ((char *) str, 1, len); |
| 195 | } | 196 | } |
| 196 | 197 | ||
| @@ -2203,16 +2204,17 @@ general_insert_function (void (*insert_func) | |||
| 2203 | val = args[argnum]; | 2204 | val = args[argnum]; |
| 2204 | if (CHARACTERP (val)) | 2205 | if (CHARACTERP (val)) |
| 2205 | { | 2206 | { |
| 2207 | int c = XFASTINT (val); | ||
| 2206 | unsigned char str[MAX_MULTIBYTE_LENGTH]; | 2208 | unsigned char str[MAX_MULTIBYTE_LENGTH]; |
| 2207 | int len; | 2209 | int len; |
| 2208 | 2210 | ||
| 2209 | if (!NILP (BVAR (current_buffer, enable_multibyte_characters))) | 2211 | if (!NILP (BVAR (current_buffer, enable_multibyte_characters))) |
| 2210 | len = CHAR_STRING (XFASTINT (val), str); | 2212 | len = CHAR_STRING (c, str); |
| 2211 | else | 2213 | else |
| 2212 | { | 2214 | { |
| 2213 | str[0] = (ASCII_CHAR_P (XINT (val)) | 2215 | str[0] = (ASCII_CHAR_P (c) |
| 2214 | ? XINT (val) | 2216 | ? c |
| 2215 | : multibyte_char_to_unibyte (XINT (val))); | 2217 | : multibyte_char_to_unibyte (c)); |
| 2216 | len = 1; | 2218 | len = 1; |
| 2217 | } | 2219 | } |
| 2218 | (*insert_func) ((char *) str, len); | 2220 | (*insert_func) ((char *) str, len); |
| @@ -2332,16 +2334,17 @@ from adjoining text, if those properties are sticky. */) | |||
| 2332 | register EMACS_INT stringlen; | 2334 | register EMACS_INT stringlen; |
| 2333 | register int i; | 2335 | register int i; |
| 2334 | register EMACS_INT n; | 2336 | register EMACS_INT n; |
| 2335 | int len; | 2337 | int c, len; |
| 2336 | unsigned char str[MAX_MULTIBYTE_LENGTH]; | 2338 | unsigned char str[MAX_MULTIBYTE_LENGTH]; |
| 2337 | 2339 | ||
| 2338 | CHECK_NUMBER (character); | 2340 | CHECK_CHARACTER (character); |
| 2339 | CHECK_NUMBER (count); | 2341 | CHECK_NUMBER (count); |
| 2342 | c = XFASTINT (character); | ||
| 2340 | 2343 | ||
| 2341 | if (!NILP (BVAR (current_buffer, enable_multibyte_characters))) | 2344 | if (!NILP (BVAR (current_buffer, enable_multibyte_characters))) |
| 2342 | len = CHAR_STRING (XFASTINT (character), str); | 2345 | len = CHAR_STRING (c, str); |
| 2343 | else | 2346 | else |
| 2344 | str[0] = XFASTINT (character), len = 1; | 2347 | str[0] = c, len = 1; |
| 2345 | if (BUF_BYTES_MAX / len < XINT (count)) | 2348 | if (BUF_BYTES_MAX / len < XINT (count)) |
| 2346 | error ("Maximum buffer size would be exceeded"); | 2349 | error ("Maximum buffer size would be exceeded"); |
| 2347 | n = XINT (count) * len; | 2350 | n = XINT (count) * len; |
| @@ -2784,17 +2787,20 @@ Both characters must have the same length of multi-byte form. */) | |||
| 2784 | int maybe_byte_combining = COMBINING_NO; | 2787 | int maybe_byte_combining = COMBINING_NO; |
| 2785 | EMACS_INT last_changed = 0; | 2788 | EMACS_INT last_changed = 0; |
| 2786 | int multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters)); | 2789 | int multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters)); |
| 2790 | int fromc, toc; | ||
| 2787 | 2791 | ||
| 2788 | restart: | 2792 | restart: |
| 2789 | 2793 | ||
| 2790 | validate_region (&start, &end); | 2794 | validate_region (&start, &end); |
| 2791 | CHECK_NUMBER (fromchar); | 2795 | CHECK_CHARACTER (fromchar); |
| 2792 | CHECK_NUMBER (tochar); | 2796 | CHECK_CHARACTER (tochar); |
| 2797 | fromc = XFASTINT (fromchar); | ||
| 2798 | toc = XFASTINT (tochar); | ||
| 2793 | 2799 | ||
| 2794 | if (multibyte_p) | 2800 | if (multibyte_p) |
| 2795 | { | 2801 | { |
| 2796 | len = CHAR_STRING (XFASTINT (fromchar), fromstr); | 2802 | len = CHAR_STRING (fromc, fromstr); |
| 2797 | if (CHAR_STRING (XFASTINT (tochar), tostr) != len) | 2803 | if (CHAR_STRING (toc, tostr) != len) |
| 2798 | error ("Characters in `subst-char-in-region' have different byte-lengths"); | 2804 | error ("Characters in `subst-char-in-region' have different byte-lengths"); |
| 2799 | if (!ASCII_BYTE_P (*tostr)) | 2805 | if (!ASCII_BYTE_P (*tostr)) |
| 2800 | { | 2806 | { |
| @@ -2811,8 +2817,8 @@ Both characters must have the same length of multi-byte form. */) | |||
| 2811 | else | 2817 | else |
| 2812 | { | 2818 | { |
| 2813 | len = 1; | 2819 | len = 1; |
| 2814 | fromstr[0] = XFASTINT (fromchar); | 2820 | fromstr[0] = fromc; |
| 2815 | tostr[0] = XFASTINT (tochar); | 2821 | tostr[0] = toc; |
| 2816 | } | 2822 | } |
| 2817 | 2823 | ||
| 2818 | pos = XINT (start); | 2824 | pos = XINT (start); |
| @@ -679,12 +679,13 @@ concat (size_t nargs, Lisp_Object *args, | |||
| 679 | } | 679 | } |
| 680 | else | 680 | else |
| 681 | { | 681 | { |
| 682 | CHECK_NUMBER (elt); | 682 | int c; |
| 683 | CHECK_CHARACTER (elt); | ||
| 684 | c = XFASTINT (elt); | ||
| 683 | if (some_multibyte) | 685 | if (some_multibyte) |
| 684 | toindex_byte += CHAR_STRING (XINT (elt), | 686 | toindex_byte += CHAR_STRING (c, SDATA (val) + toindex_byte); |
| 685 | SDATA (val) + toindex_byte); | ||
| 686 | else | 687 | else |
| 687 | SSET (val, toindex_byte++, XINT (elt)); | 688 | SSET (val, toindex_byte++, c); |
| 688 | toindex++; | 689 | toindex++; |
| 689 | } | 690 | } |
| 690 | } | 691 | } |
diff --git a/src/xdisp.c b/src/xdisp.c index 65f6ddd3889..c4956599295 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -19379,7 +19379,8 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_ | |||
| 19379 | else if (CHARACTERP (eoltype)) | 19379 | else if (CHARACTERP (eoltype)) |
| 19380 | { | 19380 | { |
| 19381 | unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH); | 19381 | unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH); |
| 19382 | eol_str_len = CHAR_STRING (XINT (eoltype), tmp); | 19382 | int c = XFASTINT (eoltype); |
| 19383 | eol_str_len = CHAR_STRING (c, tmp); | ||
| 19383 | eol_str = tmp; | 19384 | eol_str = tmp; |
| 19384 | } | 19385 | } |
| 19385 | else | 19386 | else |