diff options
| author | Kim F. Storm | 2004-11-30 00:30:56 +0000 |
|---|---|---|
| committer | Kim F. Storm | 2004-11-30 00:30:56 +0000 |
| commit | 212f33f185f9d93562aec9ab01625557c8003ee0 (patch) | |
| tree | 6f446fb9b00a1171f88800cc63f97bf5f3b18e53 /src/alloc.c | |
| parent | fc36888973845984731c651411f43b039ec39be3 (diff) | |
| download | emacs-212f33f185f9d93562aec9ab01625557c8003ee0.tar.gz emacs-212f33f185f9d93562aec9ab01625557c8003ee0.zip | |
Add more checks for buffer overruns.
(XMALLOC_OVERRUN_CHECK_SIZE, xmalloc_overrun_check_header)
xmalloc_overrun_check_trailer, overrun_check_malloc)
overrun_check_realloc, overrun_check_free): Add.
(GC_STRING_EXTRA, string_overrun_pattern): Add.
(check_sblock, allocate_string_data, compact_small_strings):
Set and check string_overrun_pattern if GC_CHECK_STRING_OVERRUN.
(check_cons_list): Condition on GC_CHECK_CONS_LIST.
(check_string_free_list): Add.
(allocate_string, sweep_strings): Call check_string_free_list.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 161 |
1 files changed, 152 insertions, 9 deletions
diff --git a/src/alloc.c b/src/alloc.c index be2a4fa1bbc..223a49ee567 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -518,6 +518,101 @@ buffer_memory_full () | |||
| 518 | 518 | ||
| 519 | /* Like malloc but check for no memory and block interrupt input.. */ | 519 | /* Like malloc but check for no memory and block interrupt input.. */ |
| 520 | 520 | ||
| 521 | #ifdef XMALLOC_OVERRUN_CHECK | ||
| 522 | |||
| 523 | #define XMALLOC_OVERRUN_CHECK_SIZE 16 | ||
| 524 | static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] = | ||
| 525 | { 0x9a, 0x9b, 0xae, 0xaf, | ||
| 526 | 0xbf, 0xbe, 0xce, 0xcf, | ||
| 527 | 0xea, 0xeb, 0xec, 0xed }; | ||
| 528 | |||
| 529 | static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] = | ||
| 530 | { 0xaa, 0xab, 0xac, 0xad, | ||
| 531 | 0xba, 0xbb, 0xbc, 0xbd, | ||
| 532 | 0xca, 0xcb, 0xcc, 0xcd, | ||
| 533 | 0xda, 0xdb, 0xdc, 0xdd }; | ||
| 534 | |||
| 535 | POINTER_TYPE * | ||
| 536 | overrun_check_malloc (size) | ||
| 537 | size_t size; | ||
| 538 | { | ||
| 539 | register char *val; | ||
| 540 | |||
| 541 | val = (char *) malloc (size + XMALLOC_OVERRUN_CHECK_SIZE*2); | ||
| 542 | if (val) | ||
| 543 | { | ||
| 544 | 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; | ||
| 547 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 548 | } | ||
| 549 | return (POINTER_TYPE *)val; | ||
| 550 | } | ||
| 551 | |||
| 552 | POINTER_TYPE * | ||
| 553 | overrun_check_realloc (block, size) | ||
| 554 | POINTER_TYPE *block; | ||
| 555 | size_t size; | ||
| 556 | { | ||
| 557 | register char *val = (char *)block; | ||
| 558 | |||
| 559 | if (val | ||
| 560 | && bcmp (xmalloc_overrun_check_header, | ||
| 561 | val - XMALLOC_OVERRUN_CHECK_SIZE, | ||
| 562 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | ||
| 563 | { | ||
| 564 | size_t osize; | ||
| 565 | bcopy (val - 4, &osize, sizeof (osize)); | ||
| 566 | if (bcmp (xmalloc_overrun_check_trailer, | ||
| 567 | val + osize, | ||
| 568 | XMALLOC_OVERRUN_CHECK_SIZE)) | ||
| 569 | abort (); | ||
| 570 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | ||
| 571 | } | ||
| 572 | |||
| 573 | val = (char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2); | ||
| 574 | |||
| 575 | if (val) | ||
| 576 | { | ||
| 577 | 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; | ||
| 580 | bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE); | ||
| 581 | } | ||
| 582 | return (POINTER_TYPE *)val; | ||
| 583 | } | ||
| 584 | |||
| 585 | void | ||
| 586 | overrun_check_free (block) | ||
| 587 | POINTER_TYPE *block; | ||
| 588 | { | ||
| 589 | char *val = (char *)block; | ||
| 590 | |||
| 591 | if (val | ||
| 592 | && bcmp (xmalloc_overrun_check_header, | ||
| 593 | val - XMALLOC_OVERRUN_CHECK_SIZE, | ||
| 594 | XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0) | ||
| 595 | { | ||
| 596 | size_t osize; | ||
| 597 | bcopy (val - 4, &osize, sizeof (osize)); | ||
| 598 | if (bcmp (xmalloc_overrun_check_trailer, | ||
| 599 | val + osize, | ||
| 600 | XMALLOC_OVERRUN_CHECK_SIZE)) | ||
| 601 | abort (); | ||
| 602 | val -= XMALLOC_OVERRUN_CHECK_SIZE; | ||
| 603 | } | ||
| 604 | |||
| 605 | free (val); | ||
| 606 | } | ||
| 607 | |||
| 608 | #undef malloc | ||
| 609 | #undef realloc | ||
| 610 | #undef free | ||
| 611 | #define malloc overrun_check_malloc | ||
| 612 | #define realloc overrun_check_realloc | ||
| 613 | #define free overrun_check_free | ||
| 614 | #endif | ||
| 615 | |||
| 521 | POINTER_TYPE * | 616 | POINTER_TYPE * |
| 522 | xmalloc (size) | 617 | xmalloc (size) |
| 523 | size_t size; | 618 | size_t size; |
| @@ -602,7 +697,9 @@ safe_alloca_unwind (arg) | |||
| 602 | number of bytes to allocate, TYPE describes the intended use of the | 697 | number of bytes to allocate, TYPE describes the intended use of the |
| 603 | allcated memory block (for strings, for conses, ...). */ | 698 | allcated memory block (for strings, for conses, ...). */ |
| 604 | 699 | ||
| 700 | #ifndef USE_LSB_TAG | ||
| 605 | static void *lisp_malloc_loser; | 701 | static void *lisp_malloc_loser; |
| 702 | #endif | ||
| 606 | 703 | ||
| 607 | static POINTER_TYPE * | 704 | static POINTER_TYPE * |
| 608 | lisp_malloc (nbytes, type) | 705 | lisp_malloc (nbytes, type) |
| @@ -1428,6 +1525,14 @@ static int total_string_size; | |||
| 1428 | 1525 | ||
| 1429 | #endif /* not GC_CHECK_STRING_BYTES */ | 1526 | #endif /* not GC_CHECK_STRING_BYTES */ |
| 1430 | 1527 | ||
| 1528 | |||
| 1529 | #ifdef GC_CHECK_STRING_OVERRUN | ||
| 1530 | #define GC_STRING_EXTRA 4 | ||
| 1531 | static char string_overrun_pattern[GC_STRING_EXTRA] = { 0xde, 0xad, 0xbe, 0xef }; | ||
| 1532 | #else | ||
| 1533 | #define GC_STRING_EXTRA 0 | ||
| 1534 | #endif | ||
| 1535 | |||
| 1431 | /* Value is the size of an sdata structure large enough to hold NBYTES | 1536 | /* Value is the size of an sdata structure large enough to hold NBYTES |
| 1432 | bytes of string data. The value returned includes a terminating | 1537 | bytes of string data. The value returned includes a terminating |
| 1433 | NUL byte, the size of the sdata structure, and padding. */ | 1538 | NUL byte, the size of the sdata structure, and padding. */ |
| @@ -1515,7 +1620,7 @@ check_sblock (b) | |||
| 1515 | nbytes = SDATA_NBYTES (from); | 1620 | nbytes = SDATA_NBYTES (from); |
| 1516 | 1621 | ||
| 1517 | nbytes = SDATA_SIZE (nbytes); | 1622 | nbytes = SDATA_SIZE (nbytes); |
| 1518 | from_end = (struct sdata *) ((char *) from + nbytes); | 1623 | from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); |
| 1519 | } | 1624 | } |
| 1520 | } | 1625 | } |
| 1521 | 1626 | ||
| @@ -1548,6 +1653,25 @@ check_string_bytes (all_p) | |||
| 1548 | 1653 | ||
| 1549 | #endif /* GC_CHECK_STRING_BYTES */ | 1654 | #endif /* GC_CHECK_STRING_BYTES */ |
| 1550 | 1655 | ||
| 1656 | #ifdef GC_CHECK_STRING_FREE_LIST | ||
| 1657 | |||
| 1658 | static void | ||
| 1659 | check_string_free_list () | ||
| 1660 | { | ||
| 1661 | struct Lisp_String *s; | ||
| 1662 | |||
| 1663 | /* Pop a Lisp_String off the free-list. */ | ||
| 1664 | s = string_free_list; | ||
| 1665 | while (s != NULL) | ||
| 1666 | { | ||
| 1667 | if ((unsigned)s < 1024) | ||
| 1668 | abort(); | ||
| 1669 | s = NEXT_FREE_LISP_STRING (s); | ||
| 1670 | } | ||
| 1671 | } | ||
| 1672 | #else | ||
| 1673 | #define check_string_free_list() | ||
| 1674 | #endif | ||
| 1551 | 1675 | ||
| 1552 | /* Return a new Lisp_String. */ | 1676 | /* Return a new Lisp_String. */ |
| 1553 | 1677 | ||
| @@ -1579,6 +1703,8 @@ allocate_string () | |||
| 1579 | total_free_strings += STRING_BLOCK_SIZE; | 1703 | total_free_strings += STRING_BLOCK_SIZE; |
| 1580 | } | 1704 | } |
| 1581 | 1705 | ||
| 1706 | check_string_free_list(); | ||
| 1707 | |||
| 1582 | /* Pop a Lisp_String off the free-list. */ | 1708 | /* Pop a Lisp_String off the free-list. */ |
| 1583 | s = string_free_list; | 1709 | s = string_free_list; |
| 1584 | string_free_list = NEXT_FREE_LISP_STRING (s); | 1710 | string_free_list = NEXT_FREE_LISP_STRING (s); |
| @@ -1648,7 +1774,7 @@ allocate_string_data (s, nchars, nbytes) | |||
| 1648 | mallopt (M_MMAP_MAX, 0); | 1774 | mallopt (M_MMAP_MAX, 0); |
| 1649 | #endif | 1775 | #endif |
| 1650 | 1776 | ||
| 1651 | b = (struct sblock *) lisp_malloc (size, MEM_TYPE_NON_LISP); | 1777 | b = (struct sblock *) lisp_malloc (size + GC_STRING_EXTRA, MEM_TYPE_NON_LISP); |
| 1652 | 1778 | ||
| 1653 | #ifdef DOUG_LEA_MALLOC | 1779 | #ifdef DOUG_LEA_MALLOC |
| 1654 | /* Back to a reasonable maximum of mmap'ed areas. */ | 1780 | /* Back to a reasonable maximum of mmap'ed areas. */ |
| @@ -1663,7 +1789,7 @@ allocate_string_data (s, nchars, nbytes) | |||
| 1663 | else if (current_sblock == NULL | 1789 | else if (current_sblock == NULL |
| 1664 | || (((char *) current_sblock + SBLOCK_SIZE | 1790 | || (((char *) current_sblock + SBLOCK_SIZE |
| 1665 | - (char *) current_sblock->next_free) | 1791 | - (char *) current_sblock->next_free) |
| 1666 | < needed)) | 1792 | < (needed + GC_STRING_EXTRA))) |
| 1667 | { | 1793 | { |
| 1668 | /* Not enough room in the current sblock. */ | 1794 | /* Not enough room in the current sblock. */ |
| 1669 | b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP); | 1795 | b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP); |
| @@ -1692,7 +1818,10 @@ allocate_string_data (s, nchars, nbytes) | |||
| 1692 | s->size = nchars; | 1818 | s->size = nchars; |
| 1693 | s->size_byte = nbytes; | 1819 | s->size_byte = nbytes; |
| 1694 | s->data[nbytes] = '\0'; | 1820 | s->data[nbytes] = '\0'; |
| 1695 | b->next_free = (struct sdata *) ((char *) data + needed); | 1821 | #ifdef GC_CHECK_STRING_OVERRUN |
| 1822 | bcopy(string_overrun_pattern, (char *) data + needed, GC_STRING_EXTRA); | ||
| 1823 | #endif | ||
| 1824 | b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA); | ||
| 1696 | 1825 | ||
| 1697 | /* If S had already data assigned, mark that as free by setting its | 1826 | /* If S had already data assigned, mark that as free by setting its |
| 1698 | string back-pointer to null, and recording the size of the data | 1827 | string back-pointer to null, and recording the size of the data |
| @@ -1797,9 +1926,13 @@ sweep_strings () | |||
| 1797 | } | 1926 | } |
| 1798 | } | 1927 | } |
| 1799 | 1928 | ||
| 1929 | check_string_free_list(); | ||
| 1930 | |||
| 1800 | string_blocks = live_blocks; | 1931 | string_blocks = live_blocks; |
| 1801 | free_large_strings (); | 1932 | free_large_strings (); |
| 1802 | compact_small_strings (); | 1933 | compact_small_strings (); |
| 1934 | |||
| 1935 | check_string_free_list(); | ||
| 1803 | } | 1936 | } |
| 1804 | 1937 | ||
| 1805 | 1938 | ||
| @@ -1871,28 +2004,38 @@ compact_small_strings () | |||
| 1871 | else | 2004 | else |
| 1872 | nbytes = SDATA_NBYTES (from); | 2005 | nbytes = SDATA_NBYTES (from); |
| 1873 | 2006 | ||
| 2007 | #ifdef GC_CHECK_STRING_BYTES | ||
| 2008 | if (nbytes > LARGE_STRING_BYTES) | ||
| 2009 | abort (); | ||
| 2010 | #endif | ||
| 2011 | |||
| 1874 | nbytes = SDATA_SIZE (nbytes); | 2012 | nbytes = SDATA_SIZE (nbytes); |
| 1875 | from_end = (struct sdata *) ((char *) from + nbytes); | 2013 | from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA); |
| 2014 | |||
| 2015 | #ifdef GC_CHECK_STRING_OVERRUN | ||
| 2016 | if (bcmp(string_overrun_pattern, ((char *) from_end) - GC_STRING_EXTRA, GC_STRING_EXTRA)) | ||
| 2017 | abort (); | ||
| 2018 | #endif | ||
| 1876 | 2019 | ||
| 1877 | /* FROM->string non-null means it's alive. Copy its data. */ | 2020 | /* FROM->string non-null means it's alive. Copy its data. */ |
| 1878 | if (from->string) | 2021 | if (from->string) |
| 1879 | { | 2022 | { |
| 1880 | /* If TB is full, proceed with the next sblock. */ | 2023 | /* If TB is full, proceed with the next sblock. */ |
| 1881 | to_end = (struct sdata *) ((char *) to + nbytes); | 2024 | to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); |
| 1882 | if (to_end > tb_end) | 2025 | if (to_end > tb_end) |
| 1883 | { | 2026 | { |
| 1884 | tb->next_free = to; | 2027 | tb->next_free = to; |
| 1885 | tb = tb->next; | 2028 | tb = tb->next; |
| 1886 | tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE); | 2029 | tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE); |
| 1887 | to = &tb->first_data; | 2030 | to = &tb->first_data; |
| 1888 | to_end = (struct sdata *) ((char *) to + nbytes); | 2031 | to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); |
| 1889 | } | 2032 | } |
| 1890 | 2033 | ||
| 1891 | /* Copy, and update the string's `data' pointer. */ | 2034 | /* Copy, and update the string's `data' pointer. */ |
| 1892 | if (from != to) | 2035 | if (from != to) |
| 1893 | { | 2036 | { |
| 1894 | xassert (tb != b || to <= from); | 2037 | xassert (tb != b || to <= from); |
| 1895 | safe_bcopy ((char *) from, (char *) to, nbytes); | 2038 | safe_bcopy ((char *) from, (char *) to, nbytes + GC_STRING_EXTRA); |
| 1896 | to->string->data = SDATA_DATA (to); | 2039 | to->string->data = SDATA_DATA (to); |
| 1897 | } | 2040 | } |
| 1898 | 2041 | ||
| @@ -2402,9 +2545,9 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, | |||
| 2402 | void | 2545 | void |
| 2403 | check_cons_list () | 2546 | check_cons_list () |
| 2404 | { | 2547 | { |
| 2548 | #ifdef GC_CHECK_CONS_LIST | ||
| 2405 | struct Lisp_Cons *tail = cons_free_list; | 2549 | struct Lisp_Cons *tail = cons_free_list; |
| 2406 | 2550 | ||
| 2407 | #if 0 | ||
| 2408 | while (tail) | 2551 | while (tail) |
| 2409 | tail = *(struct Lisp_Cons **)&tail->cdr; | 2552 | tail = *(struct Lisp_Cons **)&tail->cdr; |
| 2410 | #endif | 2553 | #endif |