aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-10-30 14:40:06 -0700
committerPaul Eggert2019-10-30 14:43:14 -0700
commitf2a72bb8ed29223dd1197492d4270c171db5e443 (patch)
tree60d90f60474f34750bf6c95b356c6128529cb1a4 /src
parent581601e650cc8bdcf3ed83c6ae36744601c12ce9 (diff)
downloademacs-f2a72bb8ed29223dd1197492d4270c171db5e443.tar.gz
emacs-f2a72bb8ed29223dd1197492d4270c171db5e443.zip
Fix print.c infloop on circular lists
Fix infinite loops in print.c when a circular list is passed to command-error-default-function or to error-message-string. * src/print.c (print_error_message): Use FOR_EACH_TAIL to avoid infloop on circular lists. (print_object): Use FOR_EACH_TAIL_SAFE, as it uses Brent’s teleporting tortoise-hare algorithm which is asymptotically better than the classic tortoise-hare algorithm that the code wsas using. * test/src/print-tests.el (print-circle-2): When print-circle is nil, do not insist on a particular cycle-detection heuristic. (error-message-string-circular): New test.
Diffstat (limited to 'src')
-rw-r--r--src/print.c62
1 files changed, 27 insertions, 35 deletions
diff --git a/src/print.c b/src/print.c
index 77ddd93efba..a2c199c14ad 100644
--- a/src/print.c
+++ b/src/print.c
@@ -966,13 +966,12 @@ print_error_message (Lisp_Object data, Lisp_Object stream, const char *context,
966 else 966 else
967 sep = NULL; 967 sep = NULL;
968 968
969 for (; CONSP (tail); tail = XCDR (tail), sep = ", ") 969 FOR_EACH_TAIL (tail)
970 { 970 {
971 Lisp_Object obj;
972
973 if (sep) 971 if (sep)
974 write_string (sep, stream); 972 write_string (sep, stream);
975 obj = XCAR (tail); 973 sep = ", ";
974 Lisp_Object obj = XCAR (tail);
976 if (!NILP (file_error) 975 if (!NILP (file_error)
977 || EQ (errname, Qend_of_file) || EQ (errname, Quser_error)) 976 || EQ (errname, Qend_of_file) || EQ (errname, Quser_error))
978 Fprinc (obj, stream); 977 Fprinc (obj, stream);
@@ -2087,46 +2086,33 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2087 { 2086 {
2088 printchar ('(', printcharfun); 2087 printchar ('(', printcharfun);
2089 2088
2090 Lisp_Object halftail = obj;
2091
2092 /* Negative values of print-length are invalid in CL. 2089 /* Negative values of print-length are invalid in CL.
2093 Treat them like nil, as CMUCL does. */ 2090 Treat them like nil, as CMUCL does. */
2094 intmax_t print_length = (FIXNATP (Vprint_length) 2091 intmax_t print_length = (FIXNATP (Vprint_length)
2095 ? XFIXNAT (Vprint_length) 2092 ? XFIXNAT (Vprint_length)
2096 : INTMAX_MAX); 2093 : INTMAX_MAX);
2097 2094 Lisp_Object objtail = Qnil;
2098 intmax_t i = 0; 2095 intmax_t i = 0;
2099 while (CONSP (obj)) 2096 FOR_EACH_TAIL_SAFE (obj)
2100 { 2097 {
2101 /* Detect circular list. */ 2098 if (i != 0)
2102 if (NILP (Vprint_circle))
2103 {
2104 /* Simple but incomplete way. */
2105 if (i != 0 && EQ (obj, halftail))
2106 {
2107 int len = sprintf (buf, " . #%"PRIdMAX, i >> 1);
2108 strout (buf, len, len, printcharfun);
2109 goto end_of_list;
2110 }
2111 }
2112 else
2113 { 2099 {
2114 /* With the print-circle feature. */ 2100 printchar (' ', printcharfun);
2115 if (i != 0) 2101
2102 if (!NILP (Vprint_circle))
2116 { 2103 {
2117 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil); 2104 /* With the print-circle feature. */
2105 Lisp_Object num = Fgethash (obj, Vprint_number_table,
2106 Qnil);
2118 if (FIXNUMP (num)) 2107 if (FIXNUMP (num))
2119 { 2108 {
2120 print_c_string (" . ", printcharfun); 2109 print_c_string (". ", printcharfun);
2121 print_object (obj, printcharfun, escapeflag); 2110 print_object (obj, printcharfun, escapeflag);
2122 goto end_of_list; 2111 goto end_of_list;
2123 } 2112 }
2124 } 2113 }
2125 } 2114 }
2126 2115
2127 if (i)
2128 printchar (' ', printcharfun);
2129
2130 if (print_length <= i) 2116 if (print_length <= i)
2131 { 2117 {
2132 print_c_string ("...", printcharfun); 2118 print_c_string ("...", printcharfun);
@@ -2135,17 +2121,23 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2135 2121
2136 i++; 2122 i++;
2137 print_object (XCAR (obj), printcharfun, escapeflag); 2123 print_object (XCAR (obj), printcharfun, escapeflag);
2124 objtail = XCDR (obj);
2125 }
2138 2126
2139 obj = XCDR (obj); 2127 /* OBJTAIL non-nil here means it's the end of a dotted list
2140 if (!(i & 1)) 2128 or FOR_EACH_TAIL_SAFE detected a circular list. */
2141 halftail = XCDR (halftail); 2129 if (!NILP (objtail))
2142 }
2143
2144 /* OBJ non-nil here means it's the end of a dotted list. */
2145 if (!NILP (obj))
2146 { 2130 {
2147 print_c_string (" . ", printcharfun); 2131 print_c_string (" . ", printcharfun);
2148 print_object (obj, printcharfun, escapeflag); 2132
2133 if (CONSP (objtail) && NILP (Vprint_circle))
2134 {
2135 int len = sprintf (buf, "#%"PRIdMAX, i >> 1);
2136 strout (buf, len, len, printcharfun);
2137 goto end_of_list;
2138 }
2139
2140 print_object (objtail, printcharfun, escapeflag);
2149 } 2141 }
2150 2142
2151 end_of_list: 2143 end_of_list: