diff options
| author | Paul Eggert | 2011-07-07 09:58:24 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-07-07 09:58:24 -0700 |
| commit | 903fe15d9deb28a72075c39dfd6003a2ff1af134 (patch) | |
| tree | 1fbf75b817447631ab392e9adba208680a3cde4d /src/alloc.c | |
| parent | ac82cc6ad7793d477015227629070cf87c6225b0 (diff) | |
| download | emacs-903fe15d9deb28a72075c39dfd6003a2ff1af134.tar.gz emacs-903fe15d9deb28a72075c39dfd6003a2ff1af134.zip | |
* alloc.c: Integer signedness and overflow fixes.
Do not impose an arbitrary 32-bit limit on malloc sizes when debugging.
(__malloc_size_t): Default to size_t, not to int.
(pure_size, pure_bytes_used_before_overflow, stack_copy_size)
(Fgarbage_collect, mark_object_loop_halt, mark_object):
Prefer ptrdiff_t to size_t when either would do, as we prefer
signed integers.
(XMALLOC_OVERRUN_CHECK_OVERHEAD): New macro.
(xmalloc_overrun_check_header, xmalloc_overrun_check_trailer):
Now const. Initialize with values that are in range even if char
is signed.
(XMALLOC_PUT_SIZE, XMALLOC_GET_SIZE): Remove, replacing with ...
(xmalloc_put_size, xmalloc_get_size): New functions. All uses changed.
These functions do the right thing with sizes > 2**32.
(check_depth): Now ptrdiff_t, not int.
(overrun_check_malloc, overrun_check_realloc, overrun_check_free):
Adjust to new way of storing sizes. Check for size overflow bugs
in rest of code.
(STRING_BYTES_MAX): Adjust to new overheads. The old code was
slightly wrong anyway, as it missed one instance of
XMALLOC_OVERRUN_CHECK_OVERHEAD.
(refill_memory_reserve): Omit needless cast to size_t.
(mark_object_loop_halt): Mark as externally visible.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 136 |
1 files changed, 78 insertions, 58 deletions
diff --git a/src/alloc.c b/src/alloc.c index f679787e95c..5cdd5af9ecf 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -70,7 +70,7 @@ extern POINTER_TYPE *sbrk (); | |||
| 70 | #include <malloc.h> | 70 | #include <malloc.h> |
| 71 | /* malloc.h #defines this as size_t, at least in glibc2. */ | 71 | /* malloc.h #defines this as size_t, at least in glibc2. */ |
| 72 | #ifndef __malloc_size_t | 72 | #ifndef __malloc_size_t |
| 73 | #define __malloc_size_t int | 73 | #define __malloc_size_t size_t |
| 74 | #endif | 74 | #endif |
| 75 | 75 | ||
| 76 | /* Specify maximum number of areas to mmap. It would be nice to use a | 76 | /* Specify maximum number of areas to mmap. It would be nice to use a |
| @@ -214,12 +214,12 @@ EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,}; | |||
| 214 | /* Pointer to the pure area, and its size. */ | 214 | /* Pointer to the pure area, and its size. */ |
| 215 | 215 | ||
| 216 | static char *purebeg; | 216 | static char *purebeg; |
| 217 | static size_t pure_size; | 217 | static ptrdiff_t pure_size; |
| 218 | 218 | ||
| 219 | /* Number of bytes of pure storage used before pure storage overflowed. | 219 | /* Number of bytes of pure storage used before pure storage overflowed. |
| 220 | If this is non-zero, this implies that an overflow occurred. */ | 220 | If this is non-zero, this implies that an overflow occurred. */ |
| 221 | 221 | ||
| 222 | static size_t pure_bytes_used_before_overflow; | 222 | static ptrdiff_t pure_bytes_used_before_overflow; |
| 223 | 223 | ||
| 224 | /* Value is non-zero if P points into pure space. */ | 224 | /* Value is non-zero if P points into pure space. */ |
| 225 | 225 | ||
| @@ -252,7 +252,7 @@ const char *pending_malloc_warning; | |||
| 252 | 252 | ||
| 253 | #if MAX_SAVE_STACK > 0 | 253 | #if MAX_SAVE_STACK > 0 |
| 254 | static char *stack_copy; | 254 | static char *stack_copy; |
| 255 | static size_t stack_copy_size; | 255 | static ptrdiff_t stack_copy_size; |
| 256 | #endif | 256 | #endif |
| 257 | 257 | ||
| 258 | /* Non-zero means ignore malloc warnings. Set during initialization. | 258 | /* Non-zero means ignore malloc warnings. Set during initialization. |
| @@ -486,14 +486,15 @@ buffer_memory_full (EMACS_INT nbytes) | |||
| 486 | 486 | ||
| 487 | 487 | ||
| 488 | #ifndef XMALLOC_OVERRUN_CHECK | 488 | #ifndef XMALLOC_OVERRUN_CHECK |
| 489 | #define XMALLOC_OVERRUN_CHECK_SIZE 0 | 489 | #define XMALLOC_OVERRUN_CHECK_OVERHEAD 0 |
| 490 | #else | 490 | #else |
| 491 | 491 | ||
| 492 | /* Check for overrun in malloc'ed buffers by wrapping a 16 byte header | 492 | /* Check for overrun in malloc'ed buffers by wrapping a header and trailer |
| 493 | and a 16 byte trailer around each block. | 493 | around each block. |
| 494 | 494 | ||
| 495 | The header consists of 12 fixed bytes + a 4 byte integer contaning the | 495 | The header consists of 16 fixed bytes followed by sizeof (size_t) bytes |
| 496 | original block size, while the trailer consists of 16 fixed bytes. | 496 | containing the original block size in little-endian order, |
| 497 | while the trailer consists of 16 fixed bytes. | ||
| 497 | 498 | ||
| 498 | The header is used to detect whether this block has been allocated | 499 | The header is used to detect whether this block has been allocated |
| 499 | through these functions -- as it seems that some low-level libc | 500 | through these functions -- as it seems that some low-level libc |
| @@ -502,31 +503,47 @@ buffer_memory_full (EMACS_INT nbytes) | |||
| 502 | 503 | ||
| 503 | 504 | ||
| 504 | #define XMALLOC_OVERRUN_CHECK_SIZE 16 | 505 | #define XMALLOC_OVERRUN_CHECK_SIZE 16 |
| 506 | #define XMALLOC_OVERRUN_CHECK_OVERHEAD \ | ||
| 507 | (2 * XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)) | ||
| 505 | 508 | ||
| 506 | static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] = | 509 | static char const xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE] = |
| 507 | { 0x9a, 0x9b, 0xae, 0xaf, | 510 | { '\x9a', '\x9b', '\xae', '\xaf', |
| 508 | 0xbf, 0xbe, 0xce, 0xcf, | 511 | '\xbf', '\xbe', '\xce', '\xcf', |
| 509 | 0xea, 0xeb, 0xec, 0xed }; | 512 | '\xea', '\xeb', '\xec', '\xed', |
| 513 | '\xdf', '\xde', '\x9c', '\x9d' }; | ||
| 510 | 514 | ||
| 511 | static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] = | 515 | static char const xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] = |
| 512 | { 0xaa, 0xab, 0xac, 0xad, | 516 | { '\xaa', '\xab', '\xac', '\xad', |
| 513 | 0xba, 0xbb, 0xbc, 0xbd, | 517 | '\xba', '\xbb', '\xbc', '\xbd', |
| 514 | 0xca, 0xcb, 0xcc, 0xcd, | 518 | '\xca', '\xcb', '\xcc', '\xcd', |
| 515 | 0xda, 0xdb, 0xdc, 0xdd }; | 519 | '\xda', '\xdb', '\xdc', '\xdd' }; |
| 516 | 520 | ||
| 517 | /* Macros to insert and extract the block size in the header. */ | 521 | /* Insert and extract the block size in the header. */ |
| 518 | 522 | ||
| 519 | #define XMALLOC_PUT_SIZE(ptr, size) \ | 523 | static void |
| 520 | (ptr[-1] = (size & 0xff), \ | 524 | xmalloc_put_size (unsigned char *ptr, size_t size) |
| 521 | ptr[-2] = ((size >> 8) & 0xff), \ | 525 | { |
| 522 | ptr[-3] = ((size >> 16) & 0xff), \ | 526 | int i; |
| 523 | ptr[-4] = ((size >> 24) & 0xff)) | 527 | for (i = 0; i < sizeof (size_t); i++) |
| 528 | { | ||
| 529 | *--ptr = size & (1 << CHAR_BIT) - 1; | ||
| 530 | size >>= CHAR_BIT; | ||
| 531 | } | ||
| 532 | } | ||
| 524 | 533 | ||
| 525 | #define XMALLOC_GET_SIZE(ptr) \ | 534 | static size_t |
| 526 | (size_t)((unsigned)(ptr[-1]) | \ | 535 | xmalloc_get_size (unsigned char *ptr) |
| 527 | ((unsigned)(ptr[-2]) << 8) | \ | 536 | { |
| 528 | ((unsigned)(ptr[-3]) << 16) | \ | 537 | size_t size = 0; |
| 529 | ((unsigned)(ptr[-4]) << 24)) | 538 | int i; |
| 539 | ptr -= sizeof (size_t); | ||
| 540 | for (i = 0; i < sizeof (size_t); i++) | ||
| 541 | { | ||
| 542 | size <<= CHAR_BIT; | ||
| 543 | size += *ptr++; | ||
| 544 | } | ||
| 545 | return size; | ||
| 546 | } | ||
| 530 | 547 | ||
| 531 | 548 | ||
| 532 | /* The call depth in overrun_check functions. For example, this might happen: | 549 | /* The call depth in overrun_check functions. For example, this might happen: |
| @@ -545,10 +562,10 @@ static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] = | |||
| 545 | 562 | ||
| 546 | xfree(10032) | 563 | xfree(10032) |
| 547 | overrun_check_free(10032) | 564 | overrun_check_free(10032) |
| 548 | decrease overhed | 565 | decrease overhead |
| 549 | free(10016) <- crash, because 10000 is the original pointer. */ | 566 | free(10016) <- crash, because 10000 is the original pointer. */ |
| 550 | 567 | ||
| 551 | static int check_depth; | 568 | static ptrdiff_t check_depth; |
| 552 | 569 | ||
| 553 | /* Like malloc, but wraps allocated block with header and trailer. */ | 570 | /* Like malloc, but wraps allocated block with header and trailer. */ |
| 554 | 571 | ||
| @@ -556,15 +573,16 @@ static POINTER_TYPE * | |||
| 556 | overrun_check_malloc (size_t size) | 573 | overrun_check_malloc (size_t size) |
| 557 | { | 574 | { |
| 558 | register unsigned char *val; | 575 | register unsigned char *val; |
| 559 | size_t overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_SIZE*2 : 0; | 576 | int overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_OVERHEAD : 0; |
| 577 | if (SIZE_MAX - overhead < size) | ||
| 578 | abort (); | ||
| 560 | 579 | ||
| 561 | val = (unsigned char *) malloc (size + overhead); | 580 | val = (unsigned char *) malloc (size + overhead); |
| 562 | if (val && check_depth == 1) | 581 | if (val && check_depth == 1) |
| 563 | { | 582 | { |
| 564 | memcpy (val, xmalloc_overrun_check_header, | 583 | memcpy (val, xmalloc_overrun_check_header, XMALLOC_OVERRUN_CHECK_SIZE); |
| 565 | XMALLOC_OVERRUN_CHECK_SIZE - 4); | 584 | val += XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); |
| 566 | val += XMALLOC_OVERRUN_CHECK_SIZE; | 585 | xmalloc_put_size (val, size); |
| 567 | XMALLOC_PUT_SIZE(val, size); | ||
| 568 | memcpy (val + size, xmalloc_overrun_check_trailer, | 586 | memcpy (val + size, xmalloc_overrun_check_trailer, |
| 569 | XMALLOC_OVERRUN_CHECK_SIZE); | 587 | XMALLOC_OVERRUN_CHECK_SIZE); |
| 570 | } | 588 | } |
| @@ -580,31 +598,32 @@ static POINTER_TYPE * | |||
| 580 | overrun_check_realloc (POINTER_TYPE *block, size_t size) | 598 | overrun_check_realloc (POINTER_TYPE *block, size_t size) |
| 581 | { | 599 | { |
| 582 | register unsigned char *val = (unsigned char *) block; | 600 | register unsigned char *val = (unsigned char *) block; |
| 583 | size_t overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_SIZE*2 : 0; | 601 | int overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_OVERHEAD : 0; |
| 602 | if (SIZE_MAX - overhead < size) | ||
| 603 | abort (); | ||
| 584 | 604 | ||
| 585 | if (val | 605 | if (val |
| 586 | && check_depth == 1 | 606 | && check_depth == 1 |
| 587 | && memcmp (xmalloc_overrun_check_header, | 607 | && memcmp (xmalloc_overrun_check_header, |
| 588 | val - XMALLOC_OVERRUN_CHECK_SIZE, | 608 | val - XMALLOC_OVERRUN_CHECK_SIZE - sizeof (size_t), |
| 589 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | 609 | XMALLOC_OVERRUN_CHECK_SIZE) == 0) |
| 590 | { | 610 | { |
| 591 | size_t osize = XMALLOC_GET_SIZE (val); | 611 | size_t osize = xmalloc_get_size (val); |
| 592 | if (memcmp (xmalloc_overrun_check_trailer, val + osize, | 612 | if (memcmp (xmalloc_overrun_check_trailer, val + osize, |
| 593 | XMALLOC_OVERRUN_CHECK_SIZE)) | 613 | XMALLOC_OVERRUN_CHECK_SIZE)) |
| 594 | abort (); | 614 | abort (); |
| 595 | memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); | 615 | memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); |
| 596 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | 616 | val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); |
| 597 | memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE); | 617 | memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)); |
| 598 | } | 618 | } |
| 599 | 619 | ||
| 600 | val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + overhead); | 620 | val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + overhead); |
| 601 | 621 | ||
| 602 | if (val && check_depth == 1) | 622 | if (val && check_depth == 1) |
| 603 | { | 623 | { |
| 604 | memcpy (val, xmalloc_overrun_check_header, | 624 | memcpy (val, xmalloc_overrun_check_header, XMALLOC_OVERRUN_CHECK_SIZE); |
| 605 | XMALLOC_OVERRUN_CHECK_SIZE - 4); | 625 | val += XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); |
| 606 | val += XMALLOC_OVERRUN_CHECK_SIZE; | 626 | xmalloc_put_size (val, size); |
| 607 | XMALLOC_PUT_SIZE(val, size); | ||
| 608 | memcpy (val + size, xmalloc_overrun_check_trailer, | 627 | memcpy (val + size, xmalloc_overrun_check_trailer, |
| 609 | XMALLOC_OVERRUN_CHECK_SIZE); | 628 | XMALLOC_OVERRUN_CHECK_SIZE); |
| 610 | } | 629 | } |
| @@ -623,20 +642,20 @@ overrun_check_free (POINTER_TYPE *block) | |||
| 623 | if (val | 642 | if (val |
| 624 | && check_depth == 1 | 643 | && check_depth == 1 |
| 625 | && memcmp (xmalloc_overrun_check_header, | 644 | && memcmp (xmalloc_overrun_check_header, |
| 626 | val - XMALLOC_OVERRUN_CHECK_SIZE, | 645 | val - XMALLOC_OVERRUN_CHECK_SIZE - sizeof (size_t), |
| 627 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | 646 | XMALLOC_OVERRUN_CHECK_SIZE) == 0) |
| 628 | { | 647 | { |
| 629 | size_t osize = XMALLOC_GET_SIZE (val); | 648 | size_t osize = xmalloc_get_size (val); |
| 630 | if (memcmp (xmalloc_overrun_check_trailer, val + osize, | 649 | if (memcmp (xmalloc_overrun_check_trailer, val + osize, |
| 631 | XMALLOC_OVERRUN_CHECK_SIZE)) | 650 | XMALLOC_OVERRUN_CHECK_SIZE)) |
| 632 | abort (); | 651 | abort (); |
| 633 | #ifdef XMALLOC_CLEAR_FREE_MEMORY | 652 | #ifdef XMALLOC_CLEAR_FREE_MEMORY |
| 634 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | 653 | val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); |
| 635 | memset (val, 0xff, osize + XMALLOC_OVERRUN_CHECK_SIZE*2); | 654 | memset (val, 0xff, osize + XMALLOC_OVERRUN_CHECK_OVERHEAD); |
| 636 | #else | 655 | #else |
| 637 | memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); | 656 | memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); |
| 638 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | 657 | val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); |
| 639 | memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE); | 658 | memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)); |
| 640 | #endif | 659 | #endif |
| 641 | } | 660 | } |
| 642 | 661 | ||
| @@ -1661,7 +1680,8 @@ static char const string_overrun_cookie[GC_STRING_OVERRUN_COOKIE_SIZE] = | |||
| 1661 | calculating a value to be passed to malloc. */ | 1680 | calculating a value to be passed to malloc. */ |
| 1662 | #define STRING_BYTES_MAX \ | 1681 | #define STRING_BYTES_MAX \ |
| 1663 | min (STRING_BYTES_BOUND, \ | 1682 | min (STRING_BYTES_BOUND, \ |
| 1664 | ((SIZE_MAX - XMALLOC_OVERRUN_CHECK_SIZE - GC_STRING_EXTRA \ | 1683 | ((SIZE_MAX - XMALLOC_OVERRUN_CHECK_OVERHEAD \ |
| 1684 | - GC_STRING_EXTRA \ | ||
| 1665 | - offsetof (struct sblock, first_data) \ | 1685 | - offsetof (struct sblock, first_data) \ |
| 1666 | - SDATA_DATA_OFFSET) \ | 1686 | - SDATA_DATA_OFFSET) \ |
| 1667 | & ~(sizeof (EMACS_INT) - 1))) | 1687 | & ~(sizeof (EMACS_INT) - 1))) |
| @@ -3320,7 +3340,7 @@ refill_memory_reserve (void) | |||
| 3320 | { | 3340 | { |
| 3321 | #ifndef SYSTEM_MALLOC | 3341 | #ifndef SYSTEM_MALLOC |
| 3322 | if (spare_memory[0] == 0) | 3342 | if (spare_memory[0] == 0) |
| 3323 | spare_memory[0] = (char *) malloc ((size_t) SPARE_MEMORY); | 3343 | spare_memory[0] = (char *) malloc (SPARE_MEMORY); |
| 3324 | if (spare_memory[1] == 0) | 3344 | if (spare_memory[1] == 0) |
| 3325 | spare_memory[1] = (char *) lisp_align_malloc (sizeof (struct cons_block), | 3345 | spare_memory[1] = (char *) lisp_align_malloc (sizeof (struct cons_block), |
| 3326 | MEM_TYPE_CONS); | 3346 | MEM_TYPE_CONS); |
| @@ -4922,7 +4942,7 @@ returns nil, because real GC can't be done. */) | |||
| 4922 | if (NILP (Vpurify_flag)) | 4942 | if (NILP (Vpurify_flag)) |
| 4923 | { | 4943 | { |
| 4924 | char *stack; | 4944 | char *stack; |
| 4925 | size_t stack_size; | 4945 | ptrdiff_t stack_size; |
| 4926 | if (&stack_top_variable < stack_bottom) | 4946 | if (&stack_top_variable < stack_bottom) |
| 4927 | { | 4947 | { |
| 4928 | stack = &stack_top_variable; | 4948 | stack = &stack_top_variable; |
| @@ -5233,7 +5253,7 @@ static int last_marked_index; | |||
| 5233 | links of a list, in mark_object. In debugging, | 5253 | links of a list, in mark_object. In debugging, |
| 5234 | the call to abort will hit a breakpoint. | 5254 | the call to abort will hit a breakpoint. |
| 5235 | Normally this is zero and the check never goes off. */ | 5255 | Normally this is zero and the check never goes off. */ |
| 5236 | static size_t mark_object_loop_halt; | 5256 | ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; |
| 5237 | 5257 | ||
| 5238 | static void | 5258 | static void |
| 5239 | mark_vectorlike (struct Lisp_Vector *ptr) | 5259 | mark_vectorlike (struct Lisp_Vector *ptr) |
| @@ -5290,7 +5310,7 @@ mark_object (Lisp_Object arg) | |||
| 5290 | void *po; | 5310 | void *po; |
| 5291 | struct mem_node *m; | 5311 | struct mem_node *m; |
| 5292 | #endif | 5312 | #endif |
| 5293 | size_t cdr_count = 0; | 5313 | ptrdiff_t cdr_count = 0; |
| 5294 | 5314 | ||
| 5295 | loop: | 5315 | loop: |
| 5296 | 5316 | ||