From 015137db608f0678112ae9a69a1a52889d56161d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 18 Nov 2011 14:21:42 +0200 Subject: [PATCH] Fix another crash due to incorrect hash value of glyph rows, bug #10035. src/dispnew.c (swap_glyph_pointers): Swap the used[] arrays and the hash values of the two rows. (copy_row_except_pointers): Preserve the used[] arrays and the hash values of the two rows. src/xdisp.c (row_hash): New function, body extracted from compute_line_metrics. (compute_line_metrics): Call row_hash, instead of computing the hash code inline. src/dispnew.c (verify_row_hash): Call row_hash for computing the hash code of a row, instead of duplicating code from xdisp.c. src/dispextern.h (row_hash): Add prototype. --- src/ChangeLog | 17 +++++++++++++++++ src/dispextern.h | 3 +++ src/dispnew.c | 35 +++++++++++++++++++++-------------- src/xdisp.c | 29 ++++++++++++++++++----------- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 81f7fbbdc29..b394c37354f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2011-11-18 Eli Zaretskii + + * dispnew.c (swap_glyph_pointers): Swap the used[] arrays and the + hash values of the two rows. + (copy_row_except_pointers): Preserve the used[] arrays and the + hash values of the two rows. (Bug#10035) + + * xdisp.c (row_hash): New function, body extracted from + compute_line_metrics. + (compute_line_metrics): Call row_hash, instead of computing the + hash code inline. + + * dispnew.c (verify_row_hash): Call row_hash for computing the + hash code of a row, instead of duplicating code from xdisp.c. + + * dispextern.h (row_hash): Add prototype. + 2011-11-18 Tassilo Horn * frame.c (delete_frame): Don't delete the terminal when the last diff --git a/src/dispextern.h b/src/dispextern.h index 5c60a5499da..486aa4f7a40 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3126,6 +3126,9 @@ void compute_fringe_widths (struct frame *, int); void w32_init_fringe (struct redisplay_interface *); void w32_reset_fringes (void); #endif + +extern unsigned row_hash (struct glyph_row *); + /* Defined in image.c */ #ifdef HAVE_WINDOW_SYSTEM diff --git a/src/dispnew.c b/src/dispnew.c index 6ba834ba339..07843d3e214 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -434,18 +434,7 @@ margin_glyphs_to_reserve (struct window *w, int total_glyphs, Lisp_Object margin int verify_row_hash (struct glyph_row *row) { - int area, k; - unsigned row_hash = 0; - - for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area) - for (k = 0; k < row->used[area]; ++k) - row_hash = ((((row_hash << 4) + (row_hash >> 24)) & 0x0fffffff) - + row->glyphs[area][k].u.val - + row->glyphs[area][k].face_id - + row->glyphs[area][k].padding_p - + (row->glyphs[area][k].type << 2)); - - return row_hash == row->hash; + return row->hash == row_hash (row); } #endif @@ -1083,37 +1072,55 @@ swap_glyphs_in_rows (struct glyph_row *a, struct glyph_row *b) #endif /* 0 */ -/* Exchange pointers to glyph memory between glyph rows A and B. */ +/* Exchange pointers to glyph memory between glyph rows A and B. Also + exchange the used[] array and the hash values of the rows, because + these should all go together for the row's hash value to be + correct. */ static inline void swap_glyph_pointers (struct glyph_row *a, struct glyph_row *b) { int i; + unsigned hash_tem = a->hash; + for (i = 0; i < LAST_AREA + 1; ++i) { struct glyph *temp = a->glyphs[i]; + short used_tem = a->used[i]; + a->glyphs[i] = b->glyphs[i]; b->glyphs[i] = temp; + a->used[i] = b->used[i]; + b->used[i] = used_tem; } + a->hash = b->hash; + b->hash = hash_tem; } /* Copy glyph row structure FROM to glyph row structure TO, except - that glyph pointers in the structures are left unchanged. */ + that glyph pointers, the `used' counts, and the hash values in the + structures are left unchanged. */ static inline void copy_row_except_pointers (struct glyph_row *to, struct glyph_row *from) { struct glyph *pointers[1 + LAST_AREA]; + short used[1 + LAST_AREA]; + unsigned hashval; /* Save glyph pointers of TO. */ memcpy (pointers, to->glyphs, sizeof to->glyphs); + memcpy (used, to->used, sizeof to->used); + hashval = to->hash; /* Do a structure assignment. */ *to = *from; /* Restore original pointers of TO. */ memcpy (to->glyphs, pointers, sizeof to->glyphs); + memcpy (to->used, used, sizeof to->used); + to->hash = hashval; } diff --git a/src/xdisp.c b/src/xdisp.c index 6b9270b7e80..ae19e11565b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17949,6 +17949,23 @@ insert_left_trunc_glyphs (struct it *it) } } +/* Compute the hash code for ROW. */ +unsigned +row_hash (struct glyph_row *row) +{ + int area, k; + unsigned hashval = 0; + + for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area) + for (k = 0; k < row->used[area]; ++k) + hashval = ((((hashval << 4) + (hashval >> 24)) & 0x0fffffff) + + row->glyphs[area][k].u.val + + row->glyphs[area][k].face_id + + row->glyphs[area][k].padding_p + + (row->glyphs[area][k].type << 2)); + + return hashval; +} /* Compute the pixel height and width of IT->glyph_row. @@ -18035,17 +18052,7 @@ compute_line_metrics (struct it *it) } /* Compute a hash code for this row. */ - { - int area, i; - row->hash = 0; - for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area) - for (i = 0; i < row->used[area]; ++i) - row->hash = ((((row->hash << 4) + (row->hash >> 24)) & 0x0fffffff) - + row->glyphs[area][i].u.val - + row->glyphs[area][i].face_id - + row->glyphs[area][i].padding_p - + (row->glyphs[area][i].type << 2)); - } + row->hash = row_hash (row); it->max_ascent = it->max_descent = 0; it->max_phys_ascent = it->max_phys_descent = 0; -- 2.39.2