From 10a16fbf42fe2e37426049e5e73ca8f0ed37b535 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sun, 23 Feb 2025 12:27:06 +0100 Subject: [PATCH] proj: Small fixes --- proj/server/src/intercept.py | 78 ++++++++++++++----------------- proj/server/src/server.py | 2 +- proj/test1/Makefile | 2 +- proj/test1/src/intercept.c | 91 +++++++++++++++++++++--------------- proj/test1/src/main.c | 3 +- 5 files changed, 91 insertions(+), 85 deletions(-) diff --git a/proj/server/src/intercept.py b/proj/server/src/intercept.py index 8b51082..09647c4 100755 --- a/proj/server/src/intercept.py +++ b/proj/server/src/intercept.py @@ -285,11 +285,12 @@ class Handler(StreamRequestHandler): class MemoryAllocationTester(Handler): - allocated: dict[int, int] + allocated: dict[int, tuple[str, int, int]] max_allocated: int num_malloc: int num_realloc: int num_free: int + num_invalid_free: int def before(self): self.allocated = {} @@ -297,54 +298,60 @@ class MemoryAllocationTester(Handler): self.num_malloc = 0 self.num_realloc = 0 self.num_free = 0 + self.num_invalid_free = 0 def after(self): if len(self.allocated) > 0: print("Not free'd:") - for ptr, size in self.allocated.items(): - print(f' 0x{ptr:x}: {size} bytes') + for ptr, (func, ret, size) in self.allocated.items(): + print(f' 0x{ptr:x}: {size} bytes ({func}, return address 0x{ret:x})') else: print("All blocks free'd!") print(f'Max allocated: {self.max_allocated} bytes') def update_max_allocated(self): - total = sum(self.allocated.values()) + total = sum(a[2] for a in self.allocated.values()) if total > self.max_allocated: self.max_allocated = total def after_malloc(self, size, ret_value, errno=None) -> None: self.num_malloc += 1 if ret_value != 0: - print(ret_value) - self.allocated[ret_value] = size + self.allocated[ret_value] = ('malloc', self.ret_addr, size) self.update_max_allocated() def after_calloc(self, nmemb, size, ret_value, errno=None) -> None: self.num_malloc += 1 if ret_value != 0: - self.allocated[ret_value] = nmemb * size + self.allocated[ret_value] = ('calloc', self.ret_addr, nmemb * size) self.update_max_allocated() def after_realloc(self, ptr, size, ret_value, errno=None) -> None: self.num_realloc += 1 if ptr != 0: if ret_value != 0: + v = self.allocated[ptr] del self.allocated[ptr] - self.allocated[ret_value] = size + self.allocated[ret_value] = (v[0], v[1], size) self.update_max_allocated() def after_reallocarray(self, ptr, nmemb, size, ret_value, errno=None) -> None: self.num_realloc += 1 if ptr != 0: if ret_value != 0: + v = self.allocated[ptr] del self.allocated[ptr] - self.allocated[ret_value] = nmemb * size + self.allocated[ret_value] = (v[0], v[1], nmemb * size) self.update_max_allocated() def after_free(self, ptr) -> None: self.num_free += 1 if ptr != 0: - del self.allocated[ptr] + if ptr in self.allocated: + del self.allocated[ptr] + else: + self.num_free -= 1 + self.num_invalid_free += 1 class ReturnValueCheckTester(Handler): @@ -353,6 +360,13 @@ class ReturnValueCheckTester(Handler): class InterruptedCheckTester(Handler): cycles: int = 50 + functions: dict[str, tuple[str or None, str]] = { + 'sem_wait': ('fail EINTR', 'return 0'), + 'sem_trywait': ('fail EINTR', 'return 0'), + 'sem_timedwait': ('fail EINTR', 'return 0'), + 'sem_post': (None, 'return 0'), + } + counter: int = 0 last_func_name: Optional[str] = None last_ret_addr: Optional[int] = None @@ -378,49 +392,25 @@ class InterruptedCheckTester(Handler): self.last_func_name = None self.last_ret_addr = None - def after_fallback(self, func_name: str, *args, **kwargs) -> None: - if self.while_testing and self.last_func_name != func_name: - self.error() - - def before_sem_wait(self, sem: int) -> str: - if self.last_ret_addr and self.last_ret_addr != self.ret_addr: + def before_fallback(self, func_name: str, *args) -> str: + if self.while_testing and (self.last_func_name != func_name or self.last_ret_addr != self.ret_addr): self.error() + return 'ok' + elif func_name not in self.functions: + return 'ok' + elif self.functions[func_name][0] is None: + return self.functions[func_name][1] self.counter += 1 if self.while_testing: self.last_ret_addr = self.ret_addr - self.last_func_name = 'sem_wait' + self.last_func_name = func_name self.tested_functions[(self.last_func_name, self.last_ret_addr)] = 'running' - return 'fail EINTR' + return self.functions[func_name][0] else: self.tested_functions[(self.last_func_name, self.last_ret_addr)] = 'passed' self.last_ret_addr = None self.last_func_name = None - return 'return 0' - - def before_sem_trywait(self, sem: int) -> str: - self.counter += 1 - if self.while_testing: - self.last_ret_addr = self.ret_addr - self.last_func_name = 'sem_trywait' - return 'fail EINTR' - else: - self.last_ret_addr = None - self.last_func_name = None - return 'return 0' - - def before_sem_timedwait(self, sem: int, abs_timeout: Pointer[StructTimeSpec]) -> str: - self.counter += 1 - if self.while_testing: - self.last_ret_addr = self.ret_addr - self.last_func_name = 'sem_timedwait' - return 'fail EINTR' - else: - self.last_ret_addr = None - self.last_func_name = None - return 'return 0' - - def before_sem_post(self, sem: int) -> str: - return 'return 0' + return self.functions[func_name][1] def intercept(socket: str, handler: type[Handler]) -> None: diff --git a/proj/server/src/server.py b/proj/server/src/server.py index 221d111..260c825 100755 --- a/proj/server/src/server.py +++ b/proj/server/src/server.py @@ -39,7 +39,7 @@ def main() -> None: parser = argparse.ArgumentParser() parser.add_argument('socket', metavar='FILE') args = parser.parse_args() - intercept.intercept(args.socket, intercept.InterruptedCheckTester) + intercept.intercept(args.socket, intercept.MemoryAllocationTester) if __name__ == '__main__': diff --git a/proj/test1/Makefile b/proj/test1/Makefile index 249b6c6..ca6a02e 100644 --- a/proj/test1/Makefile +++ b/proj/test1/Makefile @@ -25,7 +25,7 @@ main: bin/main.o $(CC) -o $@ $^ $(CFLAGS) -lc -lpthread main_intercept: bin/main.o src/intercept.c - $(CC) -o $@ $^ $(CFLAGS) -lc -Wl,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=reallocarray,--wrap=getopt,--wrap=close,\ + $(CC) -o $@ $^ $(CFLAGS) -lc -Wl,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=reallocarray,--wrap=getopt,--wrap=exit,--wrap=close,\ --wrap=sem_init,--wrap=sem_open,--wrap=sem_post,--wrap=sem_wait,--wrap=sem_trywait,--wrap=sem_timedwait,--wrap=sem_getvalue,--wrap=sem_close,--wrap=sem_unlink,--wrap=sem_destroy clean: diff --git a/proj/test1/src/intercept.c b/proj/test1/src/intercept.c index cf55db6..4b395f5 100644 --- a/proj/test1/src/intercept.c +++ b/proj/test1/src/intercept.c @@ -26,6 +26,7 @@ static void *(*__real_realloc)(void *, size_t); static void *(*__real_reallocarray)(void *, size_t, size_t); static void (*__real_free)(void *); static int (*__real_getopt)(int, char *const [], const char *); +static void (*__real_exit)(int); static int (*__real_close)(int); static int (*__real_sem_init)(sem_t *, int, unsigned int); static sem_t *(*__real_sem_open)(const char *, int, ...); @@ -37,12 +38,12 @@ static int (*__real_sem_getvalue)(sem_t *restrict, int *restrict); static int (*__real_sem_close)(sem_t *); static int (*__real_sem_unlink)(const char *); static int (*__real_sem_destroy)(sem_t *); -#define __load(var, name) \ +#define load(var, name) \ if (((var) = dlsym(RTLD_NEXT, name)) == NULL) { \ fprintf(stderr, "intercept: unable to load symbol '%s': %s", name, strerror(errno)); \ return; \ } -#define __sym(name) name +#define sym(name) name #else extern void *__real_malloc(size_t); extern void *__real_calloc(size_t, size_t); @@ -50,6 +51,7 @@ extern void *__real_realloc(void *, size_t); extern void *__real_reallocarray(void *, size_t, size_t); extern void __real_free(void *); extern int __real_getopt(int, char *const [], const char *); +extern void __real_exit(int); extern int __real_close(int); extern int __real_sem_init(sem_t *, int, unsigned int); extern sem_t *__real_sem_open(const char *, int, ...); @@ -61,7 +63,7 @@ extern int __real_sem_getvalue(sem_t *restrict, int *restrict); extern int __real_sem_close(sem_t *); extern int __real_sem_unlink(const char *); extern int __real_sem_destroy(sem_t *); -#define __sym(name) __wrap_ ## name +#define sym(name) __wrap_ ## name #endif #define if_invalid(name) if (strcmp(buf, "ok") != 0) { fprintf(stderr, "intercept: " #name ": invalid command: '%s'\n", buf); } @@ -423,7 +425,7 @@ static void rcv(char *buf, const int size) { static void fin(void) { if (intercept && mode > 2) - close(intercept); + __real_close(intercept); if (mode > 0) fprintf(stderr, "intercept: stopped\n"); mode = 0, intercept = 0; @@ -432,23 +434,24 @@ static void fin(void) { static void init(void) { if (mode) return; #ifdef INTERCEPT_PRELOAD - __load(__real_malloc, "malloc"); - __load(__real_calloc, "calloc"); - __load(__real_realloc, "realloc"); - __load(__real_reallocarray, "reallocarray"); - __load(__real_free, "free"); - __load(__real_getopt, "getopt"); - __load(__real_close, "close"); - __load(__real_sem_init, "sem_init"); - __load(__real_sem_open, "sem_open"); - __load(__real_sem_post, "sem_post"); - __load(__real_sem_wait, "sem_wait"); - __load(__real_sem_wait, "sem_trywait"); - __load(__real_sem_wait, "sem_timedwait"); - __load(__real_sem_getvalue, "sem_getvalue"); - __load(__real_sem_close, "sem_close"); - __load(__real_sem_unlink, "sem_unlink"); - __load(__real_sem_destroy, "sem_destroy"); + load(__real_malloc, "malloc"); + load(__real_calloc, "calloc"); + load(__real_realloc, "realloc"); + load(__real_reallocarray, "reallocarray"); + load(__real_free, "free"); + load(__real_getopt, "getopt"); + load(__real_exit, "exit"); + load(__real_close, "close"); + load(__real_sem_init, "sem_init"); + load(__real_sem_open, "sem_open"); + load(__real_sem_post, "sem_post"); + load(__real_sem_wait, "sem_wait"); + load(__real_sem_wait, "sem_trywait"); + load(__real_sem_wait, "sem_timedwait"); + load(__real_sem_getvalue, "sem_getvalue"); + load(__real_sem_close, "sem_close"); + load(__real_sem_unlink, "sem_unlink"); + load(__real_sem_destroy, "sem_destroy"); #endif atexit(fin); const char *val = getenv("INTERCEPT"); @@ -497,7 +500,7 @@ static void init(void) { } } -void *__sym(malloc)(size_t size) { +void *sym(malloc)(size_t size) { init(); msg("malloc(%li): %p", size, __builtin_return_address(0)); if (mode >= 4) { @@ -513,7 +516,7 @@ void *__sym(malloc)(size_t size) { return ret; } -void *__sym(calloc)(size_t nmemb, size_t size) { +void *sym(calloc)(size_t nmemb, size_t size) { init(); msg("calloc(%li, %li): %p", nmemb, size, __builtin_return_address(0)); if (mode >= 4) { @@ -529,7 +532,7 @@ void *__sym(calloc)(size_t nmemb, size_t size) { return ret; } -void *__sym(realloc)(void *ptr, size_t size) { +void *sym(realloc)(void *ptr, size_t size) { init(); msg("realloc(%p, %li): %p", ptr, size, __builtin_return_address(0)); if (mode >= 4) { @@ -545,7 +548,7 @@ void *__sym(realloc)(void *ptr, size_t size) { return ret; } -void *__sym(reallocarray)(void *ptr, size_t nmemb, size_t size) { +void *sym(reallocarray)(void *ptr, size_t nmemb, size_t size) { init(); msg("reallocarray(%p, %li): %p", ptr, size, __builtin_return_address(0)); if (mode >= 4) { @@ -561,7 +564,7 @@ void *__sym(reallocarray)(void *ptr, size_t nmemb, size_t size) { return ret; } -void __sym(free)(void *ptr) { +void sym(free)(void *ptr) { init(); msg("free(%p): %p", ptr, __builtin_return_address(0)); if (mode >= 4) { @@ -575,7 +578,7 @@ void __sym(free)(void *ptr) { msg("return"); } -int __sym(getopt)(const int argc, char *const argv[], const char *shortopts) { +int sym(getopt)(const int argc, char *const argv[], const char *shortopts) { init(); msg("getopt(%i, %as, %es): %p", argc, argv, argc, shortopts, __builtin_return_address(0)); if (mode >= 4) { @@ -593,7 +596,19 @@ int __sym(getopt)(const int argc, char *const argv[], const char *shortopts) { return ret; } -int __sym(close)(int fildes) { +void sym(exit)(int status) { + init(); + msg("exit(%i): %p", status, __builtin_return_address(0)); + if (mode >= 4) { + char buf[BUFFER_SIZE]; + rcv(buf, sizeof(buf)); + if_modify_int("exit", int, status) + else if_invalid(getopt) + } + __real_exit(status); +} + +int sym(close)(int fildes) { init(); msg("close(%i): %p", fildes, __builtin_return_address(0)); if (mode >= 4) { @@ -609,7 +624,7 @@ int __sym(close)(int fildes) { return ret; } -int __sym(sem_init)(sem_t *sem, int pshared, unsigned int value) { +int sym(sem_init)(sem_t *sem, int pshared, unsigned int value) { init(); msg("sem_init(%p, %i, %u): %p", sem, pshared, value, __builtin_return_address(0)); if (mode >= 4) { @@ -625,7 +640,7 @@ int __sym(sem_init)(sem_t *sem, int pshared, unsigned int value) { return ret; } -sem_t *__sym(sem_open)(const char *name, int oflag, ...) { +sem_t *sym(sem_open)(const char *name, int oflag, ...) { init(); char ostr[32] = "|"; if (oflag & O_CREAT) strcat(ostr, "O_CREAT|"); @@ -712,7 +727,7 @@ sem_t *__sym(sem_open)(const char *name, int oflag, ...) { return ret; } -int __sym(sem_post)(sem_t *sem) { +int sym(sem_post)(sem_t *sem) { init(); msg("sem_post(%p): %p", sem, __builtin_return_address(0)); if (mode >= 4) { @@ -728,7 +743,7 @@ int __sym(sem_post)(sem_t *sem) { return ret; } -int __sym(sem_wait)(sem_t *sem) { +int sym(sem_wait)(sem_t *sem) { init(); msg("sem_wait(%p): %p", sem, __builtin_return_address(0)); if (mode >= 4) { @@ -744,7 +759,7 @@ int __sym(sem_wait)(sem_t *sem) { return ret; } -int __sym(sem_trywait)(sem_t *sem) { +int sym(sem_trywait)(sem_t *sem) { init(); msg("sem_trywait(%p): %p", sem, __builtin_return_address(0)); if (mode >= 4) { @@ -760,7 +775,7 @@ int __sym(sem_trywait)(sem_t *sem) { return ret; } -int __sym(sem_timedwait)(sem_t *restrict sem, const struct timespec *restrict abs_timeout) { +int sym(sem_timedwait)(sem_t *restrict sem, const struct timespec *restrict abs_timeout) { init(); msg("sem_timedwait(%p, %p:{tv_sec: %li, tv_nsec: %li}): %p", sem, abs_timeout, abs_timeout->tv_sec, abs_timeout->tv_nsec, __builtin_return_address(0)); struct timespec overwrite; @@ -805,7 +820,7 @@ int __sym(sem_timedwait)(sem_t *restrict sem, const struct timespec *restrict ab return ret; } -int __sym(sem_getvalue)(sem_t *restrict sem, int *restrict value) { +int sym(sem_getvalue)(sem_t *restrict sem, int *restrict value) { init(); msg("sem_getvalue(%p, %p): %p", sem, value, __builtin_return_address(0)); if (mode >= 4) { @@ -821,7 +836,7 @@ int __sym(sem_getvalue)(sem_t *restrict sem, int *restrict value) { return ret; } -int __sym(sem_close)(sem_t *sem) { +int sym(sem_close)(sem_t *sem) { init(); msg("sem_close(%p): %p", sem, __builtin_return_address(0)); if (mode >= 4) { @@ -837,7 +852,7 @@ int __sym(sem_close)(sem_t *sem) { return ret; } -int __sym(sem_unlink)(const char *name) { +int sym(sem_unlink)(const char *name) { init(); msg("sem_unlink(%es): %p", name, __builtin_return_address(0)); char overwrite[BUFFER_SIZE]; @@ -868,7 +883,7 @@ int __sym(sem_unlink)(const char *name) { return ret; } -int __sym(sem_destroy)(sem_t *sem) { +int sym(sem_destroy)(sem_t *sem) { init(); msg("sem_destroy(%p): %p", sem, __builtin_return_address(0)); if (mode >= 4) { diff --git a/proj/test1/src/main.c b/proj/test1/src/main.c index c4e15ba..6ce2db6 100644 --- a/proj/test1/src/main.c +++ b/proj/test1/src/main.c @@ -32,7 +32,8 @@ void do_sem(void) { while (sem_wait(&sem) == -1) { if (errno != EINTR) { - // TODO fail + fprintf(stderr, "Unable to sem_wait: %s\n", strerror(errno)); + exit(1); } }