Bug Summary

File:XRecord.c
Location:line 516, column 6
Description:Array access (via field 'client_info') results in a null pointer dereference

Annotated Source Code

1/*
2XRecord.c - client-side library for RECORD extension
3
4Copyright 1995, 1998 The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall
24not be used in advertising or otherwise to promote the sale, use or
25other dealings in this Software without prior written authorization
26from The Open Group.
27
28*/
29/***************************************************************************
30 * Copyright 1995 Network Computing Devices
31 *
32 * Permission to use, copy, modify, distribute, and sell this software and
33 * its documentation for any purpose is hereby granted without fee, provided
34 * that the above copyright notice appear in all copies and that both that
35 * copyright notice and this permission notice appear in supporting
36 * documentation, and that the name of Network Computing Devices
37 * not be used in advertising or publicity pertaining to distribution
38 * of the software without specific, written prior permission.
39 *
40 * NETWORK COMPUTING DEVICES DISCLAIMs ALL WARRANTIES WITH REGARD TO
41 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
42 * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE
43 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
45 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
46 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47 **************************************************************************/
48/*
49 * By Stephen Gildea, X Consortium, and Martha Zimet, NCD.
50 */
51
52#ifdef HAVE_CONFIG_H1
53#include <config.h>
54#endif
55#include <stdio.h>
56#include <assert.h>
57#include <X11/Xlibint.h>
58#include <X11/extensions/Xext.h>
59#include <X11/extensions/extutil.h>
60#include <X11/extensions/recordproto.h>
61#include <X11/extensions/record.h>
62#include <limits.h>
63
64static XExtensionInfo _xrecord_info_data;
65static XExtensionInfo *xrecord_info = &_xrecord_info_data;
66static const char *xrecord_extension_name = RECORD_NAME"RECORD";
67
68#define XRecordCheckExtension(dpy,i,val)if (!((i) && ((i)->codes))) { XMissingExtension (dpy
, xrecord_extension_name); return val; }
\
69 XextCheckExtension(dpy, i, xrecord_extension_name, val)if (!((i) && ((i)->codes))) { XMissingExtension (dpy
, xrecord_extension_name); return val; }
70
71/**************************************************************************
72 * *
73 * private utility routines *
74 * *
75 **************************************************************************/
76
77static XExtDisplayInfo *find_display(Display *dpy);
78
79/*
80 * A reply buffer holds a reply from RecordEnableContext.
81 * Pieces of that buffer are passed to the XRecordEnableContext callback.
82 * ref_count is incremented each time we do that.
83 * ref_count is decremented each time XRecordFreeData is called on
84 * the buffer. When ref_count is 0, we can free or reuse the buffer.
85 */
86struct reply_buffer
87{
88 struct reply_buffer *next; /* next in list or NULL */
89 unsigned char *buf; /* pointer to malloc'd buffer */
90 int nbytes; /* size of buf */
91 int ref_count; /* callback uses pending */
92};
93
94
95/*
96 * There's some extra information the implementation finds useful
97 * to attach to an XRecordInterceptData packet to handle memory
98 * management. So we really allocate one of these.
99 */
100struct intercept_queue
101{
102 /* this struct gets passed to the user as an XRecordInterceptData,
103 so the data field must come first so we can cast the address
104 back and forth */
105 XRecordInterceptData data;
106 struct intercept_queue *next; /* next in free list or NULL */
107 struct mem_cache_str *cache; /* contains head of free list */
108};
109
110/*
111 * per-display pointers to cache of malloc'd but unused memory
112 */
113struct mem_cache_str
114{
115 struct intercept_queue *inter_data; /* free structs only */
116 struct reply_buffer *reply_buffers; /* all reply buffers */
117 int inter_data_count; /* total allocated, free and in use */
118 Boolint display_closed; /* so we know when to free ourself */
119};
120
121static int close_display(
122 Display *dpy,
123 XExtCodes *codes) /* not used */
124{
125 XExtDisplayInfo *info = find_display (dpy);
126
127 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
128 if (info && info->data) {
129 struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
130 struct intercept_queue *iq, *iq_next;
131 struct reply_buffer *rbp, **rbp_next_p;
132
133 for (iq=cache->inter_data; iq; iq=iq_next) {
134 iq_next = iq->next;
135 XFree(iq);
136 cache->inter_data_count--;
137 }
138
139 /* this is a little trickier, because some of these
140 might still be in use */
141 for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) {
142 rbp = *rbp_next_p;
143 if (rbp->ref_count == 0) {
144 *rbp_next_p = rbp->next;
145 XFree(rbp->buf);
146 XFree(rbp);
147 } else {
148 rbp_next_p = &rbp->next;
149 }
150 }
151
152 if (cache->reply_buffers == NULL((void*)0) && cache->inter_data_count == 0) {
153 /* every thing has been freed, can free ourselves, too */
154 XFree(cache);
155 } else {
156 cache->display_closed = True1;
157 cache->inter_data = NULL((void*)0); /* neatness only; won't be used */
158 }
159 }
160 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
161 return XextRemoveDisplay(xrecord_info, dpy);
162}
163
164static XPointer alloc_mem_cache(void)
165{
166 struct mem_cache_str *cache;
167
168 /* note that an error will go unnoticed */
169 cache = (struct mem_cache_str *) Xmalloc(sizeof(struct mem_cache_str))malloc(((sizeof(struct mem_cache_str)) == 0 ? 1 : (sizeof(struct
mem_cache_str))))
;
170 if (cache) {
171 cache->display_closed = False0;
172 cache->inter_data = NULL((void*)0);
173 cache->inter_data_count = 0;
174 cache->reply_buffers = NULL((void*)0);
175 }
176 return (XPointer) cache;
177}
178
179static const char *xrecord_error_list[] = {
180 "XRecordBadContext (Not a defined RECORD context)",
181};
182
183static XEXT_GENERATE_ERROR_STRING (error_string, xrecord_extension_name,char *error_string (Display *dpy, int code, XExtCodes *codes,
char *buf, int n) { code -= codes->first_error; if (code >=
0 && code < (0 + 1)) { char tmp[256]; __builtin___snprintf_chk
(tmp, sizeof(tmp), 0, __builtin_object_size (tmp, 2 > 1 ?
1 : 0), "%s.%d", xrecord_extension_name, code); XGetErrorDatabaseText
(dpy, "XProtoError", tmp, xrecord_error_list[code], buf, n);
return buf; } return (char *)0; }
184 RecordNumErrors, xrecord_error_list)char *error_string (Display *dpy, int code, XExtCodes *codes,
char *buf, int n) { code -= codes->first_error; if (code >=
0 && code < (0 + 1)) { char tmp[256]; __builtin___snprintf_chk
(tmp, sizeof(tmp), 0, __builtin_object_size (tmp, 2 > 1 ?
1 : 0), "%s.%d", xrecord_extension_name, code); XGetErrorDatabaseText
(dpy, "XProtoError", tmp, xrecord_error_list[code], buf, n);
return buf; } return (char *)0; }
185
186static XExtensionHooks xrecord_extension_hooks = {
187 NULL((void*)0), /* create_gc */
188 NULL((void*)0), /* copy_gc */
189 NULL((void*)0), /* flush_gc */
190 NULL((void*)0), /* free_gc */
191 NULL((void*)0), /* create_font */
192 NULL((void*)0), /* free_font */
193 close_display, /* close_display */
194 NULL((void*)0), /* wire_to_event */
195 NULL((void*)0), /* event_to_wire */
196 NULL((void*)0), /* error */
197 error_string /* error_string */
198};
199
200static XEXT_GENERATE_FIND_DISPLAY (find_display, xrecord_info,XExtDisplayInfo *find_display (Display *dpy) { XExtDisplayInfo
*dpyinfo; if (!xrecord_info) { if (!(xrecord_info = XextCreateExtension
())) return ((void*)0); } if (!(dpyinfo = XextFindDisplay (xrecord_info
, dpy))) dpyinfo = XextAddDisplay (xrecord_info,dpy,xrecord_extension_name
,&xrecord_extension_hooks,0L,alloc_mem_cache()); return dpyinfo
; }
201 xrecord_extension_name, &xrecord_extension_hooks, RecordNumEvents,XExtDisplayInfo *find_display (Display *dpy) { XExtDisplayInfo
*dpyinfo; if (!xrecord_info) { if (!(xrecord_info = XextCreateExtension
())) return ((void*)0); } if (!(dpyinfo = XextFindDisplay (xrecord_info
, dpy))) dpyinfo = XextAddDisplay (xrecord_info,dpy,xrecord_extension_name
,&xrecord_extension_hooks,0L,alloc_mem_cache()); return dpyinfo
; }
202 alloc_mem_cache())XExtDisplayInfo *find_display (Display *dpy) { XExtDisplayInfo
*dpyinfo; if (!xrecord_info) { if (!(xrecord_info = XextCreateExtension
())) return ((void*)0); } if (!(dpyinfo = XextFindDisplay (xrecord_info
, dpy))) dpyinfo = XextAddDisplay (xrecord_info,dpy,xrecord_extension_name
,&xrecord_extension_hooks,0L,alloc_mem_cache()); return dpyinfo
; }
203
204/**************************************************************************
205 * *
206 * private library routines *
207 * *
208 **************************************************************************/
209
210static void
211SendRange(
212 Display *dpy,
213 XRecordRange **range_item,
214 int nranges)
215{
216 int rlen = SIZEOF(xRecordRange)24;
217 while(nranges--)
218 {
219 xRecordRange xrange;
220
221 xrange.coreRequestsFirst = (*range_item)->core_requests.first;
222 xrange.coreRequestsLast = (*range_item)->core_requests.last;
223 xrange.coreRepliesFirst = (*range_item)->core_replies.first;
224 xrange.coreRepliesLast = (*range_item)->core_replies.last;
225 xrange.extRequestsMajorFirst = (*range_item)->ext_requests.ext_major.first;
226 xrange.extRequestsMajorLast = (*range_item)->ext_requests.ext_major.last;
227 xrange.extRequestsMinorFirst = (*range_item)->ext_requests.ext_minor.first;
228 xrange.extRequestsMinorLast = (*range_item)->ext_requests.ext_minor.last;
229 xrange.extRepliesMajorFirst = (*range_item)->ext_replies.ext_major.first;
230 xrange.extRepliesMajorLast = (*range_item)->ext_replies.ext_major.last;
231 xrange.extRepliesMinorFirst = (*range_item)->ext_replies.ext_minor.first;
232 xrange.extRepliesMinorLast = (*range_item)->ext_replies.ext_minor.last;
233 xrange.deliveredEventsFirst = (*range_item)->delivered_events.first;
234 xrange.deliveredEventsLast = (*range_item)->delivered_events.last;
235 xrange.deviceEventsFirst = (*range_item)->device_events.first;
236 xrange.deviceEventsLast = (*range_item)->device_events.last;
237 xrange.errorsFirst = (*range_item)->errors.first;
238 xrange.errorsLast = (*range_item)->errors.last;
239 xrange.clientStarted = (*range_item)->client_started;
240 xrange.clientDied = (*range_item)->client_died;
241
242 Data(dpy, (char *)&xrange, rlen){ if (dpy->bufptr + (rlen) <= dpy->bufmax) { __builtin___memcpy_chk
(dpy->bufptr, (char *)&xrange, (int)rlen, __builtin_object_size
(dpy->bufptr, 0)); dpy->bufptr += ((rlen) + 3) & ~
3; } else _XSend(dpy, (char *)&xrange, rlen);}
;
243 range_item++;
244 }
245}
246
247/**************************************************************************
248 * *
249 * public routines *
250 * *
251 **************************************************************************/
252
253XID
254XRecordIdBaseMask(Display *dpy)
255{
256 return 0x1fffffff & ~dpy->resource_mask;
257}
258
259Statusint
260XRecordQueryVersion(Display *dpy, int *cmajor_return, int *cminor_return)
261{
262 XExtDisplayInfo *info = find_display (dpy);
263 register xRecordQueryVersionReq *req;
264 xRecordQueryVersionReply rep;
265
266 XRecordCheckExtension (dpy, info, False)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
267
268 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
269 GetReq(RecordQueryVersion, req)req = (xRecordQueryVersionReq *) _XGetRequest(dpy, 0, 8);
270 req->reqType = info->codes->major_opcode;
271 req->recordReqType = X_RecordQueryVersion0;
272 req->majorVersion = RECORD_MAJOR_VERSION1;
273 req->minorVersion = RECORD_MINOR_VERSION13;
274 if (!_XReply(dpy,(xReply *)&rep, 0, True1)) {
275 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
276 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
277 return False0;
278 }
279 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
280 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
281 *cmajor_return = rep.majorVersion;
282 *cminor_return = rep.minorVersion;
283 return ((rep.majorVersion == RECORD_MAJOR_VERSION1) &&
284 (rep.minorVersion >= RECORD_LOWEST_MINOR_VERSION12));
285}
286
287XRecordContext
288XRecordCreateContext(Display *dpy, int datum_flags,
289 XRecordClientSpec *clients, int nclients,
290 XRecordRange **ranges, int nranges)
291{
292 XExtDisplayInfo *info = find_display (dpy);
293 register xRecordCreateContextReq *req;
294 int clen = 4 * nclients;
295
296 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
297 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
298 GetReq(RecordCreateContext, req)req = (xRecordCreateContextReq *) _XGetRequest(dpy, 1, 20);
299
300 req->reqType = info->codes->major_opcode;
301 req->recordReqType = X_RecordCreateContext1;
302 req->context = XAllocID(dpy)((*((_XPrivDisplay)(dpy))->resource_alloc)((dpy)));
303 req->length += (nclients * 4 +
304 nranges * SIZEOF(xRecordRange)24) >> 2;
305 req->elementHeader = datum_flags;
306 req->nClients = nclients;
307 req->nRanges = nranges;
308
309 Data32(dpy, (long *)clients, clen)_XData32(dpy, (const long *)(long *)clients, clen);
310 SendRange(dpy, ranges, nranges);
311
312 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
313 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
314 return req->context;
315}
316
317XRecordRange *
318XRecordAllocRange(void)
319{
320 return (XRecordRange*)Xcalloc(1, sizeof(XRecordRange))calloc(((1) == 0 ? 1 : (1)), (sizeof(XRecordRange)));
321}
322
323Statusint
324XRecordRegisterClients(Display *dpy, XRecordContext context, int datum_flags,
325 XRecordClientSpec *clients, int nclients,
326 XRecordRange **ranges, int nranges)
327{
328 XExtDisplayInfo *info = find_display (dpy);
329 register xRecordRegisterClientsReq *req;
330 int clen = 4 * nclients;
331
332 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
333 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
334 GetReq(RecordRegisterClients, req)req = (xRecordRegisterClientsReq *) _XGetRequest(dpy, 2, 20);
335
336 req->reqType = info->codes->major_opcode;
337 req->recordReqType = X_RecordRegisterClients2;
338 req->context = context;
339 req->length += (nclients * 4 +
340 nranges * SIZEOF(xRecordRange)24) >> 2;
341 req->elementHeader = datum_flags;
342 req->nClients = nclients;
343 req->nRanges = nranges;
344
345 Data32(dpy, (long *)clients, clen)_XData32(dpy, (const long *)(long *)clients, clen);
346 SendRange(dpy, ranges, nranges);
347
348 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
349 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
350 return 1;
351}
352
353Statusint
354XRecordUnregisterClients(Display *dpy, XRecordContext context,
355 XRecordClientSpec *clients, int nclients)
356{
357 XExtDisplayInfo *info = find_display (dpy);
358 register xRecordUnregisterClientsReq *req;
359 int clen = 4 * nclients;
360
361 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
362 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
363 GetReq(RecordUnregisterClients, req)req = (xRecordUnregisterClientsReq *) _XGetRequest(dpy, 3, 12
)
;
364
365 req->reqType = info->codes->major_opcode;
366 req->recordReqType = X_RecordUnregisterClients3;
367 req->context = context;
368 req->length += nclients;
369 req->nClients = nclients;
370
371 Data32(dpy, (long *)clients, clen)_XData32(dpy, (const long *)(long *)clients, clen);
372
373 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
374 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
375 return 1;
376}
377
378static void
379WireToLibRange(
380 xRecordRange *wire_range,
381 XRecordRange *lib_range)
382{
383 lib_range->core_requests.first = wire_range->coreRequestsFirst;
384 lib_range->core_requests.last = wire_range->coreRequestsLast;
385 lib_range->core_replies.first = wire_range->coreRepliesFirst;
386 lib_range->core_replies.last = wire_range->coreRepliesLast;
387 lib_range->ext_requests.ext_major.first = wire_range->extRequestsMajorFirst;
388 lib_range->ext_requests.ext_major.last = wire_range->extRequestsMajorLast;
389 lib_range->ext_requests.ext_minor.first = wire_range->extRequestsMinorFirst;
390 lib_range->ext_requests.ext_minor.last = wire_range->extRequestsMinorLast;
391 lib_range->ext_replies.ext_major.first = wire_range->extRepliesMajorFirst;
392 lib_range->ext_replies.ext_major.last = wire_range->extRepliesMajorLast;
393 lib_range->ext_replies.ext_minor.first = wire_range->extRepliesMinorFirst;
394 lib_range->ext_replies.ext_minor.last = wire_range->extRepliesMinorLast;
395 lib_range->delivered_events.first = wire_range->deliveredEventsFirst;
396 lib_range->delivered_events.last = wire_range->deliveredEventsLast;
397 lib_range->device_events.first = wire_range->deviceEventsFirst;
398 lib_range->device_events.last = wire_range->deviceEventsLast;
399 lib_range->errors.first = wire_range->errorsFirst;
400 lib_range->errors.last = wire_range->errorsLast;
401 lib_range->client_started = wire_range->clientStarted;
402 lib_range->client_died = wire_range->clientDied;
403}
404
405Statusint
406XRecordGetContext(Display *dpy, XRecordContext context,
407 XRecordState **state_return)
408{
409 XExtDisplayInfo *info = find_display (dpy);
410 register xRecordGetContextReq *req;
411 xRecordGetContextReply rep;
412 unsigned int count, i, rn;
413 xRecordRange xrange;
414 xRecordClientInfo xclient_inf;
415 XRecordState *ret;
416
417 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
418 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
419 GetReq(RecordGetContext, req)req = (xRecordGetContextReq *) _XGetRequest(dpy, 4, 8);
420 req->reqType = info->codes->major_opcode;
421 req->recordReqType = X_RecordGetContext4;
422 req->context = context;
423 if (!_XReply(dpy,(xReply *)&rep, 0, False0)) {
1
Taking false branch
424 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
425 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
426 return 0;
427 }
428 count = rep.nClients;
429
430 ret = (XRecordState*)Xmalloc(sizeof(XRecordState))malloc(((sizeof(XRecordState)) == 0 ? 1 : (sizeof(XRecordState
))))
;
431 if (!ret) {
2
Assuming 'ret' is non-null
3
Taking false branch
432 _XEatDataWords (dpy, rep.length);
433 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
434 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
435 return 0;
436 }
437
438 ret->enabled = rep.enabled;
439 ret->datum_flags = rep.elementHeader;
440 ret->nclients = count;
441
442 if (count)
4
Assuming 'count' is not equal to 0
5
Taking true branch
443 {
444 XRecordClientInfo **client_inf = NULL((void*)0);
6
'client_inf' initialized to a null pointer value
445 XRecordClientInfo *client_inf_str = NULL((void*)0);
446
447 if (count < (INT_MAX2147483647 / sizeof(XRecordClientInfo))) {
7
Taking false branch
448 client_inf = Xcalloc(count, sizeof(XRecordClientInfo *))calloc(((count) == 0 ? 1 : (count)), (sizeof(XRecordClientInfo
*)))
;
449 if (client_inf != NULL((void*)0))
450 client_inf_str = Xmalloc(count * sizeof(XRecordClientInfo))malloc(((count * sizeof(XRecordClientInfo)) == 0 ? 1 : (count
* sizeof(XRecordClientInfo))))
;
451 }
452 ret->client_info = client_inf;
8
Null pointer value stored to field 'client_info'
453 if (!client_inf || !client_inf_str)
454 {
455 free(client_inf);
456 _XEatDataWords (dpy, rep.length);
457 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
458 XRecordFreeState(ret);
9
Calling 'XRecordFreeState'
459 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
460 return 0;
461 }
462 for(i = 0; i < count; i++)
463 {
464 client_inf[i] = &(client_inf_str[i]);
465 _XRead(dpy, (char *)&xclient_inf, (long)sizeof(xRecordClientInfo));
466 client_inf_str[i].client = xclient_inf.clientResource;
467 client_inf_str[i].nranges = xclient_inf.nRanges;
468
469 if (xclient_inf.nRanges)
470 {
471 XRecordRange *ranges = NULL((void*)0);
472
473 if (xclient_inf.nRanges < (INT_MAX2147483647 / sizeof(XRecordRange))) {
474 client_inf_str[i].ranges =
475 Xcalloc(xclient_inf.nRanges, sizeof(XRecordRange *))calloc(((xclient_inf.nRanges) == 0 ? 1 : (xclient_inf.nRanges
)), (sizeof(XRecordRange *)))
;
476 if (client_inf_str[i].ranges != NULL((void*)0))
477 ranges =
478 Xmalloc(xclient_inf.nRanges * sizeof(XRecordRange))malloc(((xclient_inf.nRanges * sizeof(XRecordRange)) == 0 ? 1
: (xclient_inf.nRanges * sizeof(XRecordRange))))
;
479 }
480 else
481 client_inf_str[i].ranges = NULL((void*)0);
482
483 if (!client_inf_str[i].ranges || !ranges) {
484 /* XXX eat data */
485 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
486 XRecordFreeState(ret);
487 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
488 return 0;
489 }
490 for (rn=0; rn<xclient_inf.nRanges; rn++) {
491 client_inf_str[i].ranges[rn] = &(ranges[rn]);
492 _XRead(dpy, (char *)&xrange, (long)sizeof(xRecordRange));
493 WireToLibRange(&xrange, &(ranges[rn]));
494 }
495 } else {
496 client_inf_str[i].ranges = NULL((void*)0);
497 }
498 }
499 } else {
500 ret->client_info = NULL((void*)0);
501 }
502
503 *state_return = ret;
504
505 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
506 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
507 return 1;
508}
509
510void
511XRecordFreeState(XRecordState *state)
512{
513 int i;
514
515 for(i=0; i<state->nclients; i++) {
10
Loop condition is true. Entering loop body
516 if (state->client_info[i]->ranges) {
11
Array access (via field 'client_info') results in a null pointer dereference
517 if (state->client_info[i]->ranges[0])
518 Xfree(state->client_info[i]->ranges[0])free((state->client_info[i]->ranges[0]));
519 Xfree(state->client_info[i]->ranges)free((state->client_info[i]->ranges));
520 }
521 }
522 if (state->client_info) {
523 if (state->client_info[0])
524 Xfree(state->client_info[0])free((state->client_info[0]));
525 Xfree(state->client_info)free((state->client_info));
526 }
527 Xfree(state)free((state));
528}
529
530static struct reply_buffer *alloc_reply_buffer(
531 XExtDisplayInfo *info,
532 int nbytes)
533{
534 struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
535 struct reply_buffer *rbp;
536 struct reply_buffer *saved_rb = NULL((void*)0);
537 /*
538 * First look for an allocated buffer that is not in use.
539 * If we have a big enough buffer, use that, otherwise
540 * realloc an existing one.
541 */
542 for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) {
543 if (rbp->ref_count == 0) {
544 if (rbp->nbytes >= nbytes)
545 return rbp;
546 else
547 saved_rb = rbp;
548 }
549 }
550 if (saved_rb) {
551 saved_rb->buf = (unsigned char *)Xrealloc(saved_rb->buf, nbytes)realloc((saved_rb->buf), ((nbytes) == 0 ? 1 : (nbytes)));
552 if (!saved_rb->buf) {
553 saved_rb->nbytes = 0;
554 return NULL((void*)0);
555 }
556 saved_rb->nbytes = nbytes;
557 return saved_rb;
558 }
559
560 /*
561 * nothing available; malloc a new struct
562 */
563 rbp = (struct reply_buffer *)Xmalloc(sizeof(struct reply_buffer))malloc(((sizeof(struct reply_buffer)) == 0 ? 1 : (sizeof(struct
reply_buffer))))
;
564 if (!rbp)
565 return NULL((void*)0);
566 rbp->buf = (unsigned char *)Xmalloc(nbytes)malloc(((nbytes) == 0 ? 1 : (nbytes)));
567 if (!rbp->buf) {
568 Xfree(rbp)free((rbp));
569 return NULL((void*)0);
570 }
571 rbp->nbytes = nbytes;
572 rbp->ref_count = 0;
573 rbp->next = cache->reply_buffers;
574 cache->reply_buffers = rbp;
575 return rbp;
576}
577
578static XRecordInterceptData *alloc_inter_data(XExtDisplayInfo *info)
579{
580 struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
581 struct intercept_queue *iq;
582
583 /* if there is one on the free list, pop it */
584 if (cache->inter_data) {
585 iq = cache->inter_data;
586 cache->inter_data = iq->next;
587 return &iq->data;
588 }
589 /* allocate a new one */
590 iq = (struct intercept_queue *)Xmalloc(sizeof(struct intercept_queue))malloc(((sizeof(struct intercept_queue)) == 0 ? 1 : (sizeof(struct
intercept_queue))))
;
591 if (!iq)
592 return NULL((void*)0);
593 iq->cache = cache;
594 cache->inter_data_count++;
595 return &iq->data;
596}
597
598void
599XRecordFreeData(XRecordInterceptData *data)
600{
601 /* we can do this cast because that is what we really allocated */
602 struct intercept_queue *iq = (struct intercept_queue *)data;
603 struct reply_buffer *rbp = NULL((void*)0);
604 struct mem_cache_str *cache = iq->cache;
605
606 /*
607 * figure out what reply_buffer this points at
608 * and decrement its ref_count.
609 */
610 if (data->data) {
611
612 for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) {
613 if (data->data >= rbp->buf
614 && data->data < rbp->buf + rbp->nbytes)
615 {
616 assert(rbp->ref_count > 0)(__builtin_expect(!(rbp->ref_count > 0), 0) ? __assert_rtn
(__func__, "XRecord.c", 616, "rbp->ref_count > 0") : (void
)0)
;
617 rbp->ref_count--;
618 break;
619 }
620 }
621 /* it's an error if we didn't find something to free */
622 assert(rbp)(__builtin_expect(!(rbp), 0) ? __assert_rtn(__func__, "XRecord.c"
, 622, "rbp") : (void)0)
;
623 }
624 /*
625 * If the display is still open, put this back on the free queue.
626 *
627 * Otherwise the display is closed and we won't reuse this, so free it.
628 * See if we can free the reply buffer, too.
629 * If we can, see if this is the last reply buffer and if so
630 * free the list of reply buffers.
631 */
632 if (cache->display_closed == False0) {
633 iq->next = cache->inter_data;
634 cache->inter_data = iq;
635 } else {
636 if (rbp && rbp->ref_count == 0) {
637 struct reply_buffer *rbp2, **rbp_next_p;
638
639 /* Have to search the list again to find the prev element.
640 This is not the common case, so don't slow down the code
641 above by doing it then. */
642 for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) {
643 rbp2 = *rbp_next_p;
644 if (rbp == rbp2) {
645 *rbp_next_p = rbp2->next;
646 break;
647 } else {
648 rbp_next_p = &rbp2->next;
649 }
650 }
651 XFree(rbp->buf);
652 XFree(rbp);
653 }
654
655 XFree(iq);
656 cache->inter_data_count--;
657
658 if (cache->reply_buffers == NULL((void*)0) && cache->inter_data_count == 0) {
659 XFree(cache); /* all finished */
660 }
661 }
662}
663
664/* the EXTRACT macros are adapted from ICElibint.h */
665
666#ifndef WORD64
667
668#define EXTRACT_CARD16(swap, src, dst){ (dst) = *((CARD16 *) (src)); if (swap) (dst) = ((((dst) &
0xff) << 8) | (((dst) >> 8) & 0xff)); }
\
669{ \
670 (dst) = *((CARD16 *) (src)); \
671 if (swap) \
672 (dst) = lswaps (dst)((((dst) & 0xff) << 8) | (((dst) >> 8) & 0xff
))
; \
673}
674
675#define EXTRACT_CARD32(swap, src, dst){ (dst) = *((CARD32 *) (src)); if (swap) (dst) = ((((dst) &
0xff) << 24) | (((dst) & 0xff00) << 8) | (((
dst) & 0xff0000) >> 8) | (((dst) >> 24) &
0xff)); }
\
676{ \
677 (dst) = *((CARD32 *) (src)); \
678 if (swap) \
679 (dst) = lswapl (dst)((((dst) & 0xff) << 24) | (((dst) & 0xff00) <<
8) | (((dst) & 0xff0000) >> 8) | (((dst) >> 24
) & 0xff))
; \
680}
681
682#else /* WORD64 */
683
684#define EXTRACT_CARD16(swap, src, dst){ (dst) = *((CARD16 *) (src)); if (swap) (dst) = ((((dst) &
0xff) << 8) | (((dst) >> 8) & 0xff)); }
\
685{ \
686 (dst) = *((src) + 0); \
687 (dst) <<= 8; \
688 (dst) |= *((src) + 1); \
689 if (swap) \
690 (dst) = lswaps (dst)((((dst) & 0xff) << 8) | (((dst) >> 8) & 0xff
))
; \
691}
692
693#define EXTRACT_CARD32(swap, src, dst){ (dst) = *((CARD32 *) (src)); if (swap) (dst) = ((((dst) &
0xff) << 24) | (((dst) & 0xff00) << 8) | (((
dst) & 0xff0000) >> 8) | (((dst) >> 24) &
0xff)); }
\
694{ \
695 (dst) = *((src) + 0); \
696 (dst) <<= 8; \
697 (dst) |= *((src) + 1); \
698 (dst) <<= 8; \
699 (dst) |= *((src) + 2); \
700 (dst) <<= 8; \
701 (dst) |= *((src) + 3); \
702 if (swap) \
703 (dst) = lswapl (dst)((((dst) & 0xff) << 24) | (((dst) & 0xff00) <<
8) | (((dst) & 0xff0000) >> 8) | (((dst) >> 24
) & 0xff))
; \
704}
705
706#endif /* WORD64 */
707
708/* byte swapping macros from xfs/include/misc.h */
709
710/* byte swap a long literal */
711#define lswapl(x)((((x) & 0xff) << 24) | (((x) & 0xff00) <<
8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) &
0xff))
((((x) & 0xff) << 24) |\
712 (((x) & 0xff00) << 8) |\
713 (((x) & 0xff0000) >> 8) |\
714 (((x) >> 24) & 0xff))
715
716/* byte swap a short literal */
717#define lswaps(x)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff
))
((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
718
719enum parser_return { Continue, End, Error };
720
721static enum parser_return
722parse_reply_call_callback(
723 Display *dpy,
724 XExtDisplayInfo *info,
725 xRecordEnableContextReply *rep,
726 struct reply_buffer *reply,
727 XRecordInterceptProc callback,
728 XPointer closure)
729{
730 int current_index;
731 int datum_bytes = 0;
732 XRecordInterceptData *data;
733
734 /* call the callback for each protocol element in the reply */
735 current_index = 0;
736 do {
737 data = alloc_inter_data(info);
738 if (!data)
739 return Error;
740
741 data->id_base = rep->idBase;
742 data->category = rep->category;
743 data->client_swapped = rep->clientSwapped;
744 data->server_time = rep->serverTime;
745 data->client_seq = rep->recordedSequenceNumber;
746 /*
747 * compute the size of this protocol element.
748 */
749 switch (rep->category) {
750 case XRecordFromServer0:
751 if (rep->elementHeader&XRecordFromServerTime0x01) {
752 EXTRACT_CARD32(rep->clientSwapped,{ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
753 reply->buf+current_index,{ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
754 data->server_time){ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
;
755 current_index += 4;
756 }
757 switch (reply->buf[current_index]) {
758 case X_Reply1: /* reply */
759 EXTRACT_CARD32(rep->clientSwapped,{ (datum_bytes) = *((CARD32 *) (reply->buf+current_index+4
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 24) | (((datum_bytes) & 0xff00) <<
8) | (((datum_bytes) & 0xff0000) >> 8) | (((datum_bytes
) >> 24) & 0xff)); }
760 reply->buf+current_index+4, datum_bytes){ (datum_bytes) = *((CARD32 *) (reply->buf+current_index+4
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 24) | (((datum_bytes) & 0xff00) <<
8) | (((datum_bytes) & 0xff0000) >> 8) | (((datum_bytes
) >> 24) & 0xff)); }
;
761 datum_bytes = (datum_bytes+8) << 2;
762 break;
763 default: /* error or event */
764 datum_bytes = 32;
765 }
766 break;
767 case XRecordFromClient1:
768 if (rep->elementHeader&XRecordFromClientTime0x02) {
769 EXTRACT_CARD32(rep->clientSwapped,{ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
770 reply->buf+current_index,{ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
771 data->server_time){ (data->server_time) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->server_time) = ((((data
->server_time) & 0xff) << 24) | (((data->server_time
) & 0xff00) << 8) | (((data->server_time) & 0xff0000
) >> 8) | (((data->server_time) >> 24) & 0xff
)); }
;
772 current_index += 4;
773 }
774 if (rep->elementHeader&XRecordFromClientSequence0x04) {
775 EXTRACT_CARD32(rep->clientSwapped,{ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
776 reply->buf+current_index,{ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
777 data->client_seq){ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
;
778 current_index += 4;
779 }
780 if (reply->buf[current_index+2] == 0
781 && reply->buf[current_index+3] == 0) /* needn't swap 0 */
782 { /* BIG-REQUESTS */
783 EXTRACT_CARD32(rep->clientSwapped,{ (datum_bytes) = *((CARD32 *) (reply->buf+current_index+4
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 24) | (((datum_bytes) & 0xff00) <<
8) | (((datum_bytes) & 0xff0000) >> 8) | (((datum_bytes
) >> 24) & 0xff)); }
784 reply->buf+current_index+4, datum_bytes){ (datum_bytes) = *((CARD32 *) (reply->buf+current_index+4
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 24) | (((datum_bytes) & 0xff00) <<
8) | (((datum_bytes) & 0xff0000) >> 8) | (((datum_bytes
) >> 24) & 0xff)); }
;
785 } else {
786 EXTRACT_CARD16(rep->clientSwapped,{ (datum_bytes) = *((CARD16 *) (reply->buf+current_index+2
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 8) | (((datum_bytes) >> 8) &
0xff)); }
787 reply->buf+current_index+2, datum_bytes){ (datum_bytes) = *((CARD16 *) (reply->buf+current_index+2
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 8) | (((datum_bytes) >> 8) &
0xff)); }
;
788 }
789 datum_bytes <<= 2;
790 break;
791 case XRecordClientStarted2:
792 EXTRACT_CARD16(rep->clientSwapped,{ (datum_bytes) = *((CARD16 *) (reply->buf+current_index+6
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 8) | (((datum_bytes) >> 8) &
0xff)); }
793 reply->buf+current_index+6, datum_bytes){ (datum_bytes) = *((CARD16 *) (reply->buf+current_index+6
)); if (rep->clientSwapped) (datum_bytes) = ((((datum_bytes
) & 0xff) << 8) | (((datum_bytes) >> 8) &
0xff)); }
;
794 datum_bytes = (datum_bytes+2) << 2;
795 break;
796 case XRecordClientDied3:
797 if (rep->elementHeader&XRecordFromClientSequence0x04) {
798 EXTRACT_CARD32(rep->clientSwapped,{ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
799 reply->buf+current_index,{ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
800 data->client_seq){ (data->client_seq) = *((CARD32 *) (reply->buf+current_index
)); if (rep->clientSwapped) (data->client_seq) = ((((data
->client_seq) & 0xff) << 24) | (((data->client_seq
) & 0xff00) << 8) | (((data->client_seq) & 0xff0000
) >> 8) | (((data->client_seq) >> 24) & 0xff
)); }
;
801 current_index += 4;
802 }
803 /* fall through */
804 case XRecordStartOfData4:
805 case XRecordEndOfData5:
806 datum_bytes = 0;
807 }
808
809 if (datum_bytes > 0) {
810 if (current_index + datum_bytes > rep->length << 2)
811 fprintf(stderr__stderrp,
812 "XRecord: %lu-byte reply claims %d-byte element (seq %lu)\n",
813 (long)rep->length << 2, current_index + datum_bytes,
814 dpy->last_request_read);
815 /*
816 * This assignment (and indeed the whole buffer sharing
817 * scheme) assumes arbitrary 4-byte boundaries are
818 * addressable.
819 */
820 data->data = reply->buf+current_index;
821 reply->ref_count++;
822 } else {
823 data->data = NULL((void*)0);
824 }
825 data->data_len = datum_bytes >> 2;
826
827 (*callback)(closure, data);
828
829 current_index += datum_bytes;
830 } while (current_index<rep->length<<2);
831
832 if (rep->category == XRecordEndOfData5)
833 return End;
834
835 return Continue;
836}
837
838Statusint
839XRecordEnableContext(Display *dpy, XRecordContext context,
840 XRecordInterceptProc callback, XPointer closure)
841{
842 XExtDisplayInfo *info = find_display (dpy);
843 register xRecordEnableContextReq *req;
844 xRecordEnableContextReply rep;
845 struct reply_buffer *reply;
846 enum parser_return status;
847
848 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
849 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
850 GetReq(RecordEnableContext, req)req = (xRecordEnableContextReq *) _XGetRequest(dpy, 5, 8);
851
852 req->reqType = info->codes->major_opcode;
853 req->recordReqType = X_RecordEnableContext5;
854 req->context = context;
855
856 while (1)
857 {
858 /* This code should match that in XRecordEnableContextAsync */
859 if (!_XReply (dpy, (xReply *)&rep, 0, xFalse0))
860 {
861 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
862 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
863 return 0;
864 }
865
866 if (rep.length > 0) {
867 reply = alloc_reply_buffer(info, rep.length<<2);
868 if (!reply) {
869 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
870 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
871 return 0;
872 }
873 _XRead (dpy, (char *)reply->buf, rep.length<<2);
874 } else {
875 reply = NULL((void*)0);
876 }
877
878 status = parse_reply_call_callback(dpy, info, &rep, reply,
879 callback, closure);
880 switch (status) {
881 case Continue:
882 break;
883 case End:
884 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
885 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
886 return 1;
887 case Error:
888 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
889 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
890 return 0;
891 }
892 }
893}
894
895
896typedef struct _record_async_state
897{
898 unsigned long enable_seq;
899 _XAsyncHandler *async;
900 _XAsyncErrorState *error_state;
901 XExtDisplayInfo *info;
902 XRecordInterceptProc callback;
903 XPointer closure;
904} record_async_state;
905
906static Boolint
907record_async_handler(
908 register Display *dpy,
909 register xReply *rep,
910 char *buf,
911 int len,
912 XPointer adata)
913{
914 register record_async_state *state = (record_async_state *)adata;
915 struct reply_buffer *reply;
916 enum parser_return status;
917
918 if (dpy->last_request_read != state->enable_seq)
919 {
920 if (dpy->last_request_read > state->enable_seq) {
921 /* it is an error that we are still on the handler list */
922 fprintf(stderr__stderrp, "XRecord: handler for seq %lu never saw XRecordEndOfData. (seq now %lu)\n",
923 state->enable_seq, dpy->last_request_read);
924 DeqAsyncHandler(dpy, state->async){ if (dpy->async_handlers == (state->async)) dpy->async_handlers
= (state->async)->next; else _XDeqAsyncHandler(dpy, state
->async); }
;
925 Xfree(state->async)free((state->async));
926 }
927 return False0;
928 }
929 if (rep->generic.type == X_Error0)
930 {
931 DeqAsyncHandler(dpy, state->async){ if (dpy->async_handlers == (state->async)) dpy->async_handlers
= (state->async)->next; else _XDeqAsyncHandler(dpy, state
->async); }
;
932 Xfree(state->async)free((state->async));
933 return False0;
934 }
935
936 if (rep->generic.length > 0) {
937 reply = alloc_reply_buffer(state->info, rep->generic.length<<2);
938
939 if (!reply) {
940 DeqAsyncHandler(dpy, state->async){ if (dpy->async_handlers == (state->async)) dpy->async_handlers
= (state->async)->next; else _XDeqAsyncHandler(dpy, state
->async); }
;
941 Xfree(state->async)free((state->async));
942 return False0;
943 }
944
945 _XGetAsyncData(dpy, (char *)reply->buf, buf, len,
946 SIZEOF(xRecordEnableContextReply)32,
947 rep->generic.length << 2, 0);
948 } else {
949 reply = NULL((void*)0);
950 }
951
952 status = parse_reply_call_callback(dpy, state->info,
953 (xRecordEnableContextReply*) rep,
954 reply, state->callback, state->closure);
955
956 if (status != Continue)
957 {
958 DeqAsyncHandler(dpy, state->async){ if (dpy->async_handlers == (state->async)) dpy->async_handlers
= (state->async)->next; else _XDeqAsyncHandler(dpy, state
->async); }
;
959 Xfree(state->async)free((state->async));
960 if (status == Error)
961 return False0;
962 }
963
964 return True1;
965}
966
967/*
968 * reads the first reply, StartOfData, synchronously,
969 * then returns allowing the app to call XRecordProcessReplies
970 * to get the rest.
971 */
972Statusint
973XRecordEnableContextAsync(Display *dpy, XRecordContext context,
974 XRecordInterceptProc callback, XPointer closure)
975{
976 XExtDisplayInfo *info = find_display (dpy);
977 register xRecordEnableContextReq *req;
978 xRecordEnableContextReply rep;
979 struct reply_buffer *reply;
980 enum parser_return status;
981 _XAsyncHandler *async;
982 record_async_state *async_state;
983
984 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
985 async = (_XAsyncHandler *)Xmalloc(sizeof(_XAsyncHandler) +malloc(((sizeof(_XAsyncHandler) + sizeof(record_async_state))
== 0 ? 1 : (sizeof(_XAsyncHandler) + sizeof(record_async_state
))))
986 sizeof(record_async_state))malloc(((sizeof(_XAsyncHandler) + sizeof(record_async_state))
== 0 ? 1 : (sizeof(_XAsyncHandler) + sizeof(record_async_state
))))
;
987 if (!async)
988 return 0;
989 async_state = (record_async_state *)(async + 1);
990
991 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
992 GetReq(RecordEnableContext, req)req = (xRecordEnableContextReq *) _XGetRequest(dpy, 5, 8);
993
994 req->reqType = info->codes->major_opcode;
995 req->recordReqType = X_RecordEnableContext5;
996 req->context = context;
997
998 /* Get the StartOfData reply. */
999 /* This code should match that in XRecordEnableContext */
1000 if (!_XReply (dpy, (xReply *)&rep, 0, xFalse0))
1001 {
1002 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
1003 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
1004 Xfree(async)free((async));
1005 return 0;
1006 }
1007
1008 /* this had better be a StartOfData, which has no extra data. */
1009 if (rep.length != 0) {
1010 fprintf(stderr__stderrp, "XRecord: malformed StartOfData for sequence %lu\n",
1011 dpy->last_request_read);
1012 }
1013 reply = NULL((void*)0);
1014
1015 status = parse_reply_call_callback(dpy, info, &rep, reply,
1016 callback, closure);
1017 if (status != Continue)
1018 {
1019 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
1020 Xfree(async)free((async));
1021 return 0;
1022 }
1023
1024 /* hook in the async handler for the rest of the replies */
1025 async_state->enable_seq = dpy->request;
1026 async_state->async = async;
1027 async_state->info = info;
1028 async_state->callback = callback;
1029 async_state->closure = closure;
1030
1031 async->next = dpy->async_handlers;
1032 async->handler = record_async_handler;
1033 async->data = (XPointer)async_state;
1034 dpy->async_handlers = async;
1035
1036 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
1037 /* Don't invoke SyncHandle here, since this is an async
1038 function. Does this break XSetAfterFunction() ? */
1039 return 1;
1040}
1041
1042void
1043XRecordProcessReplies(Display *dpy)
1044{
1045 (void) XPending(dpy);
1046}
1047
1048Statusint
1049XRecordDisableContext(Display *dpy, XRecordContext context)
1050{
1051 XExtDisplayInfo *info = find_display (dpy);
1052 register xRecordDisableContextReq *req;
1053
1054 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
1055 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
1056 GetReq(RecordDisableContext, req)req = (xRecordDisableContextReq *) _XGetRequest(dpy, 6, 8);
1057 req->reqType = info->codes->major_opcode;
1058 req->recordReqType = X_RecordDisableContext6;
1059 req->context = context;
1060
1061 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
1062 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
1063 return 1;
1064}
1065
1066Statusint
1067XRecordFreeContext(Display *dpy, XRecordContext context)
1068{
1069 XExtDisplayInfo *info = find_display (dpy);
1070 register xRecordFreeContextReq *req;
1071
1072 XRecordCheckExtension (dpy, info, 0)if (!((info) && ((info)->codes))) { XMissingExtension
(dpy, xrecord_extension_name); return 0; }
;
1073
1074 LockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
1075 GetReq(RecordFreeContext, req)req = (xRecordFreeContextReq *) _XGetRequest(dpy, 7, 8);
1076 req->reqType = info->codes->major_opcode;
1077 req->recordReqType = X_RecordFreeContext7;
1078 req->context = context;
1079
1080 UnlockDisplay(dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
1081 SyncHandle()if (dpy->synchandler) (*dpy->synchandler)(dpy);
1082 return 1;
1083}