Skip to content

Commit 724af76

Browse files
committed
Fix sxhash-equal on bytecodes, markers, etc.
Problem reported by Pip Cet (Bug#38912#14). * doc/lispref/objects.texi (Equality Predicates): Document better when ‘equal’ looks inside objects. * doc/lispref/windows.texi (Window Configurations): Don’t say that ‘equal’ looks inside window configurations. * etc/NEWS: Mention the change. * src/fns.c (internal_equal): Do not look inside window configurations. (sxhash_obj): Hash markers, byte-code function objects, char-tables, and font objects consistently with Fequal. * src/window.c (compare_window_configurations): Now static. Remove last argument. Caller changed. * test/lisp/ffap-tests.el (ffap-other-window--bug-25352): Use compare-window-configurations, not ‘equal’. * test/src/fns-tests.el (test-sxhash-equal): New test.
1 parent f950b07 commit 724af76

File tree

9 files changed

+67
-47
lines changed

9 files changed

+67
-47
lines changed

doc/lispref/objects.texi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,8 +2336,12 @@ same sequence of character codes and all these codes are in the range
23362336
@end group
23372337
@end example
23382338

2339-
However, two distinct buffers are never considered @code{equal}, even if
2340-
their textual contents are the same.
2339+
The @code{equal} function recursively compares the contents of objects
2340+
if they are integers, strings, markers, vectors, bool-vectors,
2341+
byte-code function objects, char-tables, records, or font objects.
2342+
Other objects are considered @code{equal} only if they are @code{eq}.
2343+
For example, two distinct buffers are never considered @code{equal},
2344+
even if their textual contents are the same.
23412345
@end defun
23422346

23432347
For @code{equal}, equality is defined recursively; for example, given

doc/lispref/windows.texi

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5915,10 +5915,6 @@ This function compares two window configurations as regards the
59155915
structure of windows, but ignores the values of point and the
59165916
saved scrolling positions---it can return @code{t} even if those
59175917
aspects differ.
5918-
5919-
The function @code{equal} can also compare two window configurations; it
5920-
regards configurations as unequal if they differ in any respect, even a
5921-
saved point.
59225918
@end defun
59235919

59245920
@defun window-configuration-frame config

etc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ applies, and please also update docstrings as needed.
4242

4343
* Incompatible Lisp Changes in Emacs 28.1
4444

45+
** 'equal' no longer examines some contents of window configurations.
46+
Instead, it considers window configurations to be equal only if they
47+
are eq. To compare contents, use compare-window-configurations
48+
instead. This change helps fix a bug in sxhash-equal, which returned
49+
incorrect hashes for window configurations and some other objects.
50+
4551

4652
* Lisp Changes in Emacs 28.1
4753

src/fns.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,6 +2434,9 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
24342434
same size. */
24352435
if (ASIZE (o2) != size)
24362436
return false;
2437+
2438+
/* Compare bignums, overlays, markers, and boolvectors
2439+
specially, by comparing their values. */
24372440
if (BIGNUMP (o1))
24382441
return mpz_cmp (*xbignum_val (o1), *xbignum_val (o2)) == 0;
24392442
if (OVERLAYP (o1))
@@ -2454,7 +2457,6 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
24542457
&& (XMARKER (o1)->buffer == 0
24552458
|| XMARKER (o1)->bytepos == XMARKER (o2)->bytepos));
24562459
}
2457-
/* Boolvectors are compared much like strings. */
24582460
if (BOOL_VECTOR_P (o1))
24592461
{
24602462
EMACS_INT size = bool_vector_size (o1);
@@ -2465,11 +2467,6 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
24652467
return false;
24662468
return true;
24672469
}
2468-
if (WINDOW_CONFIGURATIONP (o1))
2469-
{
2470-
eassert (equal_kind != EQUAL_NO_QUIT);
2471-
return compare_window_configurations (o1, o2, false);
2472-
}
24732470

24742471
/* Aside from them, only true vectors, char-tables, compiled
24752472
functions, and fonts (font-spec, font-entity, font-object)
@@ -4703,22 +4700,35 @@ sxhash_obj (Lisp_Object obj, int depth)
47034700
hash = sxhash_string (SSDATA (obj), SBYTES (obj));
47044701
break;
47054702

4706-
/* This can be everything from a vector to an overlay. */
47074703
case Lisp_Vectorlike:
4708-
if (BIGNUMP (obj))
4709-
hash = sxhash_bignum (obj);
4710-
else if (VECTORP (obj) || RECORDP (obj))
4711-
/* According to the CL HyperSpec, two arrays are equal only if
4712-
they are `eq', except for strings and bit-vectors. In
4713-
Emacs, this works differently. We have to compare element
4714-
by element. Same for records. */
4715-
hash = sxhash_vector (obj, depth);
4716-
else if (BOOL_VECTOR_P (obj))
4717-
hash = sxhash_bool_vector (obj);
4718-
else
4719-
/* Others are `equal' if they are `eq', so let's take their
4720-
address as hash. */
4721-
hash = XHASH (obj);
4704+
{
4705+
enum pvec_type pvec_type = PSEUDOVECTOR_TYPE (XVECTOR (obj));
4706+
if (! (PVEC_NORMAL_VECTOR < pvec_type && pvec_type < PVEC_COMPILED))
4707+
{
4708+
/* According to the CL HyperSpec, two arrays are equal only if
4709+
they are 'eq', except for strings and bit-vectors. In
4710+
Emacs, this works differently. We have to compare element
4711+
by element. Same for pseudovectors that internal_equal
4712+
examines the Lisp contents of. */
4713+
hash = sxhash_vector (obj, depth);
4714+
break;
4715+
}
4716+
else if (pvec_type == PVEC_BIGNUM)
4717+
hash = sxhash_bignum (obj);
4718+
else if (pvec_type == PVEC_MARKER)
4719+
{
4720+
ptrdiff_t bytepos
4721+
= XMARKER (obj)->buffer ? XMARKER (obj)->bytepos : 0;
4722+
hash = sxhash_combine ((intptr_t) XMARKER (obj)->buffer, bytepos);
4723+
hash = SXHASH_REDUCE (hash);
4724+
}
4725+
else if (pvec_type == PVEC_BOOL_VECTOR)
4726+
hash = sxhash_bool_vector (obj);
4727+
else
4728+
/* Others are 'equal' if they are 'eq', so take their
4729+
address as hash. */
4730+
hash = XHASH (obj);
4731+
}
47224732
break;
47234733

47244734
case Lisp_Cons:

src/lisp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ DEFINE_GDB_SYMBOL_END (PSEUDOVECTOR_FLAG)
10691069
with PVEC_TYPE_MASK to indicate the actual type. */
10701070
enum pvec_type
10711071
{
1072-
PVEC_NORMAL_VECTOR,
1072+
PVEC_NORMAL_VECTOR, /* Should be first, for sxhash_obj. */
10731073
PVEC_FREE,
10741074
PVEC_BIGNUM,
10751075
PVEC_MARKER,
@@ -1094,7 +1094,7 @@ enum pvec_type
10941094
PVEC_CONDVAR,
10951095
PVEC_MODULE_FUNCTION,
10961096

1097-
/* These should be last, check internal_equal to see why. */
1097+
/* These should be last, for internal_equal and sxhash_obj. */
10981098
PVEC_COMPILED,
10991099
PVEC_CHAR_TABLE,
11001100
PVEC_SUB_CHAR_TABLE,

src/window.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7976,19 +7976,17 @@ foreach_window_1 (struct window *w, bool (*fn) (struct window *, void *),
79767976
/* Return true if window configurations CONFIGURATION1 and CONFIGURATION2
79777977
describe the same state of affairs. This is used by Fequal.
79787978
7979-
IGNORE_POSITIONS means ignore non-matching scroll positions
7980-
and the like.
7979+
Ignore non-matching scroll positions and the like.
79817980
79827981
This ignores a couple of things like the dedication status of
79837982
window, combination_limit and the like. This might have to be
79847983
fixed. */
79857984

7986-
bool
7985+
static bool
79877986
compare_window_configurations (Lisp_Object configuration1,
7988-
Lisp_Object configuration2,
7989-
bool ignore_positions)
7987+
Lisp_Object configuration2)
79907988
{
7991-
register struct save_window_data *d1, *d2;
7989+
struct save_window_data *d1, *d2;
79927990
struct Lisp_Vector *sws1, *sws2;
79937991
ptrdiff_t i;
79947992

@@ -8006,9 +8004,6 @@ compare_window_configurations (Lisp_Object configuration1,
80068004
|| d1->frame_menu_bar_lines != d2->frame_menu_bar_lines
80078005
|| !EQ (d1->selected_frame, d2->selected_frame)
80088006
|| !EQ (d1->f_current_buffer, d2->f_current_buffer)
8009-
|| (!ignore_positions
8010-
&& (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window)
8011-
|| !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window)))
80128007
|| !EQ (d1->focus_frame, d2->focus_frame)
80138008
/* Verify that the two configurations have the same number of windows. */
80148009
|| sws1->header.size != sws2->header.size)
@@ -8041,12 +8036,6 @@ compare_window_configurations (Lisp_Object configuration1,
80418036
equality. */
80428037
|| !EQ (sw1->parent, sw2->parent)
80438038
|| !EQ (sw1->prev, sw2->prev)
8044-
|| (!ignore_positions
8045-
&& (!EQ (sw1->hscroll, sw2->hscroll)
8046-
|| !EQ (sw1->min_hscroll, sw2->min_hscroll)
8047-
|| !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg)
8048-
|| NILP (Fequal (sw1->start, sw2->start))
8049-
|| NILP (Fequal (sw1->pointm, sw2->pointm))))
80508039
|| !EQ (sw1->left_margin_cols, sw2->left_margin_cols)
80518040
|| !EQ (sw1->right_margin_cols, sw2->right_margin_cols)
80528041
|| !EQ (sw1->left_fringe_width, sw2->left_fringe_width)
@@ -8071,7 +8060,7 @@ This function ignores details such as the values of point
80718060
and scrolling positions. */)
80728061
(Lisp_Object x, Lisp_Object y)
80738062
{
8074-
if (compare_window_configurations (x, y, true))
8063+
if (compare_window_configurations (x, y))
80758064
return Qt;
80768065
return Qnil;
80778066
}

src/window.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,6 @@ extern Lisp_Object window_list (void);
11841184
extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter);
11851185
extern struct window *decode_live_window (Lisp_Object);
11861186
extern struct window *decode_any_window (Lisp_Object);
1187-
extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool);
11881187
extern void mark_window_cursors_off (struct window *);
11891188
extern bool window_wants_mode_line (struct window *);
11901189
extern bool window_wants_header_line (struct window *);

test/lisp/ffap-tests.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ left alone when opening a URL in an external browser."
7474
(urls nil)
7575
(ffap-url-fetcher (lambda (url) (push url urls) nil)))
7676
(should-not (ffap-other-window "https://www.gnu.org"))
77-
(should (equal (current-window-configuration) old))
77+
(should (compare-window-configurations (current-window-configuration) old))
7878
(should (equal urls '("https://www.gnu.org")))))
7979

8080
(provide 'ffap-tests)

test/src/fns-tests.el

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,22 @@
858858
(puthash k k h)))
859859
(should (= 100 (hash-table-count h)))))
860860

861+
(ert-deftest test-sxhash-equal ()
862+
(should (= (sxhash-equal (* most-positive-fixnum most-negative-fixnum))
863+
(sxhash-equal (* most-positive-fixnum most-negative-fixnum))))
864+
(should (= (sxhash-equal (make-string 1000 ?a))
865+
(sxhash-equal (make-string 1000 ?a))))
866+
(should (= (sxhash-equal (point-marker))
867+
(sxhash-equal (point-marker))))
868+
(should (= (sxhash-equal (make-vector 1000 (make-string 10 ?a)))
869+
(sxhash-equal (make-vector 1000 (make-string 10 ?a)))))
870+
(should (= (sxhash-equal (make-bool-vector 1000 t))
871+
(sxhash-equal (make-bool-vector 1000 t))))
872+
(should (= (sxhash-equal (make-char-table nil (make-string 10 ?a)))
873+
(sxhash-equal (make-char-table nil (make-string 10 ?a)))))
874+
(should (= (sxhash-equal (record 'a (make-string 10 ?a)))
875+
(sxhash-equal (record 'a (make-string 10 ?a))))))
876+
861877
(ert-deftest test-secure-hash ()
862878
(should (equal (secure-hash 'md5 "foobar")
863879
"3858f62230ac3c915f300c664312c63f"))

0 commit comments

Comments
 (0)