From d7f0ad4d8122ff4520d0d664ee16ae04a77d0ca1 Mon Sep 17 00:00:00 2001 From: Johnothan King Date: Fri, 27 Dec 2024 02:56:27 -0800 Subject: [PATCH] WIP: Fix annoying silent crash in builtins.sh under ASan Under ASan the builtins.sh script silently exits with exit status 1 and no backtrace. After isolating the bug into a simplified script, I managed to reproduce it with an actual stacktrace. Reproducer: #!/bin/ksh set -o xtrace # Shows how far the script goes before crashing # (which is inconsistent and system-dependent # AFAICT; ALL_LIBCMD can affect it). bltin='/opt/ast/bin/basename /opt/ast/bin/cat /opt/ast/bin/cp /opt/ast/bin/cut /opt/ast/bin/dirname /opt/ast/bin/getconf /opt/ast/bin/ln /opt/ast/bin/mktemp /opt/ast/bin/mv' # Feel free to expand this with other commands # from libcmd if you with. for i in ${bltin} do ({ PATH=/opt/ast/bin; "${bltin##*/}" --this-option-does-not-exist; } 2>&1) done Stacktrace obtained after much effort: ================================================================= ==116622==ERROR: AddressSanitizer: heap-use-after-free on address 0x502000000e50 at pc 0x72ad1bb52b7f bp 0x7ffc8b5a0cd0 sp 0x7ffc8b5a0478 READ of size 3 at 0x502000000e50 thread T0 #0 0x72ad1bb52b7e in memcpy /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 #1 0x5bb0a922f3de in synthesize /home/johno/GitRepos/KornShell/ksh/src/lib/libast/port/astconf.c:466 #2 0x5bb0a92305cd in initialize /home/johno/GitRepos/KornShell/ksh/src/lib/libast/port/astconf.c:591 #3 0x5bb0a9230fac in format /home/johno/GitRepos/KornShell/ksh/src/lib/libast/port/astconf.c:632 #4 0x5bb0a923ba4b in astgetconf /home/johno/GitRepos/KornShell/ksh/src/lib/libast/port/astconf.c:1382 #5 0x5bb0a923d5c5 in astconf /home/johno/GitRepos/KornShell/ksh/src/lib/libast/port/astconf.c:1472 #6 0x5bb0a924e07b in initconformance /home/johno/GitRepos/KornShell/ksh/src/lib/libast/misc/conformance.c:50 #7 0x5bb0a924eff2 in conformance /home/johno/GitRepos/KornShell/ksh/src/lib/libast/misc/conformance.c:122 #8 0x5bb0a9288b8e in b_cp /home/johno/GitRepos/KornShell/ksh/src/lib/libcmd/cp.c:706 src/lib/libast/port/astconf.c: - If fp->value and value pointed to the same allocated memory before realloc, avoid memcpy as value now points to freed memory. - Produce an obvious panic if memory allocation fails. src/cmd/ksh93/sh/init.c: - For correctness, prevent memory leaks by freeing memory in sh_realloc upon failure. --- src/cmd/ksh93/sh/init.c | 4 ++++ src/lib/libast/port/astconf.c | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index 17d1243013e6..b85a563a9ac9 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -245,7 +245,11 @@ void *sh_realloc(void *ptr, size_t size) void *cp; cp = realloc(ptr, size); if(!cp) + { + if(ptr) + free(ptr); nomemory(size); + } return cp; } diff --git a/src/lib/libast/port/astconf.c b/src/lib/libast/port/astconf.c index 4f0f98cef38a..21d5fd83dd0c 100644 --- a/src/lib/libast/port/astconf.c +++ b/src/lib/libast/port/astconf.c @@ -306,6 +306,7 @@ synthesize(Feature_t* fp, const char* path, const char* value) char* d; char* v; char* p; + int docpy; int n; #if DEBUG_astconf @@ -458,14 +459,26 @@ synthesize(Feature_t* fp, const char* path, const char* value) fp->value = 0; if (n == 1 && (*value == '0' || *value == '-')) n = 0; - if (!(fp->value = newof(fp->value, char, n, 1))) - fp->value = null; + docpy = fp->value != value; + if (!fp->value && !(fp->value = calloc(1, n + 1))) + { + error(ERROR_SYSTEM|ERROR_PANIC,"out of memory"); + UNREACHABLE(); + } else { - fp->flags |= CONF_ALLOC; - memcpy(fp->value, value, n); - fp->value[n] = 0; + char *tofree = fp->value; + if (!(fp->value = realloc(fp->value, n + 1))) + { + free(tofree); + error(ERROR_SYSTEM|ERROR_PANIC,"out of memory"); + UNREACHABLE(); + } } + fp->flags |= CONF_ALLOC; + if(docpy) + memcpy(fp->value, value, n); + fp->value[n] = 0; return fp->value; }