mirror of
https://github.com/reactos/reactos.git
synced 2025-07-04 19:21:23 +00:00
|SHELL32]
Don't blindly delete notification item while there are still ongoing user APC. To do so, we use reference count, and attempt to release in various places: after APC ended, and on notification unregistration. This avoids race condition with item between usage and freeing and thus use-afree-free (leading to explorer crash) while browsing rapidly accross directories. CORE-10941 #resolve svn path=/trunk/; revision=71528
This commit is contained in:
parent
326b3d7e91
commit
4322caeede
1 changed files with 43 additions and 0 deletions
|
@ -58,6 +58,7 @@ typedef struct {
|
||||||
OVERLAPPED overlapped; /* Overlapped structure */
|
OVERLAPPED overlapped; /* Overlapped structure */
|
||||||
BYTE *buffer; /* Async buffer to fill */
|
BYTE *buffer; /* Async buffer to fill */
|
||||||
BYTE *backBuffer; /* Back buffer to swap buffer into */
|
BYTE *backBuffer; /* Back buffer to swap buffer into */
|
||||||
|
struct _NOTIFICATIONLIST * pParent;
|
||||||
} SHChangeNotifyEntryInternal, *LPNOTIFYREGISTER;
|
} SHChangeNotifyEntryInternal, *LPNOTIFYREGISTER;
|
||||||
#else
|
#else
|
||||||
typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
|
typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
|
||||||
|
@ -74,6 +75,9 @@ typedef struct _NOTIFICATIONLIST
|
||||||
LONG wEventMask; /* subscribed events */
|
LONG wEventMask; /* subscribed events */
|
||||||
DWORD dwFlags; /* client flags */
|
DWORD dwFlags; /* client flags */
|
||||||
ULONG id;
|
ULONG id;
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
volatile LONG wQueuedCount;
|
||||||
|
#endif
|
||||||
} NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
|
} NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
|
||||||
|
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
|
@ -156,9 +160,22 @@ static const char * NodeName(const NOTIFICATIONLIST *item)
|
||||||
static void DeleteNode(LPNOTIFICATIONLIST item)
|
static void DeleteNode(LPNOTIFICATIONLIST item)
|
||||||
{
|
{
|
||||||
UINT i;
|
UINT i;
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
LONG queued;
|
||||||
|
#endif
|
||||||
|
|
||||||
TRACE("item=%p\n", item);
|
TRACE("item=%p\n", item);
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
queued = InterlockedCompareExchange(&item->wQueuedCount, 0, 0);
|
||||||
|
if (queued != 0)
|
||||||
|
{
|
||||||
|
TRACE("Not freeing, still %d queued events\n", queued);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRACE("Freeing for real!\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* remove item from list */
|
/* remove item from list */
|
||||||
list_remove( &item->entry );
|
list_remove( &item->entry );
|
||||||
|
|
||||||
|
@ -235,6 +252,7 @@ SHChangeNotifyRegister(
|
||||||
item->cidl = cItems;
|
item->cidl = cItems;
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
item->apidl = SHAlloc(sizeof(SHChangeNotifyEntryInternal) * cItems);
|
item->apidl = SHAlloc(sizeof(SHChangeNotifyEntryInternal) * cItems);
|
||||||
|
item->wQueuedCount = 0;
|
||||||
#else
|
#else
|
||||||
item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
|
item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
|
||||||
#endif
|
#endif
|
||||||
|
@ -249,11 +267,15 @@ SHChangeNotifyRegister(
|
||||||
item->apidl[i].buffer = SHAlloc(BUFFER_SIZE);
|
item->apidl[i].buffer = SHAlloc(BUFFER_SIZE);
|
||||||
item->apidl[i].backBuffer = SHAlloc(BUFFER_SIZE);
|
item->apidl[i].backBuffer = SHAlloc(BUFFER_SIZE);
|
||||||
item->apidl[i].overlapped.hEvent = &item->apidl[i];
|
item->apidl[i].overlapped.hEvent = &item->apidl[i];
|
||||||
|
item->apidl[i].pParent = item;
|
||||||
|
|
||||||
if (fSources & SHCNRF_InterruptLevel)
|
if (fSources & SHCNRF_InterruptLevel)
|
||||||
{
|
{
|
||||||
if (_OpenDirectory( &item->apidl[i] ))
|
if (_OpenDirectory( &item->apidl[i] ))
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&item->wQueuedCount);
|
||||||
QueueUserAPC( _AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] );
|
QueueUserAPC( _AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CHAR buffer[MAX_PATH];
|
CHAR buffer[MAX_PATH];
|
||||||
|
@ -714,7 +736,11 @@ _NotificationCompletion(DWORD dwErrorCode, // completion code
|
||||||
item->pidl,
|
item->pidl,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
goto quit;
|
||||||
|
#else
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -731,12 +757,21 @@ _NotificationCompletion(DWORD dwErrorCode, // completion code
|
||||||
_BeginRead(item);
|
_BeginRead(item);
|
||||||
|
|
||||||
_ProcessNotification(item);
|
_ProcessNotification(item);
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
quit:
|
||||||
|
InterlockedDecrement(&item->pParent->wQueuedCount);
|
||||||
|
DeleteNode(item->pParent);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID _BeginRead(LPNOTIFYREGISTER item )
|
static VOID _BeginRead(LPNOTIFYREGISTER item )
|
||||||
{
|
{
|
||||||
TRACE("_BeginRead %p \n", item->hDirectory);
|
TRACE("_BeginRead %p \n", item->hDirectory);
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
InterlockedIncrement(&item->pParent->wQueuedCount);
|
||||||
|
#endif
|
||||||
/* This call needs to be reissued after every APC. */
|
/* This call needs to be reissued after every APC. */
|
||||||
if (!ReadDirectoryChangesW(item->hDirectory, // handle to directory
|
if (!ReadDirectoryChangesW(item->hDirectory, // handle to directory
|
||||||
item->buffer, // read results buffer
|
item->buffer, // read results buffer
|
||||||
|
@ -746,12 +781,20 @@ static VOID _BeginRead(LPNOTIFYREGISTER item )
|
||||||
NULL, // bytes returned
|
NULL, // bytes returned
|
||||||
&item->overlapped, // overlapped buffer
|
&item->overlapped, // overlapped buffer
|
||||||
_NotificationCompletion)) // completion routine
|
_NotificationCompletion)) // completion routine
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
{
|
||||||
|
#endif
|
||||||
ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p) Code: %u \n",
|
ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p) Code: %u \n",
|
||||||
item->hDirectory,
|
item->hDirectory,
|
||||||
item->buffer,
|
item->buffer,
|
||||||
&item->overlapped,
|
&item->overlapped,
|
||||||
_NotificationCompletion,
|
_NotificationCompletion,
|
||||||
GetLastError());
|
GetLastError());
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
InterlockedDecrement(&item->pParent->wQueuedCount);
|
||||||
|
DeleteNode(item->pParent);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD _MapAction(DWORD dwAction, BOOL isDir)
|
DWORD _MapAction(DWORD dwAction, BOOL isDir)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue