summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2011-06-12 17:36:03 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2011-06-12 17:36:03 -0700
commit13bdea59234b227bf8499a64352da3e5fd9e8c7b (patch)
treededdcce496ffa4fdb6d5ffd45ec8c2c7c5c49d0c
parentd37ca62316e7526da7d75cc44c7a4cd8a6281bb5 (diff)
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.
-rw-r--r--src/ChangeLog22
-rw-r--r--src/character.h9
-rw-r--r--src/data.c4
-rw-r--r--src/editfns.c38
-rw-r--r--src/fns.c9
-rw-r--r--src/xdisp.c3
6 files changed, 61 insertions, 24 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 921f976334..f8a4abd9cc 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,25 @@
+2011-06-13 Paul Eggert <eggert@cs.ucla.edu>
+
+
+ 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.
+
2011-06-12 Paul Eggert <eggert@cs.ucla.edu>
Remove incorrect casts to 'unsigned' that lose info on 64-bit hosts.
diff --git a/src/character.h b/src/character.h
index 695a55be3f..de97754cfc 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/>. */
#ifndef EMACS_CHARACTER_H
#define EMACS_CHARACTER_H
+#include <verify.h>
+
/* character code 1st byte byte sequence
-------------- -------- -------------
0-7F 00..7F 0xxxxxxx
@@ -173,7 +175,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
(p)[1] = (0x80 | (((c) >> 6) & 0x3F)), \
(p)[2] = (0x80 | ((c) & 0x3F)), \
3) \
- : char_string ((unsigned) c, p))
+ : (char_string (c, p) + !verify_true (sizeof (c) <= sizeof (unsigned))))
/* Store multibyte form of byte B in P. The caller should allocate at
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/>. */
*(p)++ = (0x80 | (((c) >> 6) & 0x3F)), \
*(p)++ = (0x80 | ((c) & 0x3F)); \
else \
- (p) += char_string ((c), (p)); \
+ { \
+ verify (sizeof (c) <= sizeof (unsigned)); \
+ (p) += char_string (c, p); \
+ } \
} while (0)
diff --git a/src/data.c b/src/data.c
index 57d7753e39..3a08a7a8cd 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2152,17 +2152,19 @@ bool-vector. IDX starts at 0. */)
{
EMACS_INT idxval_byte, prev_bytes, new_bytes, nbytes;
unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1;
+ int c;
if (idxval < 0 || idxval >= SCHARS (array))
args_out_of_range (array, idx);
CHECK_CHARACTER (newelt);
+ c = XFASTINT (newelt);
nbytes = SBYTES (array);
idxval_byte = string_char_to_byte (array, idxval);
p1 = SDATA (array) + idxval_byte;
prev_bytes = BYTES_BY_CHAR_HEAD (*p1);
- new_bytes = CHAR_STRING (XINT (newelt), p0);
+ new_bytes = CHAR_STRING (c, p0);
if (prev_bytes != new_bytes)
{
/* We must relocate the string data. */
diff --git a/src/editfns.c b/src/editfns.c
index 232af3595d..81e5917a80 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,
usage: (char-to-string CHAR) */)
(Lisp_Object character)
{
- int len;
+ int c, len;
unsigned char str[MAX_MULTIBYTE_LENGTH];
CHECK_CHARACTER (character);
+ c = XFASTINT (character);
- len = CHAR_STRING (XFASTINT (character), str);
+ len = CHAR_STRING (c, str);
return make_string_from_bytes ((char *) str, 1, len);
}
@@ -2203,16 +2204,17 @@ general_insert_function (void (*insert_func)
val = args[argnum];
if (CHARACTERP (val))
{
+ int c = XFASTINT (val);
unsigned char str[MAX_MULTIBYTE_LENGTH];
int len;
if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
- len = CHAR_STRING (XFASTINT (val), str);
+ len = CHAR_STRING (c, str);
else
{
- str[0] = (ASCII_CHAR_P (XINT (val))
- ? XINT (val)
- : multibyte_char_to_unibyte (XINT (val)));
+ str[0] = (ASCII_CHAR_P (c)
+ ? c
+ : multibyte_char_to_unibyte (c));
len = 1;
}
(*insert_func) ((char *) str, len);
@@ -2332,16 +2334,17 @@ from adjoining text, if those properties are sticky. */)
register EMACS_INT stringlen;
register int i;
register EMACS_INT n;
- int len;
+ int c, len;
unsigned char str[MAX_MULTIBYTE_LENGTH];
- CHECK_NUMBER (character);
+ CHECK_CHARACTER (character);
CHECK_NUMBER (count);
+ c = XFASTINT (character);
if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
- len = CHAR_STRING (XFASTINT (character), str);
+ len = CHAR_STRING (c, str);
else
- str[0] = XFASTINT (character), len = 1;
+ str[0] = c, len = 1;
if (BUF_BYTES_MAX / len < XINT (count))
error ("Maximum buffer size would be exceeded");
n = XINT (count) * len;
@@ -2784,17 +2787,20 @@ Both characters must have the same length of multi-byte form. */)
int maybe_byte_combining = COMBINING_NO;
EMACS_INT last_changed = 0;
int multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
+ int fromc, toc;
restart:
validate_region (&start, &end);
- CHECK_NUMBER (fromchar);
- CHECK_NUMBER (tochar);
+ CHECK_CHARACTER (fromchar);
+ CHECK_CHARACTER (tochar);
+ fromc = XFASTINT (fromchar);
+ toc = XFASTINT (tochar);
if (multibyte_p)
{
- len = CHAR_STRING (XFASTINT (fromchar), fromstr);
- if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
+ len = CHAR_STRING (fromc, fromstr);
+ if (CHAR_STRING (toc, tostr) != len)
error ("Characters in `subst-char-in-region' have different byte-lengths");
if (!ASCII_BYTE_P (*tostr))
{
@@ -2811,8 +2817,8 @@ Both characters must have the same length of multi-byte form. */)
else
{
len = 1;
- fromstr[0] = XFASTINT (fromchar);
- tostr[0] = XFASTINT (tochar);
+ fromstr[0] = fromc;
+ tostr[0] = toc;
}
pos = XINT (start);
diff --git a/src/fns.c b/src/fns.c
index 7a2845741f..250df728ca 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -679,12 +679,13 @@ concat (size_t nargs, Lisp_Object *args,
}
else
{
- CHECK_NUMBER (elt);
+ int c;
+ CHECK_CHARACTER (elt);
+ c = XFASTINT (elt);
if (some_multibyte)
- toindex_byte += CHAR_STRING (XINT (elt),
- SDATA (val) + toindex_byte);
+ toindex_byte += CHAR_STRING (c, SDATA (val) + toindex_byte);
else
- SSET (val, toindex_byte++, XINT (elt));
+ SSET (val, toindex_byte++, c);
toindex++;
}
}
diff --git a/src/xdisp.c b/src/xdisp.c
index 65f6ddd388..c495659929 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_
else if (CHARACTERP (eoltype))
{
unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
- eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
+ int c = XFASTINT (eoltype);
+ eol_str_len = CHAR_STRING (c, tmp);
eol_str = tmp;
}
else