Make Memory use a recursive mutex.

This allows some additional operations to be performed inside the memory
hooks, although it's still a bad idea to allocate or free memory while
inside the hook.
This commit is contained in:
Jordan Bancino 2023-06-04 18:44:37 +00:00
parent c511ca9f0f
commit 095e05e927
2 changed files with 69 additions and 13 deletions

View file

@ -57,14 +57,42 @@ struct MemoryInfo
#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((UInt8 *) p) + x)) + 1) #define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((UInt8 *) p) + x)) + 1)
#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(UInt8)) + (2 * sizeof(MEM_BOUND_TYPE))) #define MEM_SIZE_ACTUAL(x) (((x) * sizeof(UInt8)) + (2 * sizeof(MEM_BOUND_TYPE)))
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t lock;
static void (*hook) (MemoryAction, MemoryInfo *, void *) = NULL; static void (*hook) (MemoryAction, MemoryInfo *, void *) = MemoryDefaultHook;
static void *hookArgs = NULL; static void *hookArgs = NULL;
static MemoryInfo **allocations = NULL; static MemoryInfo **allocations = NULL;
static size_t allocationsSize = 0; static size_t allocationsSize = 0;
static size_t allocationsLen = 0; static size_t allocationsLen = 0;
int
MemoryRuntimeInit(void)
{
pthread_mutexattr_t attr;
int ret = 0;
if (pthread_mutexattr_init(&attr) != 0)
{
goto finish;
}
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
ret = pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
ret = (ret == 0);
finish:
return ret;
}
int
MemoryRuntimeDestroy(void)
{
MemoryFreeAll();
return pthread_mutex_destroy(&lock) == 0;
}
static size_t static size_t
MemoryHash(void *p) MemoryHash(void *p)
{ {

View file

@ -33,12 +33,18 @@
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#define ERR_BUF_SIZE 128
/* Specified by POSIX to contain environment variables */ /* Specified by POSIX to contain environment variables */
extern char **environ; extern char **environ;
/* The linking program is expected to provide Main */ /* The linking program is expected to provide Main */
extern int Main(Array *, HashMap *); extern int Main(Array *, HashMap *);
/* Functions in the Memory API that are not exported via header */
extern int MemoryRuntimeInit(void);
extern int MemoryRuntimeDestroy(void);
typedef struct MainArgs typedef struct MainArgs
{ {
Array *args; Array *args;
@ -69,32 +75,46 @@ main(int argc, char **argv)
MainArgs args; MainArgs args;
MemoryHook(MemoryDefaultHook, NULL); char errBuf[ERR_BUF_SIZE];
int errLen;
args.args = NULL; args.args = NULL;
args.env = NULL; args.env = NULL;
args.ret = EXIT_FAILURE; args.ret = EXIT_FAILURE;
if (!MemoryRuntimeInit())
{
errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to initialize Memory runtime.\n");
write(STDERR_FILENO, errBuf, errLen);
goto finish;
}
args.args = ArrayCreate(); args.args = ArrayCreate();
if (!args.args) if (!args.args)
{ {
Log(LOG_ERR, "Bootstrap error: Unable to allocate memory for arguments."); errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to allocate heap memory for program arguments.\n");
args.ret = EXIT_FAILURE; write(STDERR_FILENO, errBuf, errLen);
goto finish; goto finish;
} }
args.env = HashMapCreate(); args.env = HashMapCreate();
if (!args.env) if (!args.env)
{ {
Log(LOG_ERR, "Bootstrap error: Unable to allocate memory for environment."); errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to allocate heap memory for program environment.\n");
args.ret = EXIT_FAILURE; write(STDERR_FILENO, errBuf, errLen);
goto finish; goto finish;
} }
for (i = 0; i < (size_t) argc; i++) for (i = 0; i < (size_t) argc; i++)
{ {
ArrayAdd(args.args, StrDuplicate(argv[i])); char *arg = StrDuplicate(argv[i]);
if (!arg || !ArrayAdd(args.args, arg))
{
errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to allocate heap memory for program argument.\n");
write(STDERR_FILENO, errBuf, errLen);
goto finish;
}
} }
envp = environ; envp = environ;
@ -105,6 +125,14 @@ main(int argc, char **argv)
/* It is unclear whether or not envp strings are writable, so /* It is unclear whether or not envp strings are writable, so
* we make our own copy to manipulate it */ * we make our own copy to manipulate it */
key = StrDuplicate(*envp); key = StrDuplicate(*envp);
if (!key)
{
errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to allocate heap memory for program environment variable.\n");
write(STDERR_FILENO, errBuf, errLen);
goto finish;
}
valInd = strcspn(key, "="); valInd = strcspn(key, "=");
key[valInd] = '\0'; key[valInd] = '\0';
@ -116,15 +144,15 @@ main(int argc, char **argv)
if (pthread_create(&mainThread, NULL, MainThread, &args) != 0) if (pthread_create(&mainThread, NULL, MainThread, &args) != 0)
{ {
Log(LOG_ERR, "Bootstrap error: Unable to create main thread."); errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to create main thread.\n");
args.ret = EXIT_FAILURE; write(STDERR_FILENO, errBuf, errLen);
goto finish; goto finish;
} }
if (pthread_join(mainThread, NULL) != 0) if (pthread_join(mainThread, NULL) != 0)
{ {
/* Should never happen */ errLen = snprintf(errBuf, ERR_BUF_SIZE, "Fatal: Unable to join main thread.\n");
Log(LOG_ERR, "Unable to join main thread."); write(STDERR_FILENO, errBuf, errLen);
args.ret = EXIT_FAILURE; args.ret = EXIT_FAILURE;
goto finish; goto finish;
} }
@ -156,7 +184,7 @@ finish:
GenerateMemoryReport(argc, argv); GenerateMemoryReport(argc, argv);
MemoryFreeAll(); MemoryRuntimeDestroy();
return args.ret; return args.ret;
} }