Eliminate cyclic locks in runtime

This change introduces a new deadlock detector for Cosmo's POSIX threads
implementation. Error check mutexes will now track a DAG of nested locks
and report EDEADLK when a deadlock is theoretically possible. These will
occur rarely, but it's important for production hardening your code. You
don't even need to change your mutexes to use the POSIX error check mode
because `cosmocc -mdbg` will enable error checking on mutexes by default
globally. When cycles are found, an error message showing your demangled
symbols describing the strongly connected component are printed and then
the SIGTRAP is raised, which means you'll also get a backtrace if you're
using ShowCrashReports() too. This new error checker is so low-level and
so pure that it's able to verify the relationships of every libc runtime
lock, including those locks upon which the mutex implementation depends.
This commit is contained in:
Justine Tunney 2024-12-16 20:51:27 -08:00
parent 26c051c297
commit af7bd80430
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
141 changed files with 2094 additions and 1601 deletions

59
third_party/gdtoa/lock.c vendored Normal file
View file

@ -0,0 +1,59 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
The author of this software is David M. Gay.
Please send bug reports to David M. Gay <dmg@acm.org>
or Justine Tunney <jtunney@gmail.com>
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
#include "third_party/gdtoa/lock.h"
pthread_mutex_t __gdtoa_lock_obj = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t __gdtoa_lock1_obj = PTHREAD_MUTEX_INITIALIZER;
void
__gdtoa_lock(void)
{
pthread_mutex_lock(&__gdtoa_lock_obj);
}
void
__gdtoa_unlock(void)
{
pthread_mutex_unlock(&__gdtoa_lock_obj);
}
void
__gdtoa_lock1(void)
{
pthread_mutex_lock(&__gdtoa_lock1_obj);
}
void
__gdtoa_unlock1(void)
{
pthread_mutex_unlock(&__gdtoa_lock1_obj);
}

15
third_party/gdtoa/lock.h vendored Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_GDTOA_LOCK_H_
#define COSMOPOLITAN_THIRD_PARTY_GDTOA_LOCK_H_
#include "libc/thread/thread.h"
COSMOPOLITAN_C_START_
extern pthread_mutex_t __gdtoa_lock_obj;
extern pthread_mutex_t __gdtoa_lock1_obj;
void __gdtoa_lock(void);
void __gdtoa_unlock(void);
void __gdtoa_lock1(void);
void __gdtoa_unlock1(void);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_GDTOA_LOCK_H_ */

View file

@ -35,46 +35,9 @@
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/gdtoa/gdtoa.internal.h"
#include "third_party/gdtoa/lock.h"
static ThInfo TI0;
static pthread_mutex_t __gdtoa_lock_obj;
static pthread_mutex_t __gdtoa_lock1_obj;
static void
__gdtoa_lock(void)
{
pthread_mutex_lock(&__gdtoa_lock_obj);
}
static void
__gdtoa_unlock(void)
{
pthread_mutex_unlock(&__gdtoa_lock_obj);
}
static void
__gdtoa_initlock(void)
{
pthread_mutex_init(&__gdtoa_lock_obj, 0);
}
static void
__gdtoa_lock1(void)
{
pthread_mutex_lock(&__gdtoa_lock1_obj);
}
static void
__gdtoa_unlock1(void)
{
pthread_mutex_unlock(&__gdtoa_lock1_obj);
}
static void
__gdtoa_initlock1(void)
{
pthread_mutex_init(&__gdtoa_lock1_obj, 0);
}
static void
__gdtoa_Brelease(Bigint *rv)
@ -88,24 +51,20 @@ static void
__gdtoa_Bclear(void)
{
int i;
__gdtoa_lock();
__gdtoa_lock1();
for (i = 0; i < ARRAYLEN(TI0.Freelist); ++i)
__gdtoa_Brelease(TI0.Freelist[i]);
__gdtoa_lock1();
__gdtoa_lock();
__gdtoa_Brelease(TI0.P5s);
__gdtoa_unlock1();
bzero(&TI0, sizeof(TI0));
__gdtoa_unlock();
bzero(&TI0, sizeof(TI0));
__gdtoa_unlock1();
}
__attribute__((__constructor__(60))) static void
__gdtoa_Binit(void)
{
__gdtoa_initlock();
__gdtoa_initlock1();
atexit(__gdtoa_Bclear);
pthread_atfork(__gdtoa_lock1, __gdtoa_unlock1, __gdtoa_initlock1);
pthread_atfork(__gdtoa_lock, __gdtoa_unlock, __gdtoa_initlock);
}
static ThInfo *