diff options
| author | Paul Eggert | 2011-05-12 23:12:24 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-05-12 23:12:24 -0700 |
| commit | 2d165e9dc58924db64f73791a638c136bc6324d7 (patch) | |
| tree | dc24f2019b1fb5e0d0f3cae4b760b257fbca69e8 /src | |
| parent | bcfc5c821c672e38e5d4fad78347ab3c3f4352f7 (diff) | |
| download | emacs-2d165e9dc58924db64f73791a638c136bc6324d7.tar.gz emacs-2d165e9dc58924db64f73791a638c136bc6324d7.zip | |
* editfns.c (Fformat): Fix several integer overflow problems.
For example, without this change, (format "%2147483648d" 1) dumps
core on x86-64 GNU/Linux. Use EMACS_INT, not size_t, for sizes,
since we prefer using signed values, and EMACS_INT will be big
enough soon, even on 32-bit hosts. Also, prefer EMACS_INT to int
for sizes. Don't assume that pI is either "l" or ""; it might be
"ll" or "I64". Check for width and precision greater than
INT_MAX, as this can make sprintf go kaflooey. (Bug#8668)
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/editfns.c | 64 |
2 files changed, 45 insertions, 28 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 378d8a22808..9bdbb9a7d18 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,14 @@ | |||
| 1 | 2011-05-13 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2011-05-13 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | * editfns.c (Fformat): Fix several integer overflow problems. | ||
| 4 | For example, without this change, (format "%2147483648d" 1) dumps | ||
| 5 | core on x86-64 GNU/Linux. Use EMACS_INT, not size_t, for sizes, | ||
| 6 | since we prefer using signed values, and EMACS_INT will be big | ||
| 7 | enough soon, even on 32-bit hosts. Also, prefer EMACS_INT to int | ||
| 8 | for sizes. Don't assume that pI is either "l" or ""; it might be | ||
| 9 | "ll" or "I64". Check for width and precision greater than | ||
| 10 | INT_MAX, as this can make sprintf go kaflooey. (Bug#8668) | ||
| 11 | |||
| 3 | * dispextern.h (struct image): Don't assume time_t <= unsigned long. | 12 | * dispextern.h (struct image): Don't assume time_t <= unsigned long. |
| 4 | * image.c (clear_image_cache): Likewise. | 13 | * image.c (clear_image_cache): Likewise. |
| 5 | 14 | ||
diff --git a/src/editfns.c b/src/editfns.c index 5e1dcce0275..b5ccb481c43 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3583,11 +3583,12 @@ specifier truncates the string to the given width. | |||
| 3583 | usage: (format STRING &rest OBJECTS) */) | 3583 | usage: (format STRING &rest OBJECTS) */) |
| 3584 | (size_t nargs, register Lisp_Object *args) | 3584 | (size_t nargs, register Lisp_Object *args) |
| 3585 | { | 3585 | { |
| 3586 | register size_t n; /* The number of the next arg to substitute */ | 3586 | register EMACS_INT n; /* The number of the next arg to substitute */ |
| 3587 | register size_t total; /* An estimate of the final length */ | 3587 | register EMACS_INT total; /* An estimate of the final length */ |
| 3588 | int pIlen = sizeof pI - 1; | ||
| 3588 | char *buf, *p; | 3589 | char *buf, *p; |
| 3589 | register char *format, *end, *format_start; | 3590 | register char *format, *end, *format_start; |
| 3590 | int nchars; | 3591 | EMACS_INT nchars; |
| 3591 | /* Nonzero if the output should be a multibyte string, | 3592 | /* Nonzero if the output should be a multibyte string, |
| 3592 | which is true if any of the inputs is one. */ | 3593 | which is true if any of the inputs is one. */ |
| 3593 | int multibyte = 0; | 3594 | int multibyte = 0; |
| @@ -3603,7 +3604,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3603 | no argument, *will* be assigned to in the case that a `%' and `.' | 3604 | no argument, *will* be assigned to in the case that a `%' and `.' |
| 3604 | occur after the final format specifier. */ | 3605 | occur after the final format specifier. */ |
| 3605 | int *precision = (int *) (alloca ((nargs + 1) * sizeof (int))); | 3606 | int *precision = (int *) (alloca ((nargs + 1) * sizeof (int))); |
| 3606 | int longest_format; | 3607 | EMACS_INT longest_format; |
| 3607 | Lisp_Object val; | 3608 | Lisp_Object val; |
| 3608 | int arg_intervals = 0; | 3609 | int arg_intervals = 0; |
| 3609 | USE_SAFE_ALLOCA; | 3610 | USE_SAFE_ALLOCA; |
| @@ -3619,7 +3620,8 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3619 | info[0] is unused. Unused elements have -1 for start. */ | 3620 | info[0] is unused. Unused elements have -1 for start. */ |
| 3620 | struct info | 3621 | struct info |
| 3621 | { | 3622 | { |
| 3622 | int start, end, intervals; | 3623 | EMACS_INT start, end; |
| 3624 | int intervals; | ||
| 3623 | } *info = 0; | 3625 | } *info = 0; |
| 3624 | 3626 | ||
| 3625 | /* It should not be necessary to GCPRO ARGS, because | 3627 | /* It should not be necessary to GCPRO ARGS, because |
| @@ -3660,8 +3662,8 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3660 | 3662 | ||
| 3661 | /* Allocate the info and discarded tables. */ | 3663 | /* Allocate the info and discarded tables. */ |
| 3662 | { | 3664 | { |
| 3663 | size_t nbytes = (nargs+1) * sizeof *info; | 3665 | EMACS_INT nbytes = (nargs + 1) * sizeof *info; |
| 3664 | size_t i; | 3666 | EMACS_INT i; |
| 3665 | if (!info) | 3667 | if (!info) |
| 3666 | info = (struct info *) alloca (nbytes); | 3668 | info = (struct info *) alloca (nbytes); |
| 3667 | memset (info, 0, nbytes); | 3669 | memset (info, 0, nbytes); |
| @@ -3706,25 +3708,33 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3706 | || * format == ' ' || *format == '+')) | 3708 | || * format == ' ' || *format == '+')) |
| 3707 | ++format; | 3709 | ++format; |
| 3708 | 3710 | ||
| 3711 | /* Parse width and precision, limiting them to the range of 'int' | ||
| 3712 | because otherwise the underyling sprintf may go kaflooey. */ | ||
| 3713 | |||
| 3709 | if (*format >= '0' && *format <= '9') | 3714 | if (*format >= '0' && *format <= '9') |
| 3710 | { | 3715 | { |
| 3711 | for (field_width = 0; *format >= '0' && *format <= '9'; ++format) | 3716 | char *width_end; |
| 3712 | field_width = 10 * field_width + *format - '0'; | 3717 | unsigned long width = strtoul (format, &width_end, 10); |
| 3718 | if (INT_MAX < width) | ||
| 3719 | error ("Format string field width too large"); | ||
| 3720 | field_width = width; | ||
| 3721 | format = width_end; | ||
| 3713 | } | 3722 | } |
| 3714 | 3723 | ||
| 3715 | /* N is not incremented for another few lines below, so refer to | 3724 | /* N is not incremented for another few lines below, so refer to |
| 3716 | element N+1 (which might be precision[NARGS]). */ | 3725 | element N+1 (which might be precision[NARGS]). */ |
| 3717 | if (*format == '.') | 3726 | if (*format == '.') |
| 3718 | { | 3727 | { |
| 3719 | ++format; | 3728 | char *prec_end; |
| 3720 | for (precision[n+1] = 0; *format >= '0' && *format <= '9'; ++format) | 3729 | unsigned long prec = strtoul (format + 1, &prec_end, 10); |
| 3721 | precision[n+1] = 10 * precision[n+1] + *format - '0'; | 3730 | if (INT_MAX < prec) |
| 3731 | error ("Format string precision too large"); | ||
| 3732 | precision[n + 1] = prec; | ||
| 3733 | format = prec_end; | ||
| 3722 | } | 3734 | } |
| 3723 | 3735 | ||
| 3724 | /* Extra +1 for 'l' that we may need to insert into the | 3736 | if (longest_format < format - this_format_start + pIlen + 1) |
| 3725 | format. */ | 3737 | longest_format = format - this_format_start + pIlen + 1; |
| 3726 | if (format - this_format_start + 2 > longest_format) | ||
| 3727 | longest_format = format - this_format_start + 2; | ||
| 3728 | 3738 | ||
| 3729 | if (format == end) | 3739 | if (format == end) |
| 3730 | error ("Format string ends in middle of format specifier"); | 3740 | error ("Format string ends in middle of format specifier"); |
| @@ -3975,24 +3985,22 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3975 | } | 3985 | } |
| 3976 | else if (INTEGERP (args[n]) || FLOATP (args[n])) | 3986 | else if (INTEGERP (args[n]) || FLOATP (args[n])) |
| 3977 | { | 3987 | { |
| 3978 | int this_nchars; | 3988 | EMACS_INT this_nchars; |
| 3989 | EMACS_INT this_format_len = format - this_format_start; | ||
| 3979 | 3990 | ||
| 3980 | memcpy (this_format, this_format_start, | 3991 | memcpy (this_format, this_format_start, this_format_len); |
| 3981 | format - this_format_start); | 3992 | this_format[this_format_len] = 0; |
| 3982 | this_format[format - this_format_start] = 0; | ||
| 3983 | 3993 | ||
| 3984 | if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g') | 3994 | if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g') |
| 3985 | sprintf (p, this_format, XFLOAT_DATA (args[n])); | 3995 | sprintf (p, this_format, XFLOAT_DATA (args[n])); |
| 3986 | else | 3996 | else |
| 3987 | { | 3997 | { |
| 3988 | if (sizeof (EMACS_INT) > sizeof (int) | 3998 | if (pIlen && format[-1] != 'c') |
| 3989 | && format[-1] != 'c') | ||
| 3990 | { | 3999 | { |
| 3991 | /* Insert 'l' before format spec. */ | 4000 | /* Insert pI before format spec. */ |
| 3992 | this_format[format - this_format_start] | 4001 | memcpy (&this_format[this_format_len - 1], pI, pIlen); |
| 3993 | = this_format[format - this_format_start - 1]; | 4002 | this_format[this_format_len + pIlen - 1] = format[-1]; |
| 3994 | this_format[format - this_format_start - 1] = 'l'; | 4003 | this_format[this_format_len + pIlen] = 0; |
| 3995 | this_format[format - this_format_start + 1] = 0; | ||
| 3996 | } | 4004 | } |
| 3997 | 4005 | ||
| 3998 | if (INTEGERP (args[n])) | 4006 | if (INTEGERP (args[n])) |
| @@ -4089,7 +4097,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4089 | if (CONSP (props)) | 4097 | if (CONSP (props)) |
| 4090 | { | 4098 | { |
| 4091 | EMACS_INT bytepos = 0, position = 0, translated = 0; | 4099 | EMACS_INT bytepos = 0, position = 0, translated = 0; |
| 4092 | int argn = 1; | 4100 | EMACS_INT argn = 1; |
| 4093 | Lisp_Object list; | 4101 | Lisp_Object list; |
| 4094 | 4102 | ||
| 4095 | /* Adjust the bounds of each text property | 4103 | /* Adjust the bounds of each text property |