]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix C-h C-h bug due to mutating a hash key
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Feb 2020 23:12:34 +0000 (15:12 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Feb 2020 23:18:28 +0000 (15:18 -0800)
Problem reported by Federico Tedin (Bug#39529).
The problem was that dumping uses a hash table based on 'equal'
when purecopying compiled objects, but then modifies the compiled
objects while they are keys in the table.  This no-no was uncovered
by the sxhash fixes in 2020-01-07T19:23:11Z!eggert@cs.ucla.edu.
Eli Zaretski pinpointed the patch that triggered the bug.
* src/lread.c (read1): When reading a compiled object, replace
its docstring with a unique negative integer instead of with 0,
so that purecopy doesn’t unify it with some other compiled object
that happens to have the same Lisp code.

src/lread.c

index c124d5a1d8f272cf47a91a4a1a79cc030a6691b7..f39e81ae2cf77b30dabf8eb69e3c0bfbf107f949 100644 (file)
@@ -2974,6 +2974,21 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
          vec = XVECTOR (tmp);
          if (vec->header.size == 0)
            invalid_syntax ("Empty byte-code object");
+
+         if (COMPILED_DOC_STRING < vec->header.size
+             && AREF (tmp, COMPILED_DOC_STRING) == make_fixnum (0))
+           {
+             /* read_list found a docstring like '(#$ . 5521)' and treated it
+                as 0.  This placeholder 0 would lead to accidental sharing in
+                purecopy's hash-consing, so replace it with a (hopefully)
+                unique integer placeholder, which is negative so that it is
+                not confused with a DOC file offset.  Eventually
+                Snarf-documentation should replace the placeholder with the
+                actual docstring.  */
+             EMACS_UINT hash = XHASH (tmp) | (INTMASK - INTMASK / 2);
+             ASET (tmp, COMPILED_DOC_STRING, make_ufixnum (hash));
+           }
+
          make_byte_code (vec);
          return tmp;
        }