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)