1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
| | HOW TO USE GIT BISECT TO PINPOINT EMACS BUGS -*- outline -*-
This documents explains how to automate git bisect to find the commit
that introduced an Emacs bug. Bisecting automatically works best if
the bug is easy and quick to reproduce in a clean ‘emacs -Q’ instance.
For an Emacs-independent tutorial on bisecting, run ‘git help bisect’.
* Automating ‘git bisect’
Use ‘git bisect run <some-shell-script>’ to automate the bisecting
process. ‘<some-shell-script>’ should build Emacs, run your bug
reproduction test, and return 0 if the current revision is good, 1 if
it's bad, and 125 to skip the current revision.
Concretely, ‘<some-shell-script>’ usually looks like this:
#!/usr/bin/env bash
# Remove leftovers from previous runs
git clean -xfd > /dev/null
# Build Emacs and skip commit if build fails
(./autogen.sh && ./configure --cache-file=/tmp/emacs.config.cache && make -j4) || exit 125
# Reproduce the bug, writing output somewhere
src/emacs -Q -l "../reproduce-the-bug.el" || exit 125
Some caveats:
- This script cleans Emacs' source directory with ‘git clean -xfd’, so
make sure your uncommitted changes are saved somewhere else. Also,
for bisecting small ranges, a full clean and rebuild might not be
needed.
- You should produce the ‘../reproduce-your-bug.el’ script on your own
(it should check if the bug exists, and return the right error code
using ‘(kill-emacs EXIT-CODE)’: 1 if the bug is present, 0 if it is
not, and 125 if it can't tell).
* Using ‘git bisect’ to find display-related bugs
** Ways to programmatically detect display bugs
Most bugs that manifest graphically can be checked for by
programmatically inspecting the following elements:
- text properties
- window-start and window-end
- posn-at-point
- pos-visible-in-window-p
- frame-geometry
- window--dump-frame
- frame--size-history
- display-monitor-attributes-list
- C-u C-x =
- trace-redisplay and trace-to-stderr
- dump-glyph-matrix and dump-frame-glyph-matrix
** When the above fails
Some bugs are only apparent through visual inspection. Since building
Emacs takes a long time, it can be a pain to debug these manually.
If your display bug has a clear manifestation in a screenshot of a
particular portion of Emacs display, and you have a program, like
'xwd', that can capture the content of the Emacs frame, and also have
ImageMagick installed, you can automate the comparison of the
redisplay results to make the bisection process fully automatic.
Use the following template for ‘../reproduce-the-bug.el’: it requires
ImageMagick (mogrify and identify) and xwd (if ‘xwd’ isn't available,
you can use ImageMagick's ‘import’ tool, passing it a ‘-window’
argument where ‘xwd’ wants ‘id’).
(defun image-checksum (img-fname)
"Compute a checksum of IMG-FNAME's image data."
(car (process-lines "identify" "-quiet" "-format" "%#" img-fname)))
(defun take-screenshot-and-exit (fname x y w h reference-fname)
"Save a screenshot of Emacs as FNAME, then exit.
X and Y are the coordinates of the top-left point of the area of
interest. W, and H are its dimensions. This function sets
Emacs' return code to 0 if the resulting screenshot matches
REFERENCE-FNAME, and 1 otherwise."
(let ((wid (frame-parameter nil 'outer-window-id))
(crop-spec (format "%dx%d+%d+%d" w h x y)))
(call-process "xwd" nil nil nil "-silent" "-id" wid "-out" fname)
(call-process "mogrify" nil nil nil fname "-crop" crop-spec))
(let ((same-picture (equal (image-checksum fname)
(image-checksum reference-fname))))
(kill-emacs (if same-picture 0 1))))
(defun main ()
;; Reproduce your bug here
…
;; Force a redisplay
(redisplay t)
;; Insert rough X, Y, W, H values below
(run-with-timer 0 nil #'take-screenshot-and-exit
"screenshot.xwd" … … … … "reference-screenshot.xwd"))
(main)
This script takes and crops a screenshot of Emacs after reproducing
your bug, then compares the result to a reference (cropped)
screenshot, and returns 0 if they match, and 1 otherwise. Cropping is
useful to weed out unrelated display changes; try to include only a
small portion of the screen containing your bug.
|