Bug Summary

File:xlsclients.c
Location:line 571, column 1
Description:Potential leak of memory pointed to by 'cs'

Annotated Source Code

1/*
2Copyright 1989, 1998 The Open Group
3Copyright 2009 Open Text Corporation
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 in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24 * *
25 * Author: Jim Fulton, MIT X Consortium
26 * Author: Peter Harris, Open Text Corporation
27 */
28
29#ifdef HAVE_CONFIG_H1
30#include "config.h"
31#endif
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37#include <inttypes.h>
38#include <xcb/xcb.h>
39#include <xcb/xproto.h>
40#ifndef HAVE_STRNLEN1
41#include "strnlen.h"
42#endif
43
44#ifndef PRIx32"x"
45#define PRIx32"x" "x"
46#endif
47#ifndef PRIu32"u"
48#define PRIu32"u" "u"
49#endif
50
51static char *ProgramName;
52
53static xcb_atom_t WM_STATE;
54
55static void lookat (xcb_connection_t *dpy, xcb_window_t root, int verbose, int maxcmdlen);
56static void print_client_properties (xcb_connection_t *dpy, xcb_window_t w,
57 int verbose, int maxcmdlen );
58static void print_text_field (xcb_connection_t *dpy, const char *s, xcb_get_property_reply_t *tp );
59static int print_quoted_word (char *s, int maxlen);
60static void unknown (xcb_connection_t *dpy, xcb_atom_t actual_type, int actual_format );
61
62/* For convenience: */
63typedef int Bool;
64#define False(0) (0)
65#define True(!(0)) (!False(0))
66
67static void
68usage(const char *errmsg)
69{
70 if (errmsg != NULL((void *)0))
71 fprintf (stderr__stderrp, "%s: %s\n\n", ProgramName, errmsg);
72
73 fprintf (stderr__stderrp,
74 "usage: %s [-display dpy] [-m len] [-[a][l]] [-version]\n",
75 ProgramName);
76 exit (1);
77}
78
79typedef void (*queue_func)(void *closure);
80typedef struct queue_blob {
81 queue_func func;
82 void *closure;
83 struct queue_blob *next;
84} queue_blob;
85
86static queue_blob *head = NULL((void *)0);
87static queue_blob **tail = &head;
88
89static void enqueue(queue_func func, void *closure)
90{
91 queue_blob *blob = malloc(sizeof(*blob));
92 if (!blob)
93 return; /* TODO: print OOM error */
94
95 blob->func = func;
96 blob->closure = closure;
97 blob->next = NULL((void *)0);
98 *tail = blob;
99 tail = &blob->next;
100}
101
102static void run_queue(void)
103{
104 while (head) {
105 queue_blob *blob = head;
106 blob->func(blob->closure);
107 head = blob->next;
108 free(blob);
109 }
110 tail = &head;
111}
112
113typedef struct {
114 xcb_connection_t *c;
115 xcb_intern_atom_cookie_t cookie;
116 xcb_atom_t *atom;
117} atom_state;
118
119static void atom_done(void *closure)
120{
121 xcb_intern_atom_reply_t *reply;
122 atom_state *as = closure;
123
124 reply = xcb_intern_atom_reply(as->c, as->cookie, NULL((void *)0));
125 if (!reply)
126 goto done; /* TODO: print Error message */
127
128 *(as->atom) = reply->atom;
129 free(reply);
130
131done:
132 free(as);
133}
134
135static void init_atoms(xcb_connection_t *c)
136{
137 atom_state *as;
138
139 as = malloc(sizeof(*as));
140 as->c = c;
141 as->atom = &WM_STATE;
142 as->cookie = xcb_intern_atom(c, 0, strlen("WM_STATE"), "WM_STATE");
143 enqueue(atom_done, as);
144}
145
146int
147main(int argc, char *argv[])
148{
149 int i;
150 char *displayname = NULL((void *)0);
151 Bool all_screens = False(0);
152 Bool verbose = False(0);
153 xcb_connection_t *dpy;
154 const xcb_setup_t *setup;
155 int screen_number = 0;
156 int maxcmdlen = 10000;
157
158 ProgramName = argv[0];
159
160 for (i = 1; i < argc; i++) {
161 char *arg = argv[i];
162
163 if (arg[0] == '-') {
164 char *cp;
165
166 switch (arg[1]) {
167 case 'd': /* -display dpyname */
168 if (++i >= argc) usage ("-display requires an argument");
169 displayname = argv[i];
170 continue;
171 case 'm': /* -max maxcmdlen */
172 if (++i >= argc) usage ("-max requires an argument");
173 maxcmdlen = atoi (argv[i]);
174 continue;
175 case 'v': /* -version */
176 printf("%s\n", PACKAGE_STRING"xlsclients 1.1.3");
177 exit(0);
178 }
179
180 for (cp = &arg[1]; *cp; cp++) {
181 switch (*cp) {
182 case 'a': /* -all */
183 all_screens = True(!(0));
184 continue;
185 case 'l': /* -long */
186 verbose = True(!(0));
187 continue;
188 default:
189 fprintf (stderr__stderrp, "%s: unrecognized argument -%s\n\n",
190 ProgramName, cp);
191 usage (NULL((void *)0));
192 }
193 }
194 } else {
195 fprintf (stderr__stderrp, "%s: unrecognized argument %s\n\n",
196 ProgramName, arg);
197 usage (NULL((void *)0));
198 }
199 }
200
201 dpy = xcb_connect(displayname, &screen_number);
202 if (xcb_connection_has_error(dpy)) {
203 const char *name = displayname;
204 if (!name)
205 name = getenv("DISPLAY");
206 if (!name)
207 name = "";
208 fprintf (stderr__stderrp, "%s: unable to open display \"%s\"\r\n",
209 ProgramName, name);
210 exit (1);
211 }
212
213 init_atoms(dpy);
214
215 setup = xcb_get_setup(dpy);
216 if (all_screens) {
217 xcb_screen_iterator_t screen;
218
219 screen = xcb_setup_roots_iterator(setup);
220 do {
221 lookat(dpy, screen.data->root, verbose, maxcmdlen);
222 xcb_screen_next(&screen);
223 } while (screen.rem);
224 } else {
225 xcb_screen_iterator_t screen;
226
227 screen = xcb_setup_roots_iterator(setup);
228 for (i = 0; i < screen_number; i++)
229 xcb_screen_next(&screen);
230
231 lookat (dpy, screen.data->root, verbose, maxcmdlen);
232 }
233
234 run_queue();
235
236 xcb_disconnect(dpy);
237 exit (0);
238}
239
240typedef struct {
241 xcb_connection_t *c;
242 xcb_get_property_cookie_t *prop_cookie;
243 xcb_query_tree_cookie_t *tree_cookie;
244 xcb_window_t *win;
245 xcb_window_t orig_win;
246 int list_length;
247 int verbose;
248 int maxcmdlen;
249} child_wm_state;
250
251static void child_info(void *closure)
252{
253 child_wm_state *cs = closure;
254 xcb_window_t orig = cs->orig_win;
255 xcb_connection_t *c = cs->c;
256 int verbose = cs->verbose;
257 int maxcmdlen = cs->maxcmdlen;
258 int i, j;
259
260 int child_count, num_rep;
261 xcb_query_tree_reply_t **qt_reply;
262
263 for (i = 0; i < cs->list_length; i++) {
1
Loop condition is true. Entering loop body
264 xcb_get_property_reply_t *gp_reply;
265 gp_reply = xcb_get_property_reply(c, cs->prop_cookie[i], NULL((void *)0));
266 if (gp_reply) {
2
Assuming 'gp_reply' is non-null
3
Taking true branch
267 if (gp_reply->type) {
4
Taking true branch
268 /* Show information for this window */
269 print_client_properties(c, cs->win[i], cs->verbose, cs->maxcmdlen);
5
Calling 'print_client_properties'
270
271 free(gp_reply);
272
273 /* drain stale replies */
274 for (j = i+1; j < cs->list_length; j++) {
275 gp_reply = xcb_get_property_reply(c, cs->prop_cookie[j], NULL((void *)0));
276 if (gp_reply)
277 free(gp_reply);
278 }
279 for (j = 0; j < cs->list_length; j++) {
280 xcb_query_tree_reply_t *rep;
281 rep = xcb_query_tree_reply(c, cs->tree_cookie[j], NULL((void *)0));
282 if (rep)
283 free(rep);
284 }
285 goto done;
286 }
287 free(gp_reply);
288 }
289 }
290
291 /* WM_STATE not found. Recurse into children: */
292 num_rep = 0;
293 qt_reply = malloc(sizeof(*qt_reply) * cs->list_length);
294 if (!qt_reply)
295 goto done; /* TODO: print OOM message, drain reply queue */
296
297 for (i = 0; i < cs->list_length; i++) {
298 qt_reply[num_rep] = xcb_query_tree_reply(c, cs->tree_cookie[i], NULL((void *)0));
299 if (qt_reply[num_rep])
300 num_rep++;
301 }
302
303 child_count = 0;
304 for (i = 0; i < num_rep; i++)
305 child_count += qt_reply[i]->children_len;
306
307 if (!child_count) {
308 /* No children have CS_STATE; try the parent window */
309 print_client_properties(c, cs->orig_win, cs->verbose, cs->maxcmdlen);
310 goto reply_done;
311 }
312
313 cs = malloc(sizeof(*cs) + child_count * (sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win)));
314 if (!cs)
315 goto reply_done; /* TODO: print OOM message */
316
317 cs->c = c;
318 cs->verbose = verbose;
319 cs->maxcmdlen = maxcmdlen;
320 cs->orig_win = orig;
321 cs->prop_cookie = (void *)&cs[1];
322 cs->tree_cookie = (void *)&cs->prop_cookie[child_count];
323 cs->win = (void *)&cs->tree_cookie[child_count];
324 cs->list_length = child_count;
325
326 child_count = 0;
327 for (i = 0; i < num_rep; i++) {
328 xcb_window_t *child = xcb_query_tree_children(qt_reply[i]);
329 for (j = 0; j < qt_reply[i]->children_len; j++) {
330 cs->win[child_count] = child[j];
331 cs->prop_cookie[child_count] = xcb_get_property(c, 0, child[j],
332 WM_STATE, XCB_GET_PROPERTY_TYPE_ANY,
333 0, 0);
334 /* Just in case the property isn't there, get the tree too */
335 cs->tree_cookie[child_count++] = xcb_query_tree(c, child[j]);
336 }
337 }
338
339 enqueue(child_info, cs);
340
341reply_done:
342 for (i = 0; i < num_rep; i++)
343 free(qt_reply[i]);
344 free(qt_reply);
345
346done:
347 free(closure);
348}
349
350typedef struct {
351 xcb_connection_t *c;
352 xcb_query_tree_cookie_t cookie;
353 int verbose;
354 int maxcmdlen;
355} root_list_state;
356
357static void root_list(void *closure)
358{
359 int i;
360 xcb_window_t *child;
361 xcb_query_tree_reply_t *reply;
362 root_list_state *rl = closure;
363
364 reply = xcb_query_tree_reply(rl->c, rl->cookie, NULL((void *)0));
365 if (!reply)
366 goto done;
367
368 child = xcb_query_tree_children(reply);
369 for (i = 0; i < reply->children_len; i++) {
370 /* Get information about each child */
371 child_wm_state *cs = malloc(sizeof(*cs) + sizeof(*cs->prop_cookie) + sizeof(*cs->tree_cookie) + sizeof(*cs->win));
372 if (!cs)
373 goto done; /* TODO: print OOM message */
374 cs->c = rl->c;
375 cs->verbose = rl->verbose;
376 cs->maxcmdlen = rl->maxcmdlen;
377 cs->prop_cookie = (void *)&cs[1];
378 cs->tree_cookie = (void *)&cs->prop_cookie[1];
379 cs->win = (void *)&cs->tree_cookie[1];
380
381 cs->orig_win = child[i];
382 cs->win[0] = child[i];
383
384 cs->prop_cookie[0] = xcb_get_property(rl->c, 0, child[i],
385 WM_STATE, XCB_GET_PROPERTY_TYPE_ANY,
386 0, 0);
387 /* Just in case the property isn't there, get the tree too */
388 cs->tree_cookie[0] = xcb_query_tree(rl->c, child[i]);
389
390 cs->list_length = 1;
391 enqueue(child_info, cs);
392 }
393 free(reply);
394
395done:
396 free(rl);
397}
398
399static void
400lookat(xcb_connection_t *dpy, xcb_window_t root, int verbose, int maxcmdlen)
401{
402 root_list_state *rl = malloc(sizeof(*rl));
403
404 if (!rl)
405 return; /* TODO: OOM message */
406
407 /*
408 * get the list of windows
409 */
410
411 rl->c = dpy;
412 rl->cookie = xcb_query_tree(dpy, root);
413 rl->verbose = verbose;
414 rl->maxcmdlen = maxcmdlen;
415 enqueue(root_list, rl);
416}
417
418static const char *Nil = "(nil)";
419
420typedef struct {
421 xcb_connection_t *c;
422 xcb_get_property_cookie_t client_machine;
423 xcb_get_property_cookie_t command;
424 xcb_get_property_cookie_t name;
425 xcb_get_property_cookie_t icon_name;
426 xcb_get_property_cookie_t wm_class;
427 xcb_window_t w;
428 int verbose;
429 int maxcmdlen;
430} client_state;
431
432static void
433show_client_properties(void *closure)
434{
435 client_state *cs = closure;
436 xcb_get_property_reply_t *client_machine;
437 xcb_get_property_reply_t *command;
438 xcb_get_property_reply_t *name;
439 xcb_get_property_reply_t *icon_name;
440 xcb_get_property_reply_t *wm_class;
441 char *argv;
442 int charsleft = cs->maxcmdlen;
443 int i;
444
445 /*
446 * get the WM_MACHINE and WM_COMMAND list of strings
447 */
448 client_machine = xcb_get_property_reply(cs->c, cs->client_machine, NULL((void *)0));
449 command = xcb_get_property_reply(cs->c, cs->command, NULL((void *)0));
450 if (cs->verbose) {
451 name = xcb_get_property_reply(cs->c, cs->name, NULL((void *)0));
452 icon_name = xcb_get_property_reply(cs->c, cs->icon_name, NULL((void *)0));
453 wm_class = xcb_get_property_reply(cs->c, cs->wm_class, NULL((void *)0));
454 }
455
456 if (!command || !command->type)
457 goto done;
458
459 /*
460 * do header information
461 */
462 if (cs->verbose) {
463 printf ("Window 0x%" PRIx32"x" ":\n", cs->w);
464 print_text_field (cs->c, " Machine: ", client_machine);
465 if (name && name->type)
466 print_text_field (cs->c, " Name: ", name);
467 } else {
468 print_text_field (cs->c, NULL((void *)0), client_machine);
469 putchar (' ');
470 putchar (' ');
471 }
472
473
474 if (cs->verbose)
475 if (icon_name && icon_name->type)
476 print_text_field (cs->c, " Icon Name: ", icon_name);
477
478
479 /*
480 * do the command
481 */
482 if (cs->verbose)
483 printf (" Command: ");
484 argv = xcb_get_property_value(command);
485 for (i = 0; i < command->value_len && charsleft > 0; ) {
486 charsleft -= print_quoted_word (argv + i, charsleft);
487 i += strnlen(argv + i, command->value_len - i) + 1;
488 if (i < command->value_len && charsleft > 0) {
489 putchar (' ');
490 charsleft--;
491 }
492 }
493 putchar ('\n');
494
495
496 /*
497 * do trailer information
498 */
499 if (cs->verbose) {
500 if (wm_class && wm_class->type) {
501 const char *res_name, *res_class;
502 int name_len, class_len;
503 res_name = xcb_get_property_value(wm_class);
504 name_len = strnlen(res_name, wm_class->value_len) + 1;
505 class_len = wm_class->value_len - name_len;
506 if (class_len > 0) {
507 res_class = res_name + name_len;
508 } else {
509 res_class = Nil;
510 class_len = strlen(res_class);
511 }
512
513 printf (" Instance/Class: %.*s/%.*s",
514 name_len, res_name,
515 class_len, res_class);
516 putchar ('\n');
517 }
518 }
519
520done:
521 if (client_machine)
522 free(client_machine);
523 if (command)
524 free(command);
525 if (cs->verbose) {
526 if (name)
527 free(name);
528 if (icon_name)
529 free(icon_name);
530 if (wm_class)
531 free(wm_class);
532 }
533 free(cs);
534}
535
536static void
537print_client_properties(xcb_connection_t *dpy, xcb_window_t w, int verbose, int maxcmdlen)
538{
539 client_state *cs = malloc(sizeof(*cs));
6
Memory is allocated
540 if (!cs)
7
Assuming 'cs' is non-null
8
Taking false branch
541 return; /* TODO: print OOM message */
542
543 cs->c = dpy;
544 cs->w = w;
545 cs->verbose = verbose;
546 cs->maxcmdlen = maxcmdlen;
547
548 /*
549 * get the WM_CLIENT_MACHINE and WM_COMMAND list of strings
550 */
551 cs->client_machine = xcb_get_property(dpy, 0, w,
552 XCB_ATOM_WM_CLIENT_MACHINE, XCB_GET_PROPERTY_TYPE_ANY,
553 0, 1000000L);
554 cs->command = xcb_get_property(dpy, 0, w,
555 XCB_ATOM_WM_COMMAND, XCB_GET_PROPERTY_TYPE_ANY,
556 0, 1000000L);
557
558 if (verbose) {
9
Assuming 'verbose' is 0
10
Taking false branch
559 cs->name = xcb_get_property(dpy, 0, w,
560 XCB_ATOM_WM_NAME, XCB_GET_PROPERTY_TYPE_ANY,
561 0, 1000000L);
562 cs->icon_name = xcb_get_property(dpy, 0, w,
563 XCB_ATOM_WM_ICON_NAME, XCB_GET_PROPERTY_TYPE_ANY,
564 0, 1000000L);
565 cs->wm_class = xcb_get_property(dpy, 0, w,
566 XCB_ATOM_WM_CLASS, XCB_ATOM_STRING,
567 0, 1000000L);
568 }
569
570 enqueue(show_client_properties, cs);
571}
11
Potential leak of memory pointed to by 'cs'
572
573static void
574print_text_field(xcb_connection_t *dpy, const char *s, xcb_get_property_reply_t *tp)
575{
576 if (tp->type == XCB_NONE0L || tp->format == 0) { /* Or XCB_ATOM_NONE after libxcb 1.5 */
577 printf ("''");
578 return;
579 }
580
581 if (s) printf ("%s", s);
582 if (tp->type == XCB_ATOM_STRING && tp->format == 8) {
583 printf ("%.*s", (int)tp->value_len, (char *)xcb_get_property_value(tp));
584 } else {
585 unknown (dpy, tp->type, tp->format);
586 }
587 if (s) putchar ('\n');
588}
589
590/* returns the number of characters printed */
591static int
592print_quoted_word(char *s,
593 int maxlen) /* max number of chars we can print */
594{
595 register char *cp;
596 Bool need_quote = False(0), in_quote = False(0);
597 char quote_char = '\'', other_quote = '"';
598 int charsprinted = 0;
599
600 /*
601 * walk down seeing whether or not we need to quote
602 */
603 for (cp = s; *cp; cp++) {
604
605 if (! ((isascii(*cp) && isalnum(*cp)) ||
606 (*cp == '-' || *cp == '_' || *cp == '.' || *cp == '+' ||
607 *cp == '/' || *cp == '=' || *cp == ':' || *cp == ','))) {
608 need_quote = True(!(0));
609 break;
610 }
611 }
612
613 /*
614 * write out the string: if we hit a quote, then close any previous quote,
615 * emit the other quote, swap quotes and continue on.
616 */
617 in_quote = need_quote;
618 if (need_quote) {
619 putchar (quote_char);
620 charsprinted++; maxlen--;
621 }
622 for (cp = s; *cp && maxlen>0; cp++) {
623 if (*cp == quote_char) {
624 if (in_quote) {
625 putchar (quote_char);
626 charsprinted++; maxlen--;
627 }
628 putchar (other_quote);
629 charsprinted++; maxlen--;
630 {
631 char tmp = other_quote;
632 other_quote = quote_char; quote_char = tmp;
633 }
634 in_quote = True(!(0));
635 }
636 putchar (*cp);
637 charsprinted++; maxlen--;
638 }
639 /* close the quote if we opened one and if we printed the whole string */
640 if (in_quote && maxlen>0) {
641 putchar (quote_char);
642 charsprinted++; maxlen--;
643 }
644
645 return charsprinted;
646}
647
648static void
649unknown(xcb_connection_t *dpy, xcb_atom_t actual_type, int actual_format)
650{
651 printf ("<unknown type ");
652 if (actual_type == XCB_NONE0L)
653 printf ("None");
654 else {
655 /* This should happen so rarely as to make no odds. Eat a round-trip: */
656 xcb_get_atom_name_reply_t *atom =
657 xcb_get_atom_name_reply(dpy,
658 xcb_get_atom_name(dpy, actual_type), NULL((void *)0));
659 if (atom) {
660 printf("%.*s", xcb_get_atom_name_name_length(atom),
661 xcb_get_atom_name_name(atom));
662 free(atom);
663 } else
664 fputs (Nil, stdout__stdoutp);
665 }
666 printf (" (%" PRIu32"u" ") or format %d>", actual_type, actual_format);
667}