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)