Bug Summary

File:xkill.c
Location:line 143, column 16
Description:Access to field 'default_screen' results in a dereference of a null pointer (loaded from variable 'dpy')

Annotated Source Code

1/*
2
3Copyright 1988, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * xkill - simple program for destroying unwanted clients
31 * Author: Jim Fulton, MIT X Consortium; Dana Chee, Bellcore
32 */
33
34/*
35 * Warning, this is a very dangerous client....
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <ctype.h>
41
42#include <X11/Xos.h>
43#include <X11/Xlib.h>
44#include <X11/cursorfont.h>
45#include <X11/Xproto.h>
46
47#include <X11/Xmu/WinUtil.h>
48
49static Display *dpy = NULL((void*)0);
50static char *ProgramName;
51
52#define SelectButtonAny(-1) (-1)
53#define SelectButtonFirst(-2) (-2)
54
55static int parse_button ( char *s, int *buttonp );
56static XID parse_id ( char *s );
57static XID get_window_id ( Display *dpy, int screen, int button, char *msg );
58static int catch_window_errors ( Display *dpy, XErrorEvent *ev );
59static int kill_all_windows ( Display *dpy, int screenno, Boolint top );
60static int verify_okay_to_kill ( Display *dpy, int screenno );
61static Boolint wm_state_set ( Display *dpy, Window win );
62static Boolint wm_running ( Display *dpy, int screenno );
63
64static void
65Exit(int code)
66{
67 if (dpy) {
68 XCloseDisplay (dpy);
69 }
70 exit (code);
71}
72
73static void
74usage(void)
75{
76 const char *options =
77"where options include:\n"
78" -display displayname X server to contact\n"
79" -id resource resource whose client is to be killed\n"
80" -frame don't ignore window manager frames\n"
81" -button number specific button to be pressed to select window\n"
82" -all kill all clients with top level windows\n"
83"\n";
84 char **cpp;
85
86 fprintf (stderrstderr, "usage: %s [-option ...]\n%s",
87 ProgramName, options);
88 Exit (1);
89}
90
91int
92main(int argc, char *argv[])
93{
94 int i; /* iterator, temp variable */
95 char *displayname = NULL((void*)0); /* name of server to contact */
96 int screenno; /* screen number of dpy */
97 XID id = None0L; /* resource to kill */
98 char *button_name = NULL((void*)0); /* name of button for window select */
99 int button; /* button number or negative for all */
100 Boolint kill_all = False0;
101 Boolint top = False0;
102
103 ProgramName = argv[0];
104 button = SelectButtonFirst(-2);
105
106 for (i = 1; i < argc; i++) {
1
Assuming 'i' is >= 'argc'
2
Loop condition is false. Execution continues on line 137
107 char *arg = argv[i];
108
109 if (arg[0] == '-') {
110 switch (arg[1]) {
111 case 'd': /* -display displayname */
112 if (++i >= argc) usage ();
113 displayname = argv[i];
114 continue;
115 case 'i': /* -id resourceid */
116 if (++i >= argc) usage ();
117 id = parse_id (argv[i]);
118 continue;
119 case 'b': /* -button number */
120 if (++i >= argc) usage ();
121 button_name = argv[i];
122 continue;
123 case 'f': /* -frame */
124 top = True1;
125 continue;
126 case 'a': /* -all */
127 kill_all = True1;
128 continue;
129 default:
130 usage ();
131 }
132 } else {
133 usage ();
134 }
135 } /* end for */
136
137 dpy = XOpenDisplay (displayname);
138 if (!dpy) {
3
Assuming 'dpy' is null
4
Taking true branch
139 fprintf (stderrstderr, "%s: unable to open display \"%s\"\n",
140 ProgramName, XDisplayName (displayname));
141 Exit (1);
142 }
143 screenno = DefaultScreen (dpy)(((_XPrivDisplay)dpy)->default_screen);
5
Within the expansion of the macro 'DefaultScreen':
a
Access to field 'default_screen' results in a dereference of a null pointer (loaded from variable 'dpy')
144
145 if (kill_all) {
146 if (verify_okay_to_kill (dpy, screenno))
147 kill_all_windows (dpy, screenno, top);
148 Exit (0);
149 }
150
151 /*
152 * if no id was given, we need to choose a window
153 */
154
155 if (id == None0L) {
156 if (!button_name)
157 button_name = XGetDefault (dpy, ProgramName, "Button");
158
159 if (button_name && !parse_button (button_name, &button)) {
160 fprintf (stderrstderr, "%s: invalid button specification \"%s\"\n",
161 ProgramName, button_name);
162 Exit (1);
163 }
164
165 if (button >= 0 || button == SelectButtonFirst(-2)) {
166 unsigned char pointer_map[256]; /* 8 bits of pointer num */
167 int count, j;
168 unsigned int ub = (unsigned int) button;
169
170
171 count = XGetPointerMapping (dpy, pointer_map, 256);
172 if (count <= 0) {
173 fprintf (stderrstderr,
174 "%s: no pointer mapping, can't select window\n",
175 ProgramName);
176 Exit (1);
177 }
178
179 if (button >= 0) { /* check button */
180 for (j = 0; j < count; j++) {
181 if (ub == (unsigned int) pointer_map[j]) break;
182 }
183 if (j == count) {
184 fprintf (stderrstderr,
185 "%s: no button number %u in pointer map, can't select window\n",
186 ProgramName, ub);
187 Exit (1);
188 }
189 } else { /* get first entry */
190 button = (int) ((unsigned int) pointer_map[0]);
191 }
192 }
193 if ((id = get_window_id (dpy, screenno, button,
194 "the window whose client you wish to kill"))) {
195 if (id == RootWindow(dpy,screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root)) id = None0L;
196 else if (!top) {
197 XID indicated = id;
198 if ((id = XmuClientWindow(dpy, indicated)) == indicated) {
199
200 /* Try not to kill the window manager when the user
201 * indicates an icon to xkill.
202 */
203
204 if (! wm_state_set(dpy, id) && wm_running(dpy, screenno))
205 id = None0L;
206
207 }
208 }
209 }
210 }
211
212 if (id != None0L) {
213 printf ("%s: killing creator of resource 0x%lx\n", ProgramName, id);
214 XSync (dpy, 0); /* give xterm a chance */
215 XKillClient (dpy, id);
216 XSync (dpy, 0);
217 }
218
219 Exit (0);
220 /*NOTREACHED*/
221 return 0;
222}
223
224static int
225parse_button(char *s, int *buttonp)
226{
227 register char *cp;
228
229 /* lower case name */
230 for (cp = s; *cp; cp++) {
231 if (isascii (*cp)(((*cp) & ~0x7f) == 0) && isupper (*cp)((*__ctype_b_loc ())[(int) ((*cp))] & (unsigned short int
) _ISupper)
) {
232#ifdef _tolower
233 *cp = _tolower (*cp)((int) (*__ctype_tolower_loc ())[(int) (*cp)]);
234#else
235 *cp = tolower (*cp);
236#endif /* _tolower */
237 }
238 }
239
240 if (strcmp (s, "any") == 0) {
241 *buttonp = SelectButtonAny(-1);
242 return (1);
243 }
244
245 /* check for non-numeric input */
246 for (cp = s; *cp; cp++) {
247 if (!(isascii (*cp)(((*cp) & ~0x7f) == 0) && isdigit (*cp)((*__ctype_b_loc ())[(int) ((*cp))] & (unsigned short int
) _ISdigit)
)) return (0); /* bogus name */
248 }
249
250 *buttonp = atoi (s);
251 return (1);
252}
253
254
255static XID
256parse_id(char *s)
257{
258 XID retval = None0L;
259 char *fmt = "%ld"; /* since XID is long */
260
261 if (s) {
262 if (*s == '0') s++, fmt = "%lo";
263 if (*s == 'x' || *s == 'X') s++, fmt = "%lx";
264 sscanf (s, fmt, &retval);
265 }
266 return (retval);
267}
268
269static XID
270get_window_id(Display *dpy, int screen, int button, char *msg)
271{
272 Cursor cursor; /* cursor to use when selecting */
273 Window root; /* the current root */
274 Window retwin = None0L; /* the window that got selected */
275 int retbutton = -1; /* button used to select window */
276 int pressed = 0; /* count of number of buttons pressed */
277
278#define MASK((1L<<2) | (1L<<3)) (ButtonPressMask(1L<<2) | ButtonReleaseMask(1L<<3))
279
280 root = RootWindow (dpy, screen)((&((_XPrivDisplay)dpy)->screens[screen])->root);
281 cursor = XCreateFontCursor (dpy, XC_pirate88);
282 if (cursor == None0L) {
283 fprintf (stderrstderr, "%s: unable to create selection cursor\n",
284 ProgramName);
285 Exit (1);
286 }
287
288 printf ("Select %s with ", msg);
289 if (button == -1)
290 printf ("any button");
291 else
292 printf ("button %d", button);
293 printf ("....\n");
294 XSync (dpy, 0); /* give xterm a chance */
295
296 if (XGrabPointer (dpy, root, False0, MASK((1L<<2) | (1L<<3)), GrabModeSync0, GrabModeAsync1,
297 None0L, cursor, CurrentTime0L) != GrabSuccess0) {
298 fprintf (stderrstderr, "%s: unable to grab cursor\n", ProgramName);
299 Exit (1);
300 }
301
302 /* from dsimple.c in xwininfo */
303 while (retwin == None0L || pressed != 0) {
304 XEvent event;
305
306 XAllowEvents (dpy, SyncPointer1, CurrentTime0L);
307 XWindowEvent (dpy, root, MASK((1L<<2) | (1L<<3)), &event);
308 switch (event.type) {
309 case ButtonPress4:
310 if (retwin == None0L) {
311 retbutton = event.xbutton.button;
312 retwin = ((event.xbutton.subwindow != None0L) ?
313 event.xbutton.subwindow : root);
314 }
315 pressed++;
316 continue;
317 case ButtonRelease5:
318 if (pressed > 0) pressed--;
319 continue;
320 } /* end switch */
321 } /* end for */
322
323 XUngrabPointer (dpy, CurrentTime0L);
324 XFreeCursor (dpy, cursor);
325 XSync (dpy, 0);
326
327 return ((button == -1 || retbutton == button) ? retwin : None0L);
328}
329
330
331static int
332catch_window_errors(Display *dpy, XErrorEvent *ev)
333{
334 return 0;
335}
336
337static int
338kill_all_windows(Display *dpy, int screenno, Boolint top)
339{
340 Window root = RootWindow (dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root);
341 Window dummywindow;
342 Window *children;
343 unsigned int nchildren;
344 unsigned int i;
345 XWindowAttributes attr;
346
347 XSync (dpy, 0);
348 XSetErrorHandler (catch_window_errors);
349
350 nchildren = 0;
351 XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren);
352 if (!top) {
353 for (i = 0; i < nchildren; i++) {
354 if (XGetWindowAttributes(dpy, children[i], &attr) &&
355 (attr.map_state == IsViewable2))
356 children[i] = XmuClientWindow(dpy, children[i]);
357 else
358 children[i] = 0;
359 }
360 }
361 for (i = 0; i < nchildren; i++) {
362 if (children[i])
363 XKillClient (dpy, children[i]);
364 }
365 XFree ((char *)children);
366
367 XSync (dpy, 0);
368 XSetErrorHandler (NULL((void*)0)); /* pretty stupid way to do things... */
369
370 return 0;
371}
372
373/*
374 * ask the user to press in the root with each button in succession
375 */
376static int
377verify_okay_to_kill(Display *dpy, int screenno)
378{
379 unsigned char pointer_map[256];
380 int count = XGetPointerMapping (dpy, pointer_map, 256);
381 int i;
382 int button;
383 static char *msg = "the root window";
384 Window root = RootWindow (dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root);
385 int okay = 0;
386
387 for (i = 0; i < count; i++) {
388 button = (int) pointer_map[i];
389 if (button == 0) continue; /* disabled */
390 if (get_window_id (dpy, screenno, button, msg) != root) {
391 okay = 0;
392 break;
393 }
394 okay++; /* must have at least one button */
395 }
396 if (okay) {
397 return 1;
398 } else {
399 printf ("Aborting.\n");
400 return 0;
401 }
402}
403
404/* Return True if the property WM_STATE is set on the window, otherwise
405 * return False.
406 */
407static Boolint
408wm_state_set(Display *dpy, Window win)
409{
410 Atom wm_state;
411 Atom actual_type;
412 int success;
413 int actual_format;
414 unsigned long nitems, remaining;
415 unsigned char* prop = NULL((void*)0);
416
417 wm_state = XInternAtom(dpy, "WM_STATE", True1);
418 if (wm_state == None0L) return False0;
419 success = XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False0,
420 AnyPropertyType0L, &actual_type, &actual_format,
421 &nitems, &remaining, &prop);
422 if (prop) XFree((char *) prop);
423 return (success == Success0 && actual_type != None0L && actual_format);
424}
425
426/* Using a heuristic method, return True if a window manager is running,
427 * otherwise, return False.
428 */
429
430static Boolint
431wm_running(Display *dpy, int screenno)
432{
433 XWindowAttributes xwa;
434 Statusint status;
435
436 status = XGetWindowAttributes(dpy, RootWindow(dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root), &xwa);
437 return (status &&
438 ((xwa.all_event_masks & SubstructureRedirectMask(1L<<20)) ||
439 (xwa.all_event_masks & SubstructureNotifyMask(1L<<19))));
440}