On Tue, Mar 19, 2019 at 12:10 PM William A Rowe Jr <wr...@rowe-clan.net> wrote:
> On Tue, Mar 19, 2019 at 11:41 AM Michael Schlenker < > michael.schlen...@contact-software.com> wrote: > >> *Von:* William A Rowe Jr [mailto:wr...@rowe-clan.net] >> *Gesendet:* Dienstag, 19. März 2019 16:36 >> *An:* Michael Schlenker <michael.schlen...@contact-software.com> >> *Cc:* Stefan Sperling <s...@stsp.name>; dev@apr.apache.org >> *Betreff:* Re: APR thread_mutex_cleanup on windows mishandles being >> called twice >> >> > > >> > > You're right that acting on a corrupt memory is bad. >> > > >> > > It looks like your proposed patch detects and then skips a redundant >> call to >> > > DeleteCriticalSection() when a mutex is unlocked twice: >> > > >> > > if (lock->type == thread_mutex_critical_section) { >> > > lock->type = -1; >> > > DeleteCriticalSection(&lock->section); >> > > + } >> > > + else if (lock->type == -1) { >> > > + /* do nothing */ >> > > } >> > > >> > > I'd prefer thread_mutex_cleanup() to loudly complain when this >> happens, >> > > and perhaps even abort the program, forcing API users to fix their >> code. >> > >> > Agreed. That should probably be a kind of assert that aborts or fails >> loud, not sure what the APR convention/function for that case would be. >> > >> > Just initializing the handle member to default INVALID_HANDLE is enough >> to prevent the memory corruption/freed random handles. >> >> If this is the consensus, to avoid further corruption, I'd suggest we >> reset (*mutex)->handle = NULL on first close. >> >> >> >> Still should trigger a fault where it is double-closed. Won't silently >> continue to close random handles. And avoids the extra test. >> >> >> >> Do we agree on that band-aid? >> >> >> >> The proper reset value wouldn't be NULL but INVALID_HANDLE_VALUE, which >> is defined like: >> >> >> >> #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) >> >> >> >> Otherwise agreed. >> > Trying this again... we patch this; @@ -61,10 +64,11 @@ * use a [slower] mutex object, instead. */ IF_WIN_OS_IS_UNICODE { InitializeCriticalSection(&(*mutex)->section); (*mutex)->type = thread_mutex_critical_section; + (*mutex)->handle = INVALID_HANDLE_VALUE; } #endif #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { (*mutex)->type = thread_mutex_nested_mutex; And we omit this change, causing us to attempt to CloseHandle(INVALID_HANDLE_VALUE)... @@ -28,10 +28,13 @@ apr_thread_mutex_t *lock = data; if (lock->type == thread_mutex_critical_section) { lock->type = -1; DeleteCriticalSection(&lock->section); + } + else if (lock->type == -1) { + /* do nothing */ } else { if (!CloseHandle(lock->handle)) { return apr_get_os_error(); } Just want to be clear that we concur, before I commit.