diff options
| author | Kim F. Storm | 2004-12-01 14:10:23 +0000 |
|---|---|---|
| committer | Kim F. Storm | 2004-12-01 14:10:23 +0000 |
| commit | bdbed949970b828b02ef8746543337968d89f83b (patch) | |
| tree | d4a0f480a3057479e21ddd6d8fa2cf395a10ae5d /src/alloc.c | |
| parent | 1cae6d39e6c10cc785dff977039294a8971d7de9 (diff) | |
| download | emacs-bdbed949970b828b02ef8746543337968d89f83b.tar.gz emacs-bdbed949970b828b02ef8746543337968d89f83b.zip | |
Add commentary for last change.
(XMALLOC_PUT_SIZE, XMALLOC_GET_SIZE): New macros to handle
sizeof(size_t) != 4.
(overrun_check_malloc, overrun_check_realloc, overrun_check_free):
Use them. Also clear header and trailer of freed memory.
(GC_STRING_OVERRUN_COOKIE_SIZE): Rename from GC_STRING_EXTRA.
(string_overrun_cookie): Rename from string_overrun_pattern.
(GC_STRING_EXTRA): Define from GC_STRING_OVERRUN_COOKIE_SIZE.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 100 |
1 files changed, 77 insertions, 23 deletions
diff --git a/src/alloc.c b/src/alloc.c index 223a49ee567..e0c14e8bb9c 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -516,11 +516,22 @@ buffer_memory_full () | |||
| 516 | } | 516 | } |
| 517 | 517 | ||
| 518 | 518 | ||
| 519 | /* Like malloc but check for no memory and block interrupt input.. */ | ||
| 520 | |||
| 521 | #ifdef XMALLOC_OVERRUN_CHECK | 519 | #ifdef XMALLOC_OVERRUN_CHECK |
| 522 | 520 | ||
| 521 | /* Check for overrun in malloc'ed buffers by wrapping a 16 byte header | ||
| 522 | and a 16 byte trailer around each block. | ||
| 523 | |||
| 524 | The header consists of 12 fixed bytes + a 4 byte integer contaning the | ||
| 525 | original block size, while the trailer consists of 16 fixed bytes. | ||
| 526 | |||
| 527 | The header is used to detect whether this block has been allocated | ||
| 528 | through these functions -- as it seems that some low-level libc | ||
| 529 | functions may bypass the malloc hooks. | ||
| 530 | */ | ||
| 531 | |||
| 532 | |||
| 523 | #define XMALLOC_OVERRUN_CHECK_SIZE 16 | 533 | #define XMALLOC_OVERRUN_CHECK_SIZE 16 |
| 534 | |||
| 524 | static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] = | 535 | static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] = |
| 525 | { 0x9a, 0x9b, 0xae, 0xaf, | 536 | { 0x9a, 0x9b, 0xae, 0xaf, |
| 526 | 0xbf, 0xbe, 0xce, 0xcf, | 537 | 0xbf, 0xbe, 0xce, 0xcf, |
| @@ -532,74 +543,99 @@ static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] = | |||
| 532 | 0xca, 0xcb, 0xcc, 0xcd, | 543 | 0xca, 0xcb, 0xcc, 0xcd, |
| 533 | 0xda, 0xdb, 0xdc, 0xdd }; | 544 | 0xda, 0xdb, 0xdc, 0xdd }; |
| 534 | 545 | ||
| 546 | /* Macros to insert and extract the block size in the header. */ | ||
| 547 | |||
| 548 | #define XMALLOC_PUT_SIZE(ptr, size) \ | ||
| 549 | (ptr[-1] = (size & 0xff), \ | ||
| 550 | ptr[-2] = ((size >> 8) & 0xff), \ | ||
| 551 | ptr[-3] = ((size >> 16) & 0xff), \ | ||
| 552 | ptr[-4] = ((size >> 24) & 0xff)) | ||
| 553 | |||
| 554 | #define XMALLOC_GET_SIZE(ptr) \ | ||
| 555 | (size_t)((unsigned)(ptr[-1]) | \ | ||
| 556 | ((unsigned)(ptr[-2]) << 8) | \ | ||
| 557 | ((unsigned)(ptr[-3]) << 16) | \ | ||
| 558 | ((unsigned)(ptr[-4]) << 24)) | ||
| 559 | |||
| 560 | |||
| 561 | /* Like malloc, but wraps allocated block with header and trailer. */ | ||
| 562 | |||
| 535 | POINTER_TYPE * | 563 | POINTER_TYPE * |
| 536 | overrun_check_malloc (size) | 564 | overrun_check_malloc (size) |
| 537 | size_t size; | 565 | size_t size; |
| 538 | { | 566 | { |
| 539 | register char *val; | 567 | register unsigned char *val; |
| 540 | 568 | ||
| 541 | val = (char *) malloc (size + XMALLOC_OVERRUN_CHECK_SIZE*2); | 569 | val = (unsigned char *) malloc (size + XMALLOC_OVERRUN_CHECK_SIZE*2); |
| 542 | if (val) | 570 | if (val) |
| 543 | { | 571 | { |
| 544 | bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4); | 572 | bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4); |
| 545 | bcopy (&size, val + XMALLOC_OVERRUN_CHECK_SIZE - 4, sizeof (size)); | ||
| 546 | val += XMALLOC_OVERRUN_CHECK_SIZE; | 573 | val += XMALLOC_OVERRUN_CHECK_SIZE; |
| 574 | XMALLOC_PUT_SIZE(val, size); | ||
| 547 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); | 575 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); |
| 548 | } | 576 | } |
| 549 | return (POINTER_TYPE *)val; | 577 | return (POINTER_TYPE *)val; |
| 550 | } | 578 | } |
| 551 | 579 | ||
| 580 | |||
| 581 | /* Like realloc, but checks old block for overrun, and wraps new block | ||
| 582 | with header and trailer. */ | ||
| 583 | |||
| 552 | POINTER_TYPE * | 584 | POINTER_TYPE * |
| 553 | overrun_check_realloc (block, size) | 585 | overrun_check_realloc (block, size) |
| 554 | POINTER_TYPE *block; | 586 | POINTER_TYPE *block; |
| 555 | size_t size; | 587 | size_t size; |
| 556 | { | 588 | { |
| 557 | register char *val = (char *)block; | 589 | register unsigned char *val = (unsigned char *)block; |
| 558 | 590 | ||
| 559 | if (val | 591 | if (val |
| 560 | && bcmp (xmalloc_overrun_check_header, | 592 | && bcmp (xmalloc_overrun_check_header, |
| 561 | val - XMALLOC_OVERRUN_CHECK_SIZE, | 593 | val - XMALLOC_OVERRUN_CHECK_SIZE, |
| 562 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | 594 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) |
| 563 | { | 595 | { |
| 564 | size_t osize; | 596 | size_t osize = XMALLOC_GET_SIZE (val); |
| 565 | bcopy (val - 4, &osize, sizeof (osize)); | ||
| 566 | if (bcmp (xmalloc_overrun_check_trailer, | 597 | if (bcmp (xmalloc_overrun_check_trailer, |
| 567 | val + osize, | 598 | val + osize, |
| 568 | XMALLOC_OVERRUN_CHECK_SIZE)) | 599 | XMALLOC_OVERRUN_CHECK_SIZE)) |
| 569 | abort (); | 600 | abort (); |
| 601 | bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 570 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | 602 | val -= XMALLOC_OVERRUN_CHECK_SIZE; |
| 603 | bzero (val, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 571 | } | 604 | } |
| 572 | 605 | ||
| 573 | val = (char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2); | 606 | val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2); |
| 574 | 607 | ||
| 575 | if (val) | 608 | if (val) |
| 576 | { | 609 | { |
| 577 | bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4); | 610 | bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4); |
| 578 | bcopy (&size, val + XMALLOC_OVERRUN_CHECK_SIZE - 4, sizeof (size)); | ||
| 579 | val += XMALLOC_OVERRUN_CHECK_SIZE; | 611 | val += XMALLOC_OVERRUN_CHECK_SIZE; |
| 612 | XMALLOC_PUT_SIZE(val, size); | ||
| 580 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); | 613 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); |
| 581 | } | 614 | } |
| 582 | return (POINTER_TYPE *)val; | 615 | return (POINTER_TYPE *)val; |
| 583 | } | 616 | } |
| 584 | 617 | ||
| 618 | /* Like free, but checks block for overrun. */ | ||
| 619 | |||
| 585 | void | 620 | void |
| 586 | overrun_check_free (block) | 621 | overrun_check_free (block) |
| 587 | POINTER_TYPE *block; | 622 | POINTER_TYPE *block; |
| 588 | { | 623 | { |
| 589 | char *val = (char *)block; | 624 | unsigned char *val = (unsigned char *)block; |
| 590 | 625 | ||
| 591 | if (val | 626 | if (val |
| 592 | && bcmp (xmalloc_overrun_check_header, | 627 | && bcmp (xmalloc_overrun_check_header, |
| 593 | val - XMALLOC_OVERRUN_CHECK_SIZE, | 628 | val - XMALLOC_OVERRUN_CHECK_SIZE, |
| 594 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | 629 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) |
| 595 | { | 630 | { |
| 596 | size_t osize; | 631 | size_t osize = XMALLOC_GET_SIZE (val); |
| 597 | bcopy (val - 4, &osize, sizeof (osize)); | ||
| 598 | if (bcmp (xmalloc_overrun_check_trailer, | 632 | if (bcmp (xmalloc_overrun_check_trailer, |
| 599 | val + osize, | 633 | val + osize, |
| 600 | XMALLOC_OVERRUN_CHECK_SIZE)) | 634 | XMALLOC_OVERRUN_CHECK_SIZE)) |
| 601 | abort (); | 635 | abort (); |
| 636 | bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 602 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | 637 | val -= XMALLOC_OVERRUN_CHECK_SIZE; |
| 638 | bzero (val, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 603 | } | 639 | } |
| 604 | 640 | ||
| 605 | free (val); | 641 | free (val); |
| @@ -613,6 +649,9 @@ overrun_check_free (block) | |||
| 613 | #define free overrun_check_free | 649 | #define free overrun_check_free |
| 614 | #endif | 650 | #endif |
| 615 | 651 | ||
| 652 | |||
| 653 | /* Like malloc but check for no memory and block interrupt input.. */ | ||
| 654 | |||
| 616 | POINTER_TYPE * | 655 | POINTER_TYPE * |
| 617 | xmalloc (size) | 656 | xmalloc (size) |
| 618 | size_t size; | 657 | size_t size; |
| @@ -1527,10 +1566,17 @@ static int total_string_size; | |||
| 1527 | 1566 | ||
| 1528 | 1567 | ||
| 1529 | #ifdef GC_CHECK_STRING_OVERRUN | 1568 | #ifdef GC_CHECK_STRING_OVERRUN |
| 1530 | #define GC_STRING_EXTRA 4 | 1569 | |
| 1531 | static char string_overrun_pattern[GC_STRING_EXTRA] = { 0xde, 0xad, 0xbe, 0xef }; | 1570 | /* We check for overrun in string data blocks by appending a small |
| 1571 | "cookie" after each allocated string data block, and check for the | ||
| 1572 | presense of this cookie during GC. */ | ||
| 1573 | |||
| 1574 | #define GC_STRING_OVERRUN_COOKIE_SIZE 4 | ||
| 1575 | static char string_overrun_cookie[GC_STRING_OVERRUN_COOKIE_SIZE] = | ||
| 1576 | { 0xde, 0xad, 0xbe, 0xef }; | ||
| 1577 | |||
| 1532 | #else | 1578 | #else |
| 1533 | #define GC_STRING_EXTRA 0 | 1579 | #define GC_STRING_OVERRUN_COOKIE_SIZE 0 |
| 1534 | #endif | 1580 | #endif |
| 1535 | 1581 | ||
| 1536 | /* Value is the size of an sdata structure large enough to hold NBYTES | 1582 | /* Value is the size of an sdata structure large enough to hold NBYTES |
| @@ -1556,6 +1602,10 @@ static char string_overrun_pattern[GC_STRING_EXTRA] = { 0xde, 0xad, 0xbe, 0xef } | |||
| 1556 | 1602 | ||
| 1557 | #endif /* not GC_CHECK_STRING_BYTES */ | 1603 | #endif /* not GC_CHECK_STRING_BYTES */ |
| 1558 | 1604 | ||
| 1605 | /* Extra bytes to allocate for each string. */ | ||
| 1606 | |||
| 1607 | #define GC_STRING_EXTRA (GC_STRING_OVERRUN_COOKIE_SIZE) | ||
| 1608 | |||
| 1559 | /* Initialize string allocation. Called from init_alloc_once. */ | 1609 | /* Initialize string allocation. Called from init_alloc_once. */ |
| 1560 | 1610 | ||
| 1561 | void | 1611 | void |
| @@ -1655,6 +1705,9 @@ check_string_bytes (all_p) | |||
| 1655 | 1705 | ||
| 1656 | #ifdef GC_CHECK_STRING_FREE_LIST | 1706 | #ifdef GC_CHECK_STRING_FREE_LIST |
| 1657 | 1707 | ||
| 1708 | /* Walk through the string free list looking for bogus next pointers. | ||
| 1709 | This may catch buffer overrun from a previous string. */ | ||
| 1710 | |||
| 1658 | static void | 1711 | static void |
| 1659 | check_string_free_list () | 1712 | check_string_free_list () |
| 1660 | { | 1713 | { |
| @@ -1703,7 +1756,7 @@ allocate_string () | |||
| 1703 | total_free_strings += STRING_BLOCK_SIZE; | 1756 | total_free_strings += STRING_BLOCK_SIZE; |
| 1704 | } | 1757 | } |
| 1705 | 1758 | ||
| 1706 | check_string_free_list(); | 1759 | check_string_free_list (); |
| 1707 | 1760 | ||
| 1708 | /* Pop a Lisp_String off the free-list. */ | 1761 | /* Pop a Lisp_String off the free-list. */ |
| 1709 | s = string_free_list; | 1762 | s = string_free_list; |
| @@ -1819,7 +1872,8 @@ allocate_string_data (s, nchars, nbytes) | |||
| 1819 | s->size_byte = nbytes; | 1872 | s->size_byte = nbytes; |
| 1820 | s->data[nbytes] = '\0'; | 1873 | s->data[nbytes] = '\0'; |
| 1821 | #ifdef GC_CHECK_STRING_OVERRUN | 1874 | #ifdef GC_CHECK_STRING_OVERRUN |
| 1822 | bcopy(string_overrun_pattern, (char *) data + needed, GC_STRING_EXTRA); | 1875 | bcopy (string_overrun_cookie, (char *) data + needed, |
| 1876 | GC_STRING_OVERRUN_COOKIE_SIZE); | ||
| 1823 | #endif | 1877 | #endif |
| 1824 | b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA); | 1878 | b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA); |
| 1825 | 1879 | ||
| @@ -1926,13 +1980,13 @@ sweep_strings () | |||
| 1926 | } | 1980 | } |
| 1927 | } | 1981 | } |
| 1928 | 1982 | ||
| 1929 | check_string_free_list(); | 1983 | check_string_free_list (); |
| 1930 | 1984 | ||
| 1931 | string_blocks = live_blocks; | 1985 | string_blocks = live_blocks; |
| 1932 | free_large_strings (); | 1986 | free_large_strings (); |
| 1933 | compact_small_strings (); | 1987 | compact_small_strings (); |
| 1934 | 1988 | ||
| 1935 | check_string_free_list(); | 1989 | check_string_free_list (); |
| 1936 | } | 1990 | } |
| 1937 | 1991 | ||
| 1938 | 1992 | ||
| @@ -2004,16 +2058,16 @@ compact_small_strings () | |||
| 2004 | else | 2058 | else |
| 2005 | nbytes = SDATA_NBYTES (from); | 2059 | nbytes = SDATA_NBYTES (from); |
| 2006 | 2060 | ||
| 2007 | #ifdef GC_CHECK_STRING_BYTES | ||
| 2008 | if (nbytes > LARGE_STRING_BYTES) | 2061 | if (nbytes > LARGE_STRING_BYTES) |
| 2009 | abort (); | 2062 | abort (); |
| 2010 | #endif | ||
| 2011 | 2063 | ||
| 2012 | nbytes = SDATA_SIZE (nbytes); | 2064 | nbytes = SDATA_SIZE (nbytes); |
| 2013 | from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); | 2065 | from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); |
| 2014 | 2066 | ||
| 2015 | #ifdef GC_CHECK_STRING_OVERRUN | 2067 | #ifdef GC_CHECK_STRING_OVERRUN |
| 2016 | if (bcmp(string_overrun_pattern, ((char *) from_end) - GC_STRING_EXTRA, GC_STRING_EXTRA)) | 2068 | if (bcmp (string_overrun_cookie, |
| 2069 | ((char *) from_end) - GC_STRING_OVERRUN_COOKIE_SIZE, | ||
| 2070 | GC_STRING_OVERRUN_COOKIE_SIZE)) | ||
| 2017 | abort (); | 2071 | abort (); |
| 2018 | #endif | 2072 | #endif |
| 2019 | 2073 | ||