From 4050dcf84afbc93c8d8cde395a6af669dfdb8e7c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Tue, 12 Jul 2011 08:07:49 +0900 Subject: Suppress address randomization on Darwin. Do not merge into trunk. --- src/ChangeLog | 5 +++++ src/s/darwin.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 7193374972..84280a9a90 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2011-07-11 YAMAMOTO Mitsuharu + + * s/darwin.h (LD_SWITCH_SYSTEM_TEMACS): Add -fno-pie so as to suppress + address randomization (Bug#8395). + 2011-07-07 Kenichi Handa * composite.c (composition_compute_stop_pos): Ignore a static diff --git a/src/s/darwin.h b/src/s/darwin.h index 2b0addbef0..89d010a9ba 100644 --- a/src/s/darwin.h +++ b/src/s/darwin.h @@ -181,7 +181,7 @@ along with GNU Emacs. If not, see . */ end of the header for adding load commands. Needed for dumping. 0x690 is the total size of 30 segment load commands (at 56 each); under Cocoa 31 commands are required. */ -#define LD_SWITCH_SYSTEM_TEMACS -prebind LIBS_NSGUI -Xlinker -headerpad -Xlinker HEADERPAD_EXTRA +#define LD_SWITCH_SYSTEM_TEMACS -fno-pie -prebind LIBS_NSGUI -Xlinker -headerpad -Xlinker HEADERPAD_EXTRA #define C_SWITCH_SYSTEM_TEMACS -Dtemacs -- cgit v1.2.3 From 8c3e8e1144f57051117f4a1d938e92bf9c9cd169 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Tue, 12 Jul 2011 12:01:34 -0400 Subject: * window.el (split-window-horizontally): Doc fix (Bug#9060). --- lisp/ChangeLog | 4 ++++ lisp/window.el | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c05c769d2a..c624b6d49d 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2011-07-12 Chong Yidong + + * window.el (split-window-horizontally): Doc fix (Bug#9060). + 2011-06-27 Markus Heiser (tiny change) * progmodes/gud.el (gud-pdb-marker-regexp): Accept \r char (Bug#5653). diff --git a/lisp/window.el b/lisp/window.el index e8e1c6149f..837d5a418b 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -1314,7 +1314,7 @@ window." (defun split-window-horizontally (&optional size) "Split selected window into two windows side by side. The selected window becomes the left one and gets SIZE columns. -SIZE negative means the right window gets -SIZE lines. +SIZE negative means the right window gets -SIZE columns. SIZE includes the width of the window's scroll bar; if there are no scroll bars, it includes the width of the divider column to -- cgit v1.2.3 From 17c87e18e5410b7077757f9852a2bb0e0cde54c6 Mon Sep 17 00:00:00 2001 From: Glenn Morris Date: Sat, 16 Jul 2011 13:06:21 -0700 Subject: ChangeLog fix. --- lisp/ChangeLog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c624b6d49d..1b401bf758 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -7321,11 +7321,11 @@ * bookmark.el (bookmark-bmenu-list): Don't use switch-to-buffer if we're inside a dedicated or minibuffer window. -2009-10-24 Karl Fogel +2009-10-24 Drew Adams + Karl Fogel * bookmark.el: Update documentation, especially documentation - of `bookmark-alist' and of the bookmark file format. - Patch by Drew Adams, with minor tweaks from me. (Bug#4195) + of `bookmark-alist' and of the bookmark file format. (Bug#4195) 2009-10-24 Chong Yidong -- cgit v1.2.3 From 134643946085b24a695d73b3d8f7af5aa23602aa Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 16 Jul 2011 17:34:43 -0700 Subject: Overflow, signedness and related fixes for images. * dispextern.h (struct it.stack[0].u.image.image_id) (struct_it.image_id, struct image.id, struct image_cache.size) (struct image_cache.used, struct image_cache.ref_count): * gtkutil.c (update_frame_tool_bar): * image.c (x_reference_bitmap, Fimage_size, Fimage_mask_p) (Fimage_metadata, free_image_cache, clear_image_cache, lookup_image) (cache_image, mark_image_cache, x_kill_gs_process, Flookup_image): * nsmenu.m (update_frame_tool_bar): * xdisp.c (calc_pixel_width_or_height): * xfns.c (image_cache_refcount): Image IDs are now ptrdiff_t, not int, to avoid arbitrary limits on typical 64-bit hosts. * image.c (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. (x_bitmap_pixmap, x_create_x_image_and_pixmap): Omit unnecessary casts to int. (parse_image_spec): Check that integers fall into 'int' range when the callers expect that. (image_ascent): Redo ascent calculation to avoid int overflow. (clear_image_cache): Avoid overflow when sqrt (INT_MAX) < nimages. (lookup_image): Remove unnecessary tests. (xbm_image_p): Locals are now of int, not EMACS_INT, since parse_image_check makes sure they fit into int. (png_load, gif_load, svg_load_image): Prefer int to unsigned where either will do. (tiff_handler): New function, combining the cores of the old tiff_error_handler and tiff_warning_handler. This function is rewritten to use vsnprintf and thereby avoid stack buffer overflows. It uses only the features of vsnprintf that are common to both POSIX and native Microsoft. (tiff_error_handler, tiff_warning_handler): Use it. (tiff_load, gif_load, imagemagick_load_image): Don't assume :index value fits in 'int'. (gif_load): Omit unnecessary cast to double, and avoid double-rounding. (imagemagick_load_image): Check that crop parameters fit into the integer types that MagickCropImage accepts. Don't assume Vimagemagick_render_type has a nonnegative value. Don't assume size_t fits in 'long'. (gs_load): Use printmax_t to print the widest integers possible. Check for integer overflow when computing image height and width. --- src/ChangeLog | 45 ++++++++++++++ src/dispextern.h | 16 ++--- src/gtkutil.c | 2 +- src/image.c | 184 ++++++++++++++++++++++++++++++------------------------- src/nsmenu.m | 2 +- src/xdisp.c | 2 +- src/xfns.c | 3 +- 7 files changed, 160 insertions(+), 94 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index c19786fb72..680e67e05f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,48 @@ +2011-07-16 Paul Eggert + + Overflow, signedness and related fixes for images. + + * dispextern.h (struct it.stack[0].u.image.image_id) + (struct_it.image_id, struct image.id, struct image_cache.size) + (struct image_cache.used, struct image_cache.ref_count): + * gtkutil.c (update_frame_tool_bar): + * image.c (x_reference_bitmap, Fimage_size, Fimage_mask_p) + (Fimage_metadata, free_image_cache, clear_image_cache, lookup_image) + (cache_image, mark_image_cache, x_kill_gs_process, Flookup_image): + * nsmenu.m (update_frame_tool_bar): + * xdisp.c (calc_pixel_width_or_height): + * xfns.c (image_cache_refcount): + Image IDs are now ptrdiff_t, not int, to avoid arbitrary limits + on typical 64-bit hosts. + + * image.c (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. + (x_bitmap_pixmap, x_create_x_image_and_pixmap): + Omit unnecessary casts to int. + (parse_image_spec): Check that integers fall into 'int' range + when the callers expect that. + (image_ascent): Redo ascent calculation to avoid int overflow. + (clear_image_cache): Avoid overflow when sqrt (INT_MAX) < nimages. + (lookup_image): Remove unnecessary tests. + (xbm_image_p): Locals are now of int, not EMACS_INT, + since parse_image_check makes sure they fit into int. + (png_load, gif_load, svg_load_image): + Prefer int to unsigned where either will do. + (tiff_handler): New function, combining the cores of the + old tiff_error_handler and tiff_warning_handler. This + function is rewritten to use vsnprintf and thereby avoid + stack buffer overflows. It uses only the features of vsnprintf + that are common to both POSIX and native Microsoft. + (tiff_error_handler, tiff_warning_handler): Use it. + (tiff_load, gif_load, imagemagick_load_image): + Don't assume :index value fits in 'int'. + (gif_load): Omit unnecessary cast to double, and avoid double-rounding. + (imagemagick_load_image): Check that crop parameters fit into + the integer types that MagickCropImage accepts. Don't assume + Vimagemagick_render_type has a nonnegative value. Don't assume + size_t fits in 'long'. + (gs_load): Use printmax_t to print the widest integers possible. + Check for integer overflow when computing image height and width. + 2011-07-14 Paul Eggert Integer signedness and overflow and related fixes. (Bug#9079) diff --git a/src/dispextern.h b/src/dispextern.h index dc44c69816..bb4da7d52a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2246,7 +2246,7 @@ struct it struct { Lisp_Object object; struct it_slice slice; - int image_id; + ptrdiff_t image_id; } image; /* method == GET_FROM_COMPOSITION */ struct { @@ -2376,7 +2376,7 @@ struct it enum glyphless_display_method glyphless_method; /* If what == IT_IMAGE, the id of the image to display. */ - int image_id; + ptrdiff_t image_id; /* Values from `slice' property. */ struct it_slice slice; @@ -2826,7 +2826,7 @@ struct image EMACS_UINT hash; /* Image id of this image. */ - int id; + ptrdiff_t id; /* Hash collision chain. */ struct image *next, *prev; @@ -2845,13 +2845,13 @@ struct image_cache struct image **images; /* Allocated size of `images'. */ - unsigned size; + ptrdiff_t size; /* Number of images in the cache. */ - unsigned used; + ptrdiff_t used; /* Reference count (number of frames sharing this cache). */ - int refcount; + ptrdiff_t refcount; }; @@ -3117,7 +3117,7 @@ void w32_reset_fringes (void); extern int x_bitmap_height (struct frame *, ptrdiff_t); extern int x_bitmap_width (struct frame *, ptrdiff_t); extern int x_bitmap_pixmap (struct frame *, ptrdiff_t); -extern void x_reference_bitmap (struct frame *, int); +extern void x_reference_bitmap (struct frame *, ptrdiff_t); extern ptrdiff_t x_create_bitmap_from_data (struct frame *, char *, unsigned int, unsigned int); extern ptrdiff_t x_create_bitmap_from_file (struct frame *, Lisp_Object); @@ -3138,7 +3138,7 @@ void clear_image_caches (Lisp_Object); void mark_image_cache (struct image_cache *); int valid_image_p (Lisp_Object); void prepare_image_for_display (struct frame *, struct image *); -int lookup_image (struct frame *, Lisp_Object); +ptrdiff_t lookup_image (struct frame *, Lisp_Object); unsigned long image_background (struct image *, struct frame *, XImagePtr_or_DC ximg); diff --git a/src/gtkutil.c b/src/gtkutil.c index 8826b08851..70bc18a75f 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -4429,7 +4429,7 @@ update_frame_tool_bar (FRAME_PTR f) int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int idx; - int img_id; + ptrdiff_t img_id; int icon_size = 0; struct image *img = NULL; Lisp_Object image; diff --git a/src/image.c b/src/image.c index 7a5ac40b3d..3a58be5d85 100644 --- a/src/image.c +++ b/src/image.c @@ -48,6 +48,11 @@ along with GNU Emacs. If not, see . */ #include "termhooks.h" #include "font.h" +#define RANGED_INTEGERP(lo, x, hi) \ + (INTEGERP (x) && (lo) <= XINT (x) && XINT (x) <= (hi)) +#define TYPE_RANGED_INTEGERP(type, x) \ + RANGED_INTEGERP (TYPE_MINIMUM (type), x, TYPE_MAXIMUM (type)) + #ifdef HAVE_X_WINDOWS #include "xterm.h" #include @@ -196,7 +201,7 @@ x_bitmap_width (FRAME_PTR f, ptrdiff_t id) int x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id) { - return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; + return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; } #endif @@ -245,7 +250,7 @@ x_allocate_bitmap_record (FRAME_PTR f) /* Add one reference to the reference count of the bitmap with id ID. */ void -x_reference_bitmap (FRAME_PTR f, int id) +x_reference_bitmap (FRAME_PTR f, ptrdiff_t id) { ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; } @@ -807,29 +812,30 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords, break; case IMAGE_POSITIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) <= 0) + if (! RANGED_INTEGERP (1, value, INT_MAX)) return 0; break; case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR: - if (INTEGERP (value) && XINT (value) >= 0) + if (RANGED_INTEGERP (1, value, INT_MAX)) break; if (CONSP (value) - && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value)) - && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0) + && RANGED_INTEGERP (1, XCAR (value), INT_MAX) + && RANGED_INTEGERP (1, XCDR (value), INT_MAX)) break; return 0; case IMAGE_ASCENT_VALUE: if (SYMBOLP (value) && EQ (value, Qcenter)) break; - else if (INTEGERP (value) - && XINT (value) >= 0 - && XINT (value) <= 100) + else if (RANGED_INTEGERP (0, value, 100)) break; return 0; case IMAGE_NON_NEGATIVE_INTEGER_VALUE: + /* Unlike the other integer-related cases, this one does not + verify that VALUE fits in 'int'. This is because callers + want EMACS_INT. */ if (!INTEGERP (value) || XINT (value) < 0) return 0; break; @@ -849,7 +855,7 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords, break; case IMAGE_INTEGER_VALUE: - if (!INTEGERP (value)) + if (! TYPE_RANGED_INTEGERP (int, value)) return 0; break; @@ -919,7 +925,7 @@ or omitted means use the selected frame. */) if (valid_image_p (spec)) { struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec); + ptrdiff_t id = lookup_image (f, spec); struct image *img = IMAGE_FROM_ID (f, id); int width = img->width + 2 * img->hmargin; int height = img->height + 2 * img->vmargin; @@ -949,7 +955,7 @@ or omitted means use the selected frame. */) if (valid_image_p (spec)) { struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec); + ptrdiff_t id = lookup_image (f, spec); struct image *img = IMAGE_FROM_ID (f, id); if (img->mask) mask = Qt; @@ -972,7 +978,7 @@ or omitted means use the selected frame. */) if (valid_image_p (spec)) { struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec); + ptrdiff_t id = lookup_image (f, spec); struct image *img = IMAGE_FROM_ID (f, id); ext = img->lisp_data; } @@ -1121,7 +1127,7 @@ image_ascent (struct image *img, struct face *face, struct glyph_slice *slice) ascent = height / 2; } else - ascent = (int) (height * img->ascent / 100.0); + ascent = height * (img->ascent / 100.0); return ascent; } @@ -1466,7 +1472,7 @@ free_image_cache (struct frame *f) struct image_cache *c = FRAME_IMAGE_CACHE (f); if (c) { - int i; + ptrdiff_t i; /* Cache should not be referenced by any frame when freed. */ xassert (c->refcount == 0); @@ -1496,7 +1502,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter) if (c) { - int i, nfreed = 0; + ptrdiff_t i, nfreed = 0; /* Block input so that we won't be interrupted by a SIGIO while being in an inconsistent state. */ @@ -1520,8 +1526,8 @@ clear_image_cache (struct frame *f, Lisp_Object filter) { /* Free cache based on timestamp. */ EMACS_TIME t; - time_t old; - int delay, nimages = 0; + double old, delay; + ptrdiff_t nimages = 0; for (i = 0; i < c->used; ++i) if (c->images[i]) @@ -1529,9 +1535,10 @@ clear_image_cache (struct frame *f, Lisp_Object filter) /* If the number of cached images has grown unusually large, decrease the cache eviction delay (Bug#6230). */ - delay = XFASTINT (Vimage_cache_eviction_delay); + delay = XINT (Vimage_cache_eviction_delay); if (nimages > 40) - delay = max (1, 1600 * delay / (nimages*nimages)); + delay = 1600 * delay / nimages / nimages; + delay = max (delay, 1); EMACS_GET_TIME (t); old = EMACS_SECS (t) - delay; @@ -1707,7 +1714,7 @@ postprocess_image (struct frame *f, struct image *img) /* Return the id of image with Lisp specification SPEC on frame F. SPEC must be a valid Lisp image specification (see valid_image_p). */ -int +ptrdiff_t lookup_image (struct frame *f, Lisp_Object spec) { struct image *img; @@ -1766,15 +1773,12 @@ lookup_image (struct frame *f, Lisp_Object spec) img->ascent = CENTERED_IMAGE_ASCENT; margin = image_spec_value (spec, QCmargin, NULL); - if (INTEGERP (margin) && XINT (margin) >= 0) + if (INTEGERP (margin)) img->vmargin = img->hmargin = XFASTINT (margin); - else if (CONSP (margin) && INTEGERP (XCAR (margin)) - && INTEGERP (XCDR (margin))) + else if (CONSP (margin)) { - if (XINT (XCAR (margin)) > 0) - img->hmargin = XFASTINT (XCAR (margin)); - if (XINT (XCDR (margin)) > 0) - img->vmargin = XFASTINT (XCDR (margin)); + img->hmargin = XFASTINT (XCAR (margin)); + img->vmargin = XFASTINT (XCDR (margin)); } relief = image_spec_value (spec, QCrelief, NULL); @@ -1821,7 +1825,7 @@ static void cache_image (struct frame *f, struct image *img) { struct image_cache *c = FRAME_IMAGE_CACHE (f); - int i; + ptrdiff_t i; /* Find a free slot in c->images. */ for (i = 0; i < c->used; ++i) @@ -1875,7 +1879,7 @@ mark_image_cache (struct image_cache *c) { if (c) { - int i; + ptrdiff_t i; for (i = 0; i < c->used; ++i) if (c->images[i]) mark_image (c->images[i]); @@ -2066,7 +2070,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, DWORD err = GetLastError (); Lisp_Object errcode; /* All system errors are < 10000, so the following is safe. */ - XSETINT (errcode, (int) err); + XSETINT (errcode, err); image_error ("Unable to create bitmap, error code %d", errcode, Qnil); x_destroy_x_image (*ximg); return 0; @@ -2345,7 +2349,7 @@ xbm_image_p (Lisp_Object object) else { Lisp_Object data; - EMACS_INT width, height; + int width, height; /* Entries for `:width', `:height' and `:data' must be present. */ if (!kw[XBM_WIDTH].count @@ -5870,7 +5874,7 @@ png_load (struct frame *f, struct image *img) for (x = 0; x < width; ++x) { - unsigned r, g, b; + int r, g, b; r = *p++ << 8; g = *p++ << 8; @@ -6735,17 +6739,29 @@ tiff_size_of_memory (thandle_t data) } +static void tiff_handler (const char *, const char *, const char *, va_list) + ATTRIBUTE_FORMAT_PRINTF (3, 0); +static void +tiff_handler (const char *log_format, const char *title, + const char *format, va_list ap) +{ + /* doprnt is not suitable here, as TIFF handlers are called from + libtiff and are passed arbitrary printf directives. Instead, use + vsnprintf, taking care to be portable to nonstandard environments + where vsnprintf returns -1 on buffer overflow. Since it's just a + log entry, it's OK to truncate it. */ + char buf[4000]; + int len = vsnprintf (buf, sizeof buf, format, ap); + add_to_log (log_format, build_string (title), + make_string (buf, max (0, min (len, sizeof buf - 1)))); +} + static void tiff_error_handler (const char *, const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (2, 0); static void tiff_error_handler (const char *title, const char *format, va_list ap) { - char buf[512]; - int len; - - len = sprintf (buf, "TIFF error: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); + tiff_handler ("TIFF error: %s %s", title, format, ap); } @@ -6754,12 +6770,7 @@ static void tiff_warning_handler (const char *, const char *, va_list) static void tiff_warning_handler (const char *title, const char *format, va_list ap) { - char buf[512]; - int len; - - len = sprintf (buf, "TIFF warning: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); + tiff_handler ("TIFF warning: %s %s", title, format, ap); } @@ -6835,8 +6846,9 @@ tiff_load (struct frame *f, struct image *img) image = image_spec_value (img->spec, QCindex, NULL); if (INTEGERP (image)) { - int ino = XFASTINT (image); - if (!fn_TIFFSetDirectory (tiff, ino)) + EMACS_INT ino = XFASTINT (image); + if (! (TYPE_MINIMUM (tdir_t) <= ino && ino <= TYPE_MAXIMUM (tdir_t) + && fn_TIFFSetDirectory (tiff, ino))) { image_error ("Invalid image number `%s' in image `%s'", image, img->spec); @@ -7135,7 +7147,7 @@ gif_load (struct frame *f, struct image *img) Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL); Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL); unsigned long bgcolor = 0; - int idx; + EMACS_INT idx; if (NILP (specified_data)) { @@ -7365,7 +7377,7 @@ gif_load (struct frame *f, struct image *img) img->lisp_data = Qnil; if (gif->SavedImages[idx].ExtensionBlockCount > 0) { - unsigned int delay = 0; + int delay = 0; ExtensionBlock *ext = gif->SavedImages[idx].ExtensionBlocks; for (i = 0; i < gif->SavedImages[idx].ExtensionBlockCount; i++, ext++) /* Append (... FUNCTION "BYTES") */ @@ -7386,7 +7398,7 @@ gif_load (struct frame *f, struct image *img) if (delay) img->lisp_data = Fcons (Qdelay, - Fcons (make_float (((double) delay) * 0.01), + Fcons (make_float (delay / 100.0), img->lisp_data)); } @@ -7562,10 +7574,10 @@ imagemagick_load_image (struct frame *f, struct image *img, Lisp_Object image; Lisp_Object value; Lisp_Object crop; - long ino; + EMACS_INT ino; int desired_width, desired_height; double rotation; - int imagemagick_rendermethod; + EMACS_INT imagemagick_rendermethod; int pixelwidth; ImageInfo *image_info; ExceptionInfo *exception; @@ -7592,7 +7604,7 @@ imagemagick_load_image (struct frame *f, struct image *img, status = MagickPingImageBlob (ping_wand, contents, size); } - if (ino >= MagickGetNumberImages (ping_wand)) + if (! (0 <= ino && ino < MagickGetNumberImages (ping_wand))) { image_error ("Invalid image number `%s' in image `%s'", image, img->spec); @@ -7667,28 +7679,28 @@ imagemagick_load_image (struct frame *f, struct image *img, efficient. */ crop = image_spec_value (img->spec, QCcrop, NULL); - if (CONSP (crop) && INTEGERP (XCAR (crop))) + if (CONSP (crop) && TYPE_RANGED_INTEGERP (size_t, XCAR (crop))) { /* After some testing, it seems MagickCropImage is the fastest crop function in ImageMagick. This crop function seems to do less copying than the alternatives, but it still reads the entire image into memory - before croping, which is aparently difficult to avoid when using + before cropping, which is apparently difficult to avoid when using imagemagick. */ - int w, h; - w = XFASTINT (XCAR (crop)); + size_t crop_width = XINT (XCAR (crop)); crop = XCDR (crop); - if (CONSP (crop) && INTEGERP (XCAR (crop))) + if (CONSP (crop) && TYPE_RANGED_INTEGERP (size_t, XCAR (crop))) { - h = XFASTINT (XCAR (crop)); + size_t crop_height = XINT (XCAR (crop)); crop = XCDR (crop); - if (CONSP (crop) && INTEGERP (XCAR (crop))) + if (CONSP (crop) && TYPE_RANGED_INTEGERP (ssize_t, XCAR (crop))) { - x = XFASTINT (XCAR (crop)); + ssize_t crop_x = XINT (XCAR (crop)); crop = XCDR (crop); - if (CONSP (crop) && INTEGERP (XCAR (crop))) + if (CONSP (crop) && TYPE_RANGED_INTEGERP (ssize_t, XCAR (crop))) { - y = XFASTINT (XCAR (crop)); - MagickCropImage (image_wand, w, h, x, y); + ssize_t crop_y = XINT (XCAR (crop)); + MagickCropImage (image_wand, crop_width, crop_height, + crop_x, crop_y); } } } @@ -7734,9 +7746,11 @@ imagemagick_load_image (struct frame *f, struct image *img, init_color_table (); imagemagick_rendermethod = (INTEGERP (Vimagemagick_render_type) - ? XFASTINT (Vimagemagick_render_type) : 0); + ? XINT (Vimagemagick_render_type) : 0); if (imagemagick_rendermethod == 0) { + size_t image_height; + /* Try to create a x pixmap to hold the imagemagick pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) @@ -7765,7 +7779,8 @@ imagemagick_load_image (struct frame *f, struct image *img, goto imagemagick_error; } - for (y = 0; y < (long) MagickGetImageHeight (image_wand); y++) + image_height = MagickGetImageHeight (image_wand); + for (y = 0; y < image_height; y++) { pixels = PixelGetNextIteratorRow (iterator, &width); if (pixels == (PixelWand **) NULL) @@ -8271,10 +8286,10 @@ svg_load_image (struct frame *f, /* Pointer to emacs frame structure. * { for (x = 0; x < width; ++x) { - unsigned red; - unsigned green; - unsigned blue; - unsigned opacity; + int red; + int green; + int blue; + int opacity; red = *pixels++; green = *pixels++; @@ -8455,7 +8470,8 @@ gs_image_p (Lisp_Object object) static int gs_load (struct frame *f, struct image *img) { - char buffer[100]; + uprintmax_t printnum1, printnum2; + char buffer[sizeof " " + INT_STRLEN_BOUND (printmax_t)]; Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; Lisp_Object frame; double in_width, in_height; @@ -8467,16 +8483,19 @@ gs_load (struct frame *f, struct image *img) info. */ pt_width = image_spec_value (img->spec, QCpt_width, NULL); in_width = INTEGERP (pt_width) ? XFASTINT (pt_width) / 72.0 : 0; - img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx; + in_width *= FRAME_X_DISPLAY_INFO (f)->resx; pt_height = image_spec_value (img->spec, QCpt_height, NULL); in_height = INTEGERP (pt_height) ? XFASTINT (pt_height) / 72.0 : 0; - img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy; + in_height *= FRAME_X_DISPLAY_INFO (f)->resy; - if (!check_image_size (f, img->width, img->height)) + if (! (in_width <= INT_MAX && in_height <= INT_MAX + && check_image_size (f, in_width, in_height))) { image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil); return 0; } + img->width = in_width; + img->height = in_height; /* Create the pixmap. */ xassert (img->pixmap == NO_PIXMAP); @@ -8501,14 +8520,14 @@ gs_load (struct frame *f, struct image *img) if successful. We do not record_unwind_protect here because other places in redisplay like calling window scroll functions don't either. Let the Lisp loader use `unwind-protect' instead. */ - sprintf (buffer, "%lu %lu", - (unsigned long) FRAME_X_WINDOW (f), - (unsigned long) img->pixmap); + printnum1 = FRAME_X_WINDOW (f); + printnum2 = img->pixmap; + sprintf (buffer, "%"pMu" %"pMu, printnum1, printnum2); window_and_pixmap_id = build_string (buffer); - sprintf (buffer, "%lu %lu", - FRAME_FOREGROUND_PIXEL (f), - FRAME_BACKGROUND_PIXEL (f)); + printnum1 = FRAME_FOREGROUND_PIXEL (f); + printnum2 = FRAME_BACKGROUND_PIXEL (f); + sprintf (buffer, "%"pMu" %"pMu, printnum1, printnum2); pixel_colors = build_string (buffer); XSETFRAME (frame, f); @@ -8533,7 +8552,8 @@ void x_kill_gs_process (Pixmap pixmap, struct frame *f) { struct image_cache *c = FRAME_IMAGE_CACHE (f); - int class, i; + int class; + ptrdiff_t i; struct image *img; /* Find the image containing PIXMAP. */ @@ -8637,7 +8657,7 @@ DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0, DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "") (Lisp_Object spec) { - int id = -1; + ptrdiff_t id = -1; if (valid_image_p (spec)) id = lookup_image (SELECTED_FRAME (), spec); diff --git a/src/nsmenu.m b/src/nsmenu.m index 6a9ee7dd4f..95e23ff651 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -1014,7 +1014,7 @@ update_frame_tool_bar (FRAME_PTR f) BOOL enabled_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_ENABLED_P)); BOOL selected_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_SELECTED_P)); int idx; - int img_id; + ptrdiff_t img_id; struct image *img; Lisp_Object image; Lisp_Object helpObj; diff --git a/src/xdisp.c b/src/xdisp.c index 5285d94597..50f6f79c94 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -21119,7 +21119,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, if (FRAME_WINDOW_P (it->f) && valid_image_p (prop)) { - int id = lookup_image (it->f, prop); + ptrdiff_t id = lookup_image (it->f, prop); struct image *img = IMAGE_FROM_ID (it->f, id); return OK_PIXELS (width_p ? img->width : img->height); diff --git a/src/xfns.c b/src/xfns.c index 0d1e4a1bb5..623b7847c1 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -145,7 +145,8 @@ static Lisp_Object Qcompound_text, Qcancel_timer; Lisp_Object Qfont_param; #if GLYPH_DEBUG -static int image_cache_refcount, dpyinfo_refcount; +static ptrdiff_t image_cache_refcount; +static int dpyinfo_refcount; #endif #if defined (USE_GTK) && defined (HAVE_FREETYPE) -- cgit v1.2.3 From b13995dbbdab5254bc77ad5ed7318db9797be321 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 16 Jul 2011 20:00:19 -0700 Subject: * keyboard.c: Overflow, signedness and related fixes. (make_lispy_movement): Use same integer type in forward decl that is used in the definition. (read_key_sequence, keyremap_step): Change bufsize argument back to int, undoing my 2011-03-30 change. We prefer signed types, and int is wide enough here. (parse_tool_bar_item): Don't assume tool_bar_max_label_size is less than TYPE_MAXIMUM (EMACS_INT) / 2. Don't let the label size grow larger than STRING_BYTES_BOUND. Use ptrdiff_t for Emacs string length, not size_t. Use ptrdiff_t for index, not int. (keyremap_step, read_key_sequence): Redo bufsize check to avoid possibility of integer overflow. --- src/ChangeLog | 13 +++++++++++++ src/keyboard.c | 21 +++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 1dcf39498f..32a117ed76 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,18 @@ 2011-07-17 Paul Eggert + * keyboard.c: Overflow, signedness and related fixes. + (make_lispy_movement): Use same integer type in forward decl + that is used in the definition. + (read_key_sequence, keyremap_step): + Change bufsize argument back to int, undoing my 2011-03-30 change. + We prefer signed types, and int is wide enough here. + (parse_tool_bar_item): Don't assume tool_bar_max_label_size is less + than TYPE_MAXIMUM (EMACS_INT) / 2. Don't let the label size grow + larger than STRING_BYTES_BOUND. Use ptrdiff_t for Emacs string + length, not size_t. Use ptrdiff_t for index, not int. + (keyremap_step, read_key_sequence): Redo bufsize check to avoid + possibility of integer overflow. + Overflow, signedness and related fixes for images. * dispextern.h (struct it.stack[0].u.image.image_id) diff --git a/src/keyboard.c b/src/keyboard.c index 7e144b80a0..30fe0d917c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -444,7 +444,7 @@ static Lisp_Object make_lispy_event (struct input_event *); static Lisp_Object make_lispy_movement (struct frame *, Lisp_Object, enum scroll_bar_part, Lisp_Object, Lisp_Object, - unsigned long); + Time); #endif static Lisp_Object modify_event_symbol (EMACS_INT, unsigned, Lisp_Object, Lisp_Object, const char *const *, @@ -1300,7 +1300,7 @@ some_mouse_moved (void) /* This is the actual command reading loop, sans error-handling encapsulation. */ -static int read_key_sequence (Lisp_Object *, size_t, Lisp_Object, +static int read_key_sequence (Lisp_Object *, int, Lisp_Object, int, int, int); void safe_run_hooks (Lisp_Object); static void adjust_point_for_property (EMACS_INT, int); @@ -8274,10 +8274,11 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item) Lisp_Object tcapt = PROP (TOOL_BAR_ITEM_CAPTION); const char *label = SYMBOLP (tkey) ? SSDATA (SYMBOL_NAME (tkey)) : ""; const char *capt = STRINGP (tcapt) ? SSDATA (tcapt) : ""; - EMACS_INT max_lbl = 2 * tool_bar_max_label_size; + ptrdiff_t max_lbl = + 2 * max (0, min (tool_bar_max_label_size, STRING_BYTES_BOUND / 2)); char *buf = (char *) xmalloc (max_lbl + 1); Lisp_Object new_lbl; - size_t caption_len = strlen (capt); + ptrdiff_t caption_len = strlen (capt); if (caption_len <= max_lbl && capt[0] != '\0') { @@ -8290,7 +8291,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item) if (strlen (label) <= max_lbl && label[0] != '\0') { - int j; + ptrdiff_t j; if (label != buf) strcpy (buf, label); @@ -8849,7 +8850,7 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, The return value is non-zero if the remapping actually took place. */ static int -keyremap_step (Lisp_Object *keybuf, size_t bufsize, volatile keyremap *fkey, +keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey, int input, int doit, int *diff, Lisp_Object prompt) { Lisp_Object next, key; @@ -8871,7 +8872,7 @@ keyremap_step (Lisp_Object *keybuf, size_t bufsize, volatile keyremap *fkey, *diff = len - (fkey->end - fkey->start); - if (input + *diff >= bufsize) + if (bufsize - input <= *diff) error ("Key sequence too long"); /* Shift the keys that follow fkey->end. */ @@ -8942,7 +8943,7 @@ keyremap_step (Lisp_Object *keybuf, size_t bufsize, volatile keyremap *fkey, from the selected window's buffer. */ static int -read_key_sequence (Lisp_Object *keybuf, size_t bufsize, Lisp_Object prompt, +read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, int dont_downcase_last, int can_return_switch_frame, int fix_current_buffer) { @@ -9549,7 +9550,7 @@ read_key_sequence (Lisp_Object *keybuf, size_t bufsize, Lisp_Object prompt, && (NILP (fake_prefixed_keys) || NILP (Fmemq (key, fake_prefixed_keys)))) { - if (t + 1 >= bufsize) + if (bufsize - t <= 1) error ("Key sequence too long"); keybuf[t] = posn; @@ -9630,7 +9631,7 @@ read_key_sequence (Lisp_Object *keybuf, size_t bufsize, Lisp_Object prompt, insert the dummy prefix event `menu-bar'. */ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) { - if (t + 1 >= bufsize) + if (bufsize - t <= 1) error ("Key sequence too long"); keybuf[t] = posn; keybuf[t+1] = key; -- cgit v1.2.3 From 50849c52f8cf342b81c1db12b13f866ec6c049fc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 Jul 2011 13:56:13 -0700 Subject: * xterm.c: don't go over XClientMessageEvent limit (scroll_bar_windows_size): Now ptrdiff_t, as we prefer signed. (x_send_scroll_bar_event): Likewise. Check that the size does not exceed limits imposed by XClientMessageEvent, as well as the usual ptrdiff_t and size_t limits. --- src/ChangeLog | 6 ++++++ src/xterm.c | 18 +++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 32a117ed76..940beee887 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,11 @@ 2011-07-17 Paul Eggert + * xterm.c: don't go over XClientMessageEvent limit + (scroll_bar_windows_size): Now ptrdiff_t, as we prefer signed. + (x_send_scroll_bar_event): Likewise. Check that the size does not + exceed limits imposed by XClientMessageEvent, as well as the usual + ptrdiff_t and size_t limits. + * keyboard.c: Overflow, signedness and related fixes. (make_lispy_movement): Use same integer type in forward decl that is used in the definition. diff --git a/src/xterm.c b/src/xterm.c index 20516ee9d6..5b6ddbb8dd 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4190,7 +4190,7 @@ xt_action_hook (Widget widget, XtPointer client_data, String action_name, x_send_scroll_bar_event and x_scroll_bar_to_input_event. */ static struct window **scroll_bar_windows; -static size_t scroll_bar_windows_size; +static ptrdiff_t scroll_bar_windows_size; /* Send a client message with message type Xatom_Scrollbar for a @@ -4205,7 +4205,7 @@ x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole) XClientMessageEvent *ev = (XClientMessageEvent *) &event; struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); - size_t i; + ptrdiff_t i; BLOCK_INPUT; @@ -4226,12 +4226,16 @@ x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole) if (i == scroll_bar_windows_size) { - size_t new_size = max (10, 2 * scroll_bar_windows_size); - size_t nbytes = new_size * sizeof *scroll_bar_windows; - size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows; - - if ((size_t) -1 / sizeof *scroll_bar_windows < new_size) + ptrdiff_t new_size, old_nbytes, nbytes; + /* Check the 32-bit XClientMessageEvent limit, as well as the + usual ptrdiff_t/size_t limit. */ + if (min (0x7fffffff, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof *scroll_bar_windows / 2) + < scroll_bar_windows_size) memory_full (SIZE_MAX); + new_size = max (10, 2 * scroll_bar_windows_size); + nbytes = new_size * sizeof *scroll_bar_windows; + old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows; scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows, nbytes); memset (&scroll_bar_windows[i], 0, nbytes - old_nbytes); -- cgit v1.2.3 From caeeedc1afd7205303a99ef8ce7e4ce7d2055042 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 Jul 2011 23:44:01 -0700 Subject: * charset.c (read_hex): New arg OVERFLOW. All uses changed. Remove unreachable code. (read_hex, load_charset_map_from_file): Check for integer overflow. --- src/ChangeLog | 6 ++++++ src/charset.c | 35 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 940beee887..869e2637cf 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2011-07-18 Paul Eggert + + * charset.c (read_hex): New arg OVERFLOW. All uses changed. + Remove unreachable code. + (read_hex, load_charset_map_from_file): Check for integer overflow. + 2011-07-17 Paul Eggert * xterm.c: don't go over XClientMessageEvent limit diff --git a/src/charset.c b/src/charset.c index 55234aa76a..e2bfcd0867 100644 --- a/src/charset.c +++ b/src/charset.c @@ -419,7 +419,7 @@ load_charset_map (struct charset *charset, struct charset_map_entries *entries, paying attention to comment character '#'. */ static inline unsigned -read_hex (FILE *fp, int *eof) +read_hex (FILE *fp, int *eof, int *overflow) { int c; unsigned n; @@ -441,15 +441,16 @@ read_hex (FILE *fp, int *eof) *eof = 1; return 0; } - *eof = 0; n = 0; - if (c == 'x') - while ((c = getc (fp)) != EOF && isxdigit (c)) + while (isxdigit (c = getc (fp))) + { + if (UINT_MAX >> 4 < n) + *overflow = 1; n = ((n << 4) - | (c <= '9' ? c - '0' : c <= 'F' ? c - 'A' + 10 : c - 'a' + 10)); - else - while ((c = getc (fp)) != EOF && isdigit (c)) - n = (n * 10) + c - '0'; + | (c - ('0' <= c && c <= '9' ? '0' + : 'A' <= c && c <= 'F' ? 'A' - 10 + : 'a' - 10))); + } if (c != EOF) ungetc (c, fp); return n; @@ -479,7 +480,6 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co unsigned max_code = CHARSET_MAX_CODE (charset); int fd; FILE *fp; - int eof; Lisp_Object suffixes; struct charset_map_entries *head, *entries; int n_entries, count; @@ -504,22 +504,27 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co memset (entries, 0, sizeof (struct charset_map_entries)); n_entries = 0; - eof = 0; while (1) { - unsigned from, to; - int c; + unsigned from, to, c; int idx; + int eof = 0, overflow = 0; - from = read_hex (fp, &eof); + from = read_hex (fp, &eof, &overflow); if (eof) break; if (getc (fp) == '-') - to = read_hex (fp, &eof); + to = read_hex (fp, &eof, &overflow); else to = from; - c = (int) read_hex (fp, &eof); + if (eof) + break; + c = read_hex (fp, &eof, &overflow); + if (eof) + break; + if (overflow) + continue; if (from < min_code || to > max_code || from > to || c > MAX_CHAR) continue; -- cgit v1.2.3 From 18c525570121d8d3df377f85ec5b6f44fe39524a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jul 2011 14:08:22 -0700 Subject: * fileio.c: Integer overflow issues with file modes. (Fset_file_modes, auto_save_1): Don't assume EMACS_INT fits in int. --- src/ChangeLog | 3 +++ src/fileio.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 869e2637cf..c516a346a8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,8 @@ 2011-07-18 Paul Eggert + * fileio.c: Integer overflow issues with file modes. + (Fset_file_modes, auto_save_1): Don't assume EMACS_INT fits in int. + * charset.c (read_hex): New arg OVERFLOW. All uses changed. Remove unreachable code. (read_hex, load_charset_map_from_file): Check for integer overflow. diff --git a/src/fileio.c b/src/fileio.c index bdea302a0d..af11e92705 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2893,7 +2893,7 @@ symbolic notation, like the `chmod' command from GNU Coreutils. */) encoded_absname = ENCODE_FILE (absname); - if (chmod (SSDATA (encoded_absname), XINT (mode)) < 0) + if (chmod (SSDATA (encoded_absname), XINT (mode) & 07777) < 0) report_file_error ("Doing chmod", Fcons (absname, Qnil)); return Qnil; @@ -5095,11 +5095,11 @@ auto_save_1 (void) { if (stat (SSDATA (BVAR (current_buffer, filename)), &st) >= 0) /* But make sure we can overwrite it later! */ - auto_save_mode_bits = st.st_mode | 0600; + auto_save_mode_bits = (st.st_mode | 0600) & 0777; else if ((modes = Ffile_modes (BVAR (current_buffer, filename)), INTEGERP (modes))) /* Remote files don't cooperate with stat. */ - auto_save_mode_bits = XINT (modes) | 0600; + auto_save_mode_bits = (XINT (modes) | 0600) & 0777; } return -- cgit v1.2.3 From a2271ba21087837896098f97663efaa60eab943e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jul 2011 14:57:37 -0700 Subject: Don't assume that tab-width fits in int. * character.h (sanitize_width): New inline function. (SANE_TAB_WIDTH): New macro. (ASCII_CHAR_WIDTH): Use it. * indent.c (sane_tab_width): Remove. All uses replaced by SANE_TAB_WIDTH (current_buffer). * xdisp.c (init_iterator): Use SANE_TAB_WIDTH. --- src/ChangeLog | 8 ++++++++ src/character.h | 12 +++++++++++- src/indent.c | 21 ++++++--------------- src/xdisp.c | 5 +---- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index c516a346a8..909bb052fe 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,13 @@ 2011-07-18 Paul Eggert + Don't assume that tab-width fits in int. + * character.h (sanitize_width): New inline function. + (SANE_TAB_WIDTH): New macro. + (ASCII_CHAR_WIDTH): Use it. + * indent.c (sane_tab_width): Remove. All uses replaced by + SANE_TAB_WIDTH (current_buffer). + * xdisp.c (init_iterator): Use SANE_TAB_WIDTH. + * fileio.c: Integer overflow issues with file modes. (Fset_file_modes, auto_save_1): Don't assume EMACS_INT fits in int. diff --git a/src/character.h b/src/character.h index 063b5147dc..0c207113c1 100644 --- a/src/character.h +++ b/src/character.h @@ -556,6 +556,16 @@ along with GNU Emacs. If not, see . */ } while (0) +/* Return a non-outlandish value for the tab width. */ + +#define SANE_TAB_WIDTH(buf) sanitize_width (XFASTINT (BVAR (buf, tab_width))) + +static inline int +sanitize_width (EMACS_INT width) +{ + return 0 < width && width <= 1000 ? width : 8; +} + /* Return the width of ASCII character C. The width is measured by how many columns C will occupy on the screen when displayed in the current buffer. */ @@ -563,7 +573,7 @@ along with GNU Emacs. If not, see . */ #define ASCII_CHAR_WIDTH(c) \ (c < 0x20 \ ? (c == '\t' \ - ? XFASTINT (BVAR (current_buffer, tab_width)) \ + ? SANE_TAB_WIDTH (current_buffer) \ : (c == '\n' ? 0 : (NILP (BVAR (current_buffer, ctl_arrow)) ? 4 : 2))) \ : (c < 0x7f \ ? 1 \ diff --git a/src/indent.c b/src/indent.c index aaeaaf591e..d89c7a9de0 100644 --- a/src/indent.c +++ b/src/indent.c @@ -318,15 +318,6 @@ invalidate_current_column (void) last_known_column_point = 0; } -/* Return a non-outlandish value for the tab width. */ - -static int -sane_tab_width (void) -{ - EMACS_INT n = XFASTINT (BVAR (current_buffer, tab_width)); - return 0 < n && n <= 1000 ? n : 8; -} - EMACS_INT current_column (void) { @@ -335,7 +326,7 @@ current_column (void) register int tab_seen; EMACS_INT post_tab; register int c; - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow)); register struct Lisp_Char_Table *dp = buffer_display_table (); @@ -515,7 +506,7 @@ check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos) static void scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol) { - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); register int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow)); register struct Lisp_Char_Table *dp = buffer_display_table (); int multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters)); @@ -732,7 +723,7 @@ string_display_width (Lisp_Object string, Lisp_Object beg, Lisp_Object end) register int tab_seen; int post_tab; register int c; - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); int ctl_arrow = !NILP (current_buffer->ctl_arrow); register struct Lisp_Char_Table *dp = buffer_display_table (); int b, e; @@ -808,7 +799,7 @@ The return value is COLUMN. */) { EMACS_INT mincol; register EMACS_INT fromcol; - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); CHECK_NUMBER (column); if (NILP (minimum)) @@ -867,7 +858,7 @@ static EMACS_INT position_indentation (register int pos_byte) { register EMACS_INT column = 0; - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); register unsigned char *p; register unsigned char *stop; unsigned char *start; @@ -1116,7 +1107,7 @@ compute_motion (EMACS_INT from, EMACS_INT fromvpos, EMACS_INT fromhpos, int did_ register EMACS_INT pos; EMACS_INT pos_byte; register int c = 0; - int tab_width = sane_tab_width (); + int tab_width = SANE_TAB_WIDTH (current_buffer); register int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow)); register struct Lisp_Char_Table *dp = window_display_table (win); EMACS_INT selective diff --git a/src/xdisp.c b/src/xdisp.c index 4ea183ccc5..9d521ea7aa 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2478,10 +2478,7 @@ init_iterator (struct it *it, struct window *w, else if (INTEGERP (w->redisplay_end_trigger)) it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger); - /* Correct bogus values of tab_width. */ - it->tab_width = XINT (BVAR (current_buffer, tab_width)); - if (it->tab_width <= 0 || it->tab_width > 1000) - it->tab_width = 8; + it->tab_width = SANE_TAB_WIDTH (current_buffer); /* Are lines in the display truncated? */ if (base_face_id != DEFAULT_FACE_ID -- cgit v1.2.3 From 5637687fead7d57f73ea9a7677d25b93fb785dc7 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jul 2011 17:42:24 -0700 Subject: Don't assume that stated character widths fit in int. * character.c (Fchar_width, c_string_width, lisp_string_width): * character.h (CHAR_WIDTH): * indent.c (MULTIBYTE_BYTES_WIDTH): Use sanitize_char_width to avoid undefined and/or bad behavior with outlandish widths. * character.h (sanitize_tab_width): Renamed from sanitize_width, now that we have two such functions. All uses changed. (sanitize_char_width): New inline function. --- src/ChangeLog | 12 ++++++++++++ src/character.c | 6 +++--- src/character.h | 16 ++++++++++++---- src/indent.c | 2 +- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 909bb052fe..54ce0c8df4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +2011-07-19 Paul Eggert + + Don't assume that stated character widths fit in int. + * character.c (Fchar_width, c_string_width, lisp_string_width): + * character.h (CHAR_WIDTH): + * indent.c (MULTIBYTE_BYTES_WIDTH): + Use sanitize_char_width to avoid undefined and/or bad behavior + with outlandish widths. + * character.h (sanitize_tab_width): Renamed from sanitize_width, + now that we have two such functions. All uses changed. + (sanitize_char_width): New inline function. + 2011-07-18 Paul Eggert Don't assume that tab-width fits in int. diff --git a/src/character.c b/src/character.c index 8e9b3e3775..c2f23e0d8e 100644 --- a/src/character.c +++ b/src/character.c @@ -326,7 +326,7 @@ usage: (char-width CHAR) */) disp = dp ? DISP_CHAR_VECTOR (dp, c) : Qnil; if (VECTORP (disp)) - width = ASIZE (disp); + width = sanitize_char_width (ASIZE (disp)); else width = CHAR_WIDTH (c); @@ -358,7 +358,7 @@ c_string_width (const unsigned char *str, EMACS_INT len, int precision, { val = DISP_CHAR_VECTOR (dp, c); if (VECTORP (val)) - thiswidth = ASIZE (val); + thiswidth = sanitize_char_width (ASIZE (val)); else thiswidth = CHAR_WIDTH (c); } @@ -451,7 +451,7 @@ lisp_string_width (Lisp_Object string, EMACS_INT precision, { val = DISP_CHAR_VECTOR (dp, c); if (VECTORP (val)) - thiswidth = ASIZE (val); + thiswidth = sanitize_char_width (ASIZE (val)); else thiswidth = CHAR_WIDTH (c); } diff --git a/src/character.h b/src/character.h index 0c207113c1..09bcf17ab9 100644 --- a/src/character.h +++ b/src/character.h @@ -558,10 +558,10 @@ along with GNU Emacs. If not, see . */ /* Return a non-outlandish value for the tab width. */ -#define SANE_TAB_WIDTH(buf) sanitize_width (XFASTINT (BVAR (buf, tab_width))) - +#define SANE_TAB_WIDTH(buf) \ + sanitize_tab_width (XFASTINT (BVAR (buf, tab_width))) static inline int -sanitize_width (EMACS_INT width) +sanitize_tab_width (EMACS_INT width) { return 0 < width && width <= 1000 ? width : 8; } @@ -579,6 +579,14 @@ sanitize_width (EMACS_INT width) ? 1 \ : ((NILP (BVAR (current_buffer, ctl_arrow)) ? 4 : 2)))) +/* Return a non-outlandish value for a character width. */ + +static inline int +sanitize_char_width (EMACS_INT width) +{ + return 0 <= width && width <= 1000 ? width : 1000; +} + /* Return the width of character C. The width is measured by how many columns C will occupy on the screen when displayed in the current buffer. */ @@ -586,7 +594,7 @@ sanitize_width (EMACS_INT width) #define CHAR_WIDTH(c) \ (ASCII_CHAR_P (c) \ ? ASCII_CHAR_WIDTH (c) \ - : XINT (CHAR_TABLE_REF (Vchar_width_table, c))) + : sanitize_char_width (XINT (CHAR_TABLE_REF (Vchar_width_table, c)))) /* If C is a variation selector, return the index numnber of the variation selector (1..256). Otherwise, return 0. */ diff --git a/src/indent.c b/src/indent.c index d89c7a9de0..8a2117751a 100644 --- a/src/indent.c +++ b/src/indent.c @@ -284,7 +284,7 @@ skip_invisible (EMACS_INT pos, EMACS_INT *next_boundary_p, EMACS_INT to, Lisp_Ob else \ { \ if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch))) \ - width = ASIZE (DISP_CHAR_VECTOR (dp, ch)); \ + width = sanitize_char_width (ASIZE (DISP_CHAR_VECTOR (dp, ch))); \ else \ width = CHAR_WIDTH (ch); \ } \ -- cgit v1.2.3 From e097a6fa863b26952a476e71a786fa7b2460277b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jul 2011 20:34:13 -0700 Subject: * charset.c (Fdefine_charset_internal): Check for integer overflow. Add a FIXME comment about memory leaks. (syms_of_charset): Don't assume xmalloc returns. --- src/ChangeLog | 4 ++++ src/charset.c | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 54ce0c8df4..4a9e03d5da 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-19 Paul Eggert + * charset.c (Fdefine_charset_internal): Check for integer overflow. + Add a FIXME comment about memory leaks. + (syms_of_charset): Don't assume xmalloc returns. + Don't assume that stated character widths fit in int. * character.c (Fchar_width, c_string_width, lisp_string_width): * character.h (CHAR_WIDTH): diff --git a/src/charset.c b/src/charset.c index e2bfcd0867..852aeb19bc 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1150,13 +1150,28 @@ usage: (define-charset-internal ...) */) hash_code); if (charset_table_used == charset_table_size) { - struct charset *new_table + struct charset *new_table; + /* Ensure that charset IDs fit into 'int' as well as into the + restriction imposed by fixnums, ptrdiff_t, and size_t. + Although the 'int' restriction could be removed, too much other + code would need altering; for example, the IDs are stuffed into + struct coding_system.charbuf[i] entries, which are 'int'. */ + int charset_table_size_max = + min (min (INT_MAX, MOST_POSITIVE_FIXNUM), + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct charset)); + if (charset_table_size_max - 16 < charset_table_size) + memory_full (SIZE_MAX); + new_table = (struct charset *) xmalloc (sizeof (struct charset) * (charset_table_size + 16)); memcpy (new_table, charset_table, sizeof (struct charset) * charset_table_size); charset_table_size += 16; charset_table = new_table; + /* FIXME: Doesn't this leak memory? The old charset_table + becomes unreachable. If the memory leak is intentional, + a comment should be added to explain this. If not, the + old charset_table should be freed, using xfree. */ } id = charset_table_used++; new_definition_p = 1; @@ -2347,9 +2362,8 @@ syms_of_charset (void) Vcharset_hash_table = Fmake_hash_table (2, args); } + charset_table = (struct charset *) xmalloc (sizeof (struct charset) * 128); charset_table_size = 128; - charset_table = ((struct charset *) - xmalloc (sizeof (struct charset) * charset_table_size)); charset_table_used = 0; defsubr (&Scharsetp); -- cgit v1.2.3 From d3411f89d34bd1009cae738f917abf477be09882 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jul 2011 23:07:07 -0700 Subject: Use ptrdiff_t for hash table indexes. * category.c (hash_get_category_set): * ccl.c (ccl_driver): * charset.h (struct charset.hash_index, CHECK_CHARSET_GET_ID): * coding.c (coding_system_charset_list, detect_coding_system): * coding.h (struct coding_system.id): * composite.c (get_composition_id, gstring_lookup_cache): * fns.c (hash_lookup, hash_put, Fgethash, Fputhash): * image.c (xpm_get_color_table_h): * lisp.h (hash_lookup, hash_put): * minibuf.c (Ftest_completion): Use ptrdiff_t for hash table indexes, not int (which is too narrow, on 64-bit hosts) or EMACS_INT (which is too wide, on 32-bit --with-wide-int hosts). --- src/ChangeLog | 15 +++++++++++++++ src/category.c | 2 +- src/ccl.c | 4 ++-- src/charset.h | 4 ++-- src/coding.c | 4 ++-- src/coding.h | 2 +- src/composite.c | 4 ++-- src/fns.c | 12 ++++++------ src/image.c | 4 ++-- src/lisp.h | 4 ++-- src/minibuf.c | 2 +- 11 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 4a9e03d5da..cf75596f42 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,20 @@ 2011-07-19 Paul Eggert + Use ptrdiff_t for hash table indexes. + * category.c (hash_get_category_set): + * ccl.c (ccl_driver): + * charset.h (struct charset.hash_index, CHECK_CHARSET_GET_ID): + * coding.c (coding_system_charset_list, detect_coding_system): + * coding.h (struct coding_system.id): + * composite.c (get_composition_id, gstring_lookup_cache): + * fns.c (hash_lookup, hash_put, Fgethash, Fputhash): + * image.c (xpm_get_color_table_h): + * lisp.h (hash_lookup, hash_put): + * minibuf.c (Ftest_completion): + Use ptrdiff_t for hash table indexes, not int (which is too + narrow, on 64-bit hosts) or EMACS_INT (which is too wide, on + 32-bit --with-wide-int hosts). + * charset.c (Fdefine_charset_internal): Check for integer overflow. Add a FIXME comment about memory leaks. (syms_of_charset): Don't assume xmalloc returns. diff --git a/src/category.c b/src/category.c index 08eadb0473..a822bb654b 100644 --- a/src/category.c +++ b/src/category.c @@ -67,7 +67,7 @@ static Lisp_Object hash_get_category_set (Lisp_Object table, Lisp_Object category_set) { struct Lisp_Hash_Table *h; - EMACS_INT i; + ptrdiff_t i; EMACS_UINT hash; if (NILP (XCHAR_TABLE (table)->extras[1])) diff --git a/src/ccl.c b/src/ccl.c index 9cfcbfe870..087c0feb4a 100644 --- a/src/ccl.c +++ b/src/ccl.c @@ -1303,7 +1303,7 @@ ccl_driver (struct ccl_program *ccl, int *source, int *destination, int src_size case CCL_LookupIntConstTbl: { - EMACS_INT eop; + ptrdiff_t eop; struct Lisp_Hash_Table *h; GET_CCL_RANGE (eop, ccl_prog, ic++, 0, (VECTORP (Vtranslation_hash_table_vector) @@ -1329,7 +1329,7 @@ ccl_driver (struct ccl_program *ccl, int *source, int *destination, int src_size case CCL_LookupCharConstTbl: { - EMACS_INT eop; + ptrdiff_t eop; struct Lisp_Hash_Table *h; GET_CCL_RANGE (eop, ccl_prog, ic++, 0, (VECTORP (Vtranslation_hash_table_vector) diff --git a/src/charset.h b/src/charset.h index c2a52a38e7..be02bc0fea 100644 --- a/src/charset.h +++ b/src/charset.h @@ -148,7 +148,7 @@ struct charset int id; /* Index to Vcharset_hash_table. */ - EMACS_INT hash_index; + ptrdiff_t hash_index; /* Dimension of the charset: 1, 2, 3, or 4. */ int dimension; @@ -341,7 +341,7 @@ extern int emacs_mule_charset[256]; number of the charset. Otherwise, signal an error. */ #define CHECK_CHARSET_GET_ID(x, id) \ do { \ - int idx; \ + ptrdiff_t idx; \ \ if (! SYMBOLP (x) || (idx = CHARSET_SYMBOL_HASH_INDEX (x)) < 0) \ wrong_type_argument (Qcharsetp, (x)); \ diff --git a/src/coding.c b/src/coding.c index 65c8a767c2..73a4bbc5e2 100644 --- a/src/coding.c +++ b/src/coding.c @@ -5838,7 +5838,7 @@ coding_charset_list (struct coding_system *coding) Lisp_Object coding_system_charset_list (Lisp_Object coding_system) { - int id; + ptrdiff_t id; Lisp_Object attrs, charset_list; CHECK_CODING_SYSTEM_GET_ID (coding_system, id); @@ -8076,7 +8076,7 @@ detect_coding_system (const unsigned char *src, Lisp_Object attrs, eol_type; Lisp_Object val = Qnil; struct coding_system coding; - int id; + ptrdiff_t id; struct coding_detection_info detect_info; enum coding_category base_category; int null_byte_found = 0, eight_bit_found = 0; diff --git a/src/coding.h b/src/coding.h index 85e153dcc3..fdf9b762e7 100644 --- a/src/coding.h +++ b/src/coding.h @@ -415,7 +415,7 @@ struct coding_system setup_coding_system. At the early stage of building time, this value is -1 in the array coding_categories to indicate that no coding-system of that category is yet defined. */ - int id; + ptrdiff_t id; /* Flag bits of the coding system. The meaning of each bit is common to all types of coding systems. */ diff --git a/src/composite.c b/src/composite.c index d402d5ad0c..43041f7b38 100644 --- a/src/composite.c +++ b/src/composite.c @@ -179,7 +179,7 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars, Lisp_Object id, length, components, key, *key_contents; int glyph_len; struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table); - EMACS_INT hash_index; + ptrdiff_t hash_index; EMACS_UINT hash_code; struct composition *cmp; EMACS_INT i; @@ -656,7 +656,7 @@ static Lisp_Object gstring_lookup_cache (Lisp_Object header) { struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); - EMACS_INT i = hash_lookup (h, header, NULL); + ptrdiff_t i = hash_lookup (h, header, NULL); return (i >= 0 ? HASH_VALUE (h, i) : Qnil); } diff --git a/src/fns.c b/src/fns.c index 9c9d19fe26..fdaffe947a 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3787,11 +3787,11 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) the hash code of KEY. Value is the index of the entry in H matching KEY, or -1 if not found. */ -EMACS_INT +ptrdiff_t hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash) { EMACS_UINT hash_code; - EMACS_INT start_of_bucket; + ptrdiff_t start_of_bucket; Lisp_Object idx; hash_code = h->hashfn (h, key); @@ -3821,11 +3821,11 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash) HASH is a previously computed hash code of KEY. Value is the index of the entry in H matching KEY. */ -EMACS_INT +ptrdiff_t hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value, EMACS_UINT hash) { - EMACS_INT start_of_bucket, i; + ptrdiff_t start_of_bucket, i; xassert ((hash & ~INTMASK) == 0); @@ -4482,7 +4482,7 @@ If KEY is not found, return DFLT which defaults to nil. */) (Lisp_Object key, Lisp_Object table, Lisp_Object dflt) { struct Lisp_Hash_Table *h = check_hash_table (table); - EMACS_INT i = hash_lookup (h, key, NULL); + ptrdiff_t i = hash_lookup (h, key, NULL); return i >= 0 ? HASH_VALUE (h, i) : dflt; } @@ -4494,7 +4494,7 @@ VALUE. In any case, return VALUE. */) (Lisp_Object key, Lisp_Object value, Lisp_Object table) { struct Lisp_Hash_Table *h = check_hash_table (table); - EMACS_INT i; + ptrdiff_t i; EMACS_UINT hash; i = hash_lookup (h, key, &hash); diff --git a/src/image.c b/src/image.c index 3a58be5d85..974c525c4e 100644 --- a/src/image.c +++ b/src/image.c @@ -3807,8 +3807,8 @@ xpm_get_color_table_h (Lisp_Object color_table, int chars_len) { struct Lisp_Hash_Table *table = XHASH_TABLE (color_table); - int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len), - NULL); + ptrdiff_t i = + hash_lookup (table, make_unibyte_string (chars_start, chars_len), NULL); return i >= 0 ? HASH_VALUE (table, i) : Qnil; } diff --git a/src/lisp.h b/src/lisp.h index 1e141dbb5d..2d32604361 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2562,8 +2562,8 @@ EMACS_UINT sxhash (Lisp_Object, int); Lisp_Object make_hash_table (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); -EMACS_INT hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); -EMACS_INT hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object, +ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); +ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object, EMACS_UINT); void init_weak_hash_tables (void); extern void init_fns (void); diff --git a/src/minibuf.c b/src/minibuf.c index cf37c337be..951bf028c3 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -1713,7 +1713,7 @@ the values STRING, PREDICATE and `lambda'. */) (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) { Lisp_Object regexps, tail, tem = Qnil; - EMACS_INT i = 0; + ptrdiff_t i = 0; CHECK_STRING (string); -- cgit v1.2.3 From ebfa62c01481332072f519581aaf4d8d7da49e68 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 Jul 2011 14:39:36 -0700 Subject: Use ptrdiff_t for composition IDs. * character.c (lisp_string_width): * composite.c (composition_table_size, n_compositions) (get_composition_id, composition_gstring_from_id): * dispextern.h (struct glyph_string.cmp_id, struct composition_it.id): * xdisp.c (BUILD_COMPOSITE_GLYPH_STRING): * window.c (Frecenter): Use ptrdiff_t, not int, for composition IDs. * composite.c (get_composition_id): Check for integer overflow. * composite.h: Adjust prototypes to match the above changes. --- src/ChangeLog | 11 +++++++++++ src/character.c | 2 +- src/composite.c | 22 +++++++++++++--------- src/composite.h | 8 ++++---- src/dispextern.h | 4 ++-- src/window.c | 2 +- src/xdisp.c | 2 +- 7 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 30af92a57e..b3125b2c18 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,16 @@ 2011-07-19 Paul Eggert + Use ptrdiff_t for composition IDs. + * character.c (lisp_string_width): + * composite.c (composition_table_size, n_compositions) + (get_composition_id, composition_gstring_from_id): + * dispextern.h (struct glyph_string.cmp_id, struct composition_it.id): + * xdisp.c (BUILD_COMPOSITE_GLYPH_STRING): + * window.c (Frecenter): + Use ptrdiff_t, not int, for composition IDs. + * composite.c (get_composition_id): Check for integer overflow. + * composite.h: Adjust prototypes to match the above changes. + Use ptrdiff_t for hash table indexes. * category.c (hash_get_category_set): * ccl.c (ccl_driver): diff --git a/src/character.c b/src/character.c index c2f23e0d8e..5e2eccf54d 100644 --- a/src/character.c +++ b/src/character.c @@ -423,7 +423,7 @@ lisp_string_width (Lisp_Object string, EMACS_INT precision, { EMACS_INT chars, bytes, thiswidth; Lisp_Object val; - int cmp_id; + ptrdiff_t cmp_id; EMACS_INT ignore, end; if (find_composition (i, -1, &ignore, &end, &val, string) diff --git a/src/composite.c b/src/composite.c index 43041f7b38..b25699b9ff 100644 --- a/src/composite.c +++ b/src/composite.c @@ -142,10 +142,10 @@ Lisp_Object Qcomposition; struct composition **composition_table; /* The current size of `composition_table'. */ -static int composition_table_size; +static ptrdiff_t composition_table_size; /* Number of compositions currently made. */ -int n_compositions; +ptrdiff_t n_compositions; /* Hash table for compositions. The key is COMPONENTS-VEC of `composition' property. The value is the corresponding @@ -172,7 +172,7 @@ Lisp_Object composition_temp; If the composition is invalid, return -1. */ -int +ptrdiff_t get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars, Lisp_Object prop, Lisp_Object string) { @@ -260,18 +260,22 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars, /* Check if we have sufficient memory to store this information. */ if (composition_table_size == 0) { - composition_table_size = 256; composition_table - = (struct composition **) xmalloc (sizeof (composition_table[0]) - * composition_table_size); + = (struct composition **) xmalloc (sizeof (composition_table[0]) * 256); + composition_table_size = 256; } else if (composition_table_size <= n_compositions) { - composition_table_size += 256; + if ((min (MOST_POSITIVE_FIXNUM, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof composition_table[0]) + - 256) + < composition_table_size) + memory_full (SIZE_MAX); composition_table = (struct composition **) xrealloc (composition_table, sizeof (composition_table[0]) - * composition_table_size); + * (composition_table_size + 256)); + composition_table_size += 256; } key_contents = XVECTOR (key)->contents; @@ -691,7 +695,7 @@ composition_gstring_put_cache (Lisp_Object gstring, EMACS_INT len) } Lisp_Object -composition_gstring_from_id (int id) +composition_gstring_from_id (ptrdiff_t id) { struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); diff --git a/src/composite.h b/src/composite.h index 8cedfdbe35..a43e41901e 100644 --- a/src/composite.h +++ b/src/composite.h @@ -204,7 +204,7 @@ struct composition { COMPOSITION-ID. */ extern struct composition **composition_table; /* Number of the currently registered compositions. */ -extern int n_compositions; +extern ptrdiff_t n_compositions; /* Mask bits for CHECK_MASK arg to update_compositions. For a change in the region FROM and TO, check compositions ... */ @@ -216,8 +216,8 @@ extern int n_compositions; extern Lisp_Object Qcomposition; extern Lisp_Object composition_hash_table; -extern int get_composition_id (EMACS_INT, EMACS_INT, EMACS_INT, - Lisp_Object, Lisp_Object); +extern ptrdiff_t get_composition_id (EMACS_INT, EMACS_INT, EMACS_INT, + Lisp_Object, Lisp_Object); extern int find_composition (EMACS_INT, EMACS_INT, EMACS_INT *, EMACS_INT *, Lisp_Object *, Lisp_Object); extern void update_compositions (EMACS_INT, EMACS_INT, int); @@ -299,7 +299,7 @@ struct face; struct font_metrics; extern Lisp_Object composition_gstring_put_cache (Lisp_Object, EMACS_INT); -extern Lisp_Object composition_gstring_from_id (int); +extern Lisp_Object composition_gstring_from_id (ptrdiff_t); extern int composition_gstring_p (Lisp_Object); extern int composition_gstring_width (Lisp_Object, EMACS_INT, EMACS_INT, struct font_metrics *); diff --git a/src/dispextern.h b/src/dispextern.h index bb4da7d52a..1d7bf5d53e 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1240,7 +1240,7 @@ struct glyph_string struct composition *cmp; /* If not negative, this string describes a compos. */ - int cmp_id; + ptrdiff_t cmp_id; /* Start and end glyph indices in a glyph-string. */ int cmp_from, cmp_to; @@ -2056,7 +2056,7 @@ struct composition_it EMACS_INT stop_pos; /* ID number of the composition or glyph-string. If negative, we are not iterating over a composition now. */ - int id; + ptrdiff_t id; /* If non-negative, character that triggers the automatic composition at `stop_pos', and this is an automatic composition. If negative, this is a static composition. This is set to -2 diff --git a/src/window.c b/src/window.c index 3f5a743f5c..04fea6b9bf 100644 --- a/src/window.c +++ b/src/window.c @@ -5069,7 +5069,7 @@ and redisplay normally--don't erase and redraw the frame. */) && (!EQ (Vrecenter_redisplay, Qtty) || !NILP (Ftty_type (selected_frame)))) { - int i; + ptrdiff_t i; /* Invalidate pixel data calculated for all compositions. */ for (i = 0; i < n_compositions; i++) diff --git a/src/xdisp.c b/src/xdisp.c index 43f60abb81..55296db0b8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -22002,7 +22002,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) do { \ int face_id = (row)->glyphs[area][START].face_id; \ struct face *base_face = FACE_FROM_ID (f, face_id); \ - int cmp_id = (row)->glyphs[area][START].u.cmp.id; \ + ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \ struct composition *cmp = composition_table[cmp_id]; \ XChar2b *char2b; \ struct glyph_string *first_s IF_LINT (= NULL); \ -- cgit v1.2.3 From 722e028b38b63a4f32be9670359a1344befd1578 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 Jul 2011 17:09:31 -0700 Subject: Fix incorrect comment. --- src/termhooks.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/termhooks.h b/src/termhooks.h index 6a58517a85..63d166b641 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -288,12 +288,12 @@ enum { /* The next four modifier bits are used also in keyboard events at the Lisp level. - It's probably not the greatest idea to use the 2^23 bit for any + It's probably not the greatest idea to use the 2^28 bit for any modifier. It may or may not be the sign bit, depending on - VALBITS, so using it to represent a modifier key means that + FIXNUM_BITS, so using it to represent a modifier key means that characters thus modified have different integer equivalents depending on the architecture they're running on. Oh, and - applying XINT to a character whose 2^23 bit is set sign-extends + applying XINT to a character whose 2^28 bit is set might sign-extend it, so you get a bunch of bits in the mask you didn't want. The CHAR_ macros are defined in lisp.h. */ -- cgit v1.2.3 From f7912160c498869e56edc5472b94106fd772fb8d Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 22 Jul 2011 11:23:10 -0400 Subject: Merge fix for Bug#4238 from trunk --- src/ChangeLog | 5 +++++ src/frame.c | 8 +++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 84280a9a90..09a6180e79 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2011-07-22 Chong Yidong + + * frame.c (Fmodify_frame_parameters): In tty case, update the + default face if necessary (Bug#4238). + 2011-07-11 YAMAMOTO Mitsuharu * s/darwin.h (LD_SWITCH_SYSTEM_TEMACS): Add -fno-pie so as to suppress diff --git a/src/frame.c b/src/frame.c index f1cc0ce019..a568342966 100644 --- a/src/frame.c +++ b/src/frame.c @@ -2606,11 +2606,9 @@ use is not recommended. Explicitly check for a frame-parameter instead. */) val = values[i]; store_frame_param (f, prop, val); - /* Changing the background color might change the background - mode, so that we have to load new defface specs. - Call frame-set-background-mode to do that. */ - if (EQ (prop, Qbackground_color)) - call1 (Qframe_set_background_mode, frame); + if (EQ (prop, Qforeground_color) + || EQ (prop, Qbackground_color)) + update_face_from_frame_parameter (f, prop, val); } } return Qnil; -- cgit v1.2.3 From 7963fa061a06d3d3c3bd396246fbb17e6aad9f67 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 23 Jul 2011 13:04:58 +0900 Subject: Support LC_FUNCTION_STARTS load command on Darwin. --- src/ChangeLog | 7 +++++++ src/unexmacosx.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/ChangeLog b/src/ChangeLog index 09a6180e79..62424f794c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2011-07-23 YAMAMOTO Mitsuharu + + * unexmacosx.c (print_load_command_name): Add cases LC_FUNCTION_STARTS + and LC_VERSION_MIN_MACOSX. + (copy_linkedit_data) [LC_FUNCTION_STARTS]: New function. + (dump_it) [LC_FUNCTION_STARTS]: Use it. + 2011-07-22 Chong Yidong * frame.c (Fmodify_frame_parameters): In tty case, update the diff --git a/src/unexmacosx.c b/src/unexmacosx.c index d6f170c912..e4d0314ce8 100644 --- a/src/unexmacosx.c +++ b/src/unexmacosx.c @@ -589,6 +589,16 @@ print_load_command_name (int lc) case LC_DYLD_INFO_ONLY: printf ("LC_DYLD_INFO_ONLY"); break; +#endif +#ifdef LC_VERSION_MIN_MACOSX + case LC_VERSION_MIN_MACOSX: + printf ("LC_VERSION_MIN_MACOSX"); + break; +#endif +#ifdef LC_FUNCTION_STARTS + case LC_FUNCTION_STARTS: + printf ("LC_FUNCTION_STARTS"); + break; #endif default: printf ("unknown "); @@ -1126,6 +1136,28 @@ copy_dyld_info (struct load_command *lc, long delta) } #endif +#ifdef LC_FUNCTION_STARTS +/* Copy a LC_FUNCTION_STARTS load command from the input file to the + output file, adjusting the data offset field. */ +static void +copy_linkedit_data (struct load_command *lc, long delta) +{ + struct linkedit_data_command *ldp = (struct linkedit_data_command *) lc; + + if (ldp->dataoff > 0) + ldp->dataoff += delta; + + printf ("Writing "); + print_load_command_name (lc->cmd); + printf (" command\n"); + + if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) + unexec_error ("cannot write linkedit data command to header"); + + curr_header_offset += lc->cmdsize; +} +#endif + /* Copy other kinds of load commands from the input file to the output file, ones that do not require adjustments of file offsets. */ static void @@ -1197,6 +1229,11 @@ dump_it () case LC_DYLD_INFO_ONLY: copy_dyld_info (lca[i], linkedit_delta); break; +#endif +#ifdef LC_FUNCTION_STARTS + case LC_FUNCTION_STARTS: + copy_linkedit_data (lca[i], linkedit_delta); + break; #endif default: copy_other (lca[i]); -- cgit v1.2.3 From ea180610badb3df580d68e444f4418dce7929d17 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 26 Jul 2011 13:00:23 +0200 Subject: * fontset.c (fontset_get_font_group): Add proper type checks. (Bug#9172) --- src/ChangeLog | 5 +++++ src/fontset.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 62424f794c..0587a414ac 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2011-07-26 Andreas Schwab + + * fontset.c (fontset_get_font_group): Add proper type checks. + (Bug#9172) + 2011-07-23 YAMAMOTO Mitsuharu * unexmacosx.c (print_load_command_name): Add cases LC_FUNCTION_STARTS diff --git a/src/fontset.c b/src/fontset.c index 82e46c7434..c335a5642f 100644 --- a/src/fontset.c +++ b/src/fontset.c @@ -463,7 +463,7 @@ reorder_font_vector (font_group, font) /* Return a font-group (actually a cons (-1 . FONT-GROUP-VECTOR)) for character C in FONTSET. If C is -1, return a fallback font-group. If C is not -1, the value may be Qt (FONTSET doesn't have a font - for C even in the fallback group, or 0 (a font for C may be found + for C even in the fallback group), or 0 (a font for C may be found only in the fallback group). */ static Lisp_Object @@ -481,7 +481,9 @@ fontset_get_font_group (Lisp_Object fontset, int c) if (! NILP (font_group)) return font_group; base_fontset = FONTSET_BASE (fontset); - if (c >= 0) + if (NILP (base_fontset)) + font_group = Qnil; + else if (c >= 0) font_group = char_table_ref_and_range (base_fontset, c, &from, &to); else font_group = FONTSET_FALLBACK (base_fontset); @@ -492,6 +494,8 @@ fontset_get_font_group (Lisp_Object fontset, int c) char_table_set_range (fontset, from, to, font_group); return font_group; } + if (!VECTORP (font_group)) + return font_group; font_group = Fcopy_sequence (font_group); for (i = 0; i < ASIZE (font_group); i++) if (! NILP (AREF (font_group, i))) -- cgit v1.2.3 From c897048c52b767decd44fa59805f80cd71ae9050 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Thu, 28 Jul 2011 11:45:07 -0400 Subject: Backport 2010-07-03T14:42:02Z!eliz@gnu.org from trunk --- src/ChangeLog | 6 ++++++ src/xfaces.c | 64 ++++++++++++++++++++++++++++++----------------------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 0587a414ac..1c2218f9d9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2011-07-28 Eli Zaretskii + + * xfaces.c (update_face_from_frame_parameter): Move out of + HAVE_WINDOW_SYSTEM portion. Condition window-system only parts + with HAVE_WINDOW_SYSTEM. + 2011-07-26 Andreas Schwab * fontset.c (fontset_get_font_group): Add proper type checks. diff --git a/src/xfaces.c b/src/xfaces.c index 1606113596..70850cc8a3 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -3490,37 +3490,6 @@ FRAME 0 means change the face on all frames, and change the default } -#ifdef HAVE_WINDOW_SYSTEM - -/* Set the `font' frame parameter of FRAME determined from the - font-object set in `default' face attributes LFACE. */ - -static void -set_font_frame_param (frame, lface) - Lisp_Object frame, lface; -{ - struct frame *f = XFRAME (frame); - Lisp_Object font; - - if (FRAME_WINDOW_P (f) - /* Don't do anything if the font is `unspecified'. This can - happen during frame creation. */ - && (font = LFACE_FONT (lface), - ! UNSPECIFIEDP (font))) - { - if (FONT_SPEC_P (font)) - { - font = font_load_for_lface (f, XVECTOR (lface)->contents, font); - if (NILP (font)) - return; - LFACE_FONT (lface) = font; - } - f->default_face_done_p = 0; - Fmodify_frame_parameters (frame, Fcons (Fcons (Qfont, font), Qnil)); - } -} - - /* Update the corresponding face when frame parameter PARAM on frame F has been assigned the value NEW_VALUE. */ @@ -3562,6 +3531,7 @@ update_face_from_frame_parameter (f, param, new_value) ? new_value : Qunspecified); realize_basic_faces (f); } +#ifdef HAVE_WINDOW_SYSTEM else if (EQ (param, Qborder_color)) { face = Qborder; @@ -3583,6 +3553,7 @@ update_face_from_frame_parameter (f, param, new_value) LFACE_BACKGROUND (lface) = (STRINGP (new_value) ? new_value : Qunspecified); } +#endif /* Changing a named face means that all realized faces depending on that face are invalid. Since we cannot tell which realized faces @@ -3598,6 +3569,37 @@ update_face_from_frame_parameter (f, param, new_value) } +#ifdef HAVE_WINDOW_SYSTEM + +/* Set the `font' frame parameter of FRAME determined from the + font-object set in `default' face attributes LFACE. */ + +static void +set_font_frame_param (frame, lface) + Lisp_Object frame, lface; +{ + struct frame *f = XFRAME (frame); + Lisp_Object font; + + if (FRAME_WINDOW_P (f) + /* Don't do anything if the font is `unspecified'. This can + happen during frame creation. */ + && (font = LFACE_FONT (lface), + ! UNSPECIFIEDP (font))) + { + if (FONT_SPEC_P (font)) + { + font = font_load_for_lface (f, XVECTOR (lface)->contents, font); + if (NILP (font)) + return; + LFACE_FONT (lface) = font; + } + f->default_face_done_p = 0; + Fmodify_frame_parameters (frame, Fcons (Fcons (Qfont, font), Qnil)); + } +} + + /* Get the value of X resource RESOURCE, class CLASS for the display of frame FRAME. This is here because ordinary `x-get-resource' doesn't take a frame argument. */ -- cgit v1.2.3 From 29bbcfa7054e69db0dbe8250af2c809b39ecb54d Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 28 Jul 2011 20:40:28 +0200 Subject: Fixes: debbugs:6594 * lisp/xt-mouse.el (xterm-mouse-event-read): Try to recover the raw character. --- lisp/ChangeLog | 5 +++++ lisp/xt-mouse.el | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1b401bf758..a42c0127ff 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2011-07-28 Andreas Schwab + + * xt-mouse.el (xterm-mouse-event-read): Try to recover the raw + character. (Bug#6594) + 2011-07-12 Chong Yidong * window.el (split-window-horizontally): Doc fix (Bug#9060). diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el index 5a70e6a680..f917287d2d 100644 --- a/lisp/xt-mouse.el +++ b/lisp/xt-mouse.el @@ -121,10 +121,17 @@ ;; read xterm sequences above ascii 127 (#x7f) (defun xterm-mouse-event-read () + ;; We get the characters decoded by the keyboard coding system. Try + ;; to recover the raw character. (let ((c (read-char))) - (if (> c #x3FFF80) - (+ 128 (- c #x3FFF80)) - c))) + (cond ;; If meta-flag is t we get a meta character + ((>= c ?\M-\^@) + (- c (- ?\M-\^@ 128))) + ;; Reencode the character in the keyboard coding system, if + ;; this is a non-ASCII character. + ((>= c #x80) + (aref (encode-coding-string (string c) (keyboard-coding-system)) 0)) + (t c)))) (defun xterm-mouse-truncate-wrap (f) "Truncate with wrap-around." -- cgit v1.2.3 From bc18e09ddf639fbd59e6d2ef238fdaf4e31fb6a3 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:27:41 -0700 Subject: * bidi.c: Integer overflow fix. (bidi_shelve_header_size): New constant. (bidi_cache_ensure_space, bidi_shelve_cache): Use it. (bidi_cache_ensure_space): Avoid integer overflow when allocating. --- src/ChangeLog | 7 +++++++ src/bidi.c | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index b3125b2c18..0d5b41ea20 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2011-07-28 Paul Eggert + + * bidi.c: Integer overflow fix. + (bidi_shelve_header_size): New constant. + (bidi_cache_ensure_space, bidi_shelve_cache): Use it. + (bidi_cache_ensure_space): Avoid integer overflow when allocating. + 2011-07-19 Paul Eggert Use ptrdiff_t for composition IDs. diff --git a/src/bidi.c b/src/bidi.c index 697ebb9285..a1e5721f35 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -306,6 +306,21 @@ static ptrdiff_t bidi_cache_last_idx; /* slot of last cache hit */ static ptrdiff_t bidi_cache_start = 0; /* start of cache for this "stack" level */ +/* 5-slot stack for saving the start of the previous level of the + cache. xdisp.c maintains a 5-slot stack for its iterator state, + and we need the same size of our stack. */ +static ptrdiff_t bidi_cache_start_stack[IT_STACK_SIZE]; +static int bidi_cache_sp; + +/* Size of header used by bidi_shelve_cache. */ +enum + { + bidi_shelve_header_size = + (sizeof (bidi_cache_idx) + sizeof (bidi_cache_start_stack) + + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) + + sizeof (bidi_cache_last_idx)) + }; + /* Reset the cache state to the empty state. We only reset the part of the cache relevant to iteration of the current object. Previous objects, which are pushed on the display iterator's stack, are left @@ -471,7 +486,8 @@ bidi_cache_ensure_space (ptrdiff_t idx) max (BUF_BYTES_MAX, STRING_BYTES_BOUND); /* Also, it cannot be larger than what C can represent. */ - ptrdiff_t c_bound = min (PTRDIFF_MAX, SIZE_MAX) / elsz; + ptrdiff_t c_bound = + (min (PTRDIFF_MAX, SIZE_MAX) - bidi_shelve_header_size) / elsz; if (min (string_or_buffer_bound, c_bound) <= idx) memory_full (SIZE_MAX); @@ -568,11 +584,6 @@ bidi_peek_at_next_level (struct bidi_it *bidi_it) /*********************************************************************** Pushing and popping the bidi iterator state ***********************************************************************/ -/* 5-slot stack for saving the start of the previous level of the - cache. xdisp.c maintains a 5-slot stack for its iterator state, - and we need the same size of our stack. */ -static ptrdiff_t bidi_cache_start_stack[IT_STACK_SIZE]; -static int bidi_cache_sp; /* Push the bidi iterator state in preparation for reordering a different object, e.g. display string found at certain buffer @@ -629,11 +640,8 @@ bidi_shelve_cache (void) if (bidi_cache_idx == 0) return NULL; - databuf = xmalloc (sizeof (bidi_cache_idx) - + bidi_cache_idx * sizeof (struct bidi_it) - + sizeof (bidi_cache_start_stack) - + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) - + sizeof (bidi_cache_last_idx)); + databuf = xmalloc (bidi_shelve_header_size + + bidi_cache_idx * sizeof (struct bidi_it)); memcpy (databuf, &bidi_cache_idx, sizeof (bidi_cache_idx)); memcpy (databuf + sizeof (bidi_cache_idx), bidi_cache, bidi_cache_idx * sizeof (struct bidi_it)); -- cgit v1.2.3 From 6e1fc4528b8dcb84ba7d173f6c350cfba5385634 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:28:33 -0700 Subject: * buffer.c: Memory overflow fixes. (overlays_at, overlays_in, record_overlay_string, overlay_strings): Don't update size of array until after memory allocation succeeds, because xmalloc/xrealloc may not return. --- src/ChangeLog | 5 +++++ src/buffer.c | 21 +++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 0d5b41ea20..ff5dfc0933 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-28 Paul Eggert + * buffer.c: Memory overflow fixes. + (overlays_at, overlays_in, record_overlay_string, overlay_strings): + Don't update size of array until after memory allocation succeeds, + because xmalloc/xrealloc may not return. + * bidi.c: Integer overflow fix. (bidi_shelve_header_size): New constant. (bidi_cache_ensure_space, bidi_shelve_cache): Use it. diff --git a/src/buffer.c b/src/buffer.c index a40275db8d..fc9d3b5bd4 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2572,9 +2572,9 @@ overlays_at (EMACS_INT pos, int extend, Lisp_Object **vec_ptr, memory_full (SIZE_MAX); /* Make it work with an initial len == 0. */ len = len * 2 + 4; - *len_ptr = len; vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object)); *vec_ptr = vec; + *len_ptr = len; } else inhibit_storing = 1; @@ -2615,9 +2615,9 @@ overlays_at (EMACS_INT pos, int extend, Lisp_Object **vec_ptr, memory_full (SIZE_MAX); /* Make it work with an initial len == 0. */ len = len * 2 + 4; - *len_ptr = len; vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object)); *vec_ptr = vec; + *len_ptr = len; } else inhibit_storing = 1; @@ -2712,9 +2712,9 @@ overlays_in (EMACS_INT beg, EMACS_INT end, int extend, memory_full (SIZE_MAX); /* Make it work with an initial len == 0. */ len = len * 2 + 4; - *len_ptr = len; vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object)); *vec_ptr = vec; + *len_ptr = len; } else inhibit_storing = 1; @@ -2760,9 +2760,9 @@ overlays_in (EMACS_INT beg, EMACS_INT end, int extend, memory_full (SIZE_MAX); /* Make it work with an initial len == 0. */ len = len * 2 + 4; - *len_ptr = len; vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object)); *vec_ptr = vec; + *len_ptr = len; } else inhibit_storing = 1; @@ -2978,15 +2978,12 @@ record_overlay_string (struct sortstrlist *ssl, Lisp_Object str, if (ssl->used == ssl->size) { - if (min (PTRDIFF_MAX, SIZE_MAX) / (sizeof (struct sortstr) * 2) - < ssl->size) + ptrdiff_t ssl_size = 0 < ssl->size ? ssl->size * 2 : 5; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct sortstr) < ssl_size) memory_full (SIZE_MAX); - else if (0 < ssl->size) - ssl->size *= 2; - else - ssl->size = 5; ssl->buf = ((struct sortstr *) - xrealloc (ssl->buf, ssl->size * sizeof (struct sortstr))); + xrealloc (ssl->buf, ssl_size * sizeof (struct sortstr))); + ssl->size = ssl_size; } ssl->buf[ssl->used].string = str; ssl->buf[ssl->used].string2 = str2; @@ -3111,9 +3108,9 @@ overlay_strings (EMACS_INT pos, struct window *w, unsigned char **pstr) if (total > overlay_str_len) { - overlay_str_len = total; overlay_str_buf = (unsigned char *)xrealloc (overlay_str_buf, total); + overlay_str_len = total; } p = overlay_str_buf; for (i = overlay_tails.used; --i >= 0;) -- cgit v1.2.3 From 860887db5c3c55a502795d89d43176783e0e313d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:29:09 -0700 Subject: * callproc.c (child_setup): Don't assume strlen fits in int. --- src/ChangeLog | 2 ++ src/callproc.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index ff5dfc0933..9b9a968625 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-28 Paul Eggert + * callproc.c (child_setup): Don't assume strlen fits in int. + * buffer.c: Memory overflow fixes. (overlays_at, overlays_in, record_overlay_string, overlay_strings): Don't update size of array until after memory allocation succeeds, diff --git a/src/callproc.c b/src/callproc.c index ad3eddbdd3..13d1232a34 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -1145,9 +1145,11 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L cleaned up in the usual way. */ { register char *temp; - register int i; + register ptrdiff_t i; i = SBYTES (current_dir); + if (min (PTRDIFF_MAX, SIZE_MAX) - 6 < i) + memory_full (SIZE_MAX); #ifdef MSDOS /* MSDOS must have all environment variables malloc'ed, because low-level libc functions that launch subsidiary processes rely -- cgit v1.2.3 From 69e8622f7f852f63b8f71c5b1aa4c2fd406e383d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:29:44 -0700 Subject: * ccl.c: Integer and memory overflow fixes. (Fccl_execute_on_string): Check for memory overflow. Use ptrdiff_t rather than EMACS_INT where ptrdiff_t will do. Redo buffer-overflow calculations to avoid integer overflow. --- src/ChangeLog | 5 +++++ src/ccl.c | 35 ++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 9b9a968625..b35f560761 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-28 Paul Eggert + * ccl.c: Integer and memory overflow fixes. + (Fccl_execute_on_string): Check for memory overflow. + Use ptrdiff_t rather than EMACS_INT where ptrdiff_t will do. + Redo buffer-overflow calculations to avoid integer overflow. + * callproc.c (child_setup): Don't assume strlen fits in int. * buffer.c: Memory overflow fixes. diff --git a/src/ccl.c b/src/ccl.c index 087c0feb4a..0a9b3d9070 100644 --- a/src/ccl.c +++ b/src/ccl.c @@ -2061,12 +2061,12 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING &optional CONTINUE UNIBY Lisp_Object val; struct ccl_program ccl; int i; - EMACS_INT outbufsize; + ptrdiff_t outbufsize; unsigned char *outbuf, *outp; - EMACS_INT str_chars, str_bytes; + ptrdiff_t str_chars, str_bytes; #define CCL_EXECUTE_BUF_SIZE 1024 int source[CCL_EXECUTE_BUF_SIZE], destination[CCL_EXECUTE_BUF_SIZE]; - EMACS_INT consumed_chars, consumed_bytes, produced_chars; + ptrdiff_t consumed_chars, consumed_bytes, produced_chars; if (setup_ccl_program (&ccl, ccl_prog) < 0) error ("Invalid CCL program"); @@ -2093,6 +2093,10 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING &optional CONTINUE UNIBY ccl.ic = i; } + if (((min (PTRDIFF_MAX, SIZE_MAX) - 256) + / (ccl.buf_magnification ? ccl.buf_magnification : 1)) + < str_bytes) + memory_full (SIZE_MAX); outbufsize = (ccl.buf_magnification ? str_bytes * ccl.buf_magnification + 256 : str_bytes + 256); @@ -2127,11 +2131,19 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING &optional CONTINUE UNIBY produced_chars += ccl.produced; if (NILP (unibyte_p)) { - if (outp - outbuf + MAX_MULTIBYTE_LENGTH * ccl.produced - > outbufsize) + ptrdiff_t offset = outp - outbuf; + if ((outbufsize - offset) / MAX_MULTIBYTE_LENGTH < ccl.produced) { - EMACS_INT offset = outp - outbuf; - outbufsize += MAX_MULTIBYTE_LENGTH * ccl.produced; + ptrdiff_t produced; + if (((min (PTRDIFF_MAX, SIZE_MAX) - outbufsize) + / MAX_MULTIBYTE_LENGTH) + < ccl.produced) + { + xfree (outbuf); + memory_full (SIZE_MAX); + } + produced = ccl.produced; + outbufsize += MAX_MULTIBYTE_LENGTH * produced; outbuf = (unsigned char *) xrealloc (outbuf, outbufsize); outp = outbuf + offset; } @@ -2140,9 +2152,14 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING &optional CONTINUE UNIBY } else { - if (outp - outbuf + ccl.produced > outbufsize) + ptrdiff_t offset = outp - outbuf; + if (outbufsize - offset < ccl.produced) { - EMACS_INT offset = outp - outbuf; + if (min (PTRDIFF_MAX, SIZE_MAX) - outbufsize < ccl.produced) + { + xfree (outbuf); + memory_full (SIZE_MAX); + } outbufsize += ccl.produced; outbuf = (unsigned char *) xrealloc (outbuf, outbufsize); outp = outbuf + offset; -- cgit v1.2.3 From 17828df2d81aef1c7886cddd881ad6f67f1e4abe Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:30:20 -0700 Subject: * character.c (Fstring): Check for size-calculation overflow. --- src/ChangeLog | 2 ++ src/character.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/ChangeLog b/src/ChangeLog index b35f560761..9f50e928fa 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-28 Paul Eggert + * character.c (Fstring): Check for size-calculation overflow. + * ccl.c: Integer and memory overflow fixes. (Fccl_execute_on_string): Check for memory overflow. Use ptrdiff_t rather than EMACS_INT where ptrdiff_t will do. diff --git a/src/character.c b/src/character.c index 5e2eccf54d..50b5b25287 100644 --- a/src/character.c +++ b/src/character.c @@ -902,6 +902,8 @@ usage: (string &rest CHARACTERS) */) Lisp_Object str; USE_SAFE_ALLOCA; + if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < n) + memory_full (SIZE_MAX); SAFE_ALLOCA (buf, unsigned char *, MAX_MULTIBYTE_LENGTH * n); p = buf; -- cgit v1.2.3 From 5d009b3a6a39627db04094e8164df6bb6231b991 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:31:29 -0700 Subject: * coding.c: Integer and memory overflow fixes. (produce_chars): Redo buffer-overflow calculations to avoid unnecessary integer overflow. Check for size overflow. (encode_coding_object): Don't update size until xmalloc succeeds. --- src/ChangeLog | 5 +++++ src/coding.c | 13 ++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 9f50e928fa..d86ae36027 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-28 Paul Eggert + * coding.c: Integer and memory overflow fixes. + (produce_chars): Redo buffer-overflow calculations to avoid + unnecessary integer overflow. Check for size overflow. + (encode_coding_object): Don't update size until xmalloc succeeds. + * character.c (Fstring): Check for size-calculation overflow. * ccl.c: Integer and memory overflow fixes. diff --git a/src/coding.c b/src/coding.c index 73a4bbc5e2..5fd59d394d 100644 --- a/src/coding.c +++ b/src/coding.c @@ -6683,8 +6683,12 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table, break; } - if (dst + MAX_MULTIBYTE_LENGTH * to_nchars > dst_end) + if ((dst_end - dst) / MAX_MULTIBYTE_LENGTH < to_nchars) { + if (((min (PTRDIFF_MAX, SIZE_MAX) - (buf_end - buf)) + / MAX_MULTIBYTE_LENGTH) + < to_nchars) + memory_full (SIZE_MAX); dst = alloc_destination (coding, buf_end - buf + MAX_MULTIBYTE_LENGTH * to_nchars, @@ -7888,11 +7892,10 @@ encode_coding_object (struct coding_system *coding, } else if (EQ (dst_object, Qt)) { + ptrdiff_t dst_bytes = max (1, coding->src_chars); coding->dst_object = Qnil; - coding->dst_bytes = coding->src_chars; - if (coding->dst_bytes == 0) - coding->dst_bytes = 1; - coding->destination = (unsigned char *) xmalloc (coding->dst_bytes); + coding->destination = (unsigned char *) xmalloc (dst_bytes); + coding->dst_bytes = dst_bytes; coding->dst_multibyte = 0; } else -- cgit v1.2.3 From d86d0d747f5d23db6cecfbf9385c4db1fb3c6545 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:35:09 -0700 Subject: * composite.c: Integer overflow fixes. (get_composition_id): Check for overflow in glyph length calculations. --- src/ChangeLog | 3 +++ src/composite.c | 34 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index d86ae36027..78b3b97b2d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,8 @@ 2011-07-28 Paul Eggert + * composite.c: Integer overflow fixes. + (get_composition_id): Check for overflow in glyph length calculations. + * coding.c: Integer and memory overflow fixes. (produce_chars): Redo buffer-overflow calculations to avoid unnecessary integer overflow. Check for size overflow. diff --git a/src/composite.c b/src/composite.c index b25699b9ff..4ae1d6ebb6 100644 --- a/src/composite.c +++ b/src/composite.c @@ -177,14 +177,24 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars, Lisp_Object prop, Lisp_Object string) { Lisp_Object id, length, components, key, *key_contents; - int glyph_len; + ptrdiff_t glyph_len; struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table); ptrdiff_t hash_index; EMACS_UINT hash_code; + enum composition_method method; struct composition *cmp; EMACS_INT i; int ch; + /* Maximum length of a string of glyphs. XftGlyphExtents limits this + to INT_MAX, and Emacs may limit it further. */ + enum { + glyph_len_max = + min (INT_MAX, + (min (PTRDIFF_MAX, SIZE_MAX) + / max (MAX_MULTIBYTE_LENGTH, 2 * sizeof (short)))) + }; + /* PROP should be Form-A: ((LENGTH . COMPONENTS) . MODIFICATION-FUNC) or @@ -320,18 +330,24 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars, /* Register the composition in composition_hash_table. */ hash_index = hash_put (hash_table, key, id, hash_code); + method = (NILP (components) + ? COMPOSITION_RELATIVE + : ((INTEGERP (components) || STRINGP (components)) + ? COMPOSITION_WITH_ALTCHARS + : COMPOSITION_WITH_RULE_ALTCHARS)); + + glyph_len = (method == COMPOSITION_WITH_RULE_ALTCHARS + ? (ASIZE (key) + 1) / 2 + : ASIZE (key)); + + if (glyph_len_max < glyph_len) + memory_full (SIZE_MAX); + /* Register the composition in composition_table. */ cmp = (struct composition *) xmalloc (sizeof (struct composition)); - cmp->method = (NILP (components) - ? COMPOSITION_RELATIVE - : ((INTEGERP (components) || STRINGP (components)) - ? COMPOSITION_WITH_ALTCHARS - : COMPOSITION_WITH_RULE_ALTCHARS)); + cmp->method = method; cmp->hash_index = hash_index; - glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS - ? (ASIZE (key) + 1) / 2 - : ASIZE (key)); cmp->glyph_len = glyph_len; cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2); cmp->font = NULL; -- cgit v1.2.3 From 7bd4252299e9ed464cac124ac1ff718c98396df2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 13:35:41 -0700 Subject: Fix typo in comment. --- src/composite.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/composite.h b/src/composite.h index a43e41901e..c30c683279 100644 --- a/src/composite.h +++ b/src/composite.h @@ -193,7 +193,7 @@ struct composition { void *font; /* Pointer to an array of x-offset and y-offset (by pixels) of - glyphs. This points to a sufficient memory space (sizeof (int) * + glyphs. This points to a sufficient memory space (sizeof (short) * glyph_len * 2) that is allocated when the composition is registered in composition_table. X-offset and Y-offset of Nth glyph are (2N)th and (2N+1)th elements respectively. */ -- cgit v1.2.3 From ca9ce8f2cb9d3d70c4e7d9dc9299ea4d5d71dfbc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:31:33 -0700 Subject: Integer and memory overflow fixes for display code. * dispextern.h (struct glyph_pool.nglyphs): Now ptrdiff_t, not int. * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool, scrolling_window): Check for overflow in size calculations. (line_draw_cost, realloc_glyph_pool, add_row_entry): Don't assume glyph table len fits in int. (struct row_entry.bucket, row_entry_pool_size, row_entry_idx) (row_table_size): Now ptrdiff_t, not int. (scrolling_window): Avoid overflow in size calculations. Don't update size until allocation succeeds. * fns.c (concat): Check for overflow in size calculations. (next_almost_prime): Verify NEXT_ALMOST_PRIME_LIMIT. * lisp.h (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. (NEXT_ALMOST_PRIME_LIMIT): New constant. --- src/ChangeLog | 15 ++++++++ src/dispextern.h | 2 +- src/dispnew.c | 110 ++++++++++++++++++++++++++++++++++++------------------- src/fns.c | 11 +++++- src/lisp.h | 6 +++ 5 files changed, 103 insertions(+), 41 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 78b3b97b2d..d7d32e9008 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,20 @@ 2011-07-28 Paul Eggert + Integer and memory overflow fixes for display code. + * dispextern.h (struct glyph_pool.nglyphs): Now ptrdiff_t, not int. + * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool, scrolling_window): + Check for overflow in size calculations. + (line_draw_cost, realloc_glyph_pool, add_row_entry): + Don't assume glyph table len fits in int. + (struct row_entry.bucket, row_entry_pool_size, row_entry_idx) + (row_table_size): Now ptrdiff_t, not int. + (scrolling_window): Avoid overflow in size calculations. + Don't update size until allocation succeeds. + * fns.c (concat): Check for overflow in size calculations. + (next_almost_prime): Verify NEXT_ALMOST_PRIME_LIMIT. + * lisp.h (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. + (NEXT_ALMOST_PRIME_LIMIT): New constant. + * composite.c: Integer overflow fixes. (get_composition_id): Check for overflow in glyph length calculations. diff --git a/src/dispextern.h b/src/dispextern.h index 1d7bf5d53e..70f426f95a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -575,7 +575,7 @@ struct glyph_pool struct glyph *glyphs; /* Allocated size of `glyphs'. */ - int nglyphs; + ptrdiff_t nglyphs; /* Number of rows and columns in a matrix. */ int nrows, ncolumns; diff --git a/src/dispnew.c b/src/dispnew.c index b2f416701c..4cc101d98b 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -499,7 +499,10 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y /* Enlarge MATRIX->rows if necessary. New rows are cleared. */ if (matrix->rows_allocated < dim.height) { - ptrdiff_t size = dim.height * sizeof (struct glyph_row); + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct glyph_row) < dim.height) + memory_full (SIZE_MAX); + size = dim.height * sizeof (struct glyph_row); new_rows = dim.height - matrix->rows_allocated; matrix->rows = (struct glyph_row *) xrealloc (matrix->rows, size); memset (matrix->rows + matrix->rows_allocated, 0, @@ -573,6 +576,9 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y struct glyph_row *row = matrix->rows; struct glyph_row *end = row + matrix->rows_allocated; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct glyph) < dim.width) + memory_full (SIZE_MAX); + while (row < end) { row->glyphs[LEFT_MARGIN_AREA] @@ -1217,7 +1223,7 @@ line_draw_cost (struct glyph_matrix *matrix, int vpos) struct glyph *end = beg + row->used[TEXT_AREA]; int len; Lisp_Object *glyph_table_base = GLYPH_TABLE_BASE; - int glyph_table_len = GLYPH_TABLE_LENGTH; + ptrdiff_t glyph_table_len = GLYPH_TABLE_LENGTH; /* Ignore trailing and leading spaces if we can. */ if (!FRAME_MUST_WRITE_SPACES (SELECTED_FRAME ())) /* XXX Is SELECTED_FRAME OK here? */ @@ -1391,31 +1397,26 @@ free_glyph_pool (struct glyph_pool *pool) static int realloc_glyph_pool (struct glyph_pool *pool, struct dim matrix_dim) { - int needed; + ptrdiff_t needed; int changed_p; changed_p = (pool->glyphs == 0 || matrix_dim.height != pool->nrows || matrix_dim.width != pool->ncolumns); + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct glyph) / matrix_dim.width + < matrix_dim.height) + memory_full (SIZE_MAX); + /* Enlarge the glyph pool. */ - needed = matrix_dim.width * matrix_dim.height; + needed = matrix_dim.width; + needed *= matrix_dim.height; if (needed > pool->nglyphs) { ptrdiff_t size = needed * sizeof (struct glyph); - - if (pool->glyphs) - { - pool->glyphs = (struct glyph *) xrealloc (pool->glyphs, size); - memset (pool->glyphs + pool->nglyphs, 0, - size - pool->nglyphs * sizeof (struct glyph)); - } - else - { - pool->glyphs = (struct glyph *) xmalloc (size); - memset (pool->glyphs, 0, size); - } - + pool->glyphs = (struct glyph *) xrealloc (pool->glyphs, size); + memset (pool->glyphs + pool->nglyphs, 0, + size - pool->nglyphs * sizeof (struct glyph)); pool->nglyphs = needed; } @@ -4166,7 +4167,7 @@ struct row_entry int new_line_number; /* Bucket index of this row_entry in the hash table row_table. */ - int bucket; + ptrdiff_t bucket; /* The row described by this entry. */ struct glyph_row *row; @@ -4180,18 +4181,18 @@ struct row_entry that we need a larger one. */ static struct row_entry *row_entry_pool; -static int row_entry_pool_size; +static ptrdiff_t row_entry_pool_size; /* Index of next free entry in row_entry_pool. */ -static int row_entry_idx; +static ptrdiff_t row_entry_idx; /* The hash table used during scrolling, and the table's size. This table is used to quickly identify equal rows in the desired and current matrix. */ static struct row_entry **row_table; -static int row_table_size; +static ptrdiff_t row_table_size; /* Vectors of pointers to row_entry structures belonging to the current and desired matrix, and the size of the vectors. */ @@ -4214,7 +4215,7 @@ static inline struct row_entry * add_row_entry (struct glyph_row *row) { struct row_entry *entry; - int i = row->hash % row_table_size; + ptrdiff_t i = row->hash % row_table_size; entry = row_table[i]; while (entry && !row_equal_p (entry->row, row, 1)) @@ -4267,9 +4268,10 @@ scrolling_window (struct window *w, int header_line_p) struct glyph_matrix *desired_matrix = w->desired_matrix; struct glyph_matrix *current_matrix = w->current_matrix; int yb = window_text_bottom_y (w); - int i, j, first_old, first_new, last_old, last_new; - int nruns, n, run_idx; - ptrdiff_t nbytes; + ptrdiff_t i; + int j, first_old, first_new, last_old, last_new; + int nruns, run_idx; + ptrdiff_t n, nbytes; struct row_entry *entry; struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); @@ -4354,45 +4356,77 @@ scrolling_window (struct window *w, int header_line_p) if (last_new == first_new) return 0; + /* Check for integer overflow in xrealloc size calculation. + + If next_almost_prime checks (N) for divisibility by 2..10, then + it can return at most N + 10, e.g., next_almost_prime (1) == 11. + So, set next_almost_prime_increment_max to 10. + + It's just a coincidence that next_almost_prime_increment_max == + NEXT_ALMOST_PRIME_LIMIT - 1. If NEXT_ALMOST_PRIME_LIMIT were + 13, then next_almost_prime_increment_max would be 14, e.g., + because next_almost_prime (113) would be 127. */ + { + verify (NEXT_ALMOST_PRIME_LIMIT == 11); + enum { next_almost_prime_increment_max = 10 }; + ptrdiff_t alloc_max = min (PTRDIFF_MAX, SIZE_MAX); + ptrdiff_t row_table_max = + ((alloc_max - next_almost_prime_increment_max) + / (3 * sizeof *row_table)); + ptrdiff_t row_entry_pool_max = alloc_max / sizeof *row_entry_pool; + int n_max = min (INT_MAX, min (row_table_max, row_entry_pool_max)); + ptrdiff_t old_lines_max = alloc_max / sizeof *old_lines; + int current_nrows_max = min (n_max - desired_matrix->nrows, old_lines_max); + int desired_nrows_max = + min (INT_MAX, + alloc_max / max (sizeof *new_lines, + max (sizeof *runs, sizeof *run_pool))); + if (current_nrows_max < current_matrix->nrows + || desired_nrows_max < desired_matrix->nrows) + memory_full (SIZE_MAX); + } + /* Reallocate vectors, tables etc. if necessary. */ if (current_matrix->nrows > old_lines_size) { - old_lines_size = current_matrix->nrows; - nbytes = old_lines_size * sizeof *old_lines; + nbytes = current_matrix->nrows * sizeof *old_lines; old_lines = (struct row_entry **) xrealloc (old_lines, nbytes); + old_lines_size = current_matrix->nrows; } if (desired_matrix->nrows > new_lines_size) { - new_lines_size = desired_matrix->nrows; - nbytes = new_lines_size * sizeof *new_lines; + nbytes = desired_matrix->nrows * sizeof *new_lines; new_lines = (struct row_entry **) xrealloc (new_lines, nbytes); + new_lines_size = desired_matrix->nrows; } - n = desired_matrix->nrows + current_matrix->nrows; - if (3 * n > row_table_size) + n = desired_matrix->nrows; + n += current_matrix->nrows; + if (row_table_size / 3 < n) { - row_table_size = next_almost_prime (3 * n); - nbytes = row_table_size * sizeof *row_table; + ptrdiff_t size = next_almost_prime (3 * n); + nbytes = size * sizeof *row_table; row_table = (struct row_entry **) xrealloc (row_table, nbytes); + row_table_size = size; memset (row_table, 0, nbytes); } if (n > row_entry_pool_size) { - row_entry_pool_size = n; - nbytes = row_entry_pool_size * sizeof *row_entry_pool; + nbytes = n * sizeof *row_entry_pool; row_entry_pool = (struct row_entry *) xrealloc (row_entry_pool, nbytes); + row_entry_pool_size = n; } if (desired_matrix->nrows > runs_size) { - runs_size = desired_matrix->nrows; - nbytes = runs_size * sizeof *runs; + nbytes = desired_matrix->nrows * sizeof *runs; runs = (struct run **) xrealloc (runs, nbytes); - nbytes = runs_size * sizeof *run_pool; + nbytes = desired_matrix->nrows * sizeof *run_pool; run_pool = (struct run *) xrealloc (run_pool, nbytes); + runs_size = desired_matrix->nrows; } nruns = run_idx = 0; diff --git a/src/fns.c b/src/fns.c index fdaffe947a..e5538d6acb 100644 --- a/src/fns.c +++ b/src/fns.c @@ -602,7 +602,12 @@ concat (ptrdiff_t nargs, Lisp_Object *args, prev = Qnil; if (STRINGP (val)) - SAFE_ALLOCA (textprops, struct textprop_rec *, sizeof (struct textprop_rec) * nargs); + { + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *textprops < nargs) + memory_full (SIZE_MAX); + SAFE_ALLOCA (textprops, struct textprop_rec *, + sizeof *textprops * nargs); + } for (argnum = 0; argnum < nargs; argnum++) { @@ -3395,11 +3400,13 @@ check_hash_table (Lisp_Object obj) /* Value is the next integer I >= N, N >= 0 which is "almost" a prime - number. */ + number. A number is "almost" a prime number if it is not divisible + by any integer in the range 2 .. (NEXT_ALMOST_PRIME_LIMIT - 1). */ EMACS_INT next_almost_prime (EMACS_INT n) { + verify (NEXT_ALMOST_PRIME_LIMIT == 11); for (n |= 1; ; n += 2) if (n % 3 != 0 && n % 5 != 0 && n % 7 != 0) return n; diff --git a/src/lisp.h b/src/lisp.h index 2d32604361..267bfe1b21 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -1704,6 +1704,11 @@ typedef struct { #define NUMBERP(x) (INTEGERP (x) || FLOATP (x)) #define NATNUMP(x) (INTEGERP (x) && XINT (x) >= 0) +#define RANGED_INTEGERP(lo, x, hi) \ + (INTEGERP (x) && (lo) <= XINT (x) && XINT (x) <= (hi)) +#define TYPE_RANGED_INTEGERP(type, x) \ + RANGED_INTEGERP (TYPE_MINIMUM (type), x, TYPE_MAXIMUM (type)) + #define INTEGERP(x) (LISP_INT_TAG_P (XTYPE ((x)))) #define SYMBOLP(x) (XTYPE ((x)) == Lisp_Symbol) #define MISCP(x) (XTYPE ((x)) == Lisp_Misc) @@ -2551,6 +2556,7 @@ extern void syms_of_syntax (void); /* Defined in fns.c */ extern Lisp_Object QCrehash_size, QCrehash_threshold; +enum { NEXT_ALMOST_PRIME_LIMIT = 11 }; extern EMACS_INT next_almost_prime (EMACS_INT); extern Lisp_Object larger_vector (Lisp_Object, EMACS_INT, Lisp_Object); extern void sweep_weak_hash_tables (void); -- cgit v1.2.3 From 3d0c92a26bb73fdc542e4d9e467b31fd0ad02417 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:34:39 -0700 Subject: * doc.c: Integer and memory overflow fixes. (get_doc_string_buffer_size): Now ptrdiff_t, not int. (get_doc_string): Check for size calculation overflow. Don't update size until allocation succeeds. (get_doc_string, Fsubstitute_command_keys): Use ptrdiff_t, not EMACS_INT, where ptrdiff_t will do. (Fsubstitute_command_keys): Check for string overflow. --- src/ChangeLog | 8 ++++++++ src/doc.c | 37 +++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index d7d32e9008..6cf9a1f862 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,13 @@ 2011-07-28 Paul Eggert + * doc.c: Integer and memory overflow fixes. + (get_doc_string_buffer_size): Now ptrdiff_t, not int. + (get_doc_string): Check for size calculation overflow. + Don't update size until allocation succeeds. + (get_doc_string, Fsubstitute_command_keys): Use ptrdiff_t, not + EMACS_INT, where ptrdiff_t will do. + (Fsubstitute_command_keys): Check for string overflow. + Integer and memory overflow fixes for display code. * dispextern.h (struct glyph_pool.nglyphs): Now ptrdiff_t, not int. * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool, scrolling_window): diff --git a/src/doc.c b/src/doc.c index 69646f5af5..bd1831dde0 100644 --- a/src/doc.c +++ b/src/doc.c @@ -39,7 +39,7 @@ Lisp_Object Qfunction_documentation; extern Lisp_Object Qclosure; /* Buffer used for reading from documentation file. */ static char *get_doc_string_buffer; -static int get_doc_string_buffer_size; +static ptrdiff_t get_doc_string_buffer_size; static unsigned char *read_bytecode_pointer; static Lisp_Object Fdocumentation_property (Lisp_Object, Lisp_Object, @@ -166,18 +166,23 @@ get_doc_string (Lisp_Object filepos, int unibyte, int definition) p = get_doc_string_buffer; while (1) { - EMACS_INT space_left = (get_doc_string_buffer_size + ptrdiff_t space_left = (get_doc_string_buffer_size - (p - get_doc_string_buffer)); int nread; /* Allocate or grow the buffer if we need to. */ if (space_left == 0) { - EMACS_INT in_buffer = p - get_doc_string_buffer; - get_doc_string_buffer_size += 16 * 1024; + ptrdiff_t in_buffer = p - get_doc_string_buffer; + enum { incr = 16 * 1024 }; + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) - 1 - incr + < get_doc_string_buffer_size) + memory_full (SIZE_MAX); + size = get_doc_string_buffer_size + incr; get_doc_string_buffer - = (char *) xrealloc (get_doc_string_buffer, - get_doc_string_buffer_size + 1); + = (char *) xrealloc (get_doc_string_buffer, size + 1); + get_doc_string_buffer_size = size; p = get_doc_string_buffer + in_buffer; space_left = (get_doc_string_buffer_size - (p - get_doc_string_buffer)); @@ -713,16 +718,16 @@ a new string, without any text properties, is returned. */) int changed = 0; register unsigned char *strp; register char *bufp; - EMACS_INT idx; - EMACS_INT bsize; + ptrdiff_t idx; + ptrdiff_t bsize; Lisp_Object tem; Lisp_Object keymap; unsigned char *start; - EMACS_INT length, length_byte; + ptrdiff_t length, length_byte; Lisp_Object name; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; int multibyte; - EMACS_INT nchars; + ptrdiff_t nchars; if (NILP (string)) return Qnil; @@ -774,7 +779,7 @@ a new string, without any text properties, is returned. */) } else if (strp[0] == '\\' && strp[1] == '[') { - EMACS_INT start_idx; + ptrdiff_t start_idx; int follow_remap = 1; changed = 1; @@ -813,7 +818,9 @@ a new string, without any text properties, is returned. */) if (NILP (tem)) /* but not on any keys */ { - EMACS_INT offset = bufp - buf; + ptrdiff_t offset = bufp - buf; + if (STRING_BYTES_BOUND - 4 < bsize) + string_overflow (); buf = (char *) xrealloc (buf, bsize += 4); bufp = buf + offset; memcpy (bufp, "M-x ", 4); @@ -836,7 +843,7 @@ a new string, without any text properties, is returned. */) else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<')) { struct buffer *oldbuf; - EMACS_INT start_idx; + ptrdiff_t start_idx; /* This is for computing the SHADOWS arg for describe_map_tree. */ Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil); Lisp_Object earlier_maps; @@ -907,7 +914,9 @@ a new string, without any text properties, is returned. */) length_byte = SBYTES (tem); subst: { - EMACS_INT offset = bufp - buf; + ptrdiff_t offset = bufp - buf; + if (STRING_BYTES_BOUND - length_byte < bsize) + string_overflow (); buf = (char *) xrealloc (buf, bsize += length_byte); bufp = buf + offset; memcpy (bufp, start, length_byte); -- cgit v1.2.3 From c9f8d652ab67b148cd0a1cb375b0e51e673c4094 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:37:15 -0700 Subject: * editfns.c: Integer and memory overflow fixes. (set_time_zone_rule): Don't assume environment length fits in int. (message_length): Now ptrdiff_t, not int. (Fmessage_box): Don't update size until allocation succeeds. Don't assume message length fits in int. (Fformat): Use ptrdiff_t, not EMACS_INT, where ptrdiff_t will do. --- src/ChangeLog | 7 +++++++ src/editfns.c | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 6cf9a1f862..b823dd5449 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,12 @@ 2011-07-28 Paul Eggert + * editfns.c: Integer and memory overflow fixes. + (set_time_zone_rule): Don't assume environment length fits in int. + (message_length): Now ptrdiff_t, not int. + (Fmessage_box): Don't update size until allocation succeeds. + Don't assume message length fits in int. + (Fformat): Use ptrdiff_t, not EMACS_INT, where ptrdiff_t will do. + * doc.c: Integer and memory overflow fixes. (get_doc_string_buffer_size): Now ptrdiff_t, not int. (get_doc_string): Check for size calculation overflow. diff --git a/src/editfns.c b/src/editfns.c index 18fefa5e3b..1616305faa 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -2105,7 +2105,7 @@ static char set_time_zone_rule_tz2[] = "TZ=GMT+1"; void set_time_zone_rule (const char *tzstring) { - int envptrs; + ptrdiff_t envptrs; char **from, **to, **newenv; /* Make the ENVIRON vector longer with room for TZSTRING. */ @@ -3355,7 +3355,7 @@ usage: (save-restriction &rest BODY) */) static char *message_text; /* Allocated length of that buffer. */ -static int message_length; +static ptrdiff_t message_length; DEFUN ("message", Fmessage, Smessage, 1, MANY, 0, doc: /* Display a message at the bottom of the screen. @@ -3437,8 +3437,8 @@ usage: (message-box FORMAT-STRING &rest ARGS) */) } if (SBYTES (val) > message_length) { + message_text = (char *) xrealloc (message_text, SBYTES (val)); message_length = SBYTES (val); - message_text = (char *)xrealloc (message_text, message_length); } memcpy (message_text, SDATA (val), SBYTES (val)); message2 (message_text, SBYTES (val), @@ -4163,7 +4163,7 @@ usage: (format STRING &rest OBJECTS) */) character. CONVBYTES says how much room is needed. Allocate enough room (and then some) and do it again. */ { - EMACS_INT used = p - buf; + ptrdiff_t used = p - buf; if (max_bufsize - used < convbytes) string_overflow (); -- cgit v1.2.3 From b4fb63147af14661b28c59d07987f8306deb5ed1 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:38:23 -0700 Subject: * emacs.c (main, sort_args): Check for size-calculation overflow. --- src/ChangeLog | 2 ++ src/emacs.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index b823dd5449..52f1a76e54 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-28 Paul Eggert + * emacs.c (main, sort_args): Check for size-calculation overflow. + * editfns.c: Integer and memory overflow fixes. (set_time_zone_rule): Don't assume environment length fits in int. (message_length): Now ptrdiff_t, not int. diff --git a/src/emacs.c b/src/emacs.c index 39870ec007..4de567a558 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1360,9 +1360,12 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem This requires inserting a new element into argv. */ if (displayname != 0 && skip_args - count_before == 1) { - char **new = (char **) xmalloc (sizeof (char *) * (argc + 2)); + char **new; int j; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (char *) - 2 < argc) + memory_full (SIZE_MAX); + new = (char **) xmalloc (sizeof *new * argc + sizeof *new * 2); for (j = 0; j < count_before + 1; j++) new[j] = argv[j]; new[count_before + 1] = (char *) "-d"; @@ -1838,13 +1841,19 @@ sort_args (int argc, char **argv) 0 for an option that takes no arguments, 1 for an option that takes one argument, etc. -1 for an ordinary non-option argument. */ - int *options = (int *) xmalloc (sizeof (int) * argc); - int *priority = (int *) xmalloc (sizeof (int) * argc); + int *options; + int *priority; int to = 1; int incoming_used = 1; int from; int i; + if (sizeof (char *) < sizeof (int) + && min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < argc) + memory_full (SIZE_MAX); + options = (int *) xmalloc (sizeof (int) * argc); + priority = (int *) xmalloc (sizeof (int) * argc); + /* Categorize all the options, and figure out which argv elts are option arguments. */ for (from = 1; from < argc; from++) -- cgit v1.2.3 From 98e8eae1372c6656c82ec0f9600128a2ecb522cc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:42:59 -0700 Subject: * eval.c: Integer and memory overflow fixes. (init_eval_once, grow_specpdl): Don't update size until alloc succeeds. (call_debugger, grow_specpdl): Redo calculations to avoid overflow. --- src/ChangeLog | 4 ++++ src/eval.c | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 52f1a76e54..7a7c8c1440 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-28 Paul Eggert + * eval.c: Integer and memory overflow fixes. + (init_eval_once, grow_specpdl): Don't update size until alloc succeeds. + (call_debugger, grow_specpdl): Redo calculations to avoid overflow. + * emacs.c (main, sort_args): Check for size-calculation overflow. * editfns.c: Integer and memory overflow fixes. diff --git a/src/eval.c b/src/eval.c index ef169e80e2..bcb77574fe 100644 --- a/src/eval.c +++ b/src/eval.c @@ -133,8 +133,9 @@ static Lisp_Object Ffetch_bytecode (Lisp_Object); void init_eval_once (void) { - specpdl_size = 50; - specpdl = (struct specbinding *) xmalloc (specpdl_size * sizeof (struct specbinding)); + enum { size = 50 }; + specpdl = (struct specbinding *) xmalloc (size * sizeof (struct specbinding)); + specpdl_size = size; specpdl_ptr = specpdl; /* Don't forget to update docs (lispref node "Local Variables"). */ max_specpdl_size = 1300; /* 1000 is not enough for CEDET's c-by.el. */ @@ -192,7 +193,7 @@ call_debugger (Lisp_Object arg) if (lisp_eval_depth + 40 > max_lisp_eval_depth) max_lisp_eval_depth = lisp_eval_depth + 40; - if (SPECPDL_INDEX () + 100 > max_specpdl_size) + if (max_specpdl_size - 100 < SPECPDL_INDEX ()) max_specpdl_size = SPECPDL_INDEX () + 100; #ifdef HAVE_WINDOW_SYSTEM @@ -3274,17 +3275,22 @@ static void grow_specpdl (void) { register int count = SPECPDL_INDEX (); - if (specpdl_size >= max_specpdl_size) + int max_size = + min (max_specpdl_size, + min (max (PTRDIFF_MAX, SIZE_MAX) / sizeof (struct specbinding), + INT_MAX)); + int size; + if (max_size <= specpdl_size) { if (max_specpdl_size < 400) - max_specpdl_size = 400; - if (specpdl_size >= max_specpdl_size) + max_size = max_specpdl_size = 400; + if (max_size <= specpdl_size) signal_error ("Variable binding depth exceeds max-specpdl-size", Qnil); } - specpdl_size *= 2; - if (specpdl_size > max_specpdl_size) - specpdl_size = max_specpdl_size; - specpdl = (struct specbinding *) xrealloc (specpdl, specpdl_size * sizeof (struct specbinding)); + size = specpdl_size < max_size / 2 ? 2 * specpdl_size : max_size; + specpdl = ((struct specbinding *) + xrealloc (specpdl, size * sizeof (struct specbinding))); + specpdl_size = size; specpdl_ptr = specpdl + count; } -- cgit v1.2.3 From b8898fdae2fd08ca3406c47a18de3465dd1a4a39 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:49:16 -0700 Subject: * frame.c: Integer overflow fixes. (set_menu_bar_lines, x_set_frame_parameters, x_set_scroll_bar_width) (x_figure_window_size): Check for integer overflow. (x_set_alpha): Do not assume XINT fits in int. --- src/ChangeLog | 5 +++++ src/frame.c | 38 ++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 7a7c8c1440..c46eec626b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-28 Paul Eggert + * frame.c: Integer overflow fixes. + (set_menu_bar_lines, x_set_frame_parameters, x_set_scroll_bar_width) + (x_figure_window_size): Check for integer overflow. + (x_set_alpha): Do not assume XINT fits in int. + * eval.c: Integer and memory overflow fixes. (init_eval_once, grow_specpdl): Don't update size until alloc succeeds. (call_debugger, grow_specpdl): Redo calculations to avoid overflow. diff --git a/src/frame.c b/src/frame.c index 635996ca42..ca3ca49577 100644 --- a/src/frame.c +++ b/src/frame.c @@ -160,7 +160,7 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) if (FRAME_MINIBUF_ONLY_P (f)) return; - if (INTEGERP (value)) + if (TYPE_RANGED_INTEGERP (int, value)) nlines = XINT (value); else nlines = 0; @@ -2994,7 +2994,7 @@ x_set_frame_parameters (FRAME_PTR f, Lisp_Object alist) f->size_hint_flags &= ~ (XNegative | YNegative); if (EQ (left, Qminus)) f->size_hint_flags |= XNegative; - else if (INTEGERP (left)) + else if (TYPE_RANGED_INTEGERP (int, left)) { leftpos = XINT (left); if (leftpos < 0) @@ -3002,21 +3002,21 @@ x_set_frame_parameters (FRAME_PTR f, Lisp_Object alist) } else if (CONSP (left) && EQ (XCAR (left), Qminus) && CONSP (XCDR (left)) - && INTEGERP (XCAR (XCDR (left)))) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) { leftpos = - XINT (XCAR (XCDR (left))); f->size_hint_flags |= XNegative; } else if (CONSP (left) && EQ (XCAR (left), Qplus) && CONSP (XCDR (left)) - && INTEGERP (XCAR (XCDR (left)))) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) { leftpos = XINT (XCAR (XCDR (left))); } if (EQ (top, Qminus)) f->size_hint_flags |= YNegative; - else if (INTEGERP (top)) + else if (TYPE_RANGED_INTEGERP (int, top)) { toppos = XINT (top); if (toppos < 0) @@ -3024,14 +3024,14 @@ x_set_frame_parameters (FRAME_PTR f, Lisp_Object alist) } else if (CONSP (top) && EQ (XCAR (top), Qminus) && CONSP (XCDR (top)) - && INTEGERP (XCAR (XCDR (top)))) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) { toppos = - XINT (XCAR (XCDR (top))); f->size_hint_flags |= YNegative; } else if (CONSP (top) && EQ (XCAR (top), Qplus) && CONSP (XCDR (top)) - && INTEGERP (XCAR (XCDR (top)))) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) { toppos = XINT (XCAR (XCDR (top))); } @@ -3483,7 +3483,7 @@ x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f)); do_pending_window_change (0); } - else if (INTEGERP (arg) && XINT (arg) > 0 + else if (RANGED_INTEGERP (1, arg, INT_MAX) && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_WIDTH (f)) { if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM) @@ -3522,7 +3522,7 @@ x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { double alpha = 1.0; double newval[2]; - int i, ialpha; + int i; Lisp_Object item; for (i = 0; i < 2; i++) @@ -3546,7 +3546,7 @@ x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) } else if (INTEGERP (item)) { - ialpha = XINT (item); + EMACS_INT ialpha = XINT (item); if (ialpha < 0 || 100 < ialpha) args_out_of_range (make_number (0), make_number (100)); else @@ -4033,11 +4033,15 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, int toolbar_p) if (!EQ (tem0, Qunbound)) { CHECK_NUMBER (tem0); + if (! (0 <= XINT (tem0) && XINT (tem0) <= INT_MAX)) + xsignal1 (Qargs_out_of_range, tem0); FRAME_LINES (f) = XINT (tem0); } if (!EQ (tem1, Qunbound)) { CHECK_NUMBER (tem1); + if (! (0 <= XINT (tem1) && XINT (tem1) <= INT_MAX)) + xsignal1 (Qargs_out_of_range, tem1); SET_FRAME_COLS (f, XINT (tem1)); } if (!NILP (tem2) && !EQ (tem2, Qunbound)) @@ -4068,12 +4072,10 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, int toolbar_p) ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF); - if (INTEGERP (Vtool_bar_button_margin) - && XINT (Vtool_bar_button_margin) > 0) + if (RANGED_INTEGERP (1, Vtool_bar_button_margin, INT_MAX)) margin = XFASTINT (Vtool_bar_button_margin); else if (CONSP (Vtool_bar_button_margin) - && INTEGERP (XCDR (Vtool_bar_button_margin)) - && XINT (XCDR (Vtool_bar_button_margin)) > 0) + && RANGED_INTEGERP (1, XCDR (Vtool_bar_button_margin), INT_MAX)) margin = XFASTINT (XCDR (Vtool_bar_button_margin)); else margin = 0; @@ -4099,14 +4101,14 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, int toolbar_p) } else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus) && CONSP (XCDR (tem0)) - && INTEGERP (XCAR (XCDR (tem0)))) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem0)), INT_MAX)) { f->top_pos = - XINT (XCAR (XCDR (tem0))); window_prompting |= YNegative; } else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus) && CONSP (XCDR (tem0)) - && INTEGERP (XCAR (XCDR (tem0)))) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem0)))) { f->top_pos = XINT (XCAR (XCDR (tem0))); } @@ -4127,14 +4129,14 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, int toolbar_p) } else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus) && CONSP (XCDR (tem1)) - && INTEGERP (XCAR (XCDR (tem1)))) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem1)), INT_MAX)) { f->left_pos = - XINT (XCAR (XCDR (tem1))); window_prompting |= XNegative; } else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus) && CONSP (XCDR (tem1)) - && INTEGERP (XCAR (XCDR (tem1)))) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem1)))) { f->left_pos = XINT (XCAR (XCDR (tem1))); } -- cgit v1.2.3 From 2f645268752fbbaf6f094dab704fce2c667f7468 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 14:51:29 -0700 Subject: * frame.h (struct frame): Use int, not EMACS_INT, where int works. This is for the members text_lines, text_cols, total_lines, total_cols, where the system imposes an 'int' limit. --- src/ChangeLog | 4 ++++ src/frame.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index c46eec626b..e2b613d03c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-28 Paul Eggert + * frame.h (struct frame): Use int, not EMACS_INT, where int works. + This is for the members text_lines, text_cols, total_lines, total_cols, + where the system imposes an 'int' limit. + * frame.c: Integer overflow fixes. (set_menu_bar_lines, x_set_frame_parameters, x_set_scroll_bar_width) (x_figure_window_size): Check for integer overflow. diff --git a/src/frame.h b/src/frame.h index 8dccfb8540..3775403810 100644 --- a/src/frame.h +++ b/src/frame.h @@ -258,11 +258,11 @@ struct frame /* Size of this frame, excluding fringes, scroll bars etc., in units of canonical characters. */ - EMACS_INT text_lines, text_cols; + int text_lines, text_cols; /* Total size of this frame (i.e. its native window), in units of canonical characters. */ - EMACS_INT total_lines, total_cols; + int total_lines, total_cols; /* New text height and width for pending size change. 0 if no change pending. */ -- cgit v1.2.3 From 483a9e21b6c8387cdbd5a5f3ab8a3fe77f7e52a0 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 16:47:01 -0700 Subject: * fringe.c (Fdefine_fringe_bitmap): Don't update size until alloc works. --- src/ChangeLog | 2 ++ src/fringe.c | 13 ++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index e2b613d03c..058c250a33 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-28 Paul Eggert + * fringe.c (Fdefine_fringe_bitmap): Don't update size until alloc works. + * frame.h (struct frame): Use int, not EMACS_INT, where int works. This is for the members text_lines, text_cols, total_lines, total_cols, where the system imposes an 'int' limit. diff --git a/src/fringe.c b/src/fringe.c index a4dc9433af..5878c54124 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -1610,22 +1610,25 @@ If BITMAP already exists, the existing definition is replaced. */) if (n == max_fringe_bitmaps) { - if ((max_fringe_bitmaps + 20) > MAX_FRINGE_BITMAPS) + int bitmaps = max_fringe_bitmaps + 20; + if (MAX_FRINGE_BITMAPS < bitmaps) error ("No free fringe bitmap slots"); i = max_fringe_bitmaps; - max_fringe_bitmaps += 20; fringe_bitmaps = ((struct fringe_bitmap **) - xrealloc (fringe_bitmaps, max_fringe_bitmaps * sizeof (struct fringe_bitmap *))); + xrealloc (fringe_bitmaps, bitmaps * sizeof *fringe_bitmaps)); fringe_faces - = (Lisp_Object *) xrealloc (fringe_faces, max_fringe_bitmaps * sizeof (Lisp_Object)); + = (Lisp_Object *) xrealloc (fringe_faces, + bitmaps * sizeof *fringe_faces); - for (; i < max_fringe_bitmaps; i++) + for (i = max_fringe_bitmaps; i < bitmaps; i++) { fringe_bitmaps[i] = NULL; fringe_faces[i] = Qnil; } + + max_fringe_bitmaps = bitmaps; } } -- cgit v1.2.3 From 1ffd9c92ea38e078ec6cde6277c7ce88895212df Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 16:51:50 -0700 Subject: * ftfont.c: Check for size overflow. (ftfont_get_open_type_spec, setup_otf_gstring, ftfont_shape_by_flt): Check for integer overflow in size calculations. --- src/ChangeLog | 4 ++++ src/ftfont.c | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 058c250a33..84d7bf4cb4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-28 Paul Eggert + * ftfont.c: Check for size overflow. + (ftfont_get_open_type_spec, setup_otf_gstring, ftfont_shape_by_flt): + Check for integer overflow in size calculations. + * fringe.c (Fdefine_fringe_bitmap): Don't update size until alloc works. * frame.h (struct frame): Use int, not EMACS_INT, where int works. diff --git a/src/ftfont.c b/src/ftfont.c index 4e313a8902..551006eef9 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -682,7 +682,10 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec) if (NILP (val)) continue; len = Flength (val); - spec->features[i] = malloc (sizeof (int) * XINT (len)); + spec->features[i] = + (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len) + ? 0 + : malloc (sizeof (int) * XINT (len))); if (! spec->features[i]) { if (i > 0 && spec->features[0]) @@ -1761,6 +1764,9 @@ static OTF_GlyphString otf_gstring; static void setup_otf_gstring (int size) { + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (OTF_Glyph) < size) + memory_full (SIZE_MAX); + if (otf_gstring.size == 0) { otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size); @@ -2390,6 +2396,8 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font, struct MFLTFontFT flt_font_ft; MFLT *flt = NULL; int with_variation_selector = 0; + int allocated_max = min (INT_MAX, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (MFLTGlyph)); if (! m17n_flt_initialized) { @@ -2445,6 +2453,9 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font, } } + if (allocated_max / 2 < len) + memory_full (SIZE_MAX); + if (gstring.allocated == 0) { gstring.allocated = len * 2; @@ -2504,6 +2515,8 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font, int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt); if (result != -2) break; + if (allocated_max / 2 < gstring.allocated) + memory_full (SIZE_MAX); gstring.allocated += gstring.allocated; gstring.glyphs = xrealloc (gstring.glyphs, sizeof (MFLTGlyph) * gstring.allocated); -- cgit v1.2.3 From 0eb0f3187d46ec0efdfc1df38565c160c759ecb2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 16:58:05 -0700 Subject: * gtkutil.c: Integer overflow fixes. (get_utf8_string, xg_store_widget_in_map): Check for size-calculation overflow. (get_utf8_string): Use ptrdiff_t, not size_t, where either will do, as we prefer signed integers. (id_to_widget.max_size, id_to_widget.used) (xg_store_widget_in_map, xg_remove_widget_from_map) (xg_get_widget_from_map, xg_get_scroll_id_for_window) (xg_remove_scroll_bar, xg_update_scrollbar_pos): Use and return ptrdiff_t, not int. (xg_gtk_scroll_destroy): Don't assume ptrdiff_t fits in int. * gtkutil.h: Change prototypes to match the above. --- src/ChangeLog | 13 +++++++++++++ src/gtkutil.c | 37 +++++++++++++++++++++++-------------- src/gtkutil.h | 7 +++---- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 84d7bf4cb4..b984072c6e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,18 @@ 2011-07-28 Paul Eggert + * gtkutil.c: Integer overflow fixes. + (get_utf8_string, xg_store_widget_in_map): + Check for size-calculation overflow. + (get_utf8_string): Use ptrdiff_t, not size_t, where either will + do, as we prefer signed integers. + (id_to_widget.max_size, id_to_widget.used) + (xg_store_widget_in_map, xg_remove_widget_from_map) + (xg_get_widget_from_map, xg_get_scroll_id_for_window) + (xg_remove_scroll_bar, xg_update_scrollbar_pos): + Use and return ptrdiff_t, not int. + (xg_gtk_scroll_destroy): Don't assume ptrdiff_t fits in int. + * gtkutil.h: Change prototypes to match the above. + * ftfont.c: Check for size overflow. (ftfont_get_open_type_spec, setup_otf_gstring, ftfont_shape_by_flt): Check for integer overflow in size calculations. diff --git a/src/gtkutil.c b/src/gtkutil.c index 70bc18a75f..f56e888e68 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -487,7 +487,8 @@ get_utf8_string (const char *str) if (!utf8_str) { /* Probably some control characters in str. Escape them. */ - size_t nr_bad = 0; + ptrdiff_t len; + ptrdiff_t nr_bad = 0; gsize bytes_read; gsize bytes_written; unsigned char *p = (unsigned char *)str; @@ -511,7 +512,10 @@ get_utf8_string (const char *str) } if (cp) g_free (cp); - up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1); + len = strlen (str); + if ((min (PTRDIFF_MAX, SIZE_MAX) - len - 1) / 4 < nr_bad) + memory_full (SIZE_MAX); + up = utf8_str = xmalloc (len + nr_bad * 4 + 1); p = (unsigned char *)str; while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read, @@ -3296,8 +3300,8 @@ static int scroll_bar_width_for_theme; static struct { GtkWidget **widgets; - int max_size; - int used; + ptrdiff_t max_size; + ptrdiff_t used; } id_to_widget; /* Grow this much every time we need to allocate more */ @@ -3306,15 +3310,20 @@ static struct /* Store the widget pointer W in id_to_widget and return the integer index. */ -static int +static ptrdiff_t xg_store_widget_in_map (GtkWidget *w) { - int i; + ptrdiff_t i; if (id_to_widget.max_size == id_to_widget.used) { - int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR; + ptrdiff_t new_size; + ptrdiff_t lim = min (TYPE_MAXIMUM (Window), + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (GtkWidget *)); + if (lim - ID_TO_WIDGET_INCR < id_to_widget.max_size) + memory_full (SIZE_MAX); + new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR; id_to_widget.widgets = xrealloc (id_to_widget.widgets, sizeof (GtkWidget *)*new_size); @@ -3345,7 +3354,7 @@ xg_store_widget_in_map (GtkWidget *w) Called when scroll bar is destroyed. */ static void -xg_remove_widget_from_map (int idx) +xg_remove_widget_from_map (ptrdiff_t idx) { if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0) { @@ -3357,7 +3366,7 @@ xg_remove_widget_from_map (int idx) /* Get the widget pointer at IDX from id_to_widget. */ static GtkWidget * -xg_get_widget_from_map (int idx) +xg_get_widget_from_map (ptrdiff_t idx) { if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0) return id_to_widget.widgets[idx]; @@ -3396,10 +3405,10 @@ xg_get_default_scrollbar_width (void) /* Return the scrollbar id for X Window WID on display DPY. Return -1 if WID not in id_to_widget. */ -int +ptrdiff_t xg_get_scroll_id_for_window (Display *dpy, Window wid) { - int idx; + ptrdiff_t idx; GtkWidget *w; w = xg_win_to_widget (dpy, wid); @@ -3421,7 +3430,7 @@ xg_get_scroll_id_for_window (Display *dpy, Window wid) static void xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data) { - int id = (intptr_t) data; + intptr_t id = (intptr_t) data; xg_remove_widget_from_map (id); } @@ -3496,7 +3505,7 @@ xg_create_scroll_bar (FRAME_PTR f, /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */ void -xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id) +xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id) { GtkWidget *w = xg_get_widget_from_map (scrollbar_id); if (w) @@ -3515,7 +3524,7 @@ xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id) void xg_update_scrollbar_pos (FRAME_PTR f, - int scrollbar_id, + ptrdiff_t scrollbar_id, int top, int left, int width, diff --git a/src/gtkutil.h b/src/gtkutil.h index 769e56da91..2dfb3a5ed6 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -114,17 +114,17 @@ extern int xg_event_is_for_menubar (FRAME_PTR f, XEvent *event); extern int xg_have_tear_offs (void); -extern int xg_get_scroll_id_for_window (Display *dpy, Window wid); +extern ptrdiff_t xg_get_scroll_id_for_window (Display *dpy, Window wid); extern void xg_create_scroll_bar (FRAME_PTR f, struct scroll_bar *bar, GCallback scroll_callback, GCallback end_callback, const char *scroll_bar_name); -extern void xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id); +extern void xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id); extern void xg_update_scrollbar_pos (FRAME_PTR f, - int scrollbar_id, + ptrdiff_t scrollbar_id, int top, int left, int width, @@ -185,4 +185,3 @@ extern int xg_ignore_gtk_scrollbar; #endif /* USE_GTK */ #endif /* GTKUTIL_H */ - -- cgit v1.2.3 From ddff315164d62859e0eb87e89de9f785b953a39a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 17:23:08 -0700 Subject: * image.c: Integer and memory overflow fixes. (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): Remove; these are duplicate now that they've been promoted to lisp.h. (x_allocate_bitmap_record, x_alloc_image_color) (make_image_cache, cache_image, xpm_load): Don't update size until alloc is done. (xpm_load, lookup_rgb_color, lookup_pixel_color, x_to_xcolors) (x_detect_edges): Check for size calculation overflow. (ct_colors_allocated_max): New constant. (x_to_xcolors, x_detect_edges): Reorder multiplicands to avoid overflow. --- src/ChangeLog | 15 +++++++++++++++ src/image.c | 61 +++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index b984072c6e..5683578fed 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,18 @@ +2011-07-29 Paul Eggert + + * image.c: Integer and memory overflow fixes. + (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): Remove; these are duplicate + now that they've been promoted to lisp.h. + (x_allocate_bitmap_record, x_alloc_image_color) + (make_image_cache, cache_image, xpm_load): + Don't update size until alloc is done. + (xpm_load, lookup_rgb_color, lookup_pixel_color, x_to_xcolors) + (x_detect_edges): + Check for size calculation overflow. + (ct_colors_allocated_max): New constant. + (x_to_xcolors, x_detect_edges): Reorder multiplicands to avoid + overflow. + 2011-07-28 Paul Eggert * gtkutil.c: Integer overflow fixes. diff --git a/src/image.c b/src/image.c index 974c525c4e..52fd945e32 100644 --- a/src/image.c +++ b/src/image.c @@ -48,11 +48,6 @@ along with GNU Emacs. If not, see . */ #include "termhooks.h" #include "font.h" -#define RANGED_INTEGERP(lo, x, hi) \ - (INTEGERP (x) && (lo) <= XINT (x) && XINT (x) <= (hi)) -#define TYPE_RANGED_INTEGERP(type, x) \ - RANGED_INTEGERP (TYPE_MINIMUM (type), x, TYPE_MAXIMUM (type)) - #ifdef HAVE_X_WINDOWS #include "xterm.h" #include @@ -223,9 +218,9 @@ x_allocate_bitmap_record (FRAME_PTR f) if (dpyinfo->bitmaps == NULL) { - dpyinfo->bitmaps_size = 10; dpyinfo->bitmaps - = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record)); + = (Bitmap_Record *) xmalloc (10 * sizeof (Bitmap_Record)); + dpyinfo->bitmaps_size = 10; dpyinfo->bitmaps_last = 1; return 1; } @@ -240,10 +235,11 @@ x_allocate_bitmap_record (FRAME_PTR f) if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (Bitmap_Record) / 2 < dpyinfo->bitmaps_size) memory_full (SIZE_MAX); - dpyinfo->bitmaps_size *= 2; dpyinfo->bitmaps = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps, - dpyinfo->bitmaps_size * sizeof (Bitmap_Record)); + (dpyinfo->bitmaps_size + * (2 * sizeof (Bitmap_Record)))); + dpyinfo->bitmaps_size *= 2; return ++dpyinfo->bitmaps_last; } @@ -1373,11 +1369,12 @@ x_alloc_image_color (struct frame *f, struct image *img, Lisp_Object color_name, { /* This isn't called frequently so we get away with simply reallocating the color vector to the needed size, here. */ - ++img->ncolors; + ptrdiff_t ncolors = img->ncolors + 1; img->colors = (unsigned long *) xrealloc (img->colors, - img->ncolors * sizeof *img->colors); - img->colors[img->ncolors - 1] = color.pixel; + ncolors * sizeof *img->colors); + img->colors[ncolors - 1] = color.pixel; + img->ncolors = ncolors; result = color.pixel; } else @@ -1405,8 +1402,9 @@ make_image_cache (void) int size; memset (c, 0, sizeof *c); - c->size = 50; - c->images = (struct image **) xmalloc (c->size * sizeof *c->images); + size = 50; + c->images = (struct image **) xmalloc (size * sizeof *c->images); + c->size = size; size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; c->buckets = (struct image **) xmalloc (size); memset (c->buckets, 0, size); @@ -1837,9 +1835,10 @@ cache_image (struct frame *f, struct image *img) { if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *c->images / 2 < c->size) memory_full (SIZE_MAX); + c->images = + (struct image **) xrealloc (c->images, + c->size * (2 * sizeof *c->images)); c->size *= 2; - c->images = (struct image **) xrealloc (c->images, - c->size * sizeof *c->images); } /* Add IMG to c->images, and assign IMG an id. */ @@ -3581,9 +3580,12 @@ xpm_load (struct frame *f, struct image *img) #endif /* HAVE_NTGUI */ /* Remember allocated colors. */ - img->ncolors = attrs.nalloc_pixels; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *img->colors + < attrs.nalloc_pixels) + memory_full (SIZE_MAX); img->colors = (unsigned long *) xmalloc (img->ncolors * sizeof *img->colors); + img->ncolors = attrs.nalloc_pixels; for (i = 0; i < attrs.nalloc_pixels; ++i) { img->colors[i] = attrs.alloc_pixels[i]; @@ -4157,6 +4159,12 @@ static struct ct_color **ct_table; /* Number of entries in the color table. */ static int ct_colors_allocated; +enum +{ + ct_colors_allocated_max = + min (INT_MAX, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (unsigned long)) +}; /* Initialize the color table. */ @@ -4243,7 +4251,14 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) XColor color; Colormap cmap; int rc; +#else + COLORREF color; +#endif + if (ct_colors_allocated_max <= ct_colors_allocated) + return FRAME_FOREGROUND_PIXEL (f); + +#ifdef HAVE_X_WINDOWS color.red = r; color.green = g; color.blue = b; @@ -4265,7 +4280,6 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) return FRAME_FOREGROUND_PIXEL (f); #else - COLORREF color; #ifdef HAVE_NTGUI color = PALETTERGB (r, g, b); #else @@ -4306,6 +4320,9 @@ lookup_pixel_color (struct frame *f, unsigned long pixel) Colormap cmap; int rc; + if (ct_colors_allocated_max <= ct_colors_allocated) + return FRAME_FOREGROUND_PIXEL (f); + #ifdef HAVE_X_WINDOWS cmap = FRAME_X_COLORMAP (f); color.pixel = pixel; @@ -4444,7 +4461,9 @@ x_to_xcolors (struct frame *f, struct image *img, int rgb_p) HGDIOBJ prev; #endif /* HAVE_NTGUI */ - colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors); + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *colors / img->width < img->height) + memory_full (SIZE_MAX); + colors = (XColor *) xmalloc (sizeof *colors * img->width * img->height); #ifndef HAVE_NTGUI /* Get the X image IMG->pixmap. */ @@ -4596,7 +4615,9 @@ x_detect_edges (struct frame *f, struct image *img, int *matrix, int color_adjus #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X)) - new = (XColor *) xmalloc (img->width * img->height * sizeof *new); + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *new / img->width < img->height) + memory_full (SIZE_MAX); + new = (XColor *) xmalloc (sizeof *new * img->width * img->height); for (y = 0; y < img->height; ++y) { -- cgit v1.2.3 From 34db673b3978bd88aea081882a70bdcdf53028a7 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 17:30:00 -0700 Subject: * keyboard.c: Integer and memory overflow fixes. (read_char, menu_bar_items, tool_bar_items, read_char_x_menu_prompt) (read_char_minibuf_menu_width, read_char_minibuf_menu_prompt) (follow_key, read_key_sequence): Use ptrdiff_t, not int, to count maps. (read_char_minibuf_menu_prompt): Check for overflow in size calculations. Don't update size until allocation succeeds. Redo calculations to avoid overflow. * keyboard.h: Change prototypes to match the above. --- src/ChangeLog | 9 +++++++ src/keyboard.c | 80 ++++++++++++++++++++++++++++------------------------------ src/keyboard.h | 2 +- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 5683578fed..e42d536e6d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,14 @@ 2011-07-29 Paul Eggert + * keyboard.c: Integer and memory overflow fixes. + (read_char, menu_bar_items, tool_bar_items, read_char_x_menu_prompt) + (read_char_minibuf_menu_width, read_char_minibuf_menu_prompt) + (follow_key, read_key_sequence): Use ptrdiff_t, not int, to count maps. + (read_char_minibuf_menu_prompt): Check for overflow in size + calculations. Don't update size until allocation succeeds. Redo + calculations to avoid overflow. + * keyboard.h: Change prototypes to match the above. + * image.c: Integer and memory overflow fixes. (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): Remove; these are duplicate now that they've been promoted to lisp.h. diff --git a/src/keyboard.c b/src/keyboard.c index 30fe0d917c..622f7ca448 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -435,9 +435,9 @@ static void (*keyboard_init_hook) (void); static int read_avail_input (int); static void get_input_pending (int *, int); static int readable_events (int); -static Lisp_Object read_char_x_menu_prompt (int, Lisp_Object *, +static Lisp_Object read_char_x_menu_prompt (ptrdiff_t, Lisp_Object *, Lisp_Object, int *); -static Lisp_Object read_char_minibuf_menu_prompt (int, int, +static Lisp_Object read_char_minibuf_menu_prompt (int, ptrdiff_t, Lisp_Object *); static Lisp_Object make_lispy_event (struct input_event *); #if defined (HAVE_MOUSE) || defined (HAVE_GPM) @@ -2267,7 +2267,8 @@ do { if (polling_stopped_here) start_polling (); \ Value is t if we showed a menu and the user rejected it. */ Lisp_Object -read_char (int commandflag, int nmaps, Lisp_Object *maps, Lisp_Object prev_event, +read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps, + Lisp_Object prev_event, int *used_mouse_menu, struct timeval *end_time) { volatile Lisp_Object c; @@ -7405,7 +7406,7 @@ menu_bar_items (Lisp_Object old) { /* The number of keymaps we're scanning right now, and the number of keymaps we have allocated space for. */ - int nmaps; + ptrdiff_t nmaps; /* maps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1] in the current keymaps, or nil where it is not a prefix. */ @@ -7413,7 +7414,7 @@ menu_bar_items (Lisp_Object old) Lisp_Object def, tail; - int mapno; + ptrdiff_t mapno; Lisp_Object oquit; /* In order to build the menus, we need to call the keymap @@ -7458,7 +7459,7 @@ menu_bar_items (Lisp_Object old) recognized when the menu-bar (or mode-line) is updated, which does not normally happen after every command. */ Lisp_Object tem; - int nminor; + ptrdiff_t nminor; nminor = current_minor_maps (NULL, &tmaps); maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0])); nmaps = 0; @@ -7962,7 +7963,7 @@ Lisp_Object tool_bar_items (Lisp_Object reuse, int *nitems) { Lisp_Object *maps; - int nmaps, i; + ptrdiff_t nmaps, i; Lisp_Object oquit; Lisp_Object *tmaps; @@ -8002,7 +8003,7 @@ tool_bar_items (Lisp_Object reuse, int *nitems) recognized when the tool-bar (or mode-line) is updated, which does not normally happen after every command. */ Lisp_Object tem; - int nminor; + ptrdiff_t nminor; nminor = current_minor_maps (NULL, &tmaps); maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0])); nmaps = 0; @@ -8400,10 +8401,10 @@ append_tool_bar_item (void) and do auto-saving in the inner call of read_char. */ static Lisp_Object -read_char_x_menu_prompt (int nmaps, Lisp_Object *maps, Lisp_Object prev_event, - int *used_mouse_menu) +read_char_x_menu_prompt (ptrdiff_t nmaps, Lisp_Object *maps, + Lisp_Object prev_event, int *used_mouse_menu) { - int mapno; + ptrdiff_t mapno; if (used_mouse_menu) *used_mouse_menu = 0; @@ -8431,7 +8432,7 @@ read_char_x_menu_prompt (int nmaps, Lisp_Object *maps, Lisp_Object prev_event, Lisp_Object *realmaps = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object)); Lisp_Object value; - int nmaps1 = 0; + ptrdiff_t nmaps1 = 0; /* Use the maps that are not nil. */ for (mapno = 0; mapno < nmaps; mapno++) @@ -8482,17 +8483,18 @@ read_char_x_menu_prompt (int nmaps, Lisp_Object *maps, Lisp_Object prev_event, We make this bigger when necessary, and never free it. */ static char *read_char_minibuf_menu_text; /* Size of that buffer. */ -static int read_char_minibuf_menu_width; +static ptrdiff_t read_char_minibuf_menu_width; static Lisp_Object -read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) +read_char_minibuf_menu_prompt (int commandflag, + ptrdiff_t nmaps, Lisp_Object *maps) { - int mapno; + ptrdiff_t mapno; register Lisp_Object name; - int nlength; + ptrdiff_t nlength; /* FIXME: Use the minibuffer's frame width. */ - int width = FRAME_COLS (SELECTED_FRAME ()) - 4; - int idx = -1; + ptrdiff_t width = FRAME_COLS (SELECTED_FRAME ()) - 4; + ptrdiff_t idx = -1; int nobindings = 1; Lisp_Object rest, vector; char *menu; @@ -8517,16 +8519,13 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) /* Make sure we have a big enough buffer for the menu text. */ width = max (width, SBYTES (name)); - if (read_char_minibuf_menu_text == 0) + if (STRING_BYTES_BOUND - 4 < width) + memory_full (SIZE_MAX); + if (width + 4 > read_char_minibuf_menu_width) { - read_char_minibuf_menu_width = width + 4; - read_char_minibuf_menu_text = (char *) xmalloc (width + 4); - } - else if (width + 4 > read_char_minibuf_menu_width) - { - read_char_minibuf_menu_width = width + 4; read_char_minibuf_menu_text = (char *) xrealloc (read_char_minibuf_menu_text, width + 4); + read_char_minibuf_menu_width = width + 4; } menu = read_char_minibuf_menu_text; @@ -8545,7 +8544,7 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) while (1) { int notfirst = 0; - int i = nlength; + ptrdiff_t i = nlength; Lisp_Object obj; Lisp_Object orig_defn_macro; @@ -8644,7 +8643,7 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) < width || !notfirst) { - int thiswidth; + ptrdiff_t thiswidth; /* Punctuate between strings. */ if (notfirst) @@ -8660,9 +8659,7 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) if (! char_matches) { /* Add as much of string as fits. */ - thiswidth = SCHARS (desc); - if (thiswidth + i > width) - thiswidth = width - i; + thiswidth = min (SCHARS (desc), width - i); memcpy (menu + i, SDATA (desc), thiswidth); i += thiswidth; strcpy (menu + i, " = "); @@ -8670,9 +8667,7 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) } /* Add as much of string as fits. */ - thiswidth = SCHARS (s); - if (thiswidth + i > width) - thiswidth = width - i; + thiswidth = min (SCHARS (s), width - i); memcpy (menu + i, SDATA (s), thiswidth); i += thiswidth; menu[i] = 0; @@ -8747,10 +8742,10 @@ read_char_minibuf_menu_prompt (int commandflag, int nmaps, Lisp_Object *maps) NEXT may be the same array as CURRENT. */ static int -follow_key (Lisp_Object key, int nmaps, Lisp_Object *current, Lisp_Object *defs, - Lisp_Object *next) +follow_key (Lisp_Object key, ptrdiff_t nmaps, Lisp_Object *current, + Lisp_Object *defs, Lisp_Object *next) { - int i, first_binding; + ptrdiff_t i, first_binding; first_binding = nmaps; for (i = nmaps - 1; i >= 0; i--) @@ -8960,8 +8955,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* The number of keymaps we're scanning right now, and the number of keymaps we have allocated space for. */ - int nmaps; - int nmaps_allocated = 0; + ptrdiff_t nmaps; + ptrdiff_t nmaps_allocated = 0; /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in the current keymaps. */ @@ -8985,7 +8980,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* The index in submaps[] of the first keymap that has a binding for this key sequence. In other words, the lowest i such that submaps[i] is non-nil. */ - int first_binding; + ptrdiff_t first_binding; /* Index of the first key that has no binding. It is useless to try fkey.start larger than that. */ int first_unbound; @@ -9146,8 +9141,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, } else { - int nminor; - int total; + ptrdiff_t nminor; + ptrdiff_t total; Lisp_Object *maps; nminor = current_minor_maps (0, &maps); @@ -9213,7 +9208,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, echo_local_start and keys_local_start allow us to throw away just one key. */ int echo_local_start IF_LINT (= 0); - int keys_local_start, local_first_binding; + int keys_local_start; + ptrdiff_t local_first_binding; eassert (indec.end == t || (indec.end > t && indec.end <= mock_input)); eassert (indec.start <= indec.end); diff --git a/src/keyboard.h b/src/keyboard.h index 69c804c873..d4339d0529 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -440,7 +440,7 @@ struct input_event; extern Lisp_Object parse_modifiers (Lisp_Object); extern Lisp_Object reorder_modifiers (Lisp_Object); -extern Lisp_Object read_char (int, int, Lisp_Object *, Lisp_Object, +extern Lisp_Object read_char (int, ptrdiff_t, Lisp_Object *, Lisp_Object, int *, EMACS_TIME *); extern int parse_solitary_modifier (Lisp_Object symbol); -- cgit v1.2.3 From dbe2216bb632ae0bec0cb2c1b0e38454b9d3a753 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 17:32:09 -0700 Subject: * keymap.c: Integer overflow fixes. (cmm_size, current_minor_maps): Use ptrdiff_t, not int, to count maps. (current_minor_maps): Check for size calculation overflow. * keymap.h: Change prototypes to match the above. --- src/ChangeLog | 5 +++++ src/keymap.c | 15 +++++++++++---- src/keymap.h | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index e42d536e6d..f1c7f11c7f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * keymap.c: Integer overflow fixes. + (cmm_size, current_minor_maps): Use ptrdiff_t, not int, to count maps. + (current_minor_maps): Check for size calculation overflow. + * keymap.h: Change prototypes to match the above. + * keyboard.c: Integer and memory overflow fixes. (read_char, menu_bar_items, tool_bar_items, read_char_x_menu_prompt) (read_char_minibuf_menu_width, read_char_minibuf_menu_prompt) diff --git a/src/keymap.c b/src/keymap.c index 0169276bef..c968b14d90 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -1403,7 +1403,7 @@ silly_event_symbol_error (Lisp_Object c) some systems, static gets macro-defined to be the empty string. Ickypoo. */ static Lisp_Object *cmm_modes = NULL, *cmm_maps = NULL; -static int cmm_size = 0; +static ptrdiff_t cmm_size = 0; /* Store a pointer to an array of the currently active minor modes in *modeptr, a pointer to an array of the keymaps of the currently @@ -1423,10 +1423,10 @@ static int cmm_size = 0; loop. Instead, we'll use realloc/malloc and silently truncate the list, let the key sequence be read, and hope some other piece of code signals the error. */ -int +ptrdiff_t current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr) { - int i = 0; + ptrdiff_t i = 0; int list_number = 0; Lisp_Object alist, assoc, var, val; Lisp_Object emulation_alists; @@ -1469,9 +1469,16 @@ current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr) if (i >= cmm_size) { - int newsize, allocsize; + ptrdiff_t newsize, allocsize; Lisp_Object *newmodes, *newmaps; + /* Check for size calculation overflow. Other code + (e.g., read_key_sequence) adds 3 to the count + later, so subtract 3 from the limit here. */ + if (min (PTRDIFF_MAX, SIZE_MAX) / (2 * sizeof *newmodes) - 3 + < cmm_size) + break; + newsize = cmm_size == 0 ? 30 : cmm_size * 2; allocsize = newsize * sizeof *newmodes; diff --git a/src/keymap.h b/src/keymap.h index 2c826b64e1..ec9d4cadbb 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -38,7 +38,7 @@ extern Lisp_Object get_keymap (Lisp_Object, int, int); EXFUN (Fset_keymap_parent, 2); extern int describe_map_tree (Lisp_Object, int, Lisp_Object, Lisp_Object, const char *, int, int, int, int); -extern int current_minor_maps (Lisp_Object **, Lisp_Object **); +extern ptrdiff_t current_minor_maps (Lisp_Object **, Lisp_Object **); extern void initial_define_key (Lisp_Object, int, const char *); extern void initial_define_lispy_key (Lisp_Object, const char *, const char *); extern void syms_of_keymap (void); -- cgit v1.2.3 From 37d0112bcfc0b2fb426821afc9d409236acab381 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 17:59:16 -0700 Subject: * lread.c (read1, init_obarray): Don't update size until alloc done. --- src/ChangeLog | 2 ++ src/lread.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index f1c7f11c7f..24d67e2463 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-29 Paul Eggert + * lread.c (read1, init_obarray): Don't update size until alloc done. + * keymap.c: Integer overflow fixes. (cmm_size, current_minor_maps): Use ptrdiff_t, not int, to count maps. (current_minor_maps): Check for size calculation overflow. diff --git a/src/lread.c b/src/lread.c index 0613ad037b..3703fdf5d3 100644 --- a/src/lread.c +++ b/src/lread.c @@ -2613,14 +2613,14 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (saved_doc_string_size == 0) { + saved_doc_string = (char *) xmalloc (nskip + extra); saved_doc_string_size = nskip + extra; - saved_doc_string = (char *) xmalloc (saved_doc_string_size); } if (nskip > saved_doc_string_size) { - saved_doc_string_size = nskip + extra; saved_doc_string = (char *) xrealloc (saved_doc_string, - saved_doc_string_size); + nskip + extra); + saved_doc_string_size = nskip + extra; } saved_doc_string_position = file_tell (instream); @@ -2880,7 +2880,8 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size) memory_full (SIZE_MAX); read_buffer = (char *) xrealloc (read_buffer, - read_buffer_size *= 2); + read_buffer_size * 2); + read_buffer_size *= 2; p = read_buffer + offset; end = read_buffer + read_buffer_size; } @@ -3023,7 +3024,8 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size) memory_full (SIZE_MAX); read_buffer = (char *) xrealloc (read_buffer, - read_buffer_size *= 2); + read_buffer_size * 2); + read_buffer_size *= 2; p = read_buffer + offset; end = read_buffer + read_buffer_size; } @@ -3053,7 +3055,8 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size) memory_full (SIZE_MAX); read_buffer = (char *) xrealloc (read_buffer, - read_buffer_size *= 2); + read_buffer_size * 2); + read_buffer_size *= 2; p = read_buffer + offset; end = read_buffer + read_buffer_size; } @@ -3935,6 +3938,7 @@ void init_obarray (void) { Lisp_Object oblength; + ptrdiff_t size = 100 + MAX_MULTIBYTE_LENGTH; XSETFASTINT (oblength, OBARRAY_SIZE); @@ -3967,8 +3971,8 @@ init_obarray (void) DEFSYM (Qvariable_documentation, "variable-documentation"); - read_buffer_size = 100 + MAX_MULTIBYTE_LENGTH; - read_buffer = (char *) xmalloc (read_buffer_size); + read_buffer = (char *) xmalloc (size); + read_buffer_size = size; } void -- cgit v1.2.3 From c86960f076fd12d743da2b30768323efb9c22bbf Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:00:29 -0700 Subject: * macros.c: Integer and memory overflow fixes. (Fstart_kbd_macro): Don't update size until alloc done. (store_kbd_macro_char): Reorder multiplicands to avoid overflow. --- src/ChangeLog | 4 ++++ src/macros.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 24d67e2463..435d883e14 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-29 Paul Eggert + * macros.c: Integer and memory overflow fixes. + (Fstart_kbd_macro): Don't update size until alloc done. + (store_kbd_macro_char): Reorder multiplicands to avoid overflow. + * lread.c (read1, init_obarray): Don't update size until alloc done. * keymap.c: Integer overflow fixes. diff --git a/src/macros.c b/src/macros.c index 60f30c3fbb..f6cd3a3cca 100644 --- a/src/macros.c +++ b/src/macros.c @@ -62,9 +62,9 @@ macro before appending to it. */) if (!current_kboard->kbd_macro_buffer) { - current_kboard->kbd_macro_bufsize = 30; current_kboard->kbd_macro_buffer = (Lisp_Object *)xmalloc (30 * sizeof (Lisp_Object)); + current_kboard->kbd_macro_bufsize = 30; } update_mode_lines++; if (NILP (append)) @@ -202,7 +202,7 @@ store_kbd_macro_char (Lisp_Object c) if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *kb->kbd_macro_buffer / 2 < kb->kbd_macro_bufsize) memory_full (SIZE_MAX); - nbytes = kb->kbd_macro_bufsize * 2 * sizeof *kb->kbd_macro_buffer; + nbytes = kb->kbd_macro_bufsize * (2 * sizeof *kb->kbd_macro_buffer); kb->kbd_macro_buffer = (Lisp_Object *) xrealloc (kb->kbd_macro_buffer, nbytes); kb->kbd_macro_bufsize *= 2; -- cgit v1.2.3 From ea8a7d00f9678471e960117b0b87318dcf4e7d81 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:01:17 -0700 Subject: * minibuf.c (read_minibuf_noninteractive): Don't leak memory on memory overflow. --- src/ChangeLog | 3 +++ src/minibuf.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 435d883e14..4e10537edc 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,8 @@ 2011-07-29 Paul Eggert + * minibuf.c (read_minibuf_noninteractive): Don't leak memory + on memory overflow. + * macros.c: Integer and memory overflow fixes. (Fstart_kbd_macro): Don't update size until alloc done. (store_kbd_macro_char): Reorder multiplicands to avoid overflow. diff --git a/src/minibuf.c b/src/minibuf.c index eb564a10ec..30082af903 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -261,7 +261,10 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial, if (len == size) { if (STRING_BYTES_BOUND / 2 < size) - memory_full (SIZE_MAX); + { + xfree (line); + memory_full (SIZE_MAX); + } size *= 2; line = (char *) xrealloc (line, size); } -- cgit v1.2.3 From 1ef7689b9784baa31d1d723909d226fddd95bc86 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:04:51 -0700 Subject: * nsterm.h (struct ns_color_table.size, struct ns_color_table.avail): Now ptrdiff_t, not int. * nsterm.m (ns_index_color): Use ptrdiff_t, not int, for table indexes. (ns_draw_fringe_bitmap): Rewrite to avoid overflow. --- src/ChangeLog | 5 +++++ src/nsterm.h | 4 ++-- src/nsterm.m | 21 ++++++++++++++------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 4e10537edc..748ccc333b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * nsterm.h (struct ns_color_table.size, struct ns_color_table.avail): + Now ptrdiff_t, not int. + * nsterm.m (ns_index_color): Use ptrdiff_t, not int, for table indexes. + (ns_draw_fringe_bitmap): Rewrite to avoid overflow. + * minibuf.c (read_minibuf_noninteractive): Don't leak memory on memory overflow. diff --git a/src/nsterm.h b/src/nsterm.h index f419391a11..17003ac947 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -416,8 +416,8 @@ struct ns_bitmap_record /* this to map between emacs color indices and NSColor objects */ struct ns_color_table { - unsigned int size; - unsigned int avail; + ptrdiff_t size; + ptrdiff_t avail; #ifdef __OBJC__ NSColor **colors; NSMutableSet *empty_indices; diff --git a/src/nsterm.m b/src/nsterm.m index 546247ab74..4fb9a8e8f6 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1343,7 +1343,7 @@ unsigned long ns_index_color (NSColor *color, struct frame *f) { struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table; - int idx; + ptrdiff_t idx; NSNumber *index; if (!color_table->colors) @@ -1358,7 +1358,7 @@ ns_index_color (NSColor *color, struct frame *f) /* do we already have this color ? */ { - int i; + ptrdiff_t i; for (i = 1; i < color_table->avail; i++) { if (color_table->colors[i] && [color_table->colors[i] isEqual: color]) @@ -1373,16 +1373,23 @@ ns_index_color (NSColor *color, struct frame *f) { index = [color_table->empty_indices anyObject]; [color_table->empty_indices removeObject: index]; - idx = [index unsignedIntValue]; + idx = [index unsignedLongValue]; } else { if (color_table->avail == color_table->size) { - color_table->size += NS_COLOR_CAPACITY; + ptrdiff_t size; + ptrdiff_t size_max = + min (ULONG_MAX, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (NSColor *)); + if (size_max - NS_COLOR_CAPACITY < color_table->size) + memory_full (SIZE_MAX); + size = color_table->size + NS_COLOR_CAPACITY; color_table->colors = (NSColor **)xrealloc (color_table->colors, - color_table->size * sizeof (NSColor *)); + size * sizeof (NSColor *)); + color_table->size = size; } idx = color_table->avail++; } @@ -2323,7 +2330,7 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, if (!img) { unsigned short *bits = p->bits + p->dh; - int len = 8 * p->h/8; + int len = p->h; int i; unsigned char *cbits = xmalloc (len); @@ -4705,7 +4712,7 @@ ns_term_shutdown (int sig) } } - + #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 /* if we get here we should send the key for input manager processing */ if (firstTime && [[NSInputManager currentInputManager] -- cgit v1.2.3 From bf2da747e95a3902bf715076aeee947d657c94cd Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:05:39 -0700 Subject: * process.c (Fnetwork_interface_list): Check for overflow in size calculation. --- src/ChangeLog | 3 +++ src/process.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/ChangeLog b/src/ChangeLog index 748ccc333b..46d2cdb82f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,8 @@ 2011-07-29 Paul Eggert + * process.c (Fnetwork_interface_list): Check for overflow + in size calculation. + * nsterm.h (struct ns_color_table.size, struct ns_color_table.avail): Now ptrdiff_t, not int. * nsterm.m (ns_index_color): Use ptrdiff_t, not int, for table indexes. diff --git a/src/process.c b/src/process.c index 236c27e5c3..31359a1f1f 100644 --- a/src/process.c +++ b/src/process.c @@ -3567,6 +3567,12 @@ format; see the description of ADDRESS in `make-network-process'. */) return Qnil; again: + if (min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX)) / sizeof *ifreqs - 25 + < ifaces) + { + xfree (ifreqs); + memory_full (SIZE_MAX); + } ifaces += 25; buf_size = ifaces * sizeof (ifreqs[0]); ifreqs = (struct ifreq *)xrealloc(ifreqs, buf_size); -- cgit v1.2.3 From 7d56f940979701a930cf9a7bc753fb9f39ce508b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:10:08 -0700 Subject: * region-cache.c (move_cache_gap): Check for size calculation overflow. --- src/ChangeLog | 2 ++ src/region-cache.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 46d2cdb82f..662d03aaf3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-29 Paul Eggert + * region-cache.c (move_cache_gap): Check for size calculation overflow. + * process.c (Fnetwork_interface_list): Check for overflow in size calculation. diff --git a/src/region-cache.c b/src/region-cache.c index d701f4d71b..e6cec96171 100644 --- a/src/region-cache.c +++ b/src/region-cache.c @@ -247,11 +247,16 @@ move_cache_gap (struct region_cache *c, EMACS_INT pos, EMACS_INT min_size) if (gap_len < min_size) { EMACS_INT i; + ptrdiff_t cache_len_max = + min (PTRDIFF_MAX, SIZE_MAX) / sizeof *c->boundaries; + ptrdiff_t min_size_max = cache_len_max - c->cache_len; - /* Always make at least NEW_CACHE_GAP elements, as long as we're - expanding anyway. */ - if (min_size < NEW_CACHE_GAP) - min_size = NEW_CACHE_GAP; + if (min_size_max < min_size) + memory_full (SIZE_MAX); + + /* Unless running out of space, make at least NEW_CACHE_GAP + elements, as long as we're expanding anyway. */ + min_size = max (min_size, min (min_size_max, NEW_CACHE_GAP)); c->boundaries = (struct boundary *) xrealloc (c->boundaries, -- cgit v1.2.3 From 1d5689025c709551296684432b04d1ad39e90c71 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:11:37 -0700 Subject: * scroll.c: Integer and memory overflow fixes. (do_line_insertion_deletion_costs): Check for size calculation overflow. Don't bother calling xmalloc when xrealloc will do. --- src/ChangeLog | 4 ++++ src/scroll.c | 41 +++++++++++++++-------------------------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 662d03aaf3..a80c370e0a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-29 Paul Eggert + * scroll.c: Integer and memory overflow fixes. + (do_line_insertion_deletion_costs): Check for size calculation overflow. + Don't bother calling xmalloc when xrealloc will do. + * region-cache.c (move_cache_gap): Check for size calculation overflow. * process.c (Fnetwork_interface_list): Check for overflow diff --git a/src/scroll.c b/src/scroll.c index 6291936a54..9184919f0c 100644 --- a/src/scroll.c +++ b/src/scroll.c @@ -969,32 +969,21 @@ do_line_insertion_deletion_costs (FRAME_PTR frame, const char *cleanup_string, int coefficient) { - if (FRAME_INSERT_COST (frame) != 0) - { - FRAME_INSERT_COST (frame) = - (int *) xrealloc (FRAME_INSERT_COST (frame), - FRAME_LINES (frame) * sizeof (int)); - FRAME_DELETEN_COST (frame) = - (int *) xrealloc (FRAME_DELETEN_COST (frame), - FRAME_LINES (frame) * sizeof (int)); - FRAME_INSERTN_COST (frame) = - (int *) xrealloc (FRAME_INSERTN_COST (frame), - FRAME_LINES (frame) * sizeof (int)); - FRAME_DELETE_COST (frame) = - (int *) xrealloc (FRAME_DELETE_COST (frame), - FRAME_LINES (frame) * sizeof (int)); - } - else - { - FRAME_INSERT_COST (frame) = - (int *) xmalloc (FRAME_LINES (frame) * sizeof (int)); - FRAME_DELETEN_COST (frame) = - (int *) xmalloc (FRAME_LINES (frame) * sizeof (int)); - FRAME_INSERTN_COST (frame) = - (int *) xmalloc (FRAME_LINES (frame) * sizeof (int)); - FRAME_DELETE_COST (frame) = - (int *) xmalloc (FRAME_LINES (frame) * sizeof (int)); - } + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < FRAME_LINES (frame)) + memory_full (SIZE_MAX); + + FRAME_INSERT_COST (frame) = + (int *) xrealloc (FRAME_INSERT_COST (frame), + FRAME_LINES (frame) * sizeof (int)); + FRAME_DELETEN_COST (frame) = + (int *) xrealloc (FRAME_DELETEN_COST (frame), + FRAME_LINES (frame) * sizeof (int)); + FRAME_INSERTN_COST (frame) = + (int *) xrealloc (FRAME_INSERTN_COST (frame), + FRAME_LINES (frame) * sizeof (int)); + FRAME_DELETE_COST (frame) = + (int *) xrealloc (FRAME_DELETE_COST (frame), + FRAME_LINES (frame) * sizeof (int)); ins_del_costs (frame, ins_line_string, multi_ins_string, -- cgit v1.2.3 From 5f2ab479cdd2e76862e80e37b9c0825471af8d4c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:13:10 -0700 Subject: * search.c: Integer and memory overflow fixes. (Freplace_match): Check for size calculation overflow. (Fset_match_data): Don't assume list lengths fit in 'int'. --- src/ChangeLog | 4 ++++ src/search.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index a80c370e0a..7570b0ba97 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,9 @@ 2011-07-29 Paul Eggert + * search.c: Integer and memory overflow fixes. + (Freplace_match): Check for size calculation overflow. + (Fset_match_data): Don't assume list lengths fit in 'int'. + * scroll.c: Integer and memory overflow fixes. (do_line_insertion_deletion_costs): Check for size calculation overflow. Don't bother calling xmalloc when xrealloc will do. diff --git a/src/search.c b/src/search.c index a56df784cd..79ef8b046d 100644 --- a/src/search.c +++ b/src/search.c @@ -2648,6 +2648,8 @@ since only regular expressions have distinguished subexpressions. */) int really_changed = 0; substed_alloc_size = length * 2 + 100; + if (min (PTRDIFF_MAX, SIZE_MAX) - 1 < substed_alloc_size) + memory_full (SIZE_MAX); substed = (unsigned char *) xmalloc (substed_alloc_size + 1); substed_len = 0; @@ -2736,6 +2738,13 @@ since only regular expressions have distinguished subexpressions. */) /* Make sure SUBSTED is big enough. */ if (substed_len + add_len >= substed_alloc_size) { + ptrdiff_t add_len_max = + min (PTRDIFF_MAX, SIZE_MAX) - 1 - 500 - substed_len; + if (add_len_max < add_len) + { + xfree (substed); + memory_full (SIZE_MAX); + } substed_alloc_size = substed_len + add_len + 500; substed = (unsigned char *) xrealloc (substed, substed_alloc_size + 1); @@ -2973,7 +2982,7 @@ LIST should have been created by calling `match-data' previously. If optional arg RESEAT is non-nil, make markers on LIST point nowhere. */) (register Lisp_Object list, Lisp_Object reseat) { - register int i; + ptrdiff_t i; register Lisp_Object marker; if (running_asynch_code) @@ -2987,10 +2996,13 @@ If optional arg RESEAT is non-nil, make markers on LIST point nowhere. */) /* Allocate registers if they don't already exist. */ { - int length = XFASTINT (Flength (list)) / 2; + ptrdiff_t length = XFASTINT (Flength (list)) / 2; if (length > search_regs.num_regs) { + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (regoff_t) < length) + memory_full (SIZE_MAX); + if (search_regs.num_regs == 0) { search_regs.start -- cgit v1.2.3 From fe6442b1151a0f4021181e968479459f50df63f1 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:16:54 -0700 Subject: * sysdep.c: Integer and memory overflow issues. (system_process_attributes): Use ptrdiff_t, not int, for command line length. Do not attempt to address one before the beginning of an array, as that's not portable. --- src/ChangeLog | 5 +++++ src/sysdep.c | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 7570b0ba97..d1db5e48da 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * sysdep.c: Integer and memory overflow issues. + (system_process_attributes): Use ptrdiff_t, not int, for command + line length. Do not attempt to address one before the beginning + of an array, as that's not portable. + * search.c: Integer and memory overflow fixes. (Freplace_match): Check for size calculation overflow. (Fset_match_data): Don't assume list lengths fit in 'int'. diff --git a/src/sysdep.c b/src/sysdep.c index 4bd1f54b9e..57fff94f55 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2640,7 +2640,7 @@ system_process_attributes (Lisp_Object pid) ssize_t nread; const char *cmd = NULL; char *cmdline = NULL; - size_t cmdsize = 0, cmdline_size; + ptrdiff_t cmdsize = 0, cmdline_size; unsigned char c; int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount; unsigned long long u_time, s_time, cutime, cstime, start; @@ -2822,8 +2822,10 @@ system_process_attributes (Lisp_Object pid) if (fd >= 0) { char ch; - for (cmdline_size = 0; emacs_read (fd, &ch, 1) == 1; cmdline_size++) + for (cmdline_size = 0; cmdline_size < STRING_BYTES_BOUND; cmdline_size++) { + if (emacs_read (fd, &ch, 1) != 1) + break; c = ch; if (isspace (c) || c == '\\') cmdline_size++; /* for later quoting, see below */ @@ -2844,7 +2846,7 @@ system_process_attributes (Lisp_Object pid) nread = 0; } /* We don't want trailing null characters. */ - for (p = cmdline + nread - 1; p > cmdline && !*p; p--) + for (p = cmdline + nread; p > cmdline + 1 && !p[-1]; p--) nread--; for (p = cmdline; p < cmdline + nread; p++) { -- cgit v1.2.3 From fee31f82d5279a6faeb2d4cef808e9d7fce2f210 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:22:19 -0700 Subject: * term.c: Integer and memory overflow issues. (max_frame_lines): Remove; unused. (encode_terminal_src_size, encode_terminal_dst_size): Now ptrdiff_t, not int. (encode_terminal_code, calculate_costs): Check for size calculation overflow. (encode_terminal_code): Use ptrdiff_t, not int, to record glyph table lengths and related sizes. Don't update size until alloc done. Redo calculations to avoid overflow. (calculate_costs): Don't bother calling xmalloc when xrealloc will do. --- src/ChangeLog | 11 ++++++++ src/term.c | 84 +++++++++++++++++++++++++++++------------------------------ 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index d1db5e48da..7485afb00f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,16 @@ 2011-07-29 Paul Eggert + * term.c: Integer and memory overflow issues. + (max_frame_lines): Remove; unused. + (encode_terminal_src_size, encode_terminal_dst_size): Now ptrdiff_t, + not int. + (encode_terminal_code, calculate_costs): Check for size + calculation overflow. + (encode_terminal_code): Use ptrdiff_t, not int, to record glyph + table lengths and related sizes. Don't update size until alloc + done. Redo calculations to avoid overflow. + (calculate_costs): Don't bother calling xmalloc when xrealloc will do. + * sysdep.c: Integer and memory overflow issues. (system_process_attributes): Use ptrdiff_t, not int, for command line length. Do not attempt to address one before the beginning diff --git a/src/term.c b/src/term.c index 22056451cb..bc6fa8f80f 100644 --- a/src/term.c +++ b/src/term.c @@ -136,10 +136,6 @@ enum no_color_bit static int max_frame_cols; -/* The largest frame height in any call to calculate_costs. */ - -static int max_frame_lines; - /* Non-zero if we have dropped our controlling tty and therefore should not open a frame on stdout. */ static int no_controlling_tty; @@ -497,8 +493,8 @@ tty_clear_end_of_line (struct frame *f, int first_unused_hpos) static unsigned char *encode_terminal_src; static unsigned char *encode_terminal_dst; /* Allocated sizes of the above buffers. */ -static int encode_terminal_src_size; -static int encode_terminal_dst_size; +static ptrdiff_t encode_terminal_src_size; +static ptrdiff_t encode_terminal_dst_size; /* Encode SRC_LEN glyphs starting at SRC to terminal output codes. Set CODING->produced to the byte-length of the resulting byte @@ -509,8 +505,8 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi { struct glyph *src_end = src + src_len; unsigned char *buf; - int nchars, nbytes, required; - register int tlen = GLYPH_TABLE_LENGTH; + ptrdiff_t nchars, nbytes, required; + ptrdiff_t tlen = GLYPH_TABLE_LENGTH; register Lisp_Object *tbase = GLYPH_TABLE_BASE; Lisp_Object charset_list; @@ -518,13 +514,13 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi multibyte-form. But, it may be enlarged on demand if Vglyph_table contains a string or a composite glyph is encountered. */ - required = MAX_MULTIBYTE_LENGTH * src_len; + if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len) + memory_full (SIZE_MAX); + required = src_len; + required *= MAX_MULTIBYTE_LENGTH; if (encode_terminal_src_size < required) { - if (encode_terminal_src) - encode_terminal_src = xrealloc (encode_terminal_src, required); - else - encode_terminal_src = xmalloc (required); + encode_terminal_src = xrealloc (encode_terminal_src, required); encode_terminal_src_size = required; } @@ -544,19 +540,23 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi if (src->u.cmp.automatic) { gstring = composition_gstring_from_id (src->u.cmp.id); - required = src->slice.cmp.to + 1 - src->slice.cmp.from; + required = src->slice.cmp.to - src->slice.cmp.from + 1; } else { cmp = composition_table[src->u.cmp.id]; - required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len; + required = cmp->glyph_len; + required *= MAX_MULTIBYTE_LENGTH; } - if (encode_terminal_src_size < nbytes + required) + if (encode_terminal_src_size - nbytes < required) { - encode_terminal_src_size = nbytes + required; - encode_terminal_src = xrealloc (encode_terminal_src, - encode_terminal_src_size); + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) - nbytes < required) + memory_full (SIZE_MAX); + size = nbytes + required; + encode_terminal_src = xrealloc (encode_terminal_src, size); + encode_terminal_src_size = size; buf = encode_terminal_src + nbytes; } @@ -627,11 +627,15 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi if (NILP (string)) { nbytes = buf - encode_terminal_src; - if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH) + if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH) { - encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH; - encode_terminal_src = xrealloc (encode_terminal_src, - encode_terminal_src_size); + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) - MAX_MULTIBYTE_LENGTH + < nbytes) + memory_full (SIZE_MAX); + size = nbytes + MAX_MULTIBYTE_LENGTH; + encode_terminal_src = xrealloc (encode_terminal_src, size); + encode_terminal_src_size = size; buf = encode_terminal_src + nbytes; } if (CHAR_BYTE8_P (c) @@ -659,11 +663,14 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi if (! STRING_MULTIBYTE (string)) string = string_to_multibyte (string); nbytes = buf - encode_terminal_src; - if (encode_terminal_src_size < nbytes + SBYTES (string)) + if (encode_terminal_src_size - nbytes < SBYTES (string)) { - encode_terminal_src_size = nbytes + SBYTES (string); - encode_terminal_src = xrealloc (encode_terminal_src, - encode_terminal_src_size); + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) - SBYTES (string) < nbytes) + memory_full (SIZE_MAX); + size = nbytes + SBYTES (string); + encode_terminal_src = xrealloc (encode_terminal_src, size); + encode_terminal_src_size = size; buf = encode_terminal_src + nbytes; } memcpy (buf, SDATA (string), SBYTES (string)); @@ -684,12 +691,9 @@ encode_terminal_code (struct glyph *src, int src_len, struct coding_system *codi coding->source = encode_terminal_src; if (encode_terminal_dst_size == 0) { + encode_terminal_dst = xrealloc (encode_terminal_dst, + encode_terminal_src_size); encode_terminal_dst_size = encode_terminal_src_size; - if (encode_terminal_dst) - encode_terminal_dst = xrealloc (encode_terminal_dst, - encode_terminal_dst_size); - else - encode_terminal_dst = xmalloc (encode_terminal_dst_size); } coding->destination = encode_terminal_dst; coding->dst_bytes = encode_terminal_dst_size; @@ -1156,18 +1160,14 @@ calculate_costs (struct frame *frame) char_ins_del_vector (i.e., char_ins_del_cost) isn't used because X turns off char_ins_del_ok. */ - max_frame_lines = max (max_frame_lines, FRAME_LINES (frame)); max_frame_cols = max (max_frame_cols, FRAME_COLS (frame)); + if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2 < max_frame_cols) + memory_full (SIZE_MAX); - if (char_ins_del_vector != 0) - char_ins_del_vector - = (int *) xrealloc (char_ins_del_vector, - (sizeof (int) - + 2 * max_frame_cols * sizeof (int))); - else - char_ins_del_vector - = (int *) xmalloc (sizeof (int) - + 2 * max_frame_cols * sizeof (int)); + char_ins_del_vector + = (int *) xrealloc (char_ins_del_vector, + (sizeof (int) + + 2 * max_frame_cols * sizeof (int))); memset (char_ins_del_vector, 0, (sizeof (int) + 2 * max_frame_cols * sizeof (int))); -- cgit v1.2.3 From 0d8f2df7c41d8904df693e4046849751adebd8ab Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:24:19 -0700 Subject: * termcap.c: Integer and memory overflow issues. (tgetent): Use ptrdiff_t, not int, to record results of subtracting pointers. (gobble_line): Check for overflow more carefully. Don't update size until alloc done. --- src/ChangeLog | 6 ++++++ src/termcap.c | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 7485afb00f..24610e3de9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,11 @@ 2011-07-29 Paul Eggert + * termcap.c: Integer and memory overflow issues. + (tgetent): Use ptrdiff_t, not int, to record results of + subtracting pointers. + (gobble_line): Check for overflow more carefully. Don't update size + until alloc done. + * term.c: Integer and memory overflow issues. (max_frame_lines): Remove; unused. (encode_terminal_src_size, encode_terminal_dst_size): Now ptrdiff_t, diff --git a/src/termcap.c b/src/termcap.c index 96b9303d62..791c593c06 100644 --- a/src/termcap.c +++ b/src/termcap.c @@ -480,7 +480,7 @@ tgetent (char *bp, const char *name) /* If BP is malloc'd by us, make sure it is big enough. */ if (malloc_size) { - int offset1 = bp1 - bp, offset2 = tc_search_point - bp; + ptrdiff_t offset1 = bp1 - bp, offset2 = tc_search_point - bp; malloc_size = offset1 + buf.size; bp = termcap_name = (char *) xrealloc (bp, malloc_size); bp1 = termcap_name + offset1; @@ -619,7 +619,6 @@ gobble_line (int fd, register struct termcap_buffer *bufp, char *append_end) register char *end; register int nread; register char *buf = bufp->beg; - register char *tem; if (!append_end) append_end = bufp->ptr; @@ -636,14 +635,17 @@ gobble_line (int fd, register struct termcap_buffer *bufp, char *append_end) { if (bufp->full == bufp->size) { - if ((PTRDIFF_MAX - 1) / 2 < bufp->size) + ptrdiff_t ptr_offset = bufp->ptr - buf; + ptrdiff_t append_end_offset = append_end - buf; + ptrdiff_t size; + if ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / 2 < bufp->size) memory_full (SIZE_MAX); - bufp->size *= 2; + size = 2 * bufp->size; /* Add 1 to size to ensure room for terminating null. */ - tem = (char *) xrealloc (buf, bufp->size + 1); - bufp->ptr = (bufp->ptr - buf) + tem; - append_end = (append_end - buf) + tem; - bufp->beg = buf = tem; + bufp->beg = buf = (char *) xrealloc (buf, size + 1); + bufp->size = size; + bufp->ptr = buf + ptr_offset; + append_end = buf + append_end_offset; } } else -- cgit v1.2.3 From 8fbadbe3d240897b2fb265e749cfc9bdeb4bac39 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:49:31 -0700 Subject: * tparam.c: Integer and memory overflow fixes. (tparam1): Use ptrdiff_t, not int, for sizes. Don't update size until alloc done. Redo size calculations to avoid overflow. Check for size calculation overflow. --- src/ChangeLog | 6 ++++++ src/tparam.c | 29 +++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 24610e3de9..144ec31c51 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,11 @@ 2011-07-29 Paul Eggert + * tparam.c: Integer and memory overflow fixes. + (tparam1): Use ptrdiff_t, not int, for sizes. + Don't update size until alloc done. + Redo size calculations to avoid overflow. + Check for size calculation overflow. + * termcap.c: Integer and memory overflow issues. (tgetent): Use ptrdiff_t, not int, to record results of subtracting pointers. diff --git a/src/tparam.c b/src/tparam.c index ed28cd7397..06cec87315 100644 --- a/src/tparam.c +++ b/src/tparam.c @@ -79,33 +79,38 @@ tparam1 (const char *string, char *outstring, int len, register const char *p = string; register char *op = outstring; char *outend; - int outlen = 0; + char *new = 0; + ptrdiff_t outlen = 0; register int tem; int *old_argp = argp; /* can move */ int *fixed_argp = argp; /* never moves */ int explicit_param_p = 0; /* set by %p */ - int doleft = 0; - int doup = 0; + ptrdiff_t doleft = 0; + ptrdiff_t doup = 0; + ptrdiff_t append_len = 0; outend = outstring + len; while (1) { /* If the buffer might be too short, make it bigger. */ - if (op + 5 >= outend) + while (outend - op - append_len <= 5) { - register char *new; - int offset = op - outstring; + ptrdiff_t offset = op - outstring; if (outlen == 0) { + if (min (PTRDIFF_MAX, SIZE_MAX) - 40 < len) + goto out_of_memory; outlen = len + 40; new = (char *) xmalloc (outlen); memcpy (new, outstring, offset); } else { + if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < outlen) + goto out_of_memory; outlen *= 2; new = (char *) xrealloc (outstring, outlen); } @@ -167,11 +172,19 @@ tparam1 (const char *string, char *outstring, int len, and this is one of them, increment it. */ while (tem == 0 || tem == '\n' || tem == '\t') { + ptrdiff_t append_len_incr; tem++; if (argp == old_argp) - doup++, outend -= strlen (up); + doup++, append_len_incr = strlen (up); else - doleft++, outend -= strlen (left); + doleft++, append_len_incr = strlen (left); + if (PTRDIFF_MAX - append_len < append_len_incr) + { + out_of_memory: + xfree (new); + memory_full (SIZE_MAX); + } + append_len += append_len_incr; } } *op++ = tem ? tem : 0200; -- cgit v1.2.3 From a5a5cbd4e3e55e5dd2afc6826f572c8520350855 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:50:56 -0700 Subject: * xdisp.c: Integer and memory overflow fixes. (store_mode_line_noprop_char, x_consider_frame_title): Use ptrdiff_t, not int, for sizes. (store_mode_line_noprop_char): Don't update size until alloc done. --- src/ChangeLog | 5 +++++ src/xdisp.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 144ec31c51..a7bc6bdd46 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * xdisp.c: Integer and memory overflow fixes. + (store_mode_line_noprop_char, x_consider_frame_title): + Use ptrdiff_t, not int, for sizes. + (store_mode_line_noprop_char): Don't update size until alloc done. + * tparam.c: Integer and memory overflow fixes. (tparam1): Use ptrdiff_t, not int, for sizes. Don't update size until alloc done. diff --git a/src/xdisp.c b/src/xdisp.c index 55296db0b8..92a7b20084 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10252,8 +10252,12 @@ store_mode_line_noprop_char (char c) double the buffer's size. */ if (mode_line_noprop_ptr == mode_line_noprop_buf_end) { - int len = MODE_LINE_NOPROP_LEN (0); - int new_size = 2 * len * sizeof *mode_line_noprop_buf; + ptrdiff_t len = MODE_LINE_NOPROP_LEN (0); + ptrdiff_t new_size; + + if (STRING_BYTES_BOUND / 2 < len) + memory_full (SIZE_MAX); + new_size = 2 * len; mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size); mode_line_noprop_buf_end = mode_line_noprop_buf + new_size; mode_line_noprop_ptr = mode_line_noprop_buf + len; @@ -10317,9 +10321,9 @@ x_consider_frame_title (Lisp_Object frame) /* Do we have more than one visible frame on this X display? */ Lisp_Object tail; Lisp_Object fmt; - int title_start; + ptrdiff_t title_start; char *title; - int len; + ptrdiff_t len; struct it it; int count = SPECPDL_INDEX (); -- cgit v1.2.3 From b7b603a0dca7695a852db57f8983bc0239f49678 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:52:29 -0700 Subject: * xfaces.c: Integer and memory overflow fixes. (Finternal_make_lisp_face): Use ptrdiff_t, not int, for sizes. Check for size calculation overflow. (cache_face): Do not overflow in size calculation. --- src/ChangeLog | 5 +++++ src/xfaces.c | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index a7bc6bdd46..3ac8c562a5 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * xfaces.c: Integer and memory overflow fixes. + (Finternal_make_lisp_face): Use ptrdiff_t, not int, for sizes. + Check for size calculation overflow. + (cache_face): Do not overflow in size calculation. + * xdisp.c: Integer and memory overflow fixes. (store_mode_line_noprop_char, x_consider_frame_title): Use ptrdiff_t, not int, for sizes. diff --git a/src/xfaces.c b/src/xfaces.c index e0dc2883f3..996bcdaf6a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -2667,8 +2667,13 @@ Value is a vector of face attributes. */) property `face' of the Lisp face name. */ if (next_lface_id == lface_id_to_name_size) { - int new_size = max (50, 2 * lface_id_to_name_size); - int sz = new_size * sizeof *lface_id_to_name; + ptrdiff_t new_size, sz; + if (min (min (PTRDIFF_MAX, SIZE_MAX) / 2 / sizeof *lface_id_to_name, + MOST_POSITIVE_FIXNUM) + < lface_id_to_name_size) + memory_full (SIZE_MAX); + new_size = max (50, 2 * lface_id_to_name_size); + sz = new_size * sizeof *lface_id_to_name; lface_id_to_name = (Lisp_Object *) xrealloc (lface_id_to_name, sz); lface_id_to_name_size = new_size; } @@ -4411,7 +4416,10 @@ cache_face (struct face_cache *c, struct face *face, unsigned int hash) if (c->used == c->size) { int new_size, sz; - new_size = min (2 * c->size, MAX_FACE_ID); + new_size = + min (2 * c->size, + min (MAX_FACE_ID, + min (PTRDIFF_MAX, SIZE_MAX) / sizeof *c->faces_by_id)); if (new_size == c->size) abort (); /* Alternatives? ++kfs */ sz = new_size * sizeof *c->faces_by_id; -- cgit v1.2.3 From c678c83546bee743707bd0e259cc2aba192180c3 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:55:31 -0700 Subject: * xfns.c: Integer and memory overflow fixes. (x_encode_text, x_set_name_internal, Fx_change_window_property): Use ptrdiff_t, not int, to count sizes, since they can exceed INT_MAX in size. Check for size calculation overflow. --- src/ChangeLog | 5 +++++ src/xfns.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 3ac8c562a5..7a0543e46c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * xfns.c: Integer and memory overflow fixes. + (x_encode_text, x_set_name_internal, Fx_change_window_property): + Use ptrdiff_t, not int, to count sizes, since they can exceed + INT_MAX in size. Check for size calculation overflow. + * xfaces.c: Integer and memory overflow fixes. (Finternal_make_lisp_face): Use ptrdiff_t, not int, for sizes. Check for size calculation overflow. diff --git a/src/xfns.c b/src/xfns.c index 623b7847c1..2751544d82 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1471,7 +1471,8 @@ x_set_scroll_bar_background (struct frame *f, Lisp_Object value, Lisp_Object old the result should be `COMPOUND_TEXT'. */ static unsigned char * -x_encode_text (Lisp_Object string, Lisp_Object coding_system, int selectionp, int *text_bytes, int *stringp, int *freep) +x_encode_text (Lisp_Object string, Lisp_Object coding_system, int selectionp, + ptrdiff_t *text_bytes, int *stringp, int *freep) { int result = string_xstring_p (string); struct coding_system coding; @@ -1489,6 +1490,8 @@ x_encode_text (Lisp_Object string, Lisp_Object coding_system, int selectionp, in coding.mode |= (CODING_MODE_SAFE_ENCODING | CODING_MODE_LAST_BLOCK); /* We suppress producing escape sequences for composition. */ coding.common_flags &= ~CODING_ANNOTATION_MASK; + if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < SCHARS (string)) + memory_full (SIZE_MAX); coding.dst_bytes = SCHARS (string) * 2; coding.destination = (unsigned char *) xmalloc (coding.dst_bytes); encode_coding_object (&coding, string, 0, 0, @@ -1512,7 +1515,8 @@ x_set_name_internal (FRAME_PTR f, Lisp_Object name) BLOCK_INPUT; { XTextProperty text, icon; - int bytes, stringp; + ptrdiff_t bytes; + int stringp; int do_free_icon_value = 0, do_free_text_value = 0; Lisp_Object coding_system; Lisp_Object encoded_name; @@ -1551,6 +1555,8 @@ x_set_name_internal (FRAME_PTR f, Lisp_Object name) : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT); text.format = 8; text.nitems = bytes; + if (text.nitems != bytes) + error ("Window name too large"); if (!STRINGP (f->icon_name)) { @@ -1566,6 +1572,8 @@ x_set_name_internal (FRAME_PTR f, Lisp_Object name) : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT); icon.format = 8; icon.nitems = bytes; + if (icon.nitems != bytes) + error ("Icon name too large"); encoded_icon_name = ENCODE_UTF_8 (f->icon_name); } @@ -4194,21 +4202,21 @@ FRAME. Default is to change on the edit X window. */) if (CONSP (value)) { + ptrdiff_t elsize; + nelements = x_check_property_data (value); if (nelements == -1) error ("Bad data in VALUE, must be number, string or cons"); - if (element_format == 8) - data = (unsigned char *) xmalloc (nelements); - else if (element_format == 16) - data = (unsigned char *) xmalloc (nelements*2); - else /* format == 32 */ - /* The man page for XChangeProperty: - "If the specified format is 32, the property data must be a - long array." - This applies even if long is more than 64 bits. The X library - converts to 32 bits before sending to the X server. */ - data = (unsigned char *) xmalloc (nelements * sizeof(long)); + /* The man page for XChangeProperty: + "If the specified format is 32, the property data must be a + long array." + This applies even if long is more than 32 bits. The X library + converts to 32 bits before sending to the X server. */ + elsize = element_format == 32 ? sizeof (long) : element_format >> 3; + if (min (PTRDIFF_MAX, SIZE_MAX) / elsize < nelements) + memory_full (SIZE_MAX); + data = (unsigned char *) xmalloc (nelements * elsize); x_fill_property_data (FRAME_X_DISPLAY (f), value, data, element_format); } @@ -4216,7 +4224,9 @@ FRAME. Default is to change on the edit X window. */) { CHECK_STRING (value); data = SDATA (value); - nelements = SCHARS (value); + if (INT_MAX < SBYTES (value)) + error ("VALUE too long"); + nelements = SBYTES (value); } BLOCK_INPUT; -- cgit v1.2.3 From c26f25213a70687820290a58189e58e687ef498c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:56:54 -0700 Subject: * xgselect.c (xg_select): Check for size calculation overflow. Don't update size until alloc done. --- src/ChangeLog | 3 +++ src/xgselect.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 7a0543e46c..b5c5afd7a1 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,8 @@ 2011-07-29 Paul Eggert + * xgselect.c (xg_select): Check for size calculation overflow. + Don't update size until alloc done. + * xfns.c: Integer and memory overflow fixes. (x_encode_text, x_set_name_internal, Fx_change_window_property): Use ptrdiff_t, not int, to count sizes, since they can exceed diff --git a/src/xgselect.c b/src/xgselect.c index 9ccdd37489..d184461007 100644 --- a/src/xgselect.c +++ b/src/xgselect.c @@ -54,10 +54,16 @@ xg_select (int max_fds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, do { if (n_gfds > gfds_size) { - while (n_gfds > gfds_size) - gfds_size *= 2; + int gfds_size_max = + min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX) / sizeof *gfds); + int size; + if (gfds_size_max / 2 < n_gfds) + memory_full (SIZE_MAX); + size = 2 * n_gfds; + gfds_size = 0; xfree (gfds); - gfds = xmalloc (sizeof (*gfds) * gfds_size); + gfds = xmalloc (sizeof *gfds * size); + gfds_size = size; } n_gfds = g_main_context_query (context, -- cgit v1.2.3 From a3d9c2a4ce11ea001c9ac97c8a6fb9a4f9a1d1ac Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 18:59:57 -0700 Subject: * xrdb.c: Integer and memory overflow issues. (magic_file_p): Plug memory leak on size overflow. (get_environ_db): Don't assume path length fits in int, as sprintf is limited to int lengths. --- src/ChangeLog | 5 +++++ src/xrdb.c | 21 +++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index b5c5afd7a1..09ee5a8e4d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2011-07-29 Paul Eggert + * xrdb.c: Integer and memory overflow issues. + (magic_file_p): Plug memory leak on size overflow. + (get_environ_db): Don't assume path length fits in int, + as sprintf is limited to int lengths. + * xgselect.c (xg_select): Check for size calculation overflow. Don't update size until alloc done. diff --git a/src/xrdb.c b/src/xrdb.c index 6a16e3260b..7c2cd586b0 100644 --- a/src/xrdb.c +++ b/src/xrdb.c @@ -204,7 +204,10 @@ magic_file_p (const char *string, EMACS_INT string_len, const char *class, if (path_size - path_len <= next_len) { if (min (PTRDIFF_MAX, SIZE_MAX) / 2 - 1 - path_len < next_len) - memory_full (SIZE_MAX); + { + xfree (path); + memory_full (SIZE_MAX); + } path_size = (path_len + next_len + 1) * 2; path = (char *) xrealloc (path, path_size); } @@ -426,24 +429,22 @@ get_environ_db (void) { XrmDatabase db; char *p; - char *path = 0, *home = 0; - const char *host; + char *path = 0; if ((p = getenv ("XENVIRONMENT")) == NULL) { - home = gethomedir (); - host = get_system_name (); - path = (char *) xmalloc (strlen (home) - + sizeof (".Xdefaults-") - + strlen (host)); - sprintf (path, "%s%s%s", home, ".Xdefaults-", host); + static char const xdefaults[] = ".Xdefaults-"; + char *home = gethomedir (); + char const *host = get_system_name (); + ptrdiff_t pathsize = strlen (home) + sizeof xdefaults + strlen (host); + path = (char *) xrealloc (home, pathsize); + strcat (strcat (path, xdefaults), host); p = path; } db = XrmGetFileDatabase (p); xfree (path); - xfree (home); return db; } -- cgit v1.2.3 From 864d7ce76d118b7bc157176a03a0a8a1b02fd989 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 22:08:30 -0700 Subject: * xselect.c: Integer and memory overflow issues. (X_LONG_SIZE, X_USHRT_MAX, X_ULONG_MAX): New macros. Use them to make the following changes clearer. (MAX_SELECTION_QUANTUM): Make the other bounds on this value clearer. This change doesn't affect the value now, but it may help remind future maintainers not to raise the value too much later. (SELECTION_QUANTUM): Remove, replacing with ... (selection_quantum): ... new function, which avoids overflow. All uses changed. (struct selection_data.size): Now ptrdiff_t, not int, to avoid assumption that selection length fits in 'int'. (x_reply_selection_request, x_handle_selection_request) (x_get_window_property, receive_incremental_selection) (x_get_window_property_as_lisp_data, selection_data_to_lisp_data) (lisp_data_to_selection_data, clean_local_selection_data): Use ptrdiff_t, not int, to record length of selection. (x_reply_selection_request, x_get_window_property) (receive_incremental_selection, x_property_data_to_lisp): Redo calculations to avoid overflow. (x_reply_selection_request): When sending hint, ceiling it at X_ULONG_MAX rather than relying on wraparound overflow to send something. (x_get_window_property, receive_incremental_selection) (lisp_data_to_selection_data, x_property_data_to_lisp): Check for size-calculation overflow. (x_get_window_property, receive_incremental_selection) (lisp_data_to_selection_data, Fx_register_dnd_atom): Don't store size until memory allocation succeeds. (x_get_window_property): Plug memory leak on memory exhaustion. Don't double-block input; malloc is safe here. Don't assume 2**34 - 4 fits in unsigned long. Add an xassert to check XGetWindowProperty overflow. Be more careful about overflow calculations, and distinguish size from memory overflow better. (receive_incremental_selection): When tracing, don't assume unsigned int is less than INT_MAX. (x_selection_data_to_lisp_data): Remove unnecessary (and in theory harmful) conversions of unsigned short to int. (lisp_data_to_selection_data): Don't assume that integers in the range -65535 through -1 fit in an X unsigned short. Don't assume that ULONG_MAX == X_ULONG_MAX. Don't store into result parameters unless successful. Rely on cons_to_unsigned to report problems with elements; the old code wasn't right anyway. (x_check_property_data): Check for int overflow; we cannot use a wider type due to X limits. (x_handle_dnd_message): Use unsigned int, to avoid int overflow. --- src/ChangeLog | 46 +++++++++ src/xselect.c | 307 +++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 232 insertions(+), 121 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 09ee5a8e4d..f8e5ca78b3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,51 @@ 2011-07-29 Paul Eggert + * xselect.c: Integer and memory overflow issues. + (X_LONG_SIZE, X_USHRT_MAX, X_ULONG_MAX): New macros. + Use them to make the following changes clearer. + (MAX_SELECTION_QUANTUM): Make the other bounds on this value clearer. + This change doesn't affect the value now, but it may help remind + future maintainers not to raise the value too much later. + (SELECTION_QUANTUM): Remove, replacing with ... + (selection_quantum): ... new function, which avoids overflow. + All uses changed. + (struct selection_data.size): Now ptrdiff_t, not int, to avoid + assumption that selection length fits in 'int'. + (x_reply_selection_request, x_handle_selection_request) + (x_get_window_property, receive_incremental_selection) + (x_get_window_property_as_lisp_data, selection_data_to_lisp_data) + (lisp_data_to_selection_data, clean_local_selection_data): + Use ptrdiff_t, not int, to record length of selection. + (x_reply_selection_request, x_get_window_property) + (receive_incremental_selection, x_property_data_to_lisp): + Redo calculations to avoid overflow. + (x_reply_selection_request): When sending hint, ceiling it at + X_ULONG_MAX rather than relying on wraparound overflow to send + something. + (x_get_window_property, receive_incremental_selection) + (lisp_data_to_selection_data, x_property_data_to_lisp): + Check for size-calculation overflow. + (x_get_window_property, receive_incremental_selection) + (lisp_data_to_selection_data, Fx_register_dnd_atom): + Don't store size until memory allocation succeeds. + (x_get_window_property): Plug memory leak on memory exhaustion. + Don't double-block input; malloc is safe here. Don't assume 2**34 + - 4 fits in unsigned long. Add an xassert to check + XGetWindowProperty overflow. Be more careful about overflow + calculations, and distinguish size from memory overflow better. + (receive_incremental_selection): When tracing, don't assume + unsigned int is less than INT_MAX. + (x_selection_data_to_lisp_data): Remove unnecessary (and in theory + harmful) conversions of unsigned short to int. + (lisp_data_to_selection_data): Don't assume that integers + in the range -65535 through -1 fit in an X unsigned short. + Don't assume that ULONG_MAX == X_ULONG_MAX. Don't store into + result parameters unless successful. Rely on cons_to_unsigned + to report problems with elements; the old code wasn't right anyway. + (x_check_property_data): Check for int overflow; we cannot use + a wider type due to X limits. + (x_handle_dnd_message): Use unsigned int, to avoid int overflow. + * xrdb.c: Integer and memory overflow issues. (magic_file_p): Plug memory leak on size overflow. (get_environ_db): Don't assume path length fits in int, diff --git a/src/xselect.c b/src/xselect.c index f63977a73d..d8b7b077a8 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -66,22 +66,15 @@ static Lisp_Object wait_for_property_change_unwind (Lisp_Object); static void wait_for_property_change (struct prop_location *); static Lisp_Object x_get_foreign_selection (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); -static void x_get_window_property (Display *, Window, Atom, - unsigned char **, int *, - Atom *, int *, unsigned long *, int); -static void receive_incremental_selection (Display *, Window, Atom, - Lisp_Object, unsigned, - unsigned char **, int *, - Atom *, int *, unsigned long *); static Lisp_Object x_get_window_property_as_lisp_data (Display *, Window, Atom, Lisp_Object, Atom); static Lisp_Object selection_data_to_lisp_data (Display *, const unsigned char *, - int, Atom, int); + ptrdiff_t, Atom, int); static void lisp_data_to_selection_data (Display *, Lisp_Object, unsigned char **, Atom *, - unsigned *, int *, int *); + ptrdiff_t *, int *, int *); static Lisp_Object clean_local_selection_data (Lisp_Object); /* Printing traces to stderr. */ @@ -114,15 +107,37 @@ static Lisp_Object Qcompound_text_with_extensions; static Lisp_Object Qforeign_selection; static Lisp_Object Qx_lost_selection_functions, Qx_sent_selection_functions; +/* Bytes needed to represent 'long' data. This is as per libX11; it + is not necessarily sizeof (long). */ +#define X_LONG_SIZE 4 + +/* Maximum unsigned 'short' and 'long' values suitable for libX11. */ +#define X_USHRT_MAX 0xffff +#define X_ULONG_MAX 0xffffffff + /* If this is a smaller number than the max-request-size of the display, emacs will use INCR selection transfer when the selection is larger than this. The max-request-size is usually around 64k, so if you want emacs to use incremental selection transfers when the selection is smaller than that, set this. I added this mostly for debugging the - incremental transfer stuff, but it might improve server performance. */ -#define MAX_SELECTION_QUANTUM 0xFFFFFF + incremental transfer stuff, but it might improve server performance. + + This value cannot exceed INT_MAX / max (X_LONG_SIZE, sizeof (long)) + because it is multiplied by X_LONG_SIZE and by sizeof (long) in + subscript calculations. Similarly for PTRDIFF_MAX - 1 or SIZE_MAX + - 1 in place of INT_MAX. */ +#define MAX_SELECTION_QUANTUM \ + ((int) min (0xFFFFFF, (min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX) - 1) \ + / max (X_LONG_SIZE, sizeof (long))))) -#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100) +static int +selection_quantum (Display *display) +{ + long mrs = XMaxRequestSize (display); + return (mrs < MAX_SELECTION_QUANTUM / X_LONG_SIZE + 25 + ? (mrs - 25) * X_LONG_SIZE + : MAX_SELECTION_QUANTUM); +} #define LOCAL_SELECTION(selection_symbol,dpyinfo) \ assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) @@ -477,7 +492,7 @@ static struct x_display_info *selection_request_dpyinfo; struct selection_data { unsigned char *data; - unsigned int size; + ptrdiff_t size; int format; Atom type; int nofree; @@ -581,14 +596,11 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy XSelectionEvent *reply = &(reply_base.xselection); Display *display = SELECTION_EVENT_DISPLAY (event); Window window = SELECTION_EVENT_REQUESTOR (event); - int bytes_remaining; - int max_bytes = SELECTION_QUANTUM (display); + ptrdiff_t bytes_remaining; + int max_bytes = selection_quantum (display); int count = SPECPDL_INDEX (); struct selection_data *cs; - if (max_bytes > MAX_SELECTION_QUANTUM) - max_bytes = MAX_SELECTION_QUANTUM; - reply->type = SelectionNotify; reply->display = display; reply->requestor = window; @@ -616,11 +628,12 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy if (cs->property == None) continue; - bytes_remaining = cs->size * (cs->format / 8); + bytes_remaining = cs->size; + bytes_remaining *= cs->format >> 3; if (bytes_remaining <= max_bytes) { /* Send all the data at once, with minimal handshaking. */ - TRACE1 ("Sending all %d bytes", bytes_remaining); + TRACE1 ("Sending all %"pD"d bytes", bytes_remaining); XChangeProperty (display, window, cs->property, cs->type, cs->format, PropModeReplace, cs->data, cs->size); @@ -628,9 +641,9 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy else { /* Send an INCR tag to initiate incremental transfer. */ - long value[1]; + unsigned long value[1]; - TRACE2 ("Start sending %d bytes incrementally (%s)", + TRACE2 ("Start sending %"pD"d bytes incrementally (%s)", bytes_remaining, XGetAtomName (display, cs->property)); cs->wait_object = expect_property_change (display, window, cs->property, @@ -638,7 +651,7 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy /* XChangeProperty expects an array of long even if long is more than 32 bits. */ - value[0] = bytes_remaining; + value[0] = min (bytes_remaining, X_ULONG_MAX); XChangeProperty (display, window, cs->property, dpyinfo->Xatom_INCR, 32, PropModeReplace, (unsigned char *) value, 1); @@ -672,7 +685,8 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy int had_errors = x_had_errors_p (display); UNBLOCK_INPUT; - bytes_remaining = cs->size * format_bytes; + bytes_remaining = cs->size; + bytes_remaining *= format_bytes; /* Wait for the requester to ack by deleting the property. This can run Lisp code (process handlers) or signal. */ @@ -810,7 +824,7 @@ x_handle_selection_request (struct input_event *event) non-None property. */ Window requestor = SELECTION_EVENT_REQUESTOR (event); Lisp_Object multprop; - int j, nselections; + ptrdiff_t j, nselections; if (property == None) goto DONE; multprop @@ -1269,19 +1283,28 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, static void x_get_window_property (Display *display, Window window, Atom property, - unsigned char **data_ret, int *bytes_ret, + unsigned char **data_ret, ptrdiff_t *bytes_ret, Atom *actual_type_ret, int *actual_format_ret, unsigned long *actual_size_ret, int delete_p) { - int total_size; + ptrdiff_t total_size; unsigned long bytes_remaining; - int offset = 0; + ptrdiff_t offset = 0; + unsigned char *data = 0; unsigned char *tmp_data = 0; int result; - int buffer_size = SELECTION_QUANTUM (display); + int buffer_size = selection_quantum (display); + + /* Wide enough to avoid overflow in expressions using it. */ + ptrdiff_t x_long_size = X_LONG_SIZE; - if (buffer_size > MAX_SELECTION_QUANTUM) - buffer_size = MAX_SELECTION_QUANTUM; + /* Maximum value for TOTAL_SIZE. It cannot exceed PTRDIFF_MAX - 1 + and SIZE_MAX - 1, for an extra byte at the end. And it cannot + exceed LONG_MAX * X_LONG_SIZE, for XGetWindowProperty. */ + ptrdiff_t total_size_max = + ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / x_long_size < LONG_MAX + ? min (PTRDIFF_MAX, SIZE_MAX) - 1 + : LONG_MAX * x_long_size); BLOCK_INPUT; @@ -1292,49 +1315,44 @@ x_get_window_property (Display *display, Window window, Atom property, actual_size_ret, &bytes_remaining, &tmp_data); if (result != Success) - { - UNBLOCK_INPUT; - *data_ret = 0; - *bytes_ret = 0; - return; - } + goto done; /* This was allocated by Xlib, so use XFree. */ XFree ((char *) tmp_data); if (*actual_type_ret == None || *actual_format_ret == 0) - { - UNBLOCK_INPUT; - return; - } + goto done; - total_size = bytes_remaining + 1; - *data_ret = (unsigned char *) xmalloc (total_size); + if (total_size_max < bytes_remaining) + goto size_overflow; + total_size = bytes_remaining; + data = malloc (total_size + 1); + if (! data) + goto memory_exhausted; /* Now read, until we've gotten it all. */ while (bytes_remaining) { -#ifdef TRACE_SELECTION - unsigned long last = bytes_remaining; -#endif + ptrdiff_t bytes_gotten; + int bytes_per_item; result = XGetWindowProperty (display, window, property, - (long)offset/4, (long)buffer_size/4, + offset / X_LONG_SIZE, + buffer_size / X_LONG_SIZE, False, AnyPropertyType, actual_type_ret, actual_format_ret, actual_size_ret, &bytes_remaining, &tmp_data); - TRACE2 ("Read %lu bytes from property %s", - last - bytes_remaining, - XGetAtomName (display, property)); - /* If this doesn't return Success at this point, it means that some clod deleted the selection while we were in the midst of reading it. Deal with that, I guess.... */ if (result != Success) break; + bytes_per_item = *actual_format_ret >> 3; + xassert (*actual_size_ret <= buffer_size / bytes_per_item); + /* The man page for XGetWindowProperty says: "If the returned format is 32, the returned data is represented as a long array and should be cast to that type to obtain the @@ -1348,32 +1366,61 @@ x_get_window_property (Display *display, Window window, Atom property, The bytes and offsets passed to XGetWindowProperty refers to the property and those are indeed in 32 bit quantities if format is 32. */ + bytes_gotten = *actual_size_ret; + bytes_gotten *= bytes_per_item; + + TRACE2 ("Read %"pD"d bytes from property %s", + bytes_gotten, XGetAtomName (display, property)); + + if (total_size - offset < bytes_gotten) + { + unsigned char *data1; + ptrdiff_t remaining_lim = total_size_max - offset - bytes_gotten; + if (remaining_lim < 0 || remaining_lim < bytes_remaining) + goto size_overflow; + total_size = offset + bytes_gotten + bytes_remaining; + data1 = realloc (data, total_size + 1); + if (! data1) + goto memory_exhausted; + data = data1; + } + if (32 < BITS_PER_LONG && *actual_format_ret == 32) { unsigned long i; - int *idata = (int *) ((*data_ret) + offset); + int *idata = (int *) (data + offset); long *ldata = (long *) tmp_data; for (i = 0; i < *actual_size_ret; ++i) - { - idata[i]= (int) ldata[i]; - offset += 4; - } + idata[i] = ldata[i]; } else - { - *actual_size_ret *= *actual_format_ret / 8; - memcpy ((*data_ret) + offset, tmp_data, *actual_size_ret); - offset += *actual_size_ret; - } + memcpy (data + offset, tmp_data, bytes_gotten); + + offset += bytes_gotten; /* This was allocated by Xlib, so use XFree. */ XFree ((char *) tmp_data); } XFlush (display); + data[offset] = '\0'; + + done: UNBLOCK_INPUT; + *data_ret = data; *bytes_ret = offset; + return; + + size_overflow: + free (data); + UNBLOCK_INPUT; + memory_full (SIZE_MAX); + + memory_exhausted: + free (data); + UNBLOCK_INPUT; + memory_full (total_size + 1); } /* Use xfree, not XFree, to free the data obtained with this function. */ @@ -1382,16 +1429,19 @@ static void receive_incremental_selection (Display *display, Window window, Atom property, Lisp_Object target_type, unsigned int min_size_bytes, - unsigned char **data_ret, int *size_bytes_ret, + unsigned char **data_ret, + ptrdiff_t *size_bytes_ret, Atom *type_ret, int *format_ret, unsigned long *size_ret) { - int offset = 0; + ptrdiff_t offset = 0; struct prop_location *wait_object; + if (min (PTRDIFF_MAX, SIZE_MAX) < min_size_bytes) + memory_full (SIZE_MAX); + *data_ret = (unsigned char *) xmalloc (min_size_bytes); *size_bytes_ret = min_size_bytes; - *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); - TRACE1 ("Read %d bytes incrementally", min_size_bytes); + TRACE1 ("Read %u bytes incrementally", min_size_bytes); /* At this point, we have read an INCR property. Delete the property to ack it. @@ -1416,7 +1466,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, while (1) { unsigned char *tmp_data; - int tmp_size_bytes; + ptrdiff_t tmp_size_bytes; TRACE0 (" Wait for property change"); wait_for_property_change (wait_object); @@ -1429,7 +1479,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, &tmp_data, &tmp_size_bytes, type_ret, format_ret, size_ret, 1); - TRACE1 (" Read increment of %d bytes", tmp_size_bytes); + TRACE1 (" Read increment of %"pD"d bytes", tmp_size_bytes); if (tmp_size_bytes == 0) /* we're done */ { @@ -1452,10 +1502,17 @@ receive_incremental_selection (Display *display, Window window, Atom property, XFlush (display); UNBLOCK_INPUT; - if (*size_bytes_ret < offset + tmp_size_bytes) + if (*size_bytes_ret - offset < tmp_size_bytes) { - *size_bytes_ret = offset + tmp_size_bytes; - *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret); + ptrdiff_t size; + if (min (PTRDIFF_MAX, SIZE_MAX) - offset < tmp_size_bytes) + { + xfree (tmp_data); + memory_full (SIZE_MAX); + } + size = offset + tmp_size_bytes; + *data_ret = (unsigned char *) xrealloc (*data_ret, size); + *size_bytes_ret = size; } memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes); @@ -1482,7 +1539,7 @@ x_get_window_property_as_lisp_data (Display *display, Window window, int actual_format; unsigned long actual_size; unsigned char *data = 0; - int bytes = 0; + ptrdiff_t bytes = 0; Lisp_Object val; struct x_display_info *dpyinfo = x_display_info_for_display (display); @@ -1574,7 +1631,7 @@ x_get_window_property_as_lisp_data (Display *display, Window window, static Lisp_Object selection_data_to_lisp_data (Display *display, const unsigned char *data, - int size, Atom type, int format) + ptrdiff_t size, Atom type, int format) { struct x_display_info *dpyinfo = x_display_info_for_display (display); @@ -1607,7 +1664,7 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data, /* Treat ATOM_PAIR type similar to list of atoms. */ || type == dpyinfo->Xatom_ATOM_PAIR) { - int i; + ptrdiff_t i; /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8. But the callers of these function has made sure the data for format == 32 is an array of int. Thus, use int instead @@ -1634,28 +1691,29 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data, else if (format == 32 && size == sizeof (int)) return INTEGER_TO_CONS (((unsigned int *) data) [0]); else if (format == 16 && size == sizeof (short)) - return make_number ((int) (((unsigned short *) data) [0])); + return make_number (((unsigned short *) data) [0]); /* Convert any other kind of data to a vector of numbers, represented as above (as an integer, or a cons of two 16 bit integers.) */ else if (format == 16) { - int i; + ptrdiff_t i; Lisp_Object v; v = Fmake_vector (make_number (size / 2), make_number (0)); for (i = 0; i < size / 2; i++) { - int j = (int) ((unsigned short *) data) [i]; + EMACS_INT j = ((unsigned short *) data) [i]; Faset (v, make_number (i), make_number (j)); } return v; } else { - int i; - Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0)); - for (i = 0; i < size / 4; i++) + ptrdiff_t i; + Lisp_Object v = Fmake_vector (make_number (size / X_LONG_SIZE), + make_number (0)); + for (i = 0; i < size / X_LONG_SIZE; i++) { unsigned int j = ((unsigned int *) data) [i]; Faset (v, make_number (i), INTEGER_TO_CONS (j)); @@ -1670,7 +1728,7 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data, static void lisp_data_to_selection_data (Display *display, Lisp_Object obj, unsigned char **data_ret, Atom *type_ret, - unsigned int *size_ret, + ptrdiff_t *size_ret, int *format_ret, int *nofree_ret) { Lisp_Object type = Qnil; @@ -1707,22 +1765,20 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, } else if (SYMBOLP (obj)) { + *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1); *format_ret = 32; *size_ret = 1; - *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1); (*data_ret) [sizeof (Atom)] = 0; (*(Atom **) data_ret) [0] = symbol_to_x_atom (dpyinfo, obj); if (NILP (type)) type = QATOM; } - else if (INTEGERP (obj) - && XINT (obj) < 0xFFFF - && XINT (obj) > -0xFFFF) + else if (RANGED_INTEGERP (0, obj, X_USHRT_MAX)) { + *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1); *format_ret = 16; *size_ret = 1; - *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1); (*data_ret) [sizeof (short)] = 0; - (*(short **) data_ret) [0] = (short) XINT (obj); + (*(unsigned short **) data_ret) [0] = XINT (obj); if (NILP (type)) type = QINTEGER; } else if (INTEGERP (obj) @@ -1731,11 +1787,11 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, || (CONSP (XCDR (obj)) && INTEGERP (XCAR (XCDR (obj))))))) { + *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1); *format_ret = 32; *size_ret = 1; - *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1); (*data_ret) [sizeof (long)] = 0; - (*(unsigned long **) data_ret) [0] = cons_to_unsigned (obj, ULONG_MAX); + (*(unsigned long **) data_ret) [0] = cons_to_unsigned (obj, X_ULONG_MAX); if (NILP (type)) type = QINTEGER; } else if (VECTORP (obj)) @@ -1744,50 +1800,54 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, a set of 16 or 32 bit INTEGERs; or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...] */ - int i; + ptrdiff_t i; + ptrdiff_t size = ASIZE (obj); if (SYMBOLP (XVECTOR (obj)->contents [0])) /* This vector is an ATOM set */ { + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (Atom) < size) + memory_full (SIZE_MAX); if (NILP (type)) type = QATOM; - *size_ret = ASIZE (obj); - *format_ret = 32; - for (i = 0; i < *size_ret; i++) + for (i = 0; i < size; i++) if (!SYMBOLP (XVECTOR (obj)->contents [i])) signal_error ("All elements of selection vector must have same type", obj); - *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom)); - for (i = 0; i < *size_ret; i++) + *data_ret = (unsigned char *) xmalloc (size * sizeof (Atom)); + *format_ret = 32; + *size_ret = size; + for (i = 0; i < size; i++) (*(Atom **) data_ret) [i] = symbol_to_x_atom (dpyinfo, XVECTOR (obj)->contents [i]); } else /* This vector is an INTEGER set, or something like it */ { + int format = 16; int data_size = 2; - *size_ret = ASIZE (obj); if (NILP (type)) type = QINTEGER; - *format_ret = 16; - for (i = 0; i < *size_ret; i++) - if (CONSP (XVECTOR (obj)->contents [i])) - *format_ret = 32; - else if (!INTEGERP (XVECTOR (obj)->contents [i])) - signal_error (/* Qselection_error */ - "Elements of selection vector must be integers or conses of integers", - obj); - - /* Use sizeof(long) even if it is more than 32 bits. See comment - in x_get_window_property and x_fill_property_data. */ - - if (*format_ret == 32) data_size = sizeof(long); - *data_ret = (unsigned char *) xmalloc (*size_ret * data_size); - for (i = 0; i < *size_ret; i++) - if (*format_ret == 32) + for (i = 0; i < size; i++) + if (X_USHRT_MAX + < cons_to_unsigned (XVECTOR (obj)->contents[i], X_ULONG_MAX)) + { + /* Use sizeof (long) even if it is more than 32 bits. + See comment in x_get_window_property and + x_fill_property_data. */ + data_size = sizeof (long); + format = 32; + } + if (min (PTRDIFF_MAX, SIZE_MAX) / data_size < size) + memory_full (SIZE_MAX); + *data_ret = (unsigned char *) xmalloc (size * data_size); + *format_ret = format; + *size_ret = size; + for (i = 0; i < size; i++) + if (format == 32) (*((unsigned long **) data_ret)) [i] = - cons_to_unsigned (XVECTOR (obj)->contents [i], ULONG_MAX); + cons_to_unsigned (XVECTOR (obj)->contents[i], X_ULONG_MAX); else (*((unsigned short **) data_ret)) [i] = - cons_to_unsigned (XVECTOR (obj)->contents [i], USHRT_MAX); + cons_to_unsigned (XVECTOR (obj)->contents[i], X_USHRT_MAX); } } else @@ -1817,8 +1877,8 @@ clean_local_selection_data (Lisp_Object obj) } if (VECTORP (obj)) { - int i; - int size = ASIZE (obj); + ptrdiff_t i; + ptrdiff_t size = ASIZE (obj); Lisp_Object copy; if (size == 1) return clean_local_selection_data (XVECTOR (obj)->contents [0]); @@ -2213,6 +2273,8 @@ x_check_property_data (Lisp_Object data) else if (CONSP (o) && (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o)))) return -1; + if (size == INT_MAX) + return -1; size++; } @@ -2294,8 +2356,11 @@ Lisp_Object x_property_data_to_lisp (struct frame *f, const unsigned char *data, Atom type, int format, long unsigned int size) { + ptrdiff_t format_bytes = format >> 3; + if (PTRDIFF_MAX / format_bytes < size) + memory_full (SIZE_MAX); return selection_data_to_lisp_data (FRAME_X_DISPLAY (f), - data, size*format/8, type, format); + data, size * format_bytes, type, format); } /* Get the mouse position in frame relative coordinates. */ @@ -2405,10 +2470,10 @@ FRAME is on. If FRAME is nil, the selected frame is used. */) if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *dpyinfo->x_dnd_atoms / 2 < dpyinfo->x_dnd_atoms_size) memory_full (SIZE_MAX); - dpyinfo->x_dnd_atoms_size *= 2; dpyinfo->x_dnd_atoms = xrealloc (dpyinfo->x_dnd_atoms, - sizeof (*dpyinfo->x_dnd_atoms) - * dpyinfo->x_dnd_atoms_size); + (2 * sizeof *dpyinfo->x_dnd_atoms + * dpyinfo->x_dnd_atoms_size)); + dpyinfo->x_dnd_atoms_size *= 2; } dpyinfo->x_dnd_atoms[dpyinfo->x_dnd_atoms_length++] = x_atom; @@ -2426,7 +2491,7 @@ x_handle_dnd_message (struct frame *f, XClientMessageEvent *event, struct x_disp unsigned long size = 160/event->format; int x, y; unsigned char *data = (unsigned char *) event->data.b; - int idata[5]; + unsigned int idata[5]; ptrdiff_t i; for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i) @@ -2444,7 +2509,7 @@ x_handle_dnd_message (struct frame *f, XClientMessageEvent *event, struct x_disp if (32 < BITS_PER_LONG && event->format == 32) { for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */ - idata[i] = (int) event->data.l[i]; + idata[i] = event->data.l[i]; data = (unsigned char *) idata; } -- cgit v1.2.3 From 1d526e2f33eb2615944717c9231bc1d27aef1117 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 22:09:32 -0700 Subject: * xsmfns.c (smc_save_yourself_CB): Check for size calc overflow. --- src/ChangeLog | 2 ++ src/xsmfns.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/ChangeLog b/src/ChangeLog index f8e5ca78b3..1f288a48f2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,7 @@ 2011-07-29 Paul Eggert + * xsmfns.c (smc_save_yourself_CB): Check for size calc overflow. + * xselect.c: Integer and memory overflow issues. (X_LONG_SIZE, X_USHRT_MAX, X_ULONG_MAX): New macros. Use them to make the following changes clearer. diff --git a/src/xsmfns.c b/src/xsmfns.c index cb56ae648d..217087dbae 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -223,6 +223,9 @@ smc_save_yourself_CB (SmcConn smcConn, props[props_idx]->name = xstrdup (SmRestartCommand); props[props_idx]->type = xstrdup (SmLISTofARRAY8); /* /path/to/emacs, --smid=xxx --no-splash --chdir=dir ... */ + if (min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX) / sizeof *vp) - 3 + < initial_argc) + memory_full (SIZE_MAX); i = 3 + initial_argc; props[props_idx]->num_vals = i; vp = (SmPropValue *) xmalloc (i * sizeof(*vp)); -- cgit v1.2.3 From 3256efcee3a7c3bf63e62666715455e834d19ea0 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 22:12:49 -0700 Subject: * xterm.c: Integer and memory overflow issues. (x_color_cells, handle_one_xevent, x_term_init): Check for size calculation overflow. (x_color_cells): Don't store size until memory allocation succeeds. (handle_one_xevent): Use ptrdiff_t, not int, for byte counts. (x_term_init): Don't assume length fits in int (sprintf is limited to int size). --- src/ChangeLog | 8 ++++++++ src/xterm.c | 30 ++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 1f288a48f2..b005b461ed 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,13 @@ 2011-07-29 Paul Eggert + * xterm.c: Integer and memory overflow issues. + (x_color_cells, handle_one_xevent, x_term_init): + Check for size calculation overflow. + (x_color_cells): Don't store size until memory allocation succeeds. + (handle_one_xevent): Use ptrdiff_t, not int, for byte counts. + (x_term_init): Don't assume length fits in int (sprintf is limited + to int size). + * xsmfns.c (smc_save_yourself_CB): Check for size calc overflow. * xselect.c: Integer and memory overflow issues. diff --git a/src/xterm.c b/src/xterm.c index 5b6ddbb8dd..4ef0061dba 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1625,19 +1625,21 @@ x_color_cells (Display *dpy, int *ncells) if (dpyinfo->color_cells == NULL) { Screen *screen = dpyinfo->screen; + int ncolor_cells = XDisplayCells (dpy, XScreenNumberOfScreen (screen)); int i; - dpyinfo->ncolor_cells - = XDisplayCells (dpy, XScreenNumberOfScreen (screen)); + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (XColor) < ncolor_cells) + memory_full (SIZE_MAX); dpyinfo->color_cells - = (XColor *) xmalloc (dpyinfo->ncolor_cells + = (XColor *) xmalloc (ncolor_cells * sizeof *dpyinfo->color_cells); + dpyinfo->ncolor_cells = ncolor_cells; - for (i = 0; i < dpyinfo->ncolor_cells; ++i) + for (i = 0; i < ncolor_cells; ++i) dpyinfo->color_cells[i].pixel = i; XQueryColors (dpy, dpyinfo->cmap, - dpyinfo->color_cells, dpyinfo->ncolor_cells); + dpyinfo->color_cells, ncolor_cells); } *ncells = dpyinfo->ncolor_cells; @@ -5817,7 +5819,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent *eventptr, } inev; int count = 0; int do_help = 0; - int nbytes = 0; + ptrdiff_t nbytes = 0; struct frame *f = NULL; struct coding_system coding; XEvent event = *eventptr; @@ -6515,7 +6517,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent *eventptr, } { /* Raw bytes, not keysym. */ - register int i; + ptrdiff_t i; int nchars, len; for (i = 0, nchars = 0; i < nbytes; i++) @@ -6528,7 +6530,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent *eventptr, if (nchars < nbytes) { /* Decode the input data. */ - int require; + ptrdiff_t require; + + if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH + < nbytes) + memory_full (SIZE_MAX); /* The input should be decoded with `coding_system' which depends on which X*LookupString function @@ -9826,6 +9832,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) struct x_display_info *dpyinfo; XrmDatabase xrdb; Mouse_HLInfo *hlinfo; + ptrdiff_t lim; BLOCK_INPUT; @@ -10044,12 +10051,15 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) XSetAfterFunction (x_current_display, x_trace_wire); #endif /* ! 0 */ + lim = min (PTRDIFF_MAX, SIZE_MAX) - sizeof "@"; + if (lim - SBYTES (Vinvocation_name) < SBYTES (Vsystem_name)) + memory_full (SIZE_MAX); dpyinfo->x_id_name = (char *) xmalloc (SBYTES (Vinvocation_name) + SBYTES (Vsystem_name) + 2); - sprintf (dpyinfo->x_id_name, "%s@%s", - SSDATA (Vinvocation_name), SSDATA (Vsystem_name)); + strcat (strcat (strcpy (dpyinfo->x_id_name, SSDATA (Vinvocation_name)), "@"), + SSDATA (Vsystem_name)); /* Figure out which modifier bits mean what. */ x_find_modifier_meanings (dpyinfo); -- cgit v1.2.3 From 726e0ab18e84ce0df6b9dc1612bf4d92b9d1e52a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 28 Jul 2011 22:27:47 -0700 Subject: Alphabetize the long ChangeLog entry. --- src/ChangeLog | 390 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 186 insertions(+), 204 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index b005b461ed..1796455e55 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,17 +1,188 @@ 2011-07-29 Paul Eggert - * xterm.c: Integer and memory overflow issues. - (x_color_cells, handle_one_xevent, x_term_init): + Integer and memory overflow issues. + + * bidi.c (bidi_shelve_header_size): New constant. + (bidi_cache_ensure_space, bidi_shelve_cache): Use it. + (bidi_cache_ensure_space): Avoid integer overflow when allocating. + + * buffer.c (overlays_at, overlays_in, record_overlay_string) + (overlay_strings): + Don't update size of array until after memory allocation succeeds, + because xmalloc/xrealloc may not return. + + * callproc.c (child_setup): Don't assume strlen fits in int. + + * ccl.c (Fccl_execute_on_string): Check for memory overflow. + Use ptrdiff_t rather than EMACS_INT where ptrdiff_t will do. + Redo buffer-overflow calculations to avoid integer overflow. + + * character.c (Fstring): Check for size-calculation overflow. + + * coding.c (produce_chars): Redo buffer-overflow calculations to avoid + unnecessary integer overflow. Check for size overflow. + (encode_coding_object): Don't update size until xmalloc succeeds. + + * composite.c (get_composition_id): Check for overflow in glyph + length calculations. + + Integer and memory overflow fixes for display code. + * dispextern.h (struct glyph_pool.nglyphs): Now ptrdiff_t, not int. + * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool) + (scrolling_window): Check for overflow in size calculations. + (line_draw_cost, realloc_glyph_pool, add_row_entry): + Don't assume glyph table len fits in int. + (struct row_entry.bucket, row_entry_pool_size, row_entry_idx) + (row_table_size): Now ptrdiff_t, not int. + (scrolling_window): Avoid overflow in size calculations. + Don't update size until allocation succeeds. + * fns.c (concat): Check for overflow in size calculations. + (next_almost_prime): Verify NEXT_ALMOST_PRIME_LIMIT. + * lisp.h (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. + (NEXT_ALMOST_PRIME_LIMIT): New constant. + + * doc.c (get_doc_string_buffer_size): Now ptrdiff_t, not int. + (get_doc_string): Check for size calculation overflow. + Don't update size until allocation succeeds. + (get_doc_string, Fsubstitute_command_keys): Use ptrdiff_t, not + EMACS_INT, where ptrdiff_t will do. + (Fsubstitute_command_keys): Check for string overflow. + + * editfns.c (set_time_zone_rule): Don't assume environment length + fits in int. + (message_length): Now ptrdiff_t, not int. + (Fmessage_box): Don't update size until allocation succeeds. + Don't assume message length fits in int. + (Fformat): Use ptrdiff_t, not EMACS_INT, where ptrdiff_t will do. + + * emacs.c (main, sort_args): Check for size-calculation overflow. + + * eval.c (init_eval_once, grow_specpdl): Don't update size until + alloc succeeds. + (call_debugger, grow_specpdl): Redo calculations to avoid overflow. + + * frame.c (set_menu_bar_lines, x_set_frame_parameters) + (x_set_scroll_bar_width, x_figure_window_size): + Check for integer overflow. + (x_set_alpha): Do not assume XINT fits in int. + + * frame.h (struct frame): Use int, not EMACS_INT, where int works. + This is for the members text_lines, text_cols, total_lines, total_cols, + where the system imposes an 'int' limit. + + * fringe.c (Fdefine_fringe_bitmap): + Don't update size until alloc works. + + * ftfont.c (ftfont_get_open_type_spec, setup_otf_gstring) + (ftfont_shape_by_flt): Check for integer overflow in size calculations. + + * gtkutil.c (get_utf8_string, xg_store_widget_in_map): + Check for size-calculation overflow. + (get_utf8_string): Use ptrdiff_t, not size_t, where either will + do, as we prefer signed integers. + (id_to_widget.max_size, id_to_widget.used) + (xg_store_widget_in_map, xg_remove_widget_from_map) + (xg_get_widget_from_map, xg_get_scroll_id_for_window) + (xg_remove_scroll_bar, xg_update_scrollbar_pos): + Use and return ptrdiff_t, not int. + (xg_gtk_scroll_destroy): Don't assume ptrdiff_t fits in int. + * gtkutil.h: Change prototypes to match the above. + + * image.c (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): Remove; these + are duplicate now that they've been promoted to lisp.h. + (x_allocate_bitmap_record, x_alloc_image_color) + (make_image_cache, cache_image, xpm_load): + Don't update size until alloc is done. + (xpm_load, lookup_rgb_color, lookup_pixel_color, x_to_xcolors) + (x_detect_edges): Check for size calculation overflow. - (x_color_cells): Don't store size until memory allocation succeeds. - (handle_one_xevent): Use ptrdiff_t, not int, for byte counts. - (x_term_init): Don't assume length fits in int (sprintf is limited - to int size). + (ct_colors_allocated_max): New constant. + (x_to_xcolors, x_detect_edges): Reorder multiplicands to avoid + overflow. - * xsmfns.c (smc_save_yourself_CB): Check for size calc overflow. + * keyboard.c (read_char, menu_bar_items, tool_bar_items) + (read_char_x_menu_prompt, read_char_minibuf_menu_width) + (read_char_minibuf_menu_prompt, follow_key, read_key_sequence): + Use ptrdiff_t, not int, to count maps. + (read_char_minibuf_menu_prompt): Check for overflow in size + calculations. Don't update size until allocation succeeds. Redo + calculations to avoid overflow. + * keyboard.h: Change prototypes to match the above. + + * keymap.c (cmm_size, current_minor_maps): Use ptrdiff_t, not int, + to count maps. + (current_minor_maps): Check for size calculation overflow. + * keymap.h: Change prototypes to match the above. + + * lread.c (read1, init_obarray): Don't update size until alloc done. + + * macros.c (Fstart_kbd_macro): Don't update size until alloc done. + (store_kbd_macro_char): Reorder multiplicands to avoid overflow. + + * minibuf.c (read_minibuf_noninteractive): Don't leak memory + on memory overflow. + + * nsterm.h (struct ns_color_table.size, struct ns_color_table.avail): + Now ptrdiff_t, not int. + * nsterm.m (ns_index_color): Use ptrdiff_t, not int, for table indexes. + (ns_draw_fringe_bitmap): Rewrite to avoid overflow. + + * process.c (Fnetwork_interface_list): Check for overflow + in size calculation. + + * region-cache.c (move_cache_gap): Check for size calculation overflow. + + * scroll.c (do_line_insertion_deletion_costs): Check for size calc + overflow. Don't bother calling xmalloc when xrealloc will do. + + * search.c (Freplace_match): Check for size calculation overflow. + (Fset_match_data): Don't assume list lengths fit in 'int'. + + * sysdep.c (system_process_attributes): Use ptrdiff_t, not int, + for command line length. Do not attempt to address one before the + beginning of an array, as that's not portable. + + * term.c (max_frame_lines): Remove; unused. + (encode_terminal_src_size, encode_terminal_dst_size): Now ptrdiff_t, + not int. + (encode_terminal_code, calculate_costs): Check for size + calculation overflow. + (encode_terminal_code): Use ptrdiff_t, not int, to record glyph + table lengths and related sizes. Don't update size until alloc + done. Redo calculations to avoid overflow. + (calculate_costs): Don't bother calling xmalloc when xrealloc will do. + + * termcap.c (tgetent): Use ptrdiff_t, not int, to record results of + subtracting pointers. + (gobble_line): Check for overflow more carefully. Don't update size + until alloc done. + + * tparam.c (tparam1): Use ptrdiff_t, not int, for sizes. + Don't update size until alloc done. + Redo size calculations to avoid overflow. + Check for size calculation overflow. + + * xdisp.c (store_mode_line_noprop_char, x_consider_frame_title): + Use ptrdiff_t, not int, for sizes. + (store_mode_line_noprop_char): Don't update size until alloc done. + + * xfaces.c (Finternal_make_lisp_face): Use ptrdiff_t, not int, for + sizes. Check for size calculation overflow. + (cache_face): Do not overflow in size calculation. + + * xfns.c (x_encode_text, x_set_name_internal) + (Fx_change_window_property): Use ptrdiff_t, not int, to count + sizes, since they can exceed INT_MAX in size. Check for size + calculation overflow. + + * xgselect.c (xg_select): Check for size calculation overflow. + Don't update size until alloc done. + + * xrdb.c (magic_file_p): Plug memory leak on size overflow. + (get_environ_db): Don't assume path length fits in int, + as sprintf is limited to int lengths. - * xselect.c: Integer and memory overflow issues. - (X_LONG_SIZE, X_USHRT_MAX, X_ULONG_MAX): New macros. + * xselect.c (X_LONG_SIZE, X_USHRT_MAX, X_ULONG_MAX): New macros. Use them to make the following changes clearer. (MAX_SELECTION_QUANTUM): Make the other bounds on this value clearer. This change doesn't affect the value now, but it may help remind @@ -56,203 +227,14 @@ a wider type due to X limits. (x_handle_dnd_message): Use unsigned int, to avoid int overflow. - * xrdb.c: Integer and memory overflow issues. - (magic_file_p): Plug memory leak on size overflow. - (get_environ_db): Don't assume path length fits in int, - as sprintf is limited to int lengths. - - * xgselect.c (xg_select): Check for size calculation overflow. - Don't update size until alloc done. - - * xfns.c: Integer and memory overflow fixes. - (x_encode_text, x_set_name_internal, Fx_change_window_property): - Use ptrdiff_t, not int, to count sizes, since they can exceed - INT_MAX in size. Check for size calculation overflow. - - * xfaces.c: Integer and memory overflow fixes. - (Finternal_make_lisp_face): Use ptrdiff_t, not int, for sizes. - Check for size calculation overflow. - (cache_face): Do not overflow in size calculation. - - * xdisp.c: Integer and memory overflow fixes. - (store_mode_line_noprop_char, x_consider_frame_title): - Use ptrdiff_t, not int, for sizes. - (store_mode_line_noprop_char): Don't update size until alloc done. - - * tparam.c: Integer and memory overflow fixes. - (tparam1): Use ptrdiff_t, not int, for sizes. - Don't update size until alloc done. - Redo size calculations to avoid overflow. - Check for size calculation overflow. - - * termcap.c: Integer and memory overflow issues. - (tgetent): Use ptrdiff_t, not int, to record results of - subtracting pointers. - (gobble_line): Check for overflow more carefully. Don't update size - until alloc done. - - * term.c: Integer and memory overflow issues. - (max_frame_lines): Remove; unused. - (encode_terminal_src_size, encode_terminal_dst_size): Now ptrdiff_t, - not int. - (encode_terminal_code, calculate_costs): Check for size - calculation overflow. - (encode_terminal_code): Use ptrdiff_t, not int, to record glyph - table lengths and related sizes. Don't update size until alloc - done. Redo calculations to avoid overflow. - (calculate_costs): Don't bother calling xmalloc when xrealloc will do. - - * sysdep.c: Integer and memory overflow issues. - (system_process_attributes): Use ptrdiff_t, not int, for command - line length. Do not attempt to address one before the beginning - of an array, as that's not portable. - - * search.c: Integer and memory overflow fixes. - (Freplace_match): Check for size calculation overflow. - (Fset_match_data): Don't assume list lengths fit in 'int'. - - * scroll.c: Integer and memory overflow fixes. - (do_line_insertion_deletion_costs): Check for size calculation overflow. - Don't bother calling xmalloc when xrealloc will do. - - * region-cache.c (move_cache_gap): Check for size calculation overflow. - - * process.c (Fnetwork_interface_list): Check for overflow - in size calculation. - - * nsterm.h (struct ns_color_table.size, struct ns_color_table.avail): - Now ptrdiff_t, not int. - * nsterm.m (ns_index_color): Use ptrdiff_t, not int, for table indexes. - (ns_draw_fringe_bitmap): Rewrite to avoid overflow. - - * minibuf.c (read_minibuf_noninteractive): Don't leak memory - on memory overflow. - - * macros.c: Integer and memory overflow fixes. - (Fstart_kbd_macro): Don't update size until alloc done. - (store_kbd_macro_char): Reorder multiplicands to avoid overflow. - - * lread.c (read1, init_obarray): Don't update size until alloc done. - - * keymap.c: Integer overflow fixes. - (cmm_size, current_minor_maps): Use ptrdiff_t, not int, to count maps. - (current_minor_maps): Check for size calculation overflow. - * keymap.h: Change prototypes to match the above. - - * keyboard.c: Integer and memory overflow fixes. - (read_char, menu_bar_items, tool_bar_items, read_char_x_menu_prompt) - (read_char_minibuf_menu_width, read_char_minibuf_menu_prompt) - (follow_key, read_key_sequence): Use ptrdiff_t, not int, to count maps. - (read_char_minibuf_menu_prompt): Check for overflow in size - calculations. Don't update size until allocation succeeds. Redo - calculations to avoid overflow. - * keyboard.h: Change prototypes to match the above. + * xsmfns.c (smc_save_yourself_CB): Check for size calc overflow. - * image.c: Integer and memory overflow fixes. - (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): Remove; these are duplicate - now that they've been promoted to lisp.h. - (x_allocate_bitmap_record, x_alloc_image_color) - (make_image_cache, cache_image, xpm_load): - Don't update size until alloc is done. - (xpm_load, lookup_rgb_color, lookup_pixel_color, x_to_xcolors) - (x_detect_edges): + * xterm.c (x_color_cells, handle_one_xevent, x_term_init): Check for size calculation overflow. - (ct_colors_allocated_max): New constant. - (x_to_xcolors, x_detect_edges): Reorder multiplicands to avoid - overflow. - -2011-07-28 Paul Eggert - - * gtkutil.c: Integer overflow fixes. - (get_utf8_string, xg_store_widget_in_map): - Check for size-calculation overflow. - (get_utf8_string): Use ptrdiff_t, not size_t, where either will - do, as we prefer signed integers. - (id_to_widget.max_size, id_to_widget.used) - (xg_store_widget_in_map, xg_remove_widget_from_map) - (xg_get_widget_from_map, xg_get_scroll_id_for_window) - (xg_remove_scroll_bar, xg_update_scrollbar_pos): - Use and return ptrdiff_t, not int. - (xg_gtk_scroll_destroy): Don't assume ptrdiff_t fits in int. - * gtkutil.h: Change prototypes to match the above. - - * ftfont.c: Check for size overflow. - (ftfont_get_open_type_spec, setup_otf_gstring, ftfont_shape_by_flt): - Check for integer overflow in size calculations. - - * fringe.c (Fdefine_fringe_bitmap): Don't update size until alloc works. - - * frame.h (struct frame): Use int, not EMACS_INT, where int works. - This is for the members text_lines, text_cols, total_lines, total_cols, - where the system imposes an 'int' limit. - - * frame.c: Integer overflow fixes. - (set_menu_bar_lines, x_set_frame_parameters, x_set_scroll_bar_width) - (x_figure_window_size): Check for integer overflow. - (x_set_alpha): Do not assume XINT fits in int. - - * eval.c: Integer and memory overflow fixes. - (init_eval_once, grow_specpdl): Don't update size until alloc succeeds. - (call_debugger, grow_specpdl): Redo calculations to avoid overflow. - - * emacs.c (main, sort_args): Check for size-calculation overflow. - - * editfns.c: Integer and memory overflow fixes. - (set_time_zone_rule): Don't assume environment length fits in int. - (message_length): Now ptrdiff_t, not int. - (Fmessage_box): Don't update size until allocation succeeds. - Don't assume message length fits in int. - (Fformat): Use ptrdiff_t, not EMACS_INT, where ptrdiff_t will do. - - * doc.c: Integer and memory overflow fixes. - (get_doc_string_buffer_size): Now ptrdiff_t, not int. - (get_doc_string): Check for size calculation overflow. - Don't update size until allocation succeeds. - (get_doc_string, Fsubstitute_command_keys): Use ptrdiff_t, not - EMACS_INT, where ptrdiff_t will do. - (Fsubstitute_command_keys): Check for string overflow. - - Integer and memory overflow fixes for display code. - * dispextern.h (struct glyph_pool.nglyphs): Now ptrdiff_t, not int. - * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool, scrolling_window): - Check for overflow in size calculations. - (line_draw_cost, realloc_glyph_pool, add_row_entry): - Don't assume glyph table len fits in int. - (struct row_entry.bucket, row_entry_pool_size, row_entry_idx) - (row_table_size): Now ptrdiff_t, not int. - (scrolling_window): Avoid overflow in size calculations. - Don't update size until allocation succeeds. - * fns.c (concat): Check for overflow in size calculations. - (next_almost_prime): Verify NEXT_ALMOST_PRIME_LIMIT. - * lisp.h (RANGED_INTEGERP, TYPE_RANGED_INTEGERP): New macros. - (NEXT_ALMOST_PRIME_LIMIT): New constant. - - * composite.c: Integer overflow fixes. - (get_composition_id): Check for overflow in glyph length calculations. - - * coding.c: Integer and memory overflow fixes. - (produce_chars): Redo buffer-overflow calculations to avoid - unnecessary integer overflow. Check for size overflow. - (encode_coding_object): Don't update size until xmalloc succeeds. - - * character.c (Fstring): Check for size-calculation overflow. - - * ccl.c: Integer and memory overflow fixes. - (Fccl_execute_on_string): Check for memory overflow. - Use ptrdiff_t rather than EMACS_INT where ptrdiff_t will do. - Redo buffer-overflow calculations to avoid integer overflow. - - * callproc.c (child_setup): Don't assume strlen fits in int. - - * buffer.c: Memory overflow fixes. - (overlays_at, overlays_in, record_overlay_string, overlay_strings): - Don't update size of array until after memory allocation succeeds, - because xmalloc/xrealloc may not return. - - * bidi.c: Integer overflow fix. - (bidi_shelve_header_size): New constant. - (bidi_cache_ensure_space, bidi_shelve_cache): Use it. - (bidi_cache_ensure_space): Avoid integer overflow when allocating. + (x_color_cells): Don't store size until memory allocation succeeds. + (handle_one_xevent): Use ptrdiff_t, not int, for byte counts. + (x_term_init): Don't assume length fits in int (sprintf is limited + to int size). 2011-07-19 Paul Eggert -- cgit v1.2.3 From 469d21499d26c720d22b358ff391bf13d0e708e3 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 29 Jul 2011 22:06:43 -0400 Subject: Add Semantic grammar files to etc/grammars --- etc/grammars/README | 18 + etc/grammars/bovine-grammar.el | 439 +++++++++++++++ etc/grammars/c.by | 1205 ++++++++++++++++++++++++++++++++++++++++ etc/grammars/java-tags.wy | 753 +++++++++++++++++++++++++ etc/grammars/javascript-jv.wy | 503 +++++++++++++++++ etc/grammars/make.by | 167 ++++++ etc/grammars/python.wy | 1083 ++++++++++++++++++++++++++++++++++++ etc/grammars/scheme.by | 86 +++ etc/grammars/wisent-grammar.el | 357 ++++++++++++ 9 files changed, 4611 insertions(+) create mode 100644 etc/grammars/README create mode 100644 etc/grammars/bovine-grammar.el create mode 100644 etc/grammars/c.by create mode 100644 etc/grammars/java-tags.wy create mode 100644 etc/grammars/javascript-jv.wy create mode 100644 etc/grammars/make.by create mode 100644 etc/grammars/python.wy create mode 100644 etc/grammars/scheme.by create mode 100644 etc/grammars/wisent-grammar.el diff --git a/etc/grammars/README b/etc/grammars/README new file mode 100644 index 0000000000..657f9c20ec --- /dev/null +++ b/etc/grammars/README @@ -0,0 +1,18 @@ +This directory contains grammar files in Bison and Wisent, used to +generate the parser data in the lisp/semantic/bovine/ and +lisp/semantic/wisent/ directories. You can run the parser generators +with + +emacs -batch --no-site-file \ + -l semantic/bovine -l semantic/wisent -l semantic/grammar \ + -l semantic/lex -l bovine-grammar.el \ + -f semantic-mode -f semantic-grammar-batch-build-packages *.by + +emacs -batch --no-site-file \ + -l semantic/bovine -l semantic/wisent -l semantic/grammar \ + -l semantic/lex -l wisent-grammar.el \ + -f semantic-mode -f semantic-grammar-batch-build-packages *.wy + +Currently, the parser files in lisp/ are not generated directly from +these grammar files when making Emacs. This state of affairs, and the +contents of this directory, will change in a future version of Emacs. diff --git a/etc/grammars/bovine-grammar.el b/etc/grammars/bovine-grammar.el new file mode 100644 index 0000000000..eb094868b3 --- /dev/null +++ b/etc/grammars/bovine-grammar.el @@ -0,0 +1,439 @@ +;;; bovine-grammar.el --- Bovine's input grammar mode +;; +;; Copyright (C) 2002-2011 Free Software Foundation, Inc. +;; +;; Author: David Ponce +;; Maintainer: David Ponce +;; Created: 26 Aug 2002 +;; Keywords: syntax + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; Major mode for editing Bovine's input grammar (.by) files. + +;;; History: + +;;; Code: +(require 'semantic) +(require 'semantic/grammar) +(require 'semantic/find) + +(defun bovine-grammar-EXPAND (bounds nonterm) + "Expand call to EXPAND grammar macro. +Return the form to parse from within a nonterminal between BOUNDS. +NONTERM is the nonterminal symbol to start with." + `(semantic-bovinate-from-nonterminal + (car ,bounds) (cdr ,bounds) ',nonterm)) + +(defun bovine-grammar-EXPANDFULL (bounds nonterm) + "Expand call to EXPANDFULL grammar macro. +Return the form to recursively parse the area between BOUNDS. +NONTERM is the nonterminal symbol to start with." + `(semantic-parse-region + (car ,bounds) (cdr ,bounds) ',nonterm 1)) + +(defun bovine-grammar-TAG (name class &rest attributes) + "Expand call to TAG grammar macro. +Return the form to create a generic semantic tag. +See the function `semantic-tag' for the meaning of arguments NAME, +CLASS and ATTRIBUTES." + `(semantic-tag ,name ,class ,@attributes)) + +(defun bovine-grammar-VARIABLE-TAG (name type default-value &rest attributes) + "Expand call to VARIABLE-TAG grammar macro. +Return the form to create a semantic tag of class variable. +See the function `semantic-tag-new-variable' for the meaning of +arguments NAME, TYPE, DEFAULT-VALUE and ATTRIBUTES." + `(semantic-tag-new-variable ,name ,type ,default-value ,@attributes)) + +(defun bovine-grammar-FUNCTION-TAG (name type arg-list &rest attributes) + "Expand call to FUNCTION-TAG grammar macro. +Return the form to create a semantic tag of class function. +See the function `semantic-tag-new-function' for the meaning of +arguments NAME, TYPE, ARG-LIST and ATTRIBUTES." + `(semantic-tag-new-function ,name ,type ,arg-list ,@attributes)) + +(defun bovine-grammar-TYPE-TAG (name type members parents &rest attributes) + "Expand call to TYPE-TAG grammar macro. +Return the form to create a semantic tag of class type. +See the function `semantic-tag-new-type' for the meaning of arguments +NAME, TYPE, MEMBERS, PARENTS and ATTRIBUTES." + `(semantic-tag-new-type ,name ,type ,members ,parents ,@attributes)) + +(defun bovine-grammar-INCLUDE-TAG (name system-flag &rest attributes) + "Expand call to INCLUDE-TAG grammar macro. +Return the form to create a semantic tag of class include. +See the function `semantic-tag-new-include' for the meaning of +arguments NAME, SYSTEM-FLAG and ATTRIBUTES." + `(semantic-tag-new-include ,name ,system-flag ,@attributes)) + +(defun bovine-grammar-PACKAGE-TAG (name detail &rest attributes) + "Expand call to PACKAGE-TAG grammar macro. +Return the form to create a semantic tag of class package. +See the function `semantic-tag-new-package' for the meaning of +arguments NAME, DETAIL and ATTRIBUTES." + `(semantic-tag-new-package ,name ,detail ,@attributes)) + +(defun bovine-grammar-CODE-TAG (name detail &rest attributes) + "Expand call to CODE-TAG grammar macro. +Return the form to create a semantic tag of class code. +See the function `semantic-tag-new-code' for the meaning of arguments +NAME, DETAIL and ATTRIBUTES." + `(semantic-tag-new-code ,name ,detail ,@attributes)) + +(defun bovine-grammar-ALIAS-TAG (name aliasclass definition &rest attributes) + "Expand call to ALIAS-TAG grammar macro. +Return the form to create a semantic tag of class alias. +See the function `semantic-tag-new-alias' for the meaning of arguments +NAME, ALIASCLASS, DEFINITION and ATTRIBUTES." + `(semantic-tag-new-alias ,name ,aliasclass ,definition ,@attributes)) + +;; Cache of macro definitions currently in use. +(defvar bovine--grammar-macros nil) + +(defun bovine-grammar-expand-form (form quotemode &optional inplace) + "Expand FORM into a new one suitable to the bovine parser. +FORM is a list in which we are substituting. +Argument QUOTEMODE is non-nil if we are in backquote mode. +When non-nil, optional argument INPLACE indicates that FORM is being +expanded from elsewhere." + (when (listp form) + (when (eq (car form) 'quote) + (setq form (cdr form)) + (cond + ((and (= (length form) 1) (listp (car form))) + (insert "\n(append") + (bovine-grammar-expand-form (car form) quotemode nil) + (insert ")") + (setq form nil inplace nil) + ) + ((and (= (length form) 1) (symbolp (car form))) + (insert "\n'" (symbol-name (car form))) + (setq form nil inplace nil) + ) + (t + (insert "\n(list") + (setq inplace t) + ))) + (let ((macro (assq (car form) bovine--grammar-macros)) + inlist first n q x) + (if macro + (bovine-grammar-expand-form + (apply (cdr macro) (cdr form)) + quotemode t) + (if inplace (insert "\n(")) + (while form + (setq first (car form) + form (cdr form)) + (cond + ((eq first nil) + (when (and (not inlist) (not inplace)) + (insert "\n(list") + (setq inlist t)) + (insert " nil") + ) + ((listp first) + ;;(let ((fn (and (symbolp (caar form)) (fboundp (caar form))))) + (when (and (not inlist) (not inplace)) + (insert "\n(list") + (setq inlist t)) + ;;(if (and inplace (not fn) (not (eq (caar form) 'EXPAND))) + ;; (insert " (append")) + (bovine-grammar-expand-form + first quotemode t) ;;(and fn (not (eq fn 'quote)))) + ;;(if (and inplace (not fn) (not (eq (caar form) 'EXPAND))) + ;; (insert ")")) + ;;) + ) + ((symbolp first) + (setq n (symbol-name first) ;the name + q quotemode ;implied quote flag + x nil) ;expand flag + (if (eq (aref n 0) ?,) + (if quotemode + ;; backquote mode needs the @ + (if (eq (aref n 1) ?@) + (setq n (substring n 2) + q nil + x t) + ;; non backquote mode behaves normally. + (setq n (substring n 1) + q nil)) + (setq n (substring n 1) + x t))) + (if (string= n "") + (progn + ;; We expand only the next item in place (a list?) + ;; A regular inline-list... + (bovine-grammar-expand-form (car form) quotemode t) + (setq form (cdr form))) + (if (and (eq (aref n 0) ?$) + ;; Don't expand $ tokens in implied quote mode. + ;; This acts like quoting in other symbols. + (not q)) + (progn + (cond + ((and (not x) (not inlist) (not inplace)) + (insert "\n(list")) + ((and x inlist (not inplace)) + (insert ")") + (setq inlist nil))) + (insert "\n(nth " (int-to-string + (1- (string-to-number + (substring n 1)))) + " vals)") + (and (not x) (not inplace) + (setq inlist t))) + + (when (and (not inlist) (not inplace)) + (insert "\n(list") + (setq inlist t)) + (or (char-equal (char-before) ?\() + (insert " ")) + (insert (if (or inplace (eq first t)) + "" "'") + n))) ;; " " + ) + (t + (when (and (not inlist) (not inplace)) + (insert "\n(list") + (setq inlist t)) + (insert (format "\n%S" first)) + ) + )) + (if inlist (insert ")")) + (if inplace (insert ")"))) + ))) + +(defun bovine-grammar-expand-action (textform quotemode) + "Expand semantic action string TEXTFORM into Lisp code. +QUOTEMODE is the mode in which quoted symbols are slurred." + (if (string= "" textform) + nil + (let ((sexp (read textform))) + + ;; We converted the lambda string into a list. Now write it + ;; out as the bovine lambda expression, and do macro-like + ;; conversion upon it. + (insert "\n") + (cond + ((eq (car sexp) 'EXPAND) + (insert ",(lambda (vals start end)") + ;; The EXPAND macro definition is mandatory + (bovine-grammar-expand-form + (apply (cdr (assq 'EXPAND bovine--grammar-macros)) (cdr sexp)) + quotemode t) + ) + ((and (listp (car sexp)) (eq (caar sexp) 'EVAL)) + ;; The user wants to evaluate the following args. + ;; Use a simpler expander + ) + (t + (insert ",(semantic-lambda") + (bovine-grammar-expand-form sexp quotemode) + )) + (insert ")\n"))) +) + +(defun bovine-grammar-parsetable-builder () + "Return the parser table expression as a string value. +The format of a bovine parser table is: + + ( ( NONTERMINAL-SYMBOL1 MATCH-LIST1 ) + ( NONTERMINAL-SYMBOL2 MATCH-LIST2 ) + ... + ( NONTERMINAL-SYMBOLn MATCH-LISTn ) + +Where each NONTERMINAL-SYMBOL is an artificial symbol which can appear +in any child state. As a starting place, one of the NONTERMINAL-SYMBOLS +must be `bovine-toplevel'. + +A MATCH-LIST is a list of possible matches of the form: + + ( STATE-LIST1 + STATE-LIST2 + ... + STATE-LISTN ) + +where STATE-LIST is of the form: + ( TYPE1 [ \"VALUE1\" ] TYPE2 [ \"VALUE2\" ] ... LAMBDA ) + +where TYPE is one of the returned types of the token stream. +VALUE is a value, or range of values to match against. For +example, a SYMBOL might need to match \"foo\". Some TYPES will not +have matching criteria. + +LAMBDA is a lambda expression which is evaled with the text of the +type when it is found. It is passed the list of all buffer text +elements found since the last lambda expression. It should return a +semantic element (see below.) + +For consistency between languages, try to use common return values +from your parser. Please reference the chapter \"Writing Parsers\" in +the \"Language Support Developer's Guide -\" in the semantic texinfo +manual." + (let* ((start (semantic-grammar-start)) + (scopestart (semantic-grammar-scopestart)) + (quotemode (semantic-grammar-quotemode)) + (tags (semantic-find-tags-by-class + 'token (current-buffer))) + (nterms (semantic-find-tags-by-class + 'nonterminal (current-buffer))) + ;; Setup the cache of macro definitions. + (bovine--grammar-macros (semantic-grammar-macros)) + nterm rules items item actn prec tag type regex) + + ;; Check some trivial things + (cond + ((null nterms) + (error "Bad input grammar")) + (start + (if (cdr start) + (message "Extra start symbols %S ignored" (cdr start))) + (setq start (symbol-name (car start))) + (unless (semantic-find-first-tag-by-name start nterms) + (error "start symbol `%s' has no rule" start))) + (t + ;; Default to the first grammar rule. + (setq start (semantic-tag-name (car nterms))))) + (when scopestart + (setq scopestart (symbol-name scopestart)) + (unless (semantic-find-first-tag-by-name scopestart nterms) + (error "scopestart symbol `%s' has no rule" scopestart))) + + ;; Generate the grammar Lisp form. + (with-temp-buffer + (erase-buffer) + (insert "`(") + ;; Insert the start/scopestart rules + (insert "\n(bovine-toplevel \n(" + start + ")\n) ;; end bovine-toplevel\n") + (when scopestart + (insert "\n(bovine-inner-scope \n(" + scopestart + ")\n) ;; end bovine-inner-scope\n")) + ;; Process each nonterminal + (while nterms + (setq nterm (car nterms) + ;; We can't use the override form because the current buffer + ;; is not the originator of the tag. + rules (semantic-tag-components-semantic-grammar-mode nterm) + nterm (semantic-tag-name nterm) + nterms (cdr nterms)) + (when (member nterm '("bovine-toplevel" "bovine-inner-scope")) + (error "`%s' is a reserved internal name" nterm)) + (insert "\n(" nterm) + + ;; Process each rule + (while rules + (setq items (semantic-tag-get-attribute (car rules) :value) + prec (semantic-tag-get-attribute (car rules) :prec) + actn (semantic-tag-get-attribute (car rules) :expr) + rules (cdr rules)) + ;; Process each item + (insert "\n(") + (if (null items) + ;; EMPTY rule + (insert ";;EMPTY" (if actn "" "\n")) + ;; Expand items + (while items + (setq item (car items) + items (cdr items)) + (if (consp item) ;; mid-rule action + (message "Mid-rule action %S ignored" item) + (or (char-equal (char-before) ?\() + (insert "\n")) + (cond + ((member item '("bovine-toplevel" "bovine-inner-scope")) + (error "`%s' is a reserved internal name" item)) + ;; Replace ITEM by its %token definition. + ;; If a '%token TYPE ITEM [REGEX]' definition exists + ;; in the grammar, ITEM is replaced by TYPE [REGEX]. + ((setq tag (semantic-find-first-tag-by-name + item tags) + type (semantic-tag-get-attribute tag :type)) + (insert type) + (if (setq regex (semantic-tag-get-attribute tag :value)) + (insert (format "\n%S" regex)))) + ;; Don't change ITEM + (t + (insert (semantic-grammar-item-text item))) + )))) + + (if prec + (message "%%prec %S ignored" prec)) + (if actn + (bovine-grammar-expand-action actn quotemode)) + (insert ")")) + (insert "\n) ;; end " nterm "\n")) + (insert ")\n") + (buffer-string)))) + +(defun bovine-grammar-setupcode-builder () + "Return the text of the setup code." + (format + "(setq semantic--parse-table %s\n\ + semantic-debug-parser-source %S\n\ + semantic-debug-parser-class 'semantic-bovine-debug-parser + semantic-flex-keywords-obarray %s\n\ + %s)" + (semantic-grammar-parsetable) + (buffer-name) + (semantic-grammar-keywordtable) + (let ((mode (semantic-grammar-languagemode))) + ;; Is there more than one major mode? + (if (and (listp mode) (> (length mode) 1)) + (format "semantic-equivalent-major-modes '%S\n" mode) + "")))) + +(defvar bovine-grammar-menu + '("BY Grammar" + ) + "BY mode specific grammar menu. +Menu items are appended to the common grammar menu.") + +(define-derived-mode bovine-grammar-mode semantic-grammar-mode "BY" + "Major mode for editing Bovine grammars." + (semantic-grammar-setup-menu bovine-grammar-menu) + (semantic-install-function-overrides + '((grammar-parsetable-builder . bovine-grammar-parsetable-builder) + (grammar-setupcode-builder . bovine-grammar-setupcode-builder) + ))) + +(add-to-list 'auto-mode-alist '("\\.by$" . bovine-grammar-mode)) + +(defvar-mode-local bovine-grammar-mode semantic-grammar-macros + '( + (ASSOC . semantic-grammar-ASSOC) + (EXPAND . bovine-grammar-EXPAND) + (EXPANDFULL . bovine-grammar-EXPANDFULL) + (TAG . bovine-grammar-TAG) + (VARIABLE-TAG . bovine-grammar-VARIABLE-TAG) + (FUNCTION-TAG . bovine-grammar-FUNCTION-TAG) + (TYPE-TAG . bovine-grammar-TYPE-TAG) + (INCLUDE-TAG . bovine-grammar-INCLUDE-TAG) + (PACKAGE-TAG . bovine-grammar-PACKAGE-TAG) + (CODE-TAG . bovine-grammar-CODE-TAG) + (ALIAS-TAG . bovine-grammar-ALIAS-TAG) + ) + "Semantic grammar macros used in bovine grammars.") + +(provide 'semantic/bovine/grammar) + +;;; semantic/bovine/grammar.el ends here diff --git a/etc/grammars/c.by b/etc/grammars/c.by new file mode 100644 index 0000000000..fe8e0c2883 --- /dev/null +++ b/etc/grammars/c.by @@ -0,0 +1,1205 @@ +;;; semantic/bovine/c.by -- LL grammar for C/C++ language specification +;; +;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Eric M. Ludlam +;; Copyright (C) 2002, 2003 David Ponce +;; +;; Author: Eric M. Ludlam +;; David Ponce +;; Klaus Berndl +;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This software is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; + +;; TODO: From Nate Schley +;; > * Can't parse signature element: "const char* const rmc_ClrTxt" +;; > * Can't parse signature element: "char* const dellog_ClrTxt" +;; > * Can't parse signature element: "const char* dellog_SetTxt" +;; > * Can't parse signature element: "const RmcCmdSSPADetailedStatus& status" +;; > +;; > And FWIW I have seen the following argument cases not handled, even +;; > with no leading/trailing spaces in the split: +;; > +;; > * Can't parse signature element: "const bool currentAlarmStatus" +;; > * Can't parse signature element: "unsigned char mode" +;; > * Can't parse signature element: "TskTimingTask* tsktimingtask" +;; > * Can't parse signature element: "unsigned char htrStatus" +;; > * Can't parse signature element: "char trackPower[]" +;; > * Can't parse signature element: "const RmcCmdMCDetailedStatus& status" +;; > * Can't parse signature element: "RmcBucStatus* rftBucStatus" + +%package c-by + +%languagemode c-mode c++-mode +%start declaration +%scopestart codeblock + +%token HASH "\\`[#]\\'" +%token PERIOD "\\`[.]\\'" +%token COLON "\\`[:]\\'" +%token SEMICOLON "\\`[;]\\'" +%token STAR "\\`[*]\\'" +%token AMPERSAND "\\`[&]\\'" +%token DIVIDE "\\`[/]\\'" +%token PLUS "\\`[+]\\'" +%token MINUS "\\`[-]\\'" +%token BANG "\\`[!]\\'" +%token EQUAL "\\`[=]\\'" +%token LESS "\\`[<]\\'" +%token GREATER "\\`[>]\\'" +%token COMA "\\`[,]\\'" +%token TILDE "\\`[~]\\'" +%token MOD "\\`[%]\\'" +%token HAT "\\`\\^\\'" +%token OR "\\`[|]\\'" +%token C "\"C\"" +%token CPP "\"C\\+\\+\"" +%token ZERO "^0$" +%token RESTRICT "\\<\\(__\\)?restrict\\>" +%token LPAREN "(" +%token RPAREN ")" +%token LBRACE "{" +%token RBRACE "}" +%token BRACK_BLCK "\\[.*\\]$" +%token PAREN_BLCK "^(" +%token BRACE_BLCK "^{" +%token VOID_BLCK "^(void)$" +%token PARENS "()" +%token BRACKETS "\\[\\]" + +%token EXTERN "extern" +%put EXTERN summary "Declaration Modifier: extern ..." +%token STATIC "static" +%put STATIC summary "Declaration Modifier: static ..." +%token CONST "const" +%put CONST summary "Declaration Modifier: const ..." +%token VOLATILE "volatile" +%put VOLATILE summary "Declaration Modifier: volatile ..." +%token REGISTER "register" +%put REGISTER summary "Declaration Modifier: register ..." +%token SIGNED "signed" +%put SIGNED summary "Numeric Type Modifier: signed ..." +%token UNSIGNED "unsigned" +%put UNSIGNED summary "Numeric Type Modifier: unsigned ..." + +%token INLINE "inline" +%put INLINE summary "Function Modifier: inline (...) {...};" +%token VIRTUAL "virtual" +%put VIRTUAL summary "Method Modifier: virtual (...) ..." +%token MUTABLE "mutable" +%put MUTABLE summary "Member Declaration Modifier: mutable ..." + +%token STRUCT "struct" +%put STRUCT summary "Structure Type Declaration: struct [name] { ... };" +%token UNION "union" +%put UNION summary "Union Type Declaration: union [name] { ... };" +%token ENUM "enum" +%put ENUM summary "Enumeration Type Declaration: enum [name] { ... };" +%token TYPEDEF "typedef" +%put TYPEDEF summary "Arbitrary Type Declaration: typedef ;" +%token CLASS "class" +%put CLASS summary "Class Declaration: class [:parents] { ... };" +%token TYPENAME "typename" +%put TYPENAME summary "typename is used to handle a qualified name as a typename;" +%token NAMESPACE "namespace" +%put NAMESPACE summary "Namespace Declaration: namespace { ... };" +%token USING "using" +%put USING summary "using ;" + +%token NEW "new" +%put NEW summary "new ();" +%token DELETE "delete" +%put DELETE summary "delete ;" + +;; Despite this, this parser can find templates by ignoring the TEMPLATE +;; keyword, and finding the class/method being templateized. +%token TEMPLATE "template" +%put TEMPLATE summary "template TYPE_OR_FUNCTION" + +%token THROW "throw" +%put THROW summary " () throw () ..." +%token REENTRANT "reentrant" +%put REENTRANT summary " () reentrant ..." +%token TRY "try" +%token CATCH "catch" +%put { TRY CATCH } summary "try { } catch { }" + +;; Leave these alone for now. +%token OPERATOR "operator" +%token PUBLIC "public" +%token PRIVATE "private" +%token PROTECTED "protected" +%token FRIEND "friend" +%put FRIEND summary "friend class " + +;; These aren't used for parsing, but is a useful place to describe the keywords. +%token IF "if" +%token ELSE "else" +%put {IF ELSE} summary "if () { code } [ else { code } ]" + +%token DO "do" +%token WHILE "while" +%put DO summary " do { code } while ();" +%put WHILE summary "do { code } while (); or while () { code };" + +%token FOR "for" +%put FOR summary "for(; ; ) { code }" + +%token SWITCH "switch" +%token CASE "case" +%token DEFAULT "default" +%put {SWITCH CASE DEFAULT} summary +"switch () { case : code; ... default: code; }" + +%token RETURN "return" +%put RETURN summary "return ;" + +%token BREAK "break" +%put BREAK summary "Non-local exit within a loop or switch (for, do/while, switch): break;" +%token CONTINUE "continue" +%put CONTINUE summary "Non-local continue within a loop (for, do/while): continue;" + +%token SIZEOF "sizeof" +%put SIZEOF summary "Compile time macro: sizeof() // size in bytes" + +;; Types +%token VOID "void" +%put VOID summary "Built in typeless type: void" +%token CHAR "char" +%put CHAR summary "Integral Character Type: (0 to 256)" +%token WCHAR "wchar_t" +%put WCHAR summary "Wide Character Type" +%token SHORT "short" +%put SHORT summary "Integral Primitive Type: (-32768 to 32767)" +%token INT "int" +%put INT summary "Integral Primitive Type: (-2147483648 to 2147483647)" +%token LONG "long" +%put LONG summary "Integral primitive type (-9223372036854775808 to 9223372036854775807)" +%token FLOAT "float" +%put FLOAT summary "Primitive floating-point type (single-precision 32-bit IEEE 754)" +%token DOUBLE "double" +%put DOUBLE summary "Primitive floating-point type (double-precision 64-bit IEEE 754)" +%token BOOL "bool" +%put BOOL summary "Primitive boolean type" + +%token UNDERP "_P" +%token UNDERUNDERP "__P" +%put UNDERP summary "Common macro to eliminate prototype compatibility on some compilers" +%put UNDERUNDERP summary "Common macro to eliminate prototype compatibility on some compilers" + +%% + +declaration + : macro + | type + ;; TODO: Klaus Berndl: Is the define here necessary or even wrong? + ;; Is this part not already covered by macro?? + | define + | var-or-fun + | extern-c + | template + | using + ; + +codeblock + : define + | codeblock-var-or-fun + | type ;; type is less likely to be used here. + | using + ; + +extern-c-contents + : open-paren + ( nil ) + | declaration + | close-paren + ( nil ) + ; + +extern-c + : EXTERN C semantic-list + ;; Extern C commands which contain a list need to have the + ;; entries of the list extracted, and spliced into the main + ;; list of entries. This must be done via the function + ;; that expands singular nonterminals, such as int x,y; + (TAG "C" 'extern :members (EXPANDFULL $3 extern-c-contents) ) + | EXTERN CPP semantic-list + (TAG "C" 'extern :members (EXPANDFULL $3 extern-c-contents) ) + | EXTERN C + ;; A plain extern "C" call should add something to the token, + ;; but just strip it from the buffer here for now. + ( nil ) + | EXTERN CPP + ( nil ) + ; + +macro + : spp-macro-def + (VARIABLE-TAG $1 nil nil :constant-flag t ) + | spp-system-include + (INCLUDE-TAG $1 t) + | spp-include + (INCLUDE-TAG $1 nil) + ; + +;; This is used in struct parts. +define + : spp-macro-def + (VARIABLE-TAG $1 nil nil :constant-flag t) + | spp-macro-undef + ( nil ) + ; + +;; In C++, structures can have the same things as classes. +;; So delete this somday in the figure. +;; +;;structparts : semantic-list +;; (EXPANDFULL $1 structsubparts) +;; ; +;; +;;structsubparts : LBRACE +;; ( nil ) +;; | RBRACE +;; ( nil ) +;; | var-or-fun +;; | define +;; ;; sometimes there are defines in structs. +;; ; + +unionparts + : semantic-list + (EXPANDFULL $1 classsubparts) + ; + +opt-symbol + : symbol + | ;;EMPTY + ; + +;; @todo - support 'friend' construct. +classsubparts + : LBRACE + ( nil ) + | RBRACE + ( nil ) + | class-protection opt-symbol COLON + ;; For QT, they may put a `slot' keyword between the protection + ;; and the COLON. @todo - Have the QT stuff use macros. + (TAG (car $1) 'label) + | var-or-fun + | FRIEND func-decl + (TAG (car $2) 'friend) + | FRIEND CLASS symbol + (TAG $3 'friend) + | type + | define + | template + | ;;EMPTY + ; + +opt-class-parents + : COLON class-parents opt-template-specifier + ( $2 ) + | ;;EMPTY + ( ) + ; + +one-class-parent + : opt-class-protection opt-class-declmods namespace-symbol + (TYPE-TAG (car $3) "class" nil nil :protection (car $1)) + | opt-class-declmods opt-class-protection namespace-symbol + (TYPE-TAG (car $3) "class" nil nil :protection (car $2)) + ; + +class-parents + : one-class-parent COMA class-parents + ( ,(cons ,$1 $3 ) ) + | one-class-parent + ( $1 ) + ; + +opt-class-declmods + : class-declmods opt-class-declmods + ( nil ) + | ;;EMPTY + ; + +class-declmods + : VIRTUAL + ; + +class-protection + : PUBLIC + | PRIVATE + | PROTECTED + ; + +opt-class-protection + : class-protection + ( ,$1 ) + | ;;EMPTY - Same as private + ( "unspecified" ) + ; + +namespaceparts + : semantic-list + (EXPANDFULL $1 namespacesubparts) + ; + +namespacesubparts + : LBRACE + ( nil ) + | RBRACE + ( nil ) + | type + | var-or-fun + | define + | class-protection COLON + (TAG (car $1) 'label) + ;; In C++, this label in a classsubpart represents + ;; PUBLIC or PRIVATE bits. Ignore them for now. + | template + | using + | ;;EMPTY + ; + +enumparts + : semantic-list + (EXPANDFULL $1 enumsubparts) + ; + +enumsubparts + : symbol opt-assign + (VARIABLE-TAG $1 "int" (car $2) :constant-flag t ) + | LBRACE + ( nil ) + | RBRACE + ( nil ) + | COMA + ( nil ) + ; + +opt-name + : symbol + | ;;EMPTY + ( "" ) + ; + +typesimple + : struct-or-class opt-class opt-name opt-template-specifier + opt-class-parents semantic-list + (TYPE-TAG (car $3) (car $1) + (let ((semantic-c-classname (cons (car ,$3) (car ,$1)))) + (EXPANDFULL $6 classsubparts)) + $5 + :template-specifier $4 + :parent (car ,$2)) + | struct-or-class opt-class opt-name opt-template-specifier + opt-class-parents + (TYPE-TAG (car $3) (car $1) nil $5 + :template-specifier $4 + :prototype t + :parent (car ,$2)) + | UNION opt-class opt-name unionparts + (TYPE-TAG (car $3) $1 $4 nil + :parent (car ,$2)) + | ENUM opt-class opt-name enumparts + (TYPE-TAG (car $3) $1 $4 nil + :parent (car ,$2)) + ;; Klaus Berndl: a typedef can be a typeformbase with all this + ;; declmods stuff. + | TYPEDEF declmods typeformbase cv-declmods typedef-symbol-list + ;;;; We put the type this typedef renames into PARENT + ;;;; but will move it in the expand function. + (TYPE-TAG $5 $1 nil (list $3) ) + ; + +typedef-symbol-list + : typedefname COMA typedef-symbol-list + ( ,(cons $1 $3) ) + | typedefname + ( $1 ) + ; + +;; TODO: Klaus Berndl: symbol -> namespace-symbol?! Answer: Probably +;; symbol is correct here! +typedefname + : opt-stars symbol opt-bits opt-array + ( $1 $2 ) + ; + +struct-or-class + : STRUCT + | CLASS + ; + +type + : typesimple SEMICOLON + ( ,$1 ) + ;; named namespaces like "namespace XXX {" + | NAMESPACE symbol namespaceparts + (TYPE-TAG $2 $1 $3 nil ) + ;; unnamed namespaces like "namespace {" + | NAMESPACE namespaceparts + (TYPE-TAG "unnamed" $1 $2 nil ) + ;; David Engster: namespace alias like "namespace foo = bar;" + | NAMESPACE symbol EQUAL typeformbase SEMICOLON + (TYPE-TAG $2 $1 (list (TYPE-TAG (car $4) $1 nil nil)) nil :kind 'alias ) + ; + +;; Klaus Berndl: We must parse "using namespace XXX" too + +;; Using is vaguely like an include statement in the named portions +;; of the code. We should probably specify a new token type for this. + +using + : USING usingname SEMICOLON + (TAG (car $2) 'using :type ,$2 ) + ; + +;; Jan Moringen: Differentiate between 'using' and 'using namespace' +;; Adapted to creating type tags by EML. +usingname + : typeformbase + (TYPE-TAG (car $1) "class" nil nil :prototype t) + | NAMESPACE typeformbase + (TYPE-TAG (car $2) "namespace" nil nil :prototype t) + ; + +template + : TEMPLATE template-specifier opt-friend template-definition + ( ,(semantic-c-reconstitute-template $4 ,$2) ) + ; + +opt-friend + : FRIEND + | ;;EMPTY + ; + +opt-template-specifier + : template-specifier + ( ,$1 ) + | ;;EMPTY + ( ) + ; + +template-specifier + : LESS template-specifier-types GREATER + ( ,$2 ) + ; + +template-specifier-types + : template-var template-specifier-type-list + ( ,(cons ,$1 ,$2 ) ) + | ;;EMPTY + ; + +template-specifier-type-list + : COMA template-specifier-types + ( ,$2 ) + | ;;EMPTY + ( ) + ; + +;; template-var +;; : template-type opt-stars opt-template-equal +;; ( ,(cons (concat (car $1) (make-string (car ,$2) ?*)) +;; (cdr $1))) +;; ;; Klaus Berndl: for template-types the template-var can also be +;; ;; literals or constants. Example: map +;; ;; map_size10_var; This parses also template which is +;; ;; nonsense but who cares.... +;; | string +;; ( $1 ) +;; | number +;; ( $1 ) +;; ; + +template-var + : + ;; Klaus Berndl: The following handles all template-vars of + ;; template-definitions + template-type opt-template-equal + ( ,(cons (car $1) (cdr $1)) ) + ;; Klaus Berndl: for template-types the template-var can also be + ;; literals or constants. + ;; Example: map map_size10_var; This parses also + ;; template which is nonsense but who cares.... + | string + ( $1 ) + | number + ( $1 ) + ;; Klaus Berndl: In template-types arguments can be any symbols with + ;; optional address-operator (&) and optional dereferencing operator + ;; (*). Example map sized_map_var. + | opt-stars opt-ref namespace-symbol + ( ,$3 ) + ;; Some code can compile down into a number, but starts out as an + ;; expression, such as "sizeof(a)", or (sizeof(a)/sizeof(b)) + | semantic-list + ( $1 ) + | SIZEOF semantic-list + ( $2 ) + ; + +opt-template-equal + : EQUAL symbol LESS template-specifier-types GREATER + ( $2 ) + | EQUAL symbol + ( $2 ) + | ;;EMPTY + ( ) + ; + +template-type + : CLASS symbol + (TYPE-TAG $2 "class" nil nil ) + | STRUCT symbol + (TYPE-TAG $2 "struct" nil nil ) + ;; TODO: Klaus Berndl: For the moment is is ok, that we parse the C++ + ;; keyword typename as a class.... + | TYPENAME symbol + (TYPE-TAG $2 "class" nil nil) + ;; Klaus Berndl: template-types can be all flavors of variable-args + ;; but here the argument is ignored, only the type stuff is needed. + | declmods typeformbase cv-declmods opt-stars + opt-ref variablearg-opt-name + (TYPE-TAG (car $2) nil nil nil + :constant-flag (if (member "const" (append $1 $3)) t nil) + :typemodifiers (delete "const" (append $1 $3)) + :reference (car ,$5) + :pointer (car $4) + ) + ; + +template-definition + : type + ( ,$1 ) + | var-or-fun + ( ,$1 ) + ; + +opt-stars + : STAR opt-starmod opt-stars + ( (1+ (car $3)) ) + | ;;EMPTY + ( 0 ) + ; + +opt-starmod + : STARMOD opt-starmod + ( ,(cons (,car ,$1) $2) ) + | ;;EMPTY + () + ; + +STARMOD + : CONST + ; + +declmods + : DECLMOD declmods + ( ,(cons ,(car ,$1) $2 ) ) + | DECLMOD + ( ,$1 ) + | ;;EMPTY + () + ; + +DECLMOD + : EXTERN + | STATIC + | CVDECLMOD + ;; Klaus Berndl: IMHO signed and unsigned are not decl-modes but + ;; these are only valid for some buildin-types like short, int + ;; etc... whereas "real" declmods are valid for all types, buildin + ;; and user-defined! SIGNED UNSIGNED + | INLINE + | REGISTER + | FRIEND + ;; Klaus Berndl: There can be a few cases where TYPENAME is not + ;; allowed in C++-syntax but better than not recognizing the allowed + ;; situations. + | TYPENAME + | METADECLMOD + ;; This is a hack in case we are in a class. + | VIRTUAL + ; + +metadeclmod + : METADECLMOD + () + | ;;EMPTY + () + ; + +CVDECLMOD + : CONST + | VOLATILE + ; + +cv-declmods + : CVDECLMOD cv-declmods + ( ,(cons ,(car ,$1) $2 ) ) + | CVDECLMOD + ( ,$1 ) + | ;;EMPTY + () + ; + +METADECLMOD + : VIRTUAL + | MUTABLE + ; + +;; C++: A type can be modified into a reference by "&" +opt-ref + : AMPERSAND + ( 1 ) + | ;;EMPTY + ( 0 ) + ; + +typeformbase + : typesimple + ( ,$1 ) + | STRUCT symbol + (TYPE-TAG $2 $1 nil nil ) + | UNION symbol + (TYPE-TAG $2 $1 nil nil ) + | ENUM symbol + (TYPE-TAG $2 $1 nil nil ) + | builtintype + ( ,$1 ) + | symbol template-specifier + (TYPE-TAG $1 "class" nil nil :template-specifier $2) + ;;| namespace-symbol opt-stars opt-template-specifier + ;;| namespace-symbol opt-template-specifier + | namespace-symbol-for-typeformbase opt-template-specifier + (TYPE-TAG (car $1) "class" nil nil + :template-specifier $2) + | symbol + ( $1 ) + ; + +signedmod + : UNSIGNED + | SIGNED + ; + +;; Klaus Berndl: builtintype-types was builtintype +builtintype-types + : VOID + | CHAR + ;; Klaus Berndl: Added WCHAR + | WCHAR + | SHORT INT + ( (concat $1 " " $2) ) + | SHORT + | INT + | LONG INT + ( (concat $1 " " $2) ) + | FLOAT + | DOUBLE + | BOOL + | LONG DOUBLE + ( (concat $1 " " $2) ) + ;; TODO: Klaus Berndl: Is there a long long, i think so?! + | LONG LONG + ( (concat $1 " " $2) ) + | LONG + ; + +builtintype + : signedmod builtintype-types + ( (concat (car $1) " " (car $2)) ) + | builtintype-types + ( ,$1 ) + ;; Klaus Berndl: unsigned is synonym for unsigned int and signed for + ;; signed int. To make this confusing stuff clear we add here the + ;; int. + | signedmod + ( (concat (car $1) " int") ) + ; + +;; Klaus Berndl: This parses also nonsense like "const volatile int +;; const volatile const const volatile a ..." but IMHO nobody writes +;; such code. Normaly we shoud define a rule like typeformbase-mode +;; which exactly defines the different allowed cases and combinations +;; of declmods (minus the CVDECLMOD) typeformbase and cv-declmods so +;; we could recognize more invalid code but IMHO this is not worth the +;; effort... +codeblock-var-or-fun + : declmods typeformbase declmods + opt-ref var-or-func-decl + ( ,(semantic-c-reconstitute-token ,$5 $1 $2 ) ) + ; + +var-or-fun + : codeblock-var-or-fun + ( ,$1 ) + ;; it is possible for a function to not have a type, and + ;; it is then assumed to be an int. How annoying. + ;; In C++, this could be a constructor or a destructor. + ;; Even more annoying. Only ever do this for regular + ;; top-level items. Ignore this problem in code blocks + ;; so that we don't have to deal with regular code + ;; being erroneously converted into types. + | declmods var-or-func-decl + ( ,(semantic-c-reconstitute-token ,$2 $1 nil ) ) + ; + +var-or-func-decl + : func-decl + ( ,$1 ) + | var-decl + ( ,$1 ) + ; + +func-decl + : opt-stars opt-class opt-destructor functionname + opt-template-specifier + opt-under-p + arg-list + opt-post-fcn-modifiers + opt-throw + opt-initializers + fun-or-proto-end + ( ,$4 'function + ;; Extra stuff goes in here. + ;; Continue with the stuff we found in + ;; this definition + $2 $3 $7 $9 $8 ,$1 ,$11 $5 ,$10) + | opt-stars opt-class opt-destructor functionname + opt-template-specifier + opt-under-p + ;; arg-list - - ini this case, a try implies a fcn. + opt-post-fcn-modifiers + opt-throw + opt-initializers + fun-try-end + ( ,$4 'function + ;; Extra stuff goes in here. + ;; Continue with the stuff we found in + ;; this definition + $2 $3 nil $8 $7 ,$1 ,$10 $5 ,$9) + ; + +var-decl + : varnamelist SEMICOLON + ( $1 'variable ) + ; + +opt-under-p + : UNDERP + ( nil ) + | UNDERUNDERP + ( nil ) + | ;;EMPTY + ; + +;; Klaus Berndl: symbol -> namespace-symbol +opt-initializers + : COLON namespace-symbol semantic-list opt-initializers + | COMA namespace-symbol semantic-list opt-initializers + | ;;EMPTY + ; + +opt-post-fcn-modifiers + : post-fcn-modifiers opt-post-fcn-modifiers + ( ,(cons ,$1 $2) ) + | ;;EMPTY + ( nil ) + ; + +post-fcn-modifiers + : REENTRANT + | CONST + ; + +opt-throw + : THROW semantic-list + ( EXPAND $2 throw-exception-list ) + | ;;EMPTY + ; + +;; Is this true? I don't actually know. +throw-exception-list + : namespace-symbol COMA throw-exception-list + ( ,(cons (car $1) $3) ) + | namespace-symbol RPAREN + ( ,$1 ) + | symbol RPAREN + ( $1 ) + | LPAREN throw-exception-list + ( ,$2 ) + | RPAREN + ( ) + ; + +opt-bits + : COLON number + ( $2 ) + | ;;EMPTY + ( nil ) + ; + +opt-array + : BRACK_BLCK opt-array + ;; Eventually we want to replace the 1 below with a size + ;; (if available) + ( (cons 1 (car ,$2) ) ) + | ;;EMPTY + ( nil ) + ; + +opt-assign + : EQUAL expression + ( $2 ) + | ;;EMPTY + ( nil ) + ; + +opt-restrict + : RESTRICT + | ;;EMPTY + ; + +;; Klaus Berndl: symbol -> namespace-symbol?! I think so. Can be that +;; then also some invalid C++-syntax is parsed but this is better than +;; not parsing valid syntax. +varname + : opt-stars opt-restrict namespace-symbol opt-bits opt-array + ( ,$3 ,$1 ,$4 ,$5 ) + ; + +;; I should store more in this def, but leave it simple for now. +;; Klaus Berndl: const and volatile can be written after the type! +variablearg + : declmods typeformbase cv-declmods opt-ref variablearg-opt-name + ( VARIABLE-TAG (list $5) $2 nil + :constant-flag (if (member "const" (append $1 $3)) t nil) + :typemodifiers (delete "const" (append $1 $3)) + :reference (car ,$4) + ) + ; + +variablearg-opt-name + : varname + ( ,$1 ) + ;; Klaus Berndl: This allows variableargs without a arg-name being + ;; parsed correct even if there several pointers (*) + | opt-stars + ( "" ,$1 nil nil nil ) + ; + +varname-opt-initializer + : semantic-list + | opt-assign + | ;; EMPTY + ; + +varnamelist + : opt-ref varname varname-opt-initializer COMA varnamelist + ( ,(cons $2 $5) ) + | opt-ref varname varname-opt-initializer + ( $2 ) + ; + +;; Klaus Berndl: Is necessary to parse stuff like +;; class list_of_facts : public list, public entity +;; and +;; list >::const_iterator l; +;; Parses also invalid(?) and senseless(?) c++-syntax like +;; symbol::symbol1::test_iterator +;; but better parsing too much than to less +namespace-symbol + : symbol opt-template-specifier COLON COLON namespace-symbol + ( (concat $1 "::" (car $5)) ) + | symbol opt-template-specifier + ( $1 ) + ; + +;; Don't pull an optional template specifier at the end of the +;; namespace symbol so that it can be picked up by the type. +namespace-symbol-for-typeformbase + : symbol opt-template-specifier COLON COLON namespace-symbol-for-typeformbase + ( (concat $1 "::" (car $5)) ) + | symbol + ( $1 ) + ; +;; namespace-symbol +;; : symbol COLON COLON namespace-symbol +;; ( (concat $1 "::" (car $4)) ) +;; | symbol +;; ( $1 ) +;; ; + +namespace-opt-class + : symbol COLON COLON namespace-opt-class + ( (concat $1 "::" (car $4)) ) + ;; Klaus Berndl: We must recognize template-specifiers here so we can + ;; parse correctly the method-implementations of template-classes + ;; outside the template-class-declaration Example: + ;; TemplateClass1::method_1(...) + | symbol opt-template-specifier COLON COLON + ( $1 ) + ; + +;; Klaus Berndl: The opt-class of a func-decl must be able to +;; recognize opt-classes with namespaces, e.g. +;; Test1::Test2::classname:: +opt-class + : namespace-opt-class + ( ,$1 ) + | ;;EMPTY + ( nil ) + ; + +opt-destructor + : TILDE + ( t ) + | ;;EMPTY + ( nil ) + ; + +arg-list + : PAREN_BLCK knr-arguments + ( ,$2 ) + | PAREN_BLCK + (EXPANDFULL $1 arg-sub-list) + | VOID_BLCK + ( ) + ; + +knr-varnamelist + : varname COMA knr-varnamelist + ( ,(cons $1 $3) ) + | varname + ( $1 ) + ; + + +knr-one-variable-decl + : declmods typeformbase cv-declmods knr-varnamelist + ( VARIABLE-TAG (nreverse $4) $2 nil + :constant-flag (if (member "const" (append $3)) t nil) + :typemodifiers (delete "const" $3) + ) + ; + +knr-arguments + : knr-one-variable-decl SEMICOLON knr-arguments + ( ,(append (semantic-expand-c-tag ,$1) ,$3) ) + | knr-one-variable-decl SEMICOLON + ( ,(semantic-expand-c-tag ,$1) ) + ; + +arg-sub-list + : variablearg + ( ,$1 ) + | PERIOD PERIOD PERIOD RPAREN + (VARIABLE-TAG "..." "vararg" nil) + | COMA + ( nil ) + | LPAREN + ( nil ) + | RPAREN + ( nil ) + ; + +operatorsym + : LESS LESS EQUAL + ( "<<=" ) + | GREATER GREATER EQUAL + ( ">>=" ) + | LESS LESS + ( "<<" ) + | GREATER GREATER + ( ">>" ) + | EQUAL EQUAL + ( "==" ) + | LESS EQUAL + ( "<=" ) + | GREATER EQUAL + ( ">=" ) + | BANG EQUAL + ( "!=" ) + | PLUS EQUAL + ( "+=" ) + | MINUS EQUAL + ( "-=" ) + | STAR EQUAL + ( "*=" ) + | DIVIDE EQUAL + ( "/=" ) + | MOD EQUAL + ( "%=" ) + | AMPERSAND EQUAL + ( "&=" ) + | OR EQUAL + ( "|=" ) + | MINUS GREATER STAR + ( "->*" ) + | MINUS GREATER + ( "->" ) + | PARENS + ( "()" ) + | BRACKETS + ( "[]" ) + | LESS + | GREATER + | STAR + | PLUS PLUS + ( "++" ) + | PLUS + | MINUS MINUS + ( "--" ) + | MINUS + | AMPERSAND AMPERSAND + ( "&&" ) + | AMPERSAND + | OR OR + ( "||" ) + | OR + | DIVIDE + | EQUAL + | BANG + | TILDE + | MOD + | COMA + ;; HAT EQUAL seems to have a really unpleasant result and + ;; breaks everything after it. Leave it at the end, though it + ;; doesn't seem to work. + | HAT EQUAL + ( "^=" ) + | HAT + ; + +functionname + : OPERATOR operatorsym + ( ,$2 ) + | semantic-list + ( EXPAND $1 function-pointer ) + | symbol + ( $1 ) + ; + +function-pointer + : LPAREN STAR symbol RPAREN + ( (concat "*" $3) ) + ; + +fun-or-proto-end + : SEMICOLON + ( t ) + | semantic-list + ( nil ) + ;; Here is an anoying feature of C++ pure virtual methods + | EQUAL ZERO SEMICOLON + ( :pure-virtual-flag ) + | fun-try-end + ( nil ) + ; + +fun-try-end + : TRY opt-initializers BRACE_BLCK fun-try-several-catches + ( nil ) + ; + +fun-try-several-catches + : CATCH PAREN_BLCK BRACE_BLCK fun-try-several-catches + ( ) + | CATCH BRACE_BLCK fun-try-several-catches + ( ) + | ;; EMPTY + ( ) + ; + +type-cast + : semantic-list + ( EXPAND $1 type-cast-list ) + ; + +type-cast-list + : open-paren typeformbase close-paren + ; + +opt-stuff-after-symbol + : PAREN_BLCK + | BRACK_BLCK + | ;; EMPTY + ; + +multi-stage-dereference + : namespace-symbol opt-stuff-after-symbol PERIOD multi-stage-dereference ;; method call + | namespace-symbol opt-stuff-after-symbol MINUS GREATER multi-stage-dereference ;;method call + | namespace-symbol opt-stuff-after-symbol + ; + +string-seq + : string string-seq + ( (concat $1 (car $2)) ) + | string + ( $1 ) + ; + +expr-start + : MINUS + | PLUS + | STAR + | AMPERSAND + ; + +expr-binop + : MINUS + | PLUS + | STAR + | DIVIDE + | AMPERSAND AMPERSAND + | AMPERSAND + | OR OR + | OR + ;; There are more. + ; + +;; Use expression for parsing only. Don't actually return anything +;; for now. Hopefully we can fix this later. +expression + : unaryexpression expr-binop unaryexpression + ( (identity start) (identity end) ) + | unaryexpression + ( (identity start) (identity end) ) + ; + +unaryexpression + : number + | multi-stage-dereference + | NEW multi-stage-dereference + | NEW builtintype-types semantic-list + ;; Klaus Berndl: symbol -> namespace-symbol! + | namespace-symbol + ;; Klaus Berndl: C/C++ allows sequences of strings which are + ;; concatenated by the precompiler to one string + | string-seq + | type-cast expression ;; A cast to some other type + ;; Casting the results of one expression to something else. + | semantic-list expression + | semantic-list + | expr-start expression + ; + +;;; semantic/bovine/c.by ends here diff --git a/etc/grammars/java-tags.wy b/etc/grammars/java-tags.wy new file mode 100644 index 0000000000..f24777dc92 --- /dev/null +++ b/etc/grammars/java-tags.wy @@ -0,0 +1,753 @@ +;;; semantic/wisent/java-tags.wy -- Semantic LALR grammar for Java +;; +;; Copyright (C) 2002, 2007 David Ponce +;; Copyright (C) 2007 Eric Ludlam +;; +;; Author: David Ponce +;; Maintainer: David Ponce +;; Created: 25 Feb 2002 +;; Keywords: syntax +;; +;; This file is not part of GNU Emacs. +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2, or (at +;; your option) any later version. +;; +;; This software is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +%package java-tags-wy + +%languagemode java-mode + +;; The default start symbol +%start compilation_unit +;; Alternate entry points +;; - Needed by partial re-parse +%start package_declaration +%start import_declaration +%start class_declaration +%start field_declaration +%start method_declaration +%start formal_parameter +%start constructor_declaration +%start interface_declaration +;; - Needed by EXPANDFULL clauses +%start class_member_declaration +%start interface_member_declaration +%start formal_parameters + +;; ----------------------------- +;; Block & Parenthesis terminals +;; ----------------------------- +%type ;;syntax "\\s(\\|\\s)" matchdatatype block + +%token PAREN_BLOCK "(LPAREN RPAREN)" +%token BRACE_BLOCK "(LBRACE RBRACE)" +%token BRACK_BLOCK "(LBRACK RBRACK)" + +%token LPAREN "(" +%token RPAREN ")" +%token LBRACE "{" +%token RBRACE "}" +%token LBRACK "[" +%token RBRACK "]" + +;; ------------------ +;; Operator terminals +;; ------------------ +%type ;;syntax "\\(\\s.\\|\\s$\\|\\s'\\)+" matchdatatype string + +%token NOT "!" +%token NOTEQ "!=" +%token MOD "%" +%token MODEQ "%=" +%token AND "&" +%token ANDAND "&&" +%token ANDEQ "&=" +%token MULT "*" +%token MULTEQ "*=" +%token PLUS "+" +%token PLUSPLUS "++" +%token PLUSEQ "+=" +%token COMMA "," +%token MINUS "-" +%token MINUSMINUS "--" +%token MINUSEQ "-=" +%token DOT "." +%token DIV "/" +%token DIVEQ "/=" +%token COLON ":" +%token SEMICOLON ";" +%token LT "<" +%token LSHIFT "<<" +%token LSHIFTEQ "<<=" +%token LTEQ "<=" +%token EQ "=" +%token EQEQ "==" +%token GT ">" +%token GTEQ ">=" +%token RSHIFT ">>" +%token RSHIFTEQ ">>=" +%token URSHIFT ">>>" +%token URSHIFTEQ ">>>=" +%token QUESTION "?" +%token XOR "^" +%token XOREQ "^=" +%token OR "|" +%token OREQ "|=" +%token OROR "||" +%token COMP "~" + +;; ----------------- +;; Literal terminals +;; ----------------- +%type ;;syntax "\\(\\sw\\|\\s_\\)+" +%token IDENTIFIER + +%type ;;syntax "\\s\"" matchdatatype sexp +%token STRING_LITERAL + +%type ;;syntax semantic-lex-number-expression +%token NUMBER_LITERAL + +%type syntax "\\\\u[0-9a-f][0-9a-f][0-9a-f][0-9a-f]" +%token unicodecharacter + +;; ----------------- +;; Keyword terminals +;; ----------------- + +;; Generate a keyword analyzer +%type ;;syntax "\\(\\sw\\|\\s_\\)+" matchdatatype keyword + +%keyword ABSTRACT "abstract" +%put ABSTRACT summary +"Class|Method declaration modifier: abstract {class|} ..." + +%keyword BOOLEAN "boolean" +%put BOOLEAN summary +"Primitive logical quantity type (true or false)" + +%keyword BREAK "break" +%put BREAK summary +"break [