Mercurial > hg > xemacs-beta
comparison src/print.c @ 4847:05c519de7353
be more careful when printing to check for bad objects
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-13 Ben Wing <ben@xemacs.org>
* print.c:
* print.c (internal_object_printer):
* print.c (enum printing_badness):
* print.c (printing_major_badness):
* print.c (print_internal):
Clean up the part of the code that looks for things that might
lead to crashing in the print code:
-- Make the "badness" messages more consistent.
-- Move the checks for circularities after the checks for bad
memory, since the checks for circularities involve accessing
memory (which could be bad).
-- Add an extra check to see if the object's implementation structure
is bad memory.
-- Add extra check for object itself being a null pointer or
implementation pointer being null.
-- Add some extra comments to help in maintaining the code.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 13 Jan 2010 06:02:42 -0600 |
parents | a98ca4640147 |
children | ae81a2c00f4f |
comparison
equal
deleted
inserted
replaced
4846:a98ca4640147 | 4847:05c519de7353 |
---|---|
1 /* Lisp object printing and output streams. | 1 /* Lisp object printing and output streams. |
2 Copyright (C) 1985, 1986, 1988, 1992-1995 Free Software Foundation, Inc. | 2 Copyright (C) 1985, 1986, 1988, 1992-1995 Free Software Foundation, Inc. |
3 Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003, 2005 Ben Wing. | 3 Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003, 2005, 2010 Ben Wing. |
4 | 4 |
5 This file is part of XEmacs. | 5 This file is part of XEmacs. |
6 | 6 |
7 XEmacs is free software; you can redistribute it and/or modify it | 7 XEmacs is free software; you can redistribute it and/or modify it |
8 under the terms of the GNU General Public License as published by the | 8 under the terms of the GNU General Public License as published by the |
1555 | 1555 |
1556 void | 1556 void |
1557 internal_object_printer (Lisp_Object obj, Lisp_Object printcharfun, | 1557 internal_object_printer (Lisp_Object obj, Lisp_Object printcharfun, |
1558 int UNUSED (escapeflag)) | 1558 int UNUSED (escapeflag)) |
1559 { | 1559 { |
1560 /* Internal objects shouldn't normally escape to the Lisp level; | |
1561 that's why we say "XEmacs bug?". This can happen, however, when | |
1562 printing backtraces. */ | |
1560 write_fmt_string (printcharfun, | 1563 write_fmt_string (printcharfun, |
1561 "#<INTERNAL OBJECT (XEmacs bug?) (%s) 0x%lx>", | 1564 "#<INTERNAL OBJECT (XEmacs bug?) (%s) 0x%lx>", |
1562 XRECORD_LHEADER_IMPLEMENTATION (obj)->name, | 1565 XRECORD_LHEADER_IMPLEMENTATION (obj)->name, |
1563 (unsigned long) XPNTR (obj)); | 1566 (unsigned long) XPNTR (obj)); |
1564 } | 1567 } |
1565 | 1568 |
1566 enum printing_badness | 1569 enum printing_badness |
1567 { | 1570 { |
1568 BADNESS_INTEGER_OBJECT, | 1571 BADNESS_INTEGER_OBJECT, |
1569 BADNESS_POINTER_OBJECT, | 1572 BADNESS_POINTER_OBJECT, |
1573 BADNESS_POINTER_OBJECT_WITH_DATA, | |
1570 BADNESS_NO_TYPE | 1574 BADNESS_NO_TYPE |
1571 }; | 1575 }; |
1572 | 1576 |
1573 static void | 1577 static void |
1574 printing_major_badness (Lisp_Object printcharfun, | 1578 printing_major_badness (Lisp_Object printcharfun, |
1575 const Ascbyte *badness_string, int type, void *val, | 1579 const Ascbyte *badness_string, int type, void *val, |
1576 enum printing_badness badness) | 1580 void *val2, enum printing_badness badness) |
1577 { | 1581 { |
1578 Ibyte buf[666]; | 1582 Ibyte buf[666]; |
1579 | 1583 |
1580 switch (badness) | 1584 switch (badness) |
1581 { | 1585 { |
1582 case BADNESS_INTEGER_OBJECT: | 1586 case BADNESS_INTEGER_OBJECT: |
1583 qxesprintf (buf, "%s %d object %ld", badness_string, type, | 1587 qxesprintf (buf, "%s type %d object %ld", badness_string, type, |
1584 (EMACS_INT) val); | 1588 (EMACS_INT) val); |
1585 break; | 1589 break; |
1586 | 1590 |
1587 case BADNESS_POINTER_OBJECT: | 1591 case BADNESS_POINTER_OBJECT: |
1588 qxesprintf (buf, "%s %d object %p", badness_string, type, val); | 1592 qxesprintf (buf, "%s type %d object %p", badness_string, type, val); |
1593 break; | |
1594 | |
1595 case BADNESS_POINTER_OBJECT_WITH_DATA: | |
1596 qxesprintf (buf, "%s type %d object %p data %p", badness_string, type, | |
1597 val, val2); | |
1589 break; | 1598 break; |
1590 | 1599 |
1591 case BADNESS_NO_TYPE: | 1600 case BADNESS_NO_TYPE: |
1592 qxesprintf (buf, "%s object %p", badness_string, val); | 1601 qxesprintf (buf, "%s object %p", badness_string, val); |
1593 break; | 1602 break; |
1599 { | 1608 { |
1600 #ifdef ERROR_CHECK_TYPES | 1609 #ifdef ERROR_CHECK_TYPES |
1601 ABORT (); | 1610 ABORT (); |
1602 #else /* not ERROR_CHECK_TYPES */ | 1611 #else /* not ERROR_CHECK_TYPES */ |
1603 if (print_readably) | 1612 if (print_readably) |
1604 signal_ferror (Qinternal_error, "printing %s", buf); | 1613 signal_ferror (Qinternal_error, "SERIOUS XEMACS BUG: printing %s; " |
1614 "save your buffers immediately and please report " | |
1615 "this bug", buf); | |
1605 #endif /* not ERROR_CHECK_TYPES */ | 1616 #endif /* not ERROR_CHECK_TYPES */ |
1606 } | 1617 } |
1607 write_fmt_string (printcharfun, | 1618 write_fmt_string (printcharfun, |
1608 "#<EMACS BUG: %s Save your buffers immediately and " | 1619 "#<SERIOUS XEMACS BUG: %s Save your buffers immediately " |
1609 "please report this bug>", buf); | 1620 "and please report this bug>", buf); |
1610 } | 1621 } |
1611 | 1622 |
1612 void | 1623 void |
1613 print_internal (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | 1624 print_internal (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) |
1614 { | 1625 { |
1623 if (gc_in_progress) return; | 1634 if (gc_in_progress) return; |
1624 #endif | 1635 #endif |
1625 | 1636 |
1626 /* Just to be safe ... */ | 1637 /* Just to be safe ... */ |
1627 GCPRO2 (obj, printcharfun); | 1638 GCPRO2 (obj, printcharfun); |
1639 | |
1640 /* WARNING WARNING WARNING!!! Don't put anything here that might | |
1641 dereference memory. Instead, put it down inside of | |
1642 the case Lisp_Type_Record, after the appropriate checks to make sure | |
1643 we're not dereferencing bad memory. The idea is that, ideally, | |
1644 calling debug_print() should *NEVER* make the program crash, even when | |
1645 something very bad has happened. --ben */ | |
1628 | 1646 |
1629 #ifdef I18N3 | 1647 #ifdef I18N3 |
1630 /* #### Both input and output streams should have a flag associated | 1648 /* #### Both input and output streams should have a flag associated |
1631 with them indicating whether output to that stream, or strings | 1649 with them indicating whether output to that stream, or strings |
1632 read from the stream, get translated using Fgettext(). Such a | 1650 read from the stream, get translated using Fgettext(). Such a |
1636 it creates. This flag should also be user-settable. Perhaps it | 1654 it creates. This flag should also be user-settable. Perhaps it |
1637 should be split up into two flags, one for input and one for | 1655 should be split up into two flags, one for input and one for |
1638 output. */ | 1656 output. */ |
1639 #endif | 1657 #endif |
1640 | 1658 |
1641 /* Detect circularities and truncate them. | |
1642 No need to offer any alternative--this is better than an error. */ | |
1643 if (CONSP (obj) || VECTORP (obj) || COMPILED_FUNCTIONP (obj)) | |
1644 { | |
1645 int i; | |
1646 for (i = 0; i < print_depth; i++) | |
1647 if (EQ (obj, being_printed[i])) | |
1648 { | |
1649 char buf[DECIMAL_PRINT_SIZE (long) + 1]; | |
1650 *buf = '#'; | |
1651 long_to_string (buf + 1, i); | |
1652 write_c_string (printcharfun, buf); | |
1653 UNGCPRO; | |
1654 return; | |
1655 } | |
1656 } | |
1657 | |
1658 being_printed[print_depth] = obj; | 1659 being_printed[print_depth] = obj; |
1659 | 1660 |
1660 /* Avoid calling internal_bind_int, which conses, when called from | 1661 /* Avoid calling internal_bind_int, which conses, when called from |
1661 debug_prin1. In that case, we have bound print_depth to 0 anyway. */ | 1662 debug_prin1. In that case, we have bound print_depth to 0 anyway. */ |
1662 if (!inhibit_non_essential_conversion_operations) | 1663 if (!inhibit_non_essential_conversion_operations) |
1663 { | 1664 { |
1664 specdepth = internal_bind_int (&print_depth, print_depth + 1); | 1665 specdepth = internal_bind_int (&print_depth, print_depth + 1); |
1665 | 1666 |
1666 if (print_depth > PRINT_CIRCLE) | 1667 if (print_depth > PRINT_CIRCLE) |
1667 signal_error (Qstack_overflow, "Apparently circular structure being printed", Qunbound); | 1668 signal_error (Qstack_overflow, |
1669 "Apparently circular structure being printed", Qunbound); | |
1668 } | 1670 } |
1669 | 1671 |
1670 switch (XTYPE (obj)) | 1672 switch (XTYPE (obj)) |
1671 { | 1673 { |
1672 case Lisp_Type_Int_Even: | 1674 case Lisp_Type_Int_Even: |
1745 | 1747 |
1746 case Lisp_Type_Record: | 1748 case Lisp_Type_Record: |
1747 { | 1749 { |
1748 struct lrecord_header *lheader = XRECORD_LHEADER (obj); | 1750 struct lrecord_header *lheader = XRECORD_LHEADER (obj); |
1749 | 1751 |
1750 /* Try to check for various sorts of bogus pointers if we're in a | 1752 /* Try to check for various sorts of bogus pointers or bad memory |
1751 situation where it may be likely -- i.e. called from | 1753 if we're in a situation where it may be likely -- i.e. called |
1752 debug_print() or we're already crashing. In such cases, | 1754 from debug_print() or we're already crashing. In such cases, |
1753 (further) crashing is counterproductive. */ | 1755 (further) crashing is counterproductive. |
1754 | 1756 |
1757 We don't normally do these because they may be expensive or | |
1758 weird (e.g. under Unix we typically have to set a SIGSEGV | |
1759 handler and try to trigger a seg fault). */ | |
1760 | |
1761 if (!lheader) | |
1762 { | |
1763 /* i.e. EQ Qnull_pointer */ | |
1764 printing_major_badness (printcharfun, "NULL POINTER LRECORD", 0, | |
1765 0, 0, BADNESS_NO_TYPE); | |
1766 break; | |
1767 } | |
1768 | |
1769 /* First check to see if the lrecord header itself is garbage. */ | |
1755 if (inhibit_non_essential_conversion_operations && | 1770 if (inhibit_non_essential_conversion_operations && |
1756 !debug_can_access_memory (lheader, sizeof (*lheader))) | 1771 !debug_can_access_memory (lheader, sizeof (*lheader))) |
1757 { | 1772 { |
1758 write_fmt_string (printcharfun, "#<EMACS BUG: BAD MEMORY %p>", | 1773 printing_major_badness (printcharfun, |
1759 lheader); | 1774 "BAD MEMORY in LRECORD HEADER", 0, |
1775 lheader, 0, BADNESS_NO_TYPE); | |
1760 break; | 1776 break; |
1761 } | |
1762 | |
1763 if (CONSP (obj) || VECTORP (obj)) | |
1764 { | |
1765 /* If deeper than spec'd depth, print placeholder. */ | |
1766 if (INTP (Vprint_level) | |
1767 && print_depth > XINT (Vprint_level)) | |
1768 { | |
1769 write_c_string (printcharfun, "..."); | |
1770 break; | |
1771 } | |
1772 } | 1777 } |
1773 | 1778 |
1779 /* Check to see if the lrecord type is garbage. */ | |
1774 #ifndef NEW_GC | 1780 #ifndef NEW_GC |
1775 if (lheader->type == lrecord_type_free) | 1781 if (lheader->type == lrecord_type_free) |
1776 { | 1782 { |
1777 printing_major_badness (printcharfun, "freed lrecord", 0, | 1783 printing_major_badness (printcharfun, "FREED LRECORD", 0, |
1778 lheader, BADNESS_NO_TYPE); | 1784 lheader, 0, BADNESS_NO_TYPE); |
1779 break; | 1785 break; |
1780 } | 1786 } |
1781 else if (lheader->type == lrecord_type_undefined) | 1787 if (lheader->type == lrecord_type_undefined) |
1782 { | 1788 { |
1783 printing_major_badness (printcharfun, "lrecord_type_undefined", 0, | 1789 printing_major_badness (printcharfun, "LRECORD_TYPE_UNDEFINED", 0, |
1784 lheader, BADNESS_NO_TYPE); | 1790 lheader, 0, BADNESS_NO_TYPE); |
1785 break; | 1791 break; |
1786 } | 1792 } |
1787 #endif /* not NEW_GC */ | 1793 #endif /* not NEW_GC */ |
1788 else if ((int) (lheader->type) >= lrecord_type_count) | 1794 if ((int) (lheader->type) >= lrecord_type_count) |
1789 { | 1795 { |
1790 printing_major_badness (printcharfun, "illegal lrecord type", | 1796 printing_major_badness (printcharfun, "ILLEGAL LRECORD TYPE", |
1791 (int) (lheader->type), | 1797 (int) (lheader->type), |
1792 lheader, BADNESS_POINTER_OBJECT); | 1798 lheader, 0, BADNESS_POINTER_OBJECT); |
1793 break; | 1799 break; |
1794 } | 1800 } |
1795 | 1801 |
1796 /* Further checks for bad memory in critical situations. We don't | 1802 /* Check to see if the lrecord implementation is missing or garbage. */ |
1797 normally do these because they may be expensive or weird | 1803 { |
1798 (e.g. under Unix we typically have to set a SIGSEGV handler and | 1804 const struct lrecord_implementation *imp = |
1799 try to trigger a seg fault). */ | 1805 LHEADER_IMPLEMENTATION (lheader); |
1806 | |
1807 if (!imp) | |
1808 { | |
1809 printing_major_badness | |
1810 (printcharfun, "NO IMPLEMENTATION FOR LRECORD TYPE", | |
1811 (int) (lheader->type), | |
1812 lheader, 0, BADNESS_POINTER_OBJECT); | |
1813 break; | |
1814 } | |
1815 | |
1816 if (inhibit_non_essential_conversion_operations) | |
1817 { | |
1818 if (!debug_can_access_memory (imp, sizeof (*imp))) | |
1819 { | |
1820 printing_major_badness | |
1821 (printcharfun, "BAD MEMORY IN LRECORD IMPLEMENTATION", | |
1822 (int) (lheader->type), | |
1823 lheader, 0, BADNESS_POINTER_OBJECT); | |
1824 } | |
1825 } | |
1826 } | |
1827 | |
1828 /* Check to see if any of the memory of the lrecord is inaccessible. | |
1829 Note that we already checked above to see if the first part of | |
1830 the lrecord (the header) is inaccessible, which will catch most | |
1831 cases of a totally bad pointer. */ | |
1800 | 1832 |
1801 if (inhibit_non_essential_conversion_operations) | 1833 if (inhibit_non_essential_conversion_operations) |
1802 { | 1834 { |
1803 if (!debug_can_access_memory | 1835 if (!debug_can_access_memory |
1804 (lheader, detagged_lisp_object_size (lheader))) | 1836 (lheader, detagged_lisp_object_size (lheader))) |
1805 { | 1837 { |
1806 write_fmt_string (printcharfun, | 1838 printing_major_badness (printcharfun, |
1807 "#<EMACS BUG: type %s BAD MEMORY %p>", | 1839 "BAD MEMORY IN LRECORD", |
1808 LHEADER_IMPLEMENTATION (lheader)->name, | 1840 (int) (lheader->type), |
1809 lheader); | 1841 lheader, 0, BADNESS_POINTER_OBJECT); |
1810 break; | 1842 break; |
1811 } | 1843 } |
1812 | 1844 |
1845 /* For strings, also check the data of the string itself. */ | |
1813 if (STRINGP (obj)) | 1846 if (STRINGP (obj)) |
1814 { | 1847 { |
1815 #ifdef NEW_GC | 1848 #ifdef NEW_GC |
1816 if (!debug_can_access_memory (XSTRING_DATA (obj), | 1849 if (!debug_can_access_memory (XSTRING_DATA (obj), |
1817 XSTRING_LENGTH (obj))) | 1850 XSTRING_LENGTH (obj))) |
1824 } | 1857 } |
1825 #else /* not NEW_GC */ | 1858 #else /* not NEW_GC */ |
1826 Lisp_String *l = (Lisp_String *) lheader; | 1859 Lisp_String *l = (Lisp_String *) lheader; |
1827 if (!debug_can_access_memory (l->data_, l->size_)) | 1860 if (!debug_can_access_memory (l->data_, l->size_)) |
1828 { | 1861 { |
1829 write_fmt_string | 1862 printing_major_badness (printcharfun, |
1830 (printcharfun, | 1863 "BAD STRING DATA", (int) (lheader->type), |
1831 "#<EMACS BUG: %p (BAD STRING DATA %p)>", | 1864 lheader, l->data_, |
1832 lheader, l->data_); | 1865 BADNESS_POINTER_OBJECT_WITH_DATA); |
1833 break; | 1866 break; |
1834 } | 1867 } |
1835 #endif /* not NEW_GC */ | 1868 #endif /* not NEW_GC */ |
1869 } | |
1870 } | |
1871 | |
1872 /* Detect circularities and truncate them. | |
1873 No need to offer any alternative--this is better than an error. */ | |
1874 if (CONSP (obj) || VECTORP (obj) || COMPILED_FUNCTIONP (obj)) | |
1875 { | |
1876 int i; | |
1877 for (i = 0; i < print_depth - 1; i++) | |
1878 if (EQ (obj, being_printed[i])) | |
1879 { | |
1880 Ascbyte buf[DECIMAL_PRINT_SIZE (long) + 1]; | |
1881 *buf = '#'; | |
1882 long_to_string (buf + 1, i); | |
1883 write_c_string (printcharfun, buf); | |
1884 break; | |
1885 } | |
1886 if (i < print_depth - 1) /* Did we print something? */ | |
1887 break; | |
1888 } | |
1889 | |
1890 if (CONSP (obj) || VECTORP (obj)) | |
1891 { | |
1892 /* If deeper than spec'd depth, print placeholder. */ | |
1893 if (INTP (Vprint_level) | |
1894 && print_depth > XINT (Vprint_level)) | |
1895 { | |
1896 write_c_string (printcharfun, "..."); | |
1897 break; | |
1836 } | 1898 } |
1837 } | 1899 } |
1838 | 1900 |
1839 if (LHEADER_IMPLEMENTATION (lheader)->printer) | 1901 if (LHEADER_IMPLEMENTATION (lheader)->printer) |
1840 ((LHEADER_IMPLEMENTATION (lheader)->printer) | 1902 ((LHEADER_IMPLEMENTATION (lheader)->printer) |
1845 } | 1907 } |
1846 | 1908 |
1847 default: | 1909 default: |
1848 { | 1910 { |
1849 /* We're in trouble if this happens! */ | 1911 /* We're in trouble if this happens! */ |
1850 printing_major_badness (printcharfun, "illegal data type", XTYPE (obj), | 1912 printing_major_badness (printcharfun, "ILLEGAL LISP OBJECT TAG TYPE", |
1851 LISP_TO_VOID (obj), BADNESS_INTEGER_OBJECT); | 1913 XTYPE (obj), LISP_TO_VOID (obj), 0, |
1914 BADNESS_INTEGER_OBJECT); | |
1852 break; | 1915 break; |
1853 } | 1916 } |
1854 } | 1917 } |
1855 | 1918 |
1856 if (!inhibit_non_essential_conversion_operations) | 1919 if (!inhibit_non_essential_conversion_operations) |