Commit 094a63d56fbfb9e23210cc9ac538fb198af37cee moved the timer that handles animated cursors from the per-screen AnimCurScreenRec into the per-cursor AnimCurRec. However, the timer that runs takes the DeviceIntPtr as its argument, and looks up which screen the cursor is supposed to be on from that.
This leads to a problem when a device changes from one animated cursor to another: The timer for the first cursor is not canceled. Then, when the device transitions to a static cursor, the second timer is canceled pDev->spriteInfo->anim.pScreen is cleared. Finally, the first timer fires and AnimCurTimerNotify crashes because pScreen is NULL. Since there's only ever supposed to be one timer pending for a given device, move the timer into pDev->spriteInfo->anim.pTimer. This timer is canceled when transitioning to a static cursor, and re-armed when transitioning from one animated cursor to another. Signed-off-by: Aaron Plattner <[email protected]> Reported-by: https://devtalk.nvidia.com/default/topic/1028172/linux/titan-v-ubuntu-16-04lts-and-387-34-driver-crashes-badly/post/5230967/#5230967 --- I'm not convinced that I fully understood how these timers worked with multiple X screens before 094a63d56fbf, so hopefully this is an acceptable fix. It seems to work in my single-X-screen testing. dix/devices.c | 1 + include/inputstr.h | 1 + render/animcur.c | 14 ++++---------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/dix/devices.c b/dix/devices.c index 4a628afb0f49..98493df58fb6 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -1014,6 +1014,7 @@ CloseDevice(DeviceIntPtr dev) free(dev->last.touches); dev->config_info = NULL; dixFreePrivates(dev->devPrivates, PRIVATE_DEVICE); + TimerFree(dev->spriteInfo->anim.pTimer); free(dev); } diff --git a/include/inputstr.h b/include/inputstr.h index 5f0026b9b733..7de1ed39874d 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -514,6 +514,7 @@ typedef struct _SpriteInfoRec { struct { CursorPtr pCursor; ScreenPtr pScreen; + OsTimerPtr pTimer; int elt; } anim; } SpriteInfoRec, *SpriteInfoPtr; diff --git a/render/animcur.c b/render/animcur.c index 058bc1b3237c..83cb5572c740 100644 --- a/render/animcur.c +++ b/render/animcur.c @@ -55,7 +55,6 @@ typedef struct _AnimCurElt { typedef struct _AnimCur { int nelt; /* number of elements in the elts array */ AnimCurElt *elts; /* actually allocated right after the structure */ - OsTimerPtr timer; } AnimCurRec, *AnimCurPtr; typedef struct _AnimScrPriv { @@ -171,19 +170,16 @@ AnimCurDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) pDev->spriteInfo->anim.elt = 0; pDev->spriteInfo->anim.pCursor = pCursor; pDev->spriteInfo->anim.pScreen = pScreen; - - ac->timer = TimerSet(ac->timer, 0, ac->elts[0].delay, - AnimCurTimerNotify, pDev); + pDev->spriteInfo->anim.pTimer = + TimerSet(pDev->spriteInfo->anim.pTimer, 0, + ac->elts[0].delay, AnimCurTimerNotify, pDev); } } else ret = TRUE; } else { - CursorPtr old = pDev->spriteInfo->anim.pCursor; - - if (old && IsAnimCur(old)) - TimerCancel(GetAnimCur(old)->timer); + TimerCancel(pDev->spriteInfo->anim.pTimer); pDev->spriteInfo->anim.pCursor = 0; pDev->spriteInfo->anim.pScreen = 0; @@ -325,13 +321,11 @@ AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor, pCursor->id = cid; ac = GetAnimCur(pCursor); - ac->timer = TimerSet(NULL, 0, 0, AnimCurTimerNotify, NULL); /* security creation/labeling check */ rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, RT_NONE, NULL, DixCreateAccess); if (rc != Success) { - TimerFree(ac->timer); dixFiniPrivates(pCursor, PRIVATE_CURSOR); free(pCursor); return rc; -- 2.15.1 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel
