Mercurial > emacs
comparison src/alloc.c @ 58707:57741ce4cd6b
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.
| author | Kim F. Storm <storm@cua.dk> |
|---|---|
| date | Wed, 01 Dec 2004 14:10:23 +0000 |
| parents | 7c469d30a12d |
| children | f8cddae7d959 |
comparison
equal
deleted
inserted
replaced
| 58706:1d7bc0df04ed | 58707:57741ce4cd6b |
|---|---|
| 514 while (1) | 514 while (1) |
| 515 Fsignal (Qnil, Vmemory_signal_data); | 515 Fsignal (Qnil, Vmemory_signal_data); |
| 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, |
| 527 0xea, 0xeb, 0xec, 0xed }; | 538 0xea, 0xeb, 0xec, 0xed }; |
| 528 | 539 |
| 530 { 0xaa, 0xab, 0xac, 0xad, | 541 { 0xaa, 0xab, 0xac, 0xad, |
| 531 0xba, 0xbb, 0xbc, 0xbd, | 542 0xba, 0xbb, 0xbc, 0xbd, |
| 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 } |
| 579 | |
| 580 | |
| 581 /* Like realloc, but checks old block for overrun, and wraps new block | |
| 582 with header and trailer. */ | |
| 551 | 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; |
| 571 } | 603 bzero (val, XMALLOC_OVERRUN_CHECK_SIZE); |
| 572 | 604 } |
| 573 val = (char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2); | 605 |
| 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 } |
| 617 | |
| 618 /* Like free, but checks block for overrun. */ | |
| 584 | 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); |
| 606 } | 642 } |
| 607 | 643 |
| 610 #undef free | 646 #undef free |
| 611 #define malloc overrun_check_malloc | 647 #define malloc overrun_check_malloc |
| 612 #define realloc overrun_check_realloc | 648 #define realloc overrun_check_realloc |
| 613 #define free overrun_check_free | 649 #define free overrun_check_free |
| 614 #endif | 650 #endif |
| 651 | |
| 652 | |
| 653 /* Like malloc but check for no memory and block interrupt input.. */ | |
| 615 | 654 |
| 616 POINTER_TYPE * | 655 POINTER_TYPE * |
| 617 xmalloc (size) | 656 xmalloc (size) |
| 618 size_t size; | 657 size_t size; |
| 619 { | 658 { |
| 1525 | 1564 |
| 1526 #endif /* not GC_CHECK_STRING_BYTES */ | 1565 #endif /* not GC_CHECK_STRING_BYTES */ |
| 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 |
| 1537 bytes of string data. The value returned includes a terminating | 1583 bytes of string data. The value returned includes a terminating |
| 1538 NUL byte, the size of the sdata structure, and padding. */ | 1584 NUL byte, the size of the sdata structure, and padding. */ |
| 1554 + sizeof (EMACS_INT) - 1) \ | 1600 + sizeof (EMACS_INT) - 1) \ |
| 1555 & ~(sizeof (EMACS_INT) - 1)) | 1601 & ~(sizeof (EMACS_INT) - 1)) |
| 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 |
| 1562 init_strings () | 1612 init_strings () |
| 1563 { | 1613 { |
| 1653 | 1703 |
| 1654 #endif /* GC_CHECK_STRING_BYTES */ | 1704 #endif /* GC_CHECK_STRING_BYTES */ |
| 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 { |
| 1661 struct Lisp_String *s; | 1714 struct Lisp_String *s; |
| 1662 | 1715 |
| 1701 } | 1754 } |
| 1702 | 1755 |
| 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; |
| 1710 string_free_list = NEXT_FREE_LISP_STRING (s); | 1763 string_free_list = NEXT_FREE_LISP_STRING (s); |
| 1711 | 1764 |
| 1817 #endif | 1870 #endif |
| 1818 s->size = nchars; | 1871 s->size = nchars; |
| 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 |
| 1826 /* If S had already data assigned, mark that as free by setting its | 1880 /* If S had already data assigned, mark that as free by setting its |
| 1827 string back-pointer to null, and recording the size of the data | 1881 string back-pointer to null, and recording the size of the data |
| 1924 b->next = live_blocks; | 1978 b->next = live_blocks; |
| 1925 live_blocks = b; | 1979 live_blocks = b; |
| 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 |
| 1939 /* Free dead large strings. */ | 1993 /* Free dead large strings. */ |
| 1940 | 1994 |
| 2002 if (from->string) | 2056 if (from->string) |
| 2003 nbytes = GC_STRING_BYTES (from->string); | 2057 nbytes = GC_STRING_BYTES (from->string); |
| 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 |
| 2020 /* FROM->string non-null means it's alive. Copy its data. */ | 2074 /* FROM->string non-null means it's alive. Copy its data. */ |
| 2021 if (from->string) | 2075 if (from->string) |
