Subject: Re: bug#38912: 27.0.60; PDumper meets segmentation fault when evil is loaded

From: Stefan Monnier <[email-masked]>
Date: Mon, 06 Jan 2020 13:13:31 -0500

The problem is simply that `sxhash` doesn't use the same "rules" about
which objects are compared by identity and which objects are compared
by contents.

In `src/fns.c`, when we compare `internal_equal` and `sxhash`, we see
that `sxhash` only looks at the contents of vectorlikes if they are:

      BIGNUMP, VECTORP, RECORDP, or BOOL_VECTOR_P

whereas `internal_equal` looks inside many more vectorlikes:

	if (BIGNUMP (o1))
	  return mpz_cmp (*xbignum_val (o1), *xbignum_val (o2)) == 0;
	if (OVERLAYP (o1))
	  {
	    if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2),
				 equal_kind, depth + 1, ht)
		|| !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2),
				    equal_kind, depth + 1, ht))
	      return false;
	    o1 = XOVERLAY (o1)->plist;
	    o2 = XOVERLAY (o2)->plist;
	    depth++;
	    goto tail_recurse;
	  }
	if (MARKERP (o1))
	  {
	    return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
		    && (XMARKER (o1)->buffer == 0
			|| XMARKER (o1)->bytepos == XMARKER (o2)->bytepos));
	  }
	/* Boolvectors are compared much like strings.  */
	if (BOOL_VECTOR_P (o1))
	  {
	    EMACS_INT size = bool_vector_size (o1);
	    if (size != bool_vector_size (o2))
	      return false;
	    if (memcmp (bool_vector_data (o1), bool_vector_data (o2),
			bool_vector_bytes (size)))
	      return false;
	    return true;
	  }
	if (WINDOW_CONFIGURATIONP (o1))
	  {
	    eassert (equal_kind != EQUAL_NO_QUIT);
	    return compare_window_configurations (o1, o2, false);
	  }

	/* Aside from them, only true vectors, char-tables, compiled
	   functions, and fonts (font-spec, font-entity, font-object)
	   are sensible to compare, so eliminate the others now.  */
	if (size & PSEUDOVECTOR_FLAG)
	  {
	    if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS)
		< PVEC_COMPILED)
	      return false;
	    size &= PSEUDOVECTOR_SIZE_MASK;
	  }
	for (ptrdiff_t i = 0; i < size; i++)
	  {
	    Lisp_Object v1, v2;
	    v1 = AREF (o1, i);
	    v2 = AREF (o2, i);
	    if (!internal_equal (v1, v2, equal_kind, depth + 1, ht))
	      return false;
	  }
	return true;
      }
      break;

so the problem doesn't affect only byte-compiled objects but also
overlays, markers, windowconfigs, chartables, and fonts, AFAICT.

The fix should be to make `sxhash` follow the same rules as `internal_equal`.

This is a fairly long-standing problem, so unless it is newly triggered
in "normal" circumstances in Emacs-27, the fix is probably best on
`master`.

        Stefan