diff --git a/Xext/sync.c b/Xext/sync.c index 900858773..f4f1036d1 100644 --- a/Xext/sync.c +++ b/Xext/sync.c @@ -1162,9 +1162,12 @@ FreeCounter(void *env, XID id) SyncTriggerList *ptl, *pnext; /* tell all the counter's triggers that counter has been destroyed */ - for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { - (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); - pnext = ptl->next; + nt_list_for_each_entry_safe(ptl, pnext, pCounter->sync.pTriglist, next) { + /* Remove it from the list first so CounterDestroyed + * callbacks have a valid list to iterate */ + pCounter->sync.pTriglist = pnext; + if (ptl->pTrigger) + (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); free(ptl); /* destroy the trigger list as we go */ } if (IsSystemCounter(pCounter)) { @@ -1196,13 +1199,28 @@ FreeAwait(void *addr, XID id) for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; numwaits--, pAwait++) { - /* If the counter is being destroyed, FreeCounter will delete - * the trigger list itself, so don't do it here. + /* If the counter is being destroyed, FreeCounter/miSyncDestroyFence + * will delete the trigger list itself, so don't do it here. + * However, we must NULL out the pTrigger pointer in the trigger list + * node so the destroy loop knows not to dereference it - the backing + * SyncAwait memory is about to be freed below. */ SyncObject *pSync = pAwait->trigger.pSync; - if (pSync && !pSync->beingDestroyed) - SyncDeleteTriggerFromSyncObject(&pAwait->trigger); + if (pSync) { + if (!pSync->beingDestroyed) { + SyncDeleteTriggerFromSyncObject(&pAwait->trigger); + } else { + SyncTriggerList *ptl; + + nt_list_for_each_entry(ptl, pSync->pTriglist, next) { + if (ptl->pTrigger == &pAwait->trigger) { + ptl->pTrigger = NULL; + break; + } + } + } + } } free(pAwaitUnion); return Success; diff --git a/miext/sync/misync.c b/miext/sync/misync.c index 9a6fbbd4a..4ce249850 100644 --- a/miext/sync/misync.c +++ b/miext/sync/misync.c @@ -115,10 +115,14 @@ miSyncDestroyFence(SyncFence * pFence) SyncScreenPrivPtr pScreenPriv = SYNC_SCREEN_PRIV(pScreen); SyncTriggerList *ptl, *pNext; - /* tell all the fence's triggers that the counter has been destroyed */ - for (ptl = pFence->sync.pTriglist; ptl; ptl = pNext) { - (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); - pNext = ptl->next; + /* tell all the fence's triggers that the fence has been destroyed. + * Update pTriglist before each callback and free so that FreeAwait + * sees a valid list head when scanning for triggers to NULL out. + */ + nt_list_for_each_entry_safe(ptl, pNext, pFence->sync.pTriglist, next) { + pFence->sync.pTriglist = pNext; + if (ptl->pTrigger) + (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); free(ptl); /* destroy the trigger list as we go */ }