Bug Summary

File:mi/mieq.c
Location:line 515, column 9
Description:Dereference of null pointer

Annotated Source Code

1/*
2 *
3Copyright 1990, 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 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: Keith Packard, MIT X Consortium
26 */
27
28/*
29 * mieq.c
30 *
31 * Machine independent event queue
32 *
33 */
34
35#if HAVE_DIX_CONFIG_H1
36#include <dix-config.h>
37#endif
38
39#include <X11/X.h>
40#include <X11/Xmd.h>
41#include <X11/Xproto.h>
42#include "misc.h"
43#include "windowstr.h"
44#include "pixmapstr.h"
45#include "inputstr.h"
46#include "inpututils.h"
47#include "mi.h"
48#include "mipointer.h"
49#include "scrnintstr.h"
50#include <X11/extensions/XI.h>
51#include <X11/extensions/XIproto.h>
52#include <X11/extensions/geproto.h>
53#include "extinit.h"
54#include "exglobals.h"
55#include "eventstr.h"
56
57#ifdef DPMSExtension
58#include "dpmsproc.h"
59#include <X11/extensions/dpmsconst.h>
60#endif
61
62/* Maximum size should be initial size multiplied by a power of 2 */
63#define QUEUE_INITIAL_SIZE512 512
64#define QUEUE_RESERVED_SIZE64 64
65#define QUEUE_MAXIMUM_SIZE4096 4096
66#define QUEUE_DROP_BACKTRACE_FREQUENCY100 100
67#define QUEUE_DROP_BACKTRACE_MAX10 10
68
69#define EnqueueScreen(dev)dev->spriteInfo->sprite->pEnqueueScreen dev->spriteInfo->sprite->pEnqueueScreen
70#define DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen dev->spriteInfo->sprite->pDequeueScreen
71
72typedef struct _Event {
73 InternalEvent *events;
74 ScreenPtr pScreen;
75 DeviceIntPtr pDev; /* device this event _originated_ from */
76} EventRec, *EventPtr;
77
78typedef struct _EventQueue {
79 HWEventQueueType head, tail; /* long for SetInputCheck */
80 CARD32 lastEventTime; /* to avoid time running backwards */
81 int lastMotion; /* device ID if last event motion? */
82 EventRec *events; /* our queue as an array */
83 size_t nevents; /* the number of buckets in our queue */
84 size_t dropped; /* counter for number of consecutive dropped events */
85 mieqHandler handlers[128]; /* custom event handler */
86} EventQueueRec, *EventQueuePtr;
87
88static EventQueueRec miEventQueue;
89
90#ifdef XQUARTZ1
91extern BOOL serverRunning;
92extern pthread_mutex_t serverRunningMutex;
93extern pthread_cond_t serverRunningCond;
94
95static inline void
96wait_for_server_init(void)
97{
98 /* If the server hasn't finished initializing, wait for it... */
99 if (!serverRunning) {
100 pthread_mutex_lock(&serverRunningMutex);
101 while (!serverRunning)
102 pthread_cond_wait(&serverRunningCond, &serverRunningMutex);
103 pthread_mutex_unlock(&serverRunningMutex);
104 }
105}
106#endif
107
108static size_t
109mieqNumEnqueued(EventQueuePtr eventQueue)
110{
111 size_t n_enqueued = 0;
112
113 if (eventQueue->nevents) {
114 /* % is not well-defined with negative numbers... sigh */
115 n_enqueued = eventQueue->tail - eventQueue->head + eventQueue->nevents;
116 if (n_enqueued >= eventQueue->nevents)
117 n_enqueued -= eventQueue->nevents;
118 }
119 return n_enqueued;
120}
121
122/* Pre-condition: Called with input_lock held */
123static Bool
124mieqGrowQueue(EventQueuePtr eventQueue, size_t new_nevents)
125{
126 size_t i, n_enqueued, first_hunk;
127 EventRec *new_events;
128
129 if (!eventQueue) {
130 ErrorF("[mi] mieqGrowQueue called with a NULL eventQueue\n");
131 return FALSE0;
132 }
133
134 if (new_nevents <= eventQueue->nevents)
135 return FALSE0;
136
137 new_events = calloc(new_nevents, sizeof(EventRec));
138 if (new_events == NULL((void*)0)) {
139 ErrorF("[mi] mieqGrowQueue memory allocation error.\n");
140 return FALSE0;
141 }
142
143 n_enqueued = mieqNumEnqueued(eventQueue);
144
145 /* First copy the existing events */
146 first_hunk = eventQueue->nevents - eventQueue->head;
147 memcpy(new_events,__builtin___memcpy_chk (new_events, &eventQueue->events
[eventQueue->head], first_hunk * sizeof(EventRec), __builtin_object_size
(new_events, 0))
148 &eventQueue->events[eventQueue->head],__builtin___memcpy_chk (new_events, &eventQueue->events
[eventQueue->head], first_hunk * sizeof(EventRec), __builtin_object_size
(new_events, 0))
149 first_hunk * sizeof(EventRec))__builtin___memcpy_chk (new_events, &eventQueue->events
[eventQueue->head], first_hunk * sizeof(EventRec), __builtin_object_size
(new_events, 0))
;
150 memcpy(&new_events[first_hunk],__builtin___memcpy_chk (&new_events[first_hunk], eventQueue
->events, eventQueue->head * sizeof(EventRec), __builtin_object_size
(&new_events[first_hunk], 0))
151 eventQueue->events, eventQueue->head * sizeof(EventRec))__builtin___memcpy_chk (&new_events[first_hunk], eventQueue
->events, eventQueue->head * sizeof(EventRec), __builtin_object_size
(&new_events[first_hunk], 0))
;
152
153 /* Initialize the new portion */
154 for (i = eventQueue->nevents; i < new_nevents; i++) {
155 InternalEvent *evlist = InitEventList(1);
156
157 if (!evlist) {
158 size_t j;
159
160 for (j = 0; j < i; j++)
161 FreeEventList(new_events[j].events, 1);
162 free(new_events);
163 OsReleaseSignals();
164 return FALSE0;
165 }
166 new_events[i].events = evlist;
167 }
168
169 /* And update our record */
170 eventQueue->tail = n_enqueued;
171 eventQueue->head = 0;
172 eventQueue->nevents = new_nevents;
173 free(eventQueue->events);
174 eventQueue->events = new_events;
175
176 return TRUE1;
177}
178
179Bool
180mieqInit(void)
181{
182 memset(&miEventQueue, 0, sizeof(miEventQueue))__builtin___memset_chk (&miEventQueue, 0, sizeof(miEventQueue
), __builtin_object_size (&miEventQueue, 0))
;
183 miEventQueue.lastEventTime = GetTimeInMillis();
184
185 input_lock();
186 if (!mieqGrowQueue(&miEventQueue, QUEUE_INITIAL_SIZE512))
187 FatalError("Could not allocate event queue.\n");
188 input_unlock();
189
190 SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
191 return TRUE1;
192}
193
194void
195mieqFini(void)
196{
197 int i;
198
199 for (i = 0; i < miEventQueue.nevents; i++) {
200 if (miEventQueue.events[i].events != NULL((void*)0)) {
201 FreeEventList(miEventQueue.events[i].events, 1);
202 miEventQueue.events[i].events = NULL((void*)0);
203 }
204 }
205 free(miEventQueue.events);
206}
207
208/*
209 * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue
210 * will never be interrupted. Must be called with input_lock held
211 */
212
213void
214mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
215{
216 unsigned int oldtail = miEventQueue.tail;
217 InternalEvent *evt;
218 int isMotion = 0;
219 int evlen;
220 Time time;
221 size_t n_enqueued;
222
223#ifdef XQUARTZ1
224 wait_for_server_init();
225#endif
226
227 verify_internal_event(e);
228
229 n_enqueued = mieqNumEnqueued(&miEventQueue);
230
231 /* avoid merging events from different devices */
232 if (e->any.type == ET_Motion)
233 isMotion = pDev->id;
234
235 if (isMotion && isMotion == miEventQueue.lastMotion &&
236 oldtail != miEventQueue.head) {
237 oldtail = (oldtail - 1) % miEventQueue.nevents;
238 }
239 else if (n_enqueued + 1 == miEventQueue.nevents) {
240 if (!mieqGrowQueue(&miEventQueue, miEventQueue.nevents << 1)) {
241 /* Toss events which come in late. Usually this means your server's
242 * stuck in an infinite loop somewhere, but SIGIO is still getting
243 * handled.
244 */
245 miEventQueue.dropped++;
246 if (miEventQueue.dropped == 1) {
247 ErrorFSigSafe("[mi] EQ overflowing. Additional events will be "
248 "discarded until existing events are processed.\n");
249 xorg_backtrace();
250 ErrorFSigSafe("[mi] These backtraces from mieqEnqueue may point to "
251 "a culprit higher up the stack.\n");
252 ErrorFSigSafe("[mi] mieq is *NOT* the cause. It is a victim.\n");
253 }
254 else if (miEventQueue.dropped % QUEUE_DROP_BACKTRACE_FREQUENCY100 == 0 &&
255 miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY100 <=
256 QUEUE_DROP_BACKTRACE_MAX10) {
257 ErrorFSigSafe("[mi] EQ overflow continuing. %zu events have been "
258 "dropped.\n", miEventQueue.dropped);
259 if (miEventQueue.dropped / QUEUE_DROP_BACKTRACE_FREQUENCY100 ==
260 QUEUE_DROP_BACKTRACE_MAX10) {
261 ErrorFSigSafe("[mi] No further overflow reports will be "
262 "reported until the clog is cleared.\n");
263 }
264 xorg_backtrace();
265 }
266 return;
267 }
268 oldtail = miEventQueue.tail;
269 }
270
271 evlen = e->any.length;
272 evt = miEventQueue.events[oldtail].events;
273 memcpy(evt, e, evlen)__builtin___memcpy_chk (evt, e, evlen, __builtin_object_size (
evt, 0))
;
274
275 time = e->any.time;
276 /* Make sure that event times don't go backwards - this
277 * is "unnecessary", but very useful. */
278 if (time < miEventQueue.lastEventTime &&
279 miEventQueue.lastEventTime - time < 10000)
280 e->any.time = miEventQueue.lastEventTime;
281
282 miEventQueue.lastEventTime = evt->any.time;
283 miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev)pDev->spriteInfo->sprite->pEnqueueScreen : NULL((void*)0);
284 miEventQueue.events[oldtail].pDev = pDev;
285
286 miEventQueue.lastMotion = isMotion;
287 miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
288}
289
290/**
291 * Changes the screen reference events are being enqueued from.
292 * Input events are enqueued with a screen reference and dequeued and
293 * processed with a (potentially different) screen reference.
294 * This function is called whenever a new event has changed screen but is
295 * still logically on the previous screen as seen by the client.
296 * This usually happens whenever the visible cursor moves across screen
297 * boundaries during event generation, before the same event is processed
298 * and sent down the wire.
299 *
300 * @param pDev The device that triggered a screen change.
301 * @param pScreen The new screen events are being enqueued for.
302 * @param set_dequeue_screen If TRUE, pScreen is set as both enqueue screen
303 * and dequeue screen.
304 */
305void
306mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
307{
308 EnqueueScreen(pDev)pDev->spriteInfo->sprite->pEnqueueScreen = pScreen;
309 if (set_dequeue_screen)
310 DequeueScreen(pDev)pDev->spriteInfo->sprite->pDequeueScreen = pScreen;
311}
312
313void
314mieqSetHandler(int event, mieqHandler handler)
315{
316 if (handler && miEventQueue.handlers[event])
317 ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
318 "event %d\n", miEventQueue.handlers[event], handler, event);
319
320 miEventQueue.handlers[event] = handler;
321}
322
323/**
324 * Change the device id of the given event to the given device's id.
325 */
326static void
327ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
328{
329 switch (event->any.type) {
330 case ET_Motion:
331 case ET_KeyPress:
332 case ET_KeyRelease:
333 case ET_ButtonPress:
334 case ET_ButtonRelease:
335 case ET_ProximityIn:
336 case ET_ProximityOut:
337 case ET_Hierarchy:
338 case ET_DeviceChanged:
339 case ET_TouchBegin:
340 case ET_TouchUpdate:
341 case ET_TouchEnd:
342 event->device_event.deviceid = dev->id;
343 break;
344 case ET_TouchOwnership:
345 event->touch_ownership_event.deviceid = dev->id;
346 break;
347#if XFreeXDGA
348 case ET_DGAEvent:
349 break;
350#endif
351 case ET_RawKeyPress:
352 case ET_RawKeyRelease:
353 case ET_RawButtonPress:
354 case ET_RawButtonRelease:
355 case ET_RawMotion:
356 case ET_RawTouchBegin:
357 case ET_RawTouchEnd:
358 case ET_RawTouchUpdate:
359 event->raw_event.deviceid = dev->id;
360 break;
361 case ET_BarrierHit:
362 case ET_BarrierLeave:
363 event->barrier_event.deviceid = dev->id;
364 break;
365 default:
366 ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
367 event->any.type);
368 }
369}
370
371static void
372FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
373 InternalEvent *original, InternalEvent *master)
374{
375 verify_internal_event(original);
376 verify_internal_event(master);
377 /* Ensure chained button mappings, i.e. that the detail field is the
378 * value of the mapped button on the SD, not the physical button */
379 if (original->any.type == ET_ButtonPress ||
380 original->any.type == ET_ButtonRelease) {
381 int btn = original->device_event.detail.button;
382
383 if (!sdev->button)
384 return; /* Should never happen */
385
386 master->device_event.detail.button = sdev->button->map[btn];
387 }
388}
389
390/**
391 * Copy the given event into master.
392 * @param sdev The slave device the original event comes from
393 * @param original The event as it came from the EQ
394 * @param copy The event after being copied
395 * @return The master device or NULL if the device is a floating slave.
396 */
397DeviceIntPtr
398CopyGetMasterEvent(DeviceIntPtr sdev,
399 InternalEvent *original, InternalEvent *copy)
400{
401 DeviceIntPtr mdev;
402 int len = original->any.length;
403 int type = original->any.type;
404 int mtype; /* which master type? */
405
406 verify_internal_event(original);
407
408 /* ET_XQuartz has sdev == NULL */
409 if (!sdev || IsMaster(sdev) || IsFloating(sdev))
410 return NULL((void*)0);
411
412#if XFreeXDGA
413 if (type == ET_DGAEvent)
414 type = original->dga_event.subtype;
415#endif
416
417 switch (type) {
418 case ET_KeyPress:
419 case ET_KeyRelease:
420 mtype = MASTER_KEYBOARD2;
421 break;
422 case ET_ButtonPress:
423 case ET_ButtonRelease:
424 case ET_Motion:
425 case ET_ProximityIn:
426 case ET_ProximityOut:
427 mtype = MASTER_POINTER1;
428 break;
429 default:
430 mtype = MASTER_ATTACHED4;
431 break;
432 }
433
434 mdev = GetMaster(sdev, mtype);
435 memcpy(copy, original, len)__builtin___memcpy_chk (copy, original, len, __builtin_object_size
(copy, 0))
;
436 ChangeDeviceID(mdev, copy);
437 FixUpEventForMaster(mdev, sdev, original, copy);
438
439 return mdev;
440}
441
442static void
443mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
444{
445 if (dev && screen && screen != DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen) {
446 int x = 0, y = 0;
447
448 DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen = screen;
449 x = event->root_x;
450 y = event->root_y;
451 NewCurrentScreen(dev, DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen, x, y);
452 }
453}
454
455/**
456 * Post the given @event through the device hierarchy, as appropriate.
457 * Use this function if an event must be posted for a given device during the
458 * usual event processing cycle.
459 */
460void
461mieqProcessDeviceEvent(DeviceIntPtr dev, InternalEvent *event, ScreenPtr screen)
462{
463 mieqHandler handler;
464 DeviceIntPtr master;
465 InternalEvent mevent; /* master event */
466
467 verify_internal_event(event);
468
469 /* refuse events from disabled devices */
470 if (dev && !dev->enabled)
471 return;
472
473 /* Custom event handler */
474 handler = miEventQueue.handlers[event->any.type];
475
476 switch (event->any.type) {
10
Control jumps to 'case ET_TouchEnd:' at line 489
477 /* Catch events that include valuator information and check if they
478 * are changing the screen */
479 case ET_Motion:
480 case ET_KeyPress:
481 case ET_KeyRelease:
482 case ET_ButtonPress:
483 case ET_ButtonRelease:
484 if (!handler)
485 mieqMoveToNewScreen(dev, screen, &event->device_event);
486 break;
487 case ET_TouchBegin:
488 case ET_TouchUpdate:
489 case ET_TouchEnd:
490 if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED(1 << 5)))
11
Assuming 'handler' is null
12
Taking false branch
491 mieqMoveToNewScreen(dev, screen, &event->device_event);
492 break;
13
Execution continues on line 496
493 default:
494 break;
495 }
496 master = CopyGetMasterEvent(dev, event, &mevent);
497
498 if (master)
14
Assuming 'master' is null
15
Taking false branch
499 master->lastSlave = dev;
500
501 /* If someone's registered a custom event handler, let them
502 * steal it. */
503 if (handler) {
16
Taking false branch
504 int screenNum = dev &&
505 DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen ? DequeueScreen(dev)dev->spriteInfo->sprite->pDequeueScreen->myNum : (screen ? screen->
506 myNum : 0);
507 handler(screenNum, event, dev);
508 /* Check for the SD's master in case the device got detached
509 * during event processing */
510 if (master && !IsFloating(dev))
511 handler(screenNum, &mevent, master);
512 }
513 else {
514 /* process slave first, then master */
515 dev->public.processInputProc(event, dev);
17
Dereference of null pointer
516
517 /* Check for the SD's master in case the device got detached
518 * during event processing */
519 if (master && !IsFloating(dev))
520 master->public.processInputProc(&mevent, master);
521 }
522}
523
524/* Call this from ProcessInputEvents(). */
525void
526mieqProcessInputEvents(void)
527{
528 EventRec *e = NULL((void*)0);
529 ScreenPtr screen;
530 InternalEvent event;
531 DeviceIntPtr dev = NULL((void*)0), master = NULL((void*)0);
532 static Bool inProcessInputEvents = FALSE0;
533
534 input_lock();
535
536 /*
537 * report an error if mieqProcessInputEvents() is called recursively;
538 * this can happen, e.g., if something in the mieqProcessDeviceEvent()
539 * call chain calls UpdateCurrentTime() instead of UpdateCurrentTimeIf()
540 */
541 BUG_WARN_MSG(inProcessInputEvents, "[mi] mieqProcessInputEvents() called recursively.\n")do { if (inProcessInputEvents) { ErrorFSigSafe("BUG: triggered 'if ("
"inProcessInputEvents" ")'\n"); ErrorFSigSafe("BUG: %s:%u in %s()\n"
, "mieq.c", 541, __func__); if (1) ErrorFSigSafe("[mi] mieqProcessInputEvents() called recursively.\n"
); xorg_backtrace(); } } while(0)
;
542 inProcessInputEvents = TRUE1;
543
544 if (miEventQueue.dropped) {
1
Taking false branch
545 ErrorF("[mi] EQ processing has resumed after %lu dropped events.\n",
546 (unsigned long) miEventQueue.dropped);
547 ErrorF
548 ("[mi] This may be caused by a misbehaving driver monopolizing the server's resources.\n");
549 miEventQueue.dropped = 0;
550 }
551
552 while (miEventQueue.head != miEventQueue.tail) {
2
Loop condition is true. Entering loop body
553 e = &miEventQueue.events[miEventQueue.head];
554
555 event = *e->events;
556 dev = e->pDev;
3
Value assigned to 'dev'
557 screen = e->pScreen;
558
559 miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
560
561 input_unlock();
562
563 master = (dev) ? GetMaster(dev, MASTER_ATTACHED4) : NULL((void*)0);
4
Assuming 'dev' is null
5
'?' condition is false
564
565 if (screenIsSaved == SCREEN_SAVER_ON0)
6
Assuming 'screenIsSaved' is not equal to 0
7
Taking false branch
566 dixSaveScreens(serverClient, SCREEN_SAVER_OFF1, ScreenSaverReset0);
567#ifdef DPMSExtension
568 else if (DPMSPowerLevel != DPMSModeOn)
569 SetScreenSaverTimer();
570
571 if (DPMSPowerLevel != DPMSModeOn)
572 DPMSSet(serverClient, DPMSModeOn);
573#endif
574
575 mieqProcessDeviceEvent(dev, &event, screen);
8
Passing null pointer value via 1st parameter 'dev'
9
Calling 'mieqProcessDeviceEvent'
576
577 /* Update the sprite now. Next event may be from different device. */
578 if (master &&
579 (event.any.type == ET_Motion ||
580 ((event.any.type == ET_TouchBegin ||
581 event.any.type == ET_TouchUpdate) &&
582 event.device_event.flags & TOUCH_POINTER_EMULATED(1 << 5))))
583 miPointerUpdateSprite(dev);
584
585 input_lock();
586 }
587
588 inProcessInputEvents = FALSE0;
589
590 input_unlock();
591}