diff options
| author | Paul Eggert | 2011-05-30 09:47:35 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-05-30 09:47:35 -0700 |
| commit | 531b01656f89e093b9fa35959fa41e534b025320 (patch) | |
| tree | 190b5a279e0e8e0130b6ba070fa217ce1282e2f3 | |
| parent | de677ace77fa48962be80b668662a7009498e5d6 (diff) | |
| download | emacs-531b01656f89e093b9fa35959fa41e534b025320.tar.gz emacs-531b01656f89e093b9fa35959fa41e534b025320.zip | |
[ChangeLog]
Malloc failure behavior now depends on size of allocation.
* lib/allocator.h (struct allocator.die): New size arg.
* lib/careadlinkat.c (careadlinkat): Pass size to 'die' function.
If the actual problem is an ssize_t limitation, not a size_t or
malloc failure, fail with errno == ENAMETOOLONG instead of calling 'die'.
[src/ChangeLog]
Malloc failure behavior now depends on size of allocation.
* alloc.c (buffer_memory_full, memory_full): New arg NBYTES.
* lisp.h: Change signatures accordingly.
* alloc.c, buffer.c, editfns.c, menu.c, minibuf.c, xterm.c:
All callers changed.
| -rw-r--r-- | ChangeLog | 8 | ||||
| -rw-r--r-- | lib/allocator.h | 9 | ||||
| -rw-r--r-- | lib/careadlinkat.c | 8 | ||||
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/alloc.c | 78 | ||||
| -rw-r--r-- | src/buffer.c | 6 | ||||
| -rw-r--r-- | src/editfns.c | 2 | ||||
| -rw-r--r-- | src/lisp.h | 4 | ||||
| -rw-r--r-- | src/menu.c | 2 | ||||
| -rw-r--r-- | src/minibuf.c | 2 | ||||
| -rw-r--r-- | src/xterm.c | 2 |
11 files changed, 86 insertions, 41 deletions
| @@ -1,3 +1,11 @@ | |||
| 1 | 2011-05-30 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Malloc failure behavior now depends on size of allocation. | ||
| 4 | * lib/allocator.h (struct allocator.die): New size arg. | ||
| 5 | * lib/careadlinkat.c (careadlinkat): Pass size to 'die' function. | ||
| 6 | If the actual problem is an ssize_t limitation, not a size_t or | ||
| 7 | malloc failure, fail with errno == ENAMETOOLONG instead of calling 'die'. | ||
| 8 | |||
| 1 | 2011-05-29 Paul Eggert <eggert@cs.ucla.edu> | 9 | 2011-05-29 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 10 | ||
| 3 | Adjust to recent gnulib change for @GUARD_PREFIX@. | 11 | Adjust to recent gnulib change for @GUARD_PREFIX@. |
diff --git a/lib/allocator.h b/lib/allocator.h index 953117da83f..b8de95c0f50 100644 --- a/lib/allocator.h +++ b/lib/allocator.h | |||
| @@ -45,10 +45,11 @@ struct allocator | |||
| 45 | /* Call FREE to free memory, like 'free'. */ | 45 | /* Call FREE to free memory, like 'free'. */ |
| 46 | void (*free) (void *); | 46 | void (*free) (void *); |
| 47 | 47 | ||
| 48 | /* If nonnull, call DIE if MALLOC or REALLOC fails. DIE should not | 48 | /* If nonnull, call DIE (SIZE) if MALLOC (SIZE) or REALLOC (..., |
| 49 | return. DIE can be used by code that detects memory overflow | 49 | SIZE) fails. DIE should not return. SIZE should equal SIZE_MAX |
| 50 | while calculating sizes to be passed to MALLOC or REALLOC. */ | 50 | if size_t overflow was detected while calculating sizes to be |
| 51 | void (*die) (void); | 51 | passed to MALLOC or REALLOC. */ |
| 52 | void (*die) (size_t); | ||
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | /* An allocator using the stdlib functions and a null DIE function. */ | 55 | /* An allocator using the stdlib functions and a null DIE function. */ |
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index e2909c766d5..6e4aa1395ff 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c | |||
| @@ -135,6 +135,7 @@ careadlinkat (int fd, char const *filename, | |||
| 135 | if (buf == stack_buf) | 135 | if (buf == stack_buf) |
| 136 | { | 136 | { |
| 137 | char *b = (char *) alloc->allocate (link_size); | 137 | char *b = (char *) alloc->allocate (link_size); |
| 138 | buf_size = link_size; | ||
| 138 | if (! b) | 139 | if (! b) |
| 139 | break; | 140 | break; |
| 140 | memcpy (b, buf, link_size); | 141 | memcpy (b, buf, link_size); |
| @@ -158,6 +159,11 @@ careadlinkat (int fd, char const *filename, | |||
| 158 | buf_size *= 2; | 159 | buf_size *= 2; |
| 159 | else if (buf_size < buf_size_max) | 160 | else if (buf_size < buf_size_max) |
| 160 | buf_size = buf_size_max; | 161 | buf_size = buf_size_max; |
| 162 | else if (buf_size_max < SIZE_MAX) | ||
| 163 | { | ||
| 164 | errno = ENAMETOOLONG; | ||
| 165 | return NULL; | ||
| 166 | } | ||
| 161 | else | 167 | else |
| 162 | break; | 168 | break; |
| 163 | buf = (char *) alloc->allocate (buf_size); | 169 | buf = (char *) alloc->allocate (buf_size); |
| @@ -165,7 +171,7 @@ careadlinkat (int fd, char const *filename, | |||
| 165 | while (buf); | 171 | while (buf); |
| 166 | 172 | ||
| 167 | if (alloc->die) | 173 | if (alloc->die) |
| 168 | alloc->die (); | 174 | alloc->die (buf_size); |
| 169 | errno = ENOMEM; | 175 | errno = ENOMEM; |
| 170 | return NULL; | 176 | return NULL; |
| 171 | } | 177 | } |
diff --git a/src/ChangeLog b/src/ChangeLog index 7b0c73adbc9..aa034b3493f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,11 @@ | |||
| 1 | 2011-05-30 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2011-05-30 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Malloc failure behavior now depends on size of allocation. | ||
| 4 | * alloc.c (buffer_memory_full, memory_full): New arg NBYTES. | ||
| 5 | * lisp.h: Change signatures accordingly. | ||
| 6 | * alloc.c, buffer.c, editfns.c, menu.c, minibuf.c, xterm.c: | ||
| 7 | All callers changed. | ||
| 8 | |||
| 3 | * gnutls.c: Use Emacs's memory allocators. | 9 | * gnutls.c: Use Emacs's memory allocators. |
| 4 | Without this change, the gnutls library would invoke malloc etc. | 10 | Without this change, the gnutls library would invoke malloc etc. |
| 5 | directly, which causes problems on non-SYNC_INPUT hosts, and which | 11 | directly, which causes problems on non-SYNC_INPUT hosts, and which |
diff --git a/src/alloc.c b/src/alloc.c index 8215cc53cd3..be045be2ab4 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -471,7 +471,7 @@ display_malloc_warning (void) | |||
| 471 | /* Called if we can't allocate relocatable space for a buffer. */ | 471 | /* Called if we can't allocate relocatable space for a buffer. */ |
| 472 | 472 | ||
| 473 | void | 473 | void |
| 474 | buffer_memory_full (void) | 474 | buffer_memory_full (EMACS_INT nbytes) |
| 475 | { | 475 | { |
| 476 | /* If buffers use the relocating allocator, no need to free | 476 | /* If buffers use the relocating allocator, no need to free |
| 477 | spare_memory, because we may have plenty of malloc space left | 477 | spare_memory, because we may have plenty of malloc space left |
| @@ -481,7 +481,7 @@ buffer_memory_full (void) | |||
| 481 | malloc. */ | 481 | malloc. */ |
| 482 | 482 | ||
| 483 | #ifndef REL_ALLOC | 483 | #ifndef REL_ALLOC |
| 484 | memory_full (); | 484 | memory_full (nbytes); |
| 485 | #endif | 485 | #endif |
| 486 | 486 | ||
| 487 | /* This used to call error, but if we've run out of memory, we could | 487 | /* This used to call error, but if we've run out of memory, we could |
| @@ -677,7 +677,7 @@ xmalloc (size_t size) | |||
| 677 | MALLOC_UNBLOCK_INPUT; | 677 | MALLOC_UNBLOCK_INPUT; |
| 678 | 678 | ||
| 679 | if (!val && size) | 679 | if (!val && size) |
| 680 | memory_full (); | 680 | memory_full (size); |
| 681 | return val; | 681 | return val; |
| 682 | } | 682 | } |
| 683 | 683 | ||
| @@ -698,7 +698,8 @@ xrealloc (POINTER_TYPE *block, size_t size) | |||
| 698 | val = (POINTER_TYPE *) realloc (block, size); | 698 | val = (POINTER_TYPE *) realloc (block, size); |
| 699 | MALLOC_UNBLOCK_INPUT; | 699 | MALLOC_UNBLOCK_INPUT; |
| 700 | 700 | ||
| 701 | if (!val && size) memory_full (); | 701 | if (!val && size) |
| 702 | memory_full (size); | ||
| 702 | return val; | 703 | return val; |
| 703 | } | 704 | } |
| 704 | 705 | ||
| @@ -791,7 +792,7 @@ lisp_malloc (size_t nbytes, enum mem_type type) | |||
| 791 | 792 | ||
| 792 | MALLOC_UNBLOCK_INPUT; | 793 | MALLOC_UNBLOCK_INPUT; |
| 793 | if (!val && nbytes) | 794 | if (!val && nbytes) |
| 794 | memory_full (); | 795 | memory_full (nbytes); |
| 795 | return val; | 796 | return val; |
| 796 | } | 797 | } |
| 797 | 798 | ||
| @@ -938,7 +939,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) | |||
| 938 | if (base == 0) | 939 | if (base == 0) |
| 939 | { | 940 | { |
| 940 | MALLOC_UNBLOCK_INPUT; | 941 | MALLOC_UNBLOCK_INPUT; |
| 941 | memory_full (); | 942 | memory_full (ABLOCKS_BYTES); |
| 942 | } | 943 | } |
| 943 | 944 | ||
| 944 | aligned = (base == abase); | 945 | aligned = (base == abase); |
| @@ -964,7 +965,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) | |||
| 964 | lisp_malloc_loser = base; | 965 | lisp_malloc_loser = base; |
| 965 | free (base); | 966 | free (base); |
| 966 | MALLOC_UNBLOCK_INPUT; | 967 | MALLOC_UNBLOCK_INPUT; |
| 967 | memory_full (); | 968 | memory_full (SIZE_MAX); |
| 968 | } | 969 | } |
| 969 | } | 970 | } |
| 970 | #endif | 971 | #endif |
| @@ -3270,35 +3271,58 @@ make_event_array (register int nargs, Lisp_Object *args) | |||
| 3270 | ************************************************************************/ | 3271 | ************************************************************************/ |
| 3271 | 3272 | ||
| 3272 | 3273 | ||
| 3273 | /* Called if malloc returns zero. */ | 3274 | /* Called if malloc (NBYTES) returns zero. If NBYTES == SIZE_MAX, |
| 3275 | there may have been size_t overflow so that malloc was never | ||
| 3276 | called, or perhaps malloc was invoked successfully but the | ||
| 3277 | resulting pointer had problems fitting into a tagged EMACS_INT. In | ||
| 3278 | either case this counts as memory being full even though malloc did | ||
| 3279 | not fail. */ | ||
| 3274 | 3280 | ||
| 3275 | void | 3281 | void |
| 3276 | memory_full (void) | 3282 | memory_full (size_t nbytes) |
| 3277 | { | 3283 | { |
| 3278 | int i; | 3284 | /* Do not go into hysterics merely because a large request failed. */ |
| 3285 | int enough_free_memory = 0; | ||
| 3286 | if (SPARE_MEMORY < nbytes) | ||
| 3287 | { | ||
| 3288 | void *p = malloc (SPARE_MEMORY); | ||
| 3289 | if (p) | ||
| 3290 | { | ||
| 3291 | if (spare_memory[0]) | ||
| 3292 | free (p); | ||
| 3293 | else | ||
| 3294 | spare_memory[0] = p; | ||
| 3295 | enough_free_memory = 1; | ||
| 3296 | } | ||
| 3297 | } | ||
| 3279 | 3298 | ||
| 3280 | Vmemory_full = Qt; | 3299 | if (! enough_free_memory) |
| 3300 | { | ||
| 3301 | int i; | ||
| 3281 | 3302 | ||
| 3282 | memory_full_cons_threshold = sizeof (struct cons_block); | 3303 | Vmemory_full = Qt; |
| 3283 | 3304 | ||
| 3284 | /* The first time we get here, free the spare memory. */ | 3305 | memory_full_cons_threshold = sizeof (struct cons_block); |
| 3285 | for (i = 0; i < sizeof (spare_memory) / sizeof (char *); i++) | 3306 | |
| 3286 | if (spare_memory[i]) | 3307 | /* The first time we get here, free the spare memory. */ |
| 3287 | { | 3308 | for (i = 0; i < sizeof (spare_memory) / sizeof (char *); i++) |
| 3288 | if (i == 0) | 3309 | if (spare_memory[i]) |
| 3289 | free (spare_memory[i]); | 3310 | { |
| 3290 | else if (i >= 1 && i <= 4) | 3311 | if (i == 0) |
| 3291 | lisp_align_free (spare_memory[i]); | 3312 | free (spare_memory[i]); |
| 3292 | else | 3313 | else if (i >= 1 && i <= 4) |
| 3293 | lisp_free (spare_memory[i]); | 3314 | lisp_align_free (spare_memory[i]); |
| 3294 | spare_memory[i] = 0; | 3315 | else |
| 3295 | } | 3316 | lisp_free (spare_memory[i]); |
| 3317 | spare_memory[i] = 0; | ||
| 3318 | } | ||
| 3296 | 3319 | ||
| 3297 | /* Record the space now used. When it decreases substantially, | 3320 | /* Record the space now used. When it decreases substantially, |
| 3298 | we can refill the memory reserve. */ | 3321 | we can refill the memory reserve. */ |
| 3299 | #if !defined SYSTEM_MALLOC && !defined SYNC_INPUT | 3322 | #if !defined SYSTEM_MALLOC && !defined SYNC_INPUT |
| 3300 | bytes_used_when_full = BYTES_USED; | 3323 | bytes_used_when_full = BYTES_USED; |
| 3301 | #endif | 3324 | #endif |
| 3325 | } | ||
| 3302 | 3326 | ||
| 3303 | /* This used to call error, but if we've run out of memory, we could | 3327 | /* This used to call error, but if we've run out of memory, we could |
| 3304 | get infinite recursion trying to build the string. */ | 3328 | get infinite recursion trying to build the string. */ |
diff --git a/src/buffer.c b/src/buffer.c index 05bd129976f..e9ff8f492ba 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -328,7 +328,7 @@ even if it is dead. The return value is never nil. */) | |||
| 328 | alloc_buffer_text (b, BUF_GAP_SIZE (b) + 1); | 328 | alloc_buffer_text (b, BUF_GAP_SIZE (b) + 1); |
| 329 | UNBLOCK_INPUT; | 329 | UNBLOCK_INPUT; |
| 330 | if (! BUF_BEG_ADDR (b)) | 330 | if (! BUF_BEG_ADDR (b)) |
| 331 | buffer_memory_full (); | 331 | buffer_memory_full (BUF_GAP_SIZE (b) + 1); |
| 332 | 332 | ||
| 333 | b->pt = BEG; | 333 | b->pt = BEG; |
| 334 | b->begv = BEG; | 334 | b->begv = BEG; |
| @@ -4892,7 +4892,7 @@ alloc_buffer_text (struct buffer *b, size_t nbytes) | |||
| 4892 | if (p == NULL) | 4892 | if (p == NULL) |
| 4893 | { | 4893 | { |
| 4894 | UNBLOCK_INPUT; | 4894 | UNBLOCK_INPUT; |
| 4895 | memory_full (); | 4895 | memory_full (nbytes); |
| 4896 | } | 4896 | } |
| 4897 | 4897 | ||
| 4898 | b->text->beg = (unsigned char *) p; | 4898 | b->text->beg = (unsigned char *) p; |
| @@ -4920,7 +4920,7 @@ enlarge_buffer_text (struct buffer *b, EMACS_INT delta) | |||
| 4920 | if (p == NULL) | 4920 | if (p == NULL) |
| 4921 | { | 4921 | { |
| 4922 | UNBLOCK_INPUT; | 4922 | UNBLOCK_INPUT; |
| 4923 | memory_full (); | 4923 | memory_full (nbytes); |
| 4924 | } | 4924 | } |
| 4925 | 4925 | ||
| 4926 | BUF_BEG_ADDR (b) = (unsigned char *) p; | 4926 | BUF_BEG_ADDR (b) = (unsigned char *) p; |
diff --git a/src/editfns.c b/src/editfns.c index 8b48355fbfa..0e40fde9ca4 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3636,7 +3636,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3636 | { | 3636 | { |
| 3637 | EMACS_INT i; | 3637 | EMACS_INT i; |
| 3638 | if ((SIZE_MAX - formatlen) / sizeof (struct info) <= nargs) | 3638 | if ((SIZE_MAX - formatlen) / sizeof (struct info) <= nargs) |
| 3639 | memory_full (); | 3639 | memory_full (SIZE_MAX); |
| 3640 | SAFE_ALLOCA (info, struct info *, (nargs + 1) * sizeof *info + formatlen); | 3640 | SAFE_ALLOCA (info, struct info *, (nargs + 1) * sizeof *info + formatlen); |
| 3641 | discarded = (char *) &info[nargs + 1]; | 3641 | discarded = (char *) &info[nargs + 1]; |
| 3642 | for (i = 0; i < nargs + 1; i++) | 3642 | for (i = 0; i < nargs + 1; i++) |
diff --git a/src/lisp.h b/src/lisp.h index 26d09c6d555..ceaf7f49eb2 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2685,8 +2685,8 @@ extern void allocate_string_data (struct Lisp_String *, EMACS_INT, EMACS_INT); | |||
| 2685 | extern void reset_malloc_hooks (void); | 2685 | extern void reset_malloc_hooks (void); |
| 2686 | extern void uninterrupt_malloc (void); | 2686 | extern void uninterrupt_malloc (void); |
| 2687 | extern void malloc_warning (const char *); | 2687 | extern void malloc_warning (const char *); |
| 2688 | extern void memory_full (void) NO_RETURN; | 2688 | extern void memory_full (size_t) NO_RETURN; |
| 2689 | extern void buffer_memory_full (void) NO_RETURN; | 2689 | extern void buffer_memory_full (EMACS_INT) NO_RETURN; |
| 2690 | extern int survives_gc_p (Lisp_Object); | 2690 | extern int survives_gc_p (Lisp_Object); |
| 2691 | extern void mark_object (Lisp_Object); | 2691 | extern void mark_object (Lisp_Object); |
| 2692 | #if defined REL_ALLOC && !defined SYSTEM_MALLOC | 2692 | #if defined REL_ALLOC && !defined SYSTEM_MALLOC |
diff --git a/src/menu.c b/src/menu.c index e4338f349f6..7eda4c6ebb5 100644 --- a/src/menu.c +++ b/src/menu.c | |||
| @@ -178,7 +178,7 @@ static void | |||
| 178 | grow_menu_items (void) | 178 | grow_menu_items (void) |
| 179 | { | 179 | { |
| 180 | if ((INT_MAX - MENU_ITEMS_PANE_LENGTH) / 2 < menu_items_allocated) | 180 | if ((INT_MAX - MENU_ITEMS_PANE_LENGTH) / 2 < menu_items_allocated) |
| 181 | memory_full (); | 181 | memory_full (SIZE_MAX); |
| 182 | menu_items_allocated *= 2; | 182 | menu_items_allocated *= 2; |
| 183 | menu_items = larger_vector (menu_items, menu_items_allocated, Qnil); | 183 | menu_items = larger_vector (menu_items, menu_items_allocated, Qnil); |
| 184 | } | 184 | } |
diff --git a/src/minibuf.c b/src/minibuf.c index 3f8bd835211..fd51b0a2358 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -245,7 +245,7 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial, | |||
| 245 | len == size - 1 && line[len - 1] != '\n')) | 245 | len == size - 1 && line[len - 1] != '\n')) |
| 246 | { | 246 | { |
| 247 | if ((size_t) -1 / 2 < size) | 247 | if ((size_t) -1 / 2 < size) |
| 248 | memory_full (); | 248 | memory_full (SIZE_MAX); |
| 249 | size *= 2; | 249 | size *= 2; |
| 250 | line = (char *) xrealloc (line, size); | 250 | line = (char *) xrealloc (line, size); |
| 251 | } | 251 | } |
diff --git a/src/xterm.c b/src/xterm.c index 3b8112d972b..56d2ce0e9e5 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -4225,7 +4225,7 @@ x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole) | |||
| 4225 | size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows; | 4225 | size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows; |
| 4226 | 4226 | ||
| 4227 | if ((size_t) -1 / sizeof *scroll_bar_windows < new_size) | 4227 | if ((size_t) -1 / sizeof *scroll_bar_windows < new_size) |
| 4228 | memory_full (); | 4228 | memory_full (SIZE_MAX); |
| 4229 | scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows, | 4229 | scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows, |
| 4230 | nbytes); | 4230 | nbytes); |
| 4231 | memset (&scroll_bar_windows[i], 0, nbytes - old_nbytes); | 4231 | memset (&scroll_bar_windows[i], 0, nbytes - old_nbytes); |