From 477c781679c774836493cb29b2191e3903000154 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 28 Apr 2026 15:28:25 -0400 Subject: call va_end # Conflicts: # src/lib/core/utils.c --- src/lib/core/utils.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 54c3dce..6b689c0 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -423,26 +423,28 @@ char *git_rev_parse(const char *path, char *args) { } void msg(unsigned type, char *fmt, ...) { + va_list args; + va_start(args, fmt); + FILE *stream = NULL; char header[255]; char status[20]; if (type & STASIS_MSG_NOP) { // quiet mode + va_end(args); return; } if (!globals.verbose && type & STASIS_MSG_RESTRICT) { // Verbose mode is not active + va_end(args); return; } memset(header, 0, sizeof(header)); memset(status, 0, sizeof(status)); - va_list args; - va_start(args, fmt); - stream = stdout; fprintf(stream, "%s", STASIS_COLOR_RESET); if (type & STASIS_MSG_ERROR) { @@ -1000,7 +1002,7 @@ int grow(const size_t size_new, size_t *size_orig, char **data) { } if (size_new >= *size_orig) { const size_t new_size = *size_orig + size_new + 1; - SYSDEBUG("template data buffer new size: %zu", new_size); + SYSDEBUG("template data buffer new size: %zu\n", new_size); char *tmp = realloc(*data, new_size); if (!tmp) { @@ -1188,7 +1190,7 @@ int get_random_bytes(char *result, size_t maxlen) { if (filename != NULL) { fp = fopen(filename, "rb"); if (!fp) { - SYSERROR("unable to open random generator"); + SYSERROR("%s", "unable to open random generator"); return -1; } } @@ -1201,7 +1203,7 @@ int get_random_bytes(char *result, size_t maxlen) { ch = rand() % 255; } if (fp && ferror(fp)) { - SYSERROR("unable to read from random generator"); + SYSERROR("%s", "unable to read from random generator"); fclose(fp); return -1; } -- cgit From c6e39332f675fa10483f58ac5c4df970a7b6bd15 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:18:27 -0400 Subject: delivery_init_platform: return on allocation error --- src/lib/delivery/delivery_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index c73e7f0..b97b93a 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -201,6 +201,10 @@ int delivery_init_platform(struct Delivery *ctx) { } for (size_t i = 0; i < DELIVERY_PLATFORM_MAX; i++) { ctx->system.platform[i] = calloc(DELIVERY_PLATFORM_MAXLEN, sizeof(*ctx->system.platform[0])); + if (!ctx->system.platform[i]) { + SYSERROR("Unable to allocate record %zu in platform array\n", i); + return -1; + } } ctx->system.arch = strdup(uts.machine); -- cgit From 4b75777b000602aefd4807c0aad4e27911ed58d1 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:18:59 -0400 Subject: delivery_init: return if platform cannot be established --- src/lib/delivery/delivery_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index b97b93a..acdddf6 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -294,7 +294,10 @@ int delivery_init(struct Delivery *ctx, int render_mode) { } // Configure architecture and platform information - delivery_init_platform(ctx); + if (delivery_init_platform(ctx)) { + // memory error + return -1; + } // Create STASIS directory structure delivery_init_dirs_stage1(ctx); -- cgit From 77257cff9f84d6bfe15c352a00e1231d8984b46e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:19:25 -0400 Subject: free tests on error --- src/lib/delivery/delivery_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c index 65d0451..1ba123a 100644 --- a/src/lib/delivery/delivery_test.c +++ b/src/lib/delivery/delivery_test.c @@ -8,6 +8,7 @@ struct Tests *tests_init(const size_t num_tests) { tests->test = calloc(num_tests, sizeof(*tests->test)); if (!tests->test) { + guard_free(tests); return NULL; } tests->num_used = 0; @@ -41,6 +42,7 @@ struct Test *test_init() { result->runtime = calloc(1, sizeof(*result->runtime)); if (!result->runtime) { + guard_free(result); return NULL; } -- cgit From 081da8afbfbd808acecc1d3e54f89b90c625ee77 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:41:28 -0400 Subject: handle asprintf errors --- src/cli/stasis_indexer/helpers.c | 5 ++++- src/cli/stasis_indexer/readmes.c | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cli/stasis_indexer/helpers.c b/src/cli/stasis_indexer/helpers.c index 097b0ca..bf7efee 100644 --- a/src/cli/stasis_indexer/helpers.c +++ b/src/cli/stasis_indexer/helpers.c @@ -297,7 +297,10 @@ int get_files(struct StrList **out, const char *path, const char *pattern, ...) struct StrList *get_docker_images(struct Delivery *ctx, char *pattern) { char *tarball = NULL; - asprintf(&tarball, "%s*.tar*", pattern); + if (asprintf(&tarball, "%s*.tar*", pattern) < 0) { + SYSERROR("unable to allocate bytes for tarball pattern: %s", pattern); + return NULL; + } if (!tarball) { SYSERROR("Unable to allocate bytes for docker image wildcard pattern"); return NULL; diff --git a/src/cli/stasis_indexer/readmes.c b/src/cli/stasis_indexer/readmes.c index de9e2f2..836df5c 100644 --- a/src/cli/stasis_indexer/readmes.c +++ b/src/cli/stasis_indexer/readmes.c @@ -101,10 +101,9 @@ int indexer_readmes(struct Delivery **ctx, const size_t nelem) { fprintf(indexfp, "- Receipt: [STASIS input file](../config/%s.ini)\n", current->info.release_name); char *pattern = NULL; - asprintf(&pattern, "*%s*%s*", + if (asprintf(&pattern, "*%s*%s*", current->info.build_number, - strstr((*ctx)->rules.release_fmt, "%p") ? current->meta.python_compact : "" ); - if (!pattern) { + strstr((*ctx)->rules.release_fmt, "%p") ? current->meta.python_compact : "" ) < 0) { SYSERROR("Unable to allocate bytes for pattern"); fclose(indexfp); return -1; -- cgit From d9ce0e78895e5dfa1e57aca76bb93b4b76dc6e74 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:42:46 -0400 Subject: delivery_duplicate: handle platform allocation error --- src/lib/delivery/delivery.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index 89074c8..cbc5898 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -1,7 +1,7 @@ #include "delivery.h" #include "conda.h" -struct Delivery *delivery_duplicate(const struct Delivery *ctx) { +struct Delivery *delivery_duplicate(struct Delivery *ctx) { struct Delivery *result = calloc(1, sizeof(*result)); if (!result) { return NULL; @@ -106,6 +106,12 @@ struct Delivery *delivery_duplicate(const struct Delivery *ctx) { } for (size_t i = 0; i < DELIVERY_PLATFORM_MAX; i++) { result->system.platform[i] = strdup_maybe(ctx->system.platform[i]); + if (!result->system.platform[i]) { + SYSERROR("%s", "unable to allocate record in system platform array"); + guard_array_n_free(result->system.platform, DELIVERY_PLATFORM_MAX); + delivery_free(ctx); + return NULL; + } } } -- cgit From c985cdf4019db2957e3073fec11c9b7a9fe3487c Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:43:44 -0400 Subject: delivery_duplicate: free context on error --- src/lib/delivery/delivery.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index cbc5898..557a0ed 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -56,12 +56,16 @@ struct Delivery *delivery_duplicate(struct Delivery *ctx) { result->rules._handle = malloc(sizeof(*result->rules._handle)); if (!result->rules._handle) { SYSERROR("unable to allocate space for INIFILE handle"); + SYSERROR("%s", "unable to allocate space for INIFILE handle"); + delivery_free(ctx); return NULL; } result->rules._handle->section = malloc(ctx->rules._handle->section_count * sizeof(**ctx->rules._handle->section)); if (!result->rules._handle->section) { guard_free(result->rules._handle); SYSERROR("unable to allocate space for INIFILE section"); + SYSERROR("%s", "unable to allocate space for INIFILE section"); + delivery_free(ctx); return NULL; } memcpy(result->rules._handle, &ctx->rules._handle, sizeof(*ctx->rules._handle)); @@ -102,6 +106,8 @@ struct Delivery *delivery_duplicate(struct Delivery *ctx) { result->system.platform = malloc(DELIVERY_PLATFORM_MAX * sizeof(*result->system.platform)); if (!result->system.platform) { SYSERROR("unable to allocate space for system platform array"); + SYSERROR("%s", "unable to allocate space for system platform array"); + delivery_free(ctx); return NULL; } for (size_t i = 0; i < DELIVERY_PLATFORM_MAX; i++) { -- cgit From 050c3d13136c7f4ba056383d20105624a1af6357 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:44:03 -0400 Subject: delivery_duplicate: free INI handle --- src/lib/delivery/delivery.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index 557a0ed..500bb88 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -257,6 +257,9 @@ void delivery_free(struct Delivery *ctx) { guard_free(ctx->rules.release_fmt); guard_free(ctx->rules.build_name_fmt); guard_free(ctx->rules.build_number_fmt); + if (ctx->rules._handle) { + ini_free(&ctx->rules._handle); + } guard_free(ctx->deploy.docker.test_script); guard_free(ctx->deploy.docker.registry); -- cgit From edec33cfb671f38a13e57fe03f80eec62b8377dc Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 12:44:14 -0400 Subject: delivery_duplicate: free INI handle --- src/lib/delivery/include/delivery.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/include/delivery.h b/src/lib/delivery/include/delivery.h index f234750..3103a86 100644 --- a/src/lib/delivery/include/delivery.h +++ b/src/lib/delivery/include/delivery.h @@ -499,7 +499,7 @@ void delivery_rewrite_stage2(struct Delivery *ctx, char *specfile); * @param ctx Delivery context * @return a copy */ -struct Delivery *delivery_duplicate(const struct Delivery *ctx); +struct Delivery *delivery_duplicate(struct Delivery *ctx); /** * Initialize a `Tests` structure -- cgit From e47e37c9537cc5ad215344262ecdda6f6c56b6d9 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:06:16 -0400 Subject: fix getval_setup implementation --- src/lib/core/ini.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 81c75ac..3c52312 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -219,80 +219,82 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, int #define getval_returns(t) return result.t #define getval_setup(t, f) \ - union INIVal result; \ + union INIVal result = {0}; \ + do {\ int state_local = 0; \ state_local = ini_getval(ini, section_name, key, t, f, &result); \ if (state != NULL) { \ *state = state_local; \ - } + } \ +} while (0) int ini_getval_int(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_INT, flags) + getval_setup(INIVAL_TYPE_INT, flags); getval_returns(as_int); } unsigned int ini_getval_uint(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_UINT, flags) + getval_setup(INIVAL_TYPE_UINT, flags); getval_returns(as_uint); } long ini_getval_long(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_LONG, flags) + getval_setup(INIVAL_TYPE_LONG, flags); getval_returns(as_long); } unsigned long ini_getval_ulong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_ULONG, flags) + getval_setup(INIVAL_TYPE_ULONG, flags); getval_returns(as_ulong); } long long ini_getval_llong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_LLONG, flags) + getval_setup(INIVAL_TYPE_LLONG, flags); getval_returns(as_llong); } unsigned long long ini_getval_ullong(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_ULLONG, flags) + getval_setup(INIVAL_TYPE_ULLONG, flags); getval_returns(as_ullong); } float ini_getval_float(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_FLOAT, flags) + getval_setup(INIVAL_TYPE_FLOAT, flags); getval_returns(as_float); } double ini_getval_double(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_DOUBLE, flags) + getval_setup(INIVAL_TYPE_DOUBLE, flags); getval_returns(as_double); } bool ini_getval_bool(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_BOOL, flags) + getval_setup(INIVAL_TYPE_BOOL, flags); getval_returns(as_bool); } short ini_getval_short(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_SHORT, flags) + getval_setup(INIVAL_TYPE_SHORT, flags); getval_returns(as_short); } unsigned short ini_getval_ushort(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_USHORT, flags) + getval_setup(INIVAL_TYPE_USHORT, flags); getval_returns(as_ushort); } char ini_getval_char(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_CHAR, flags) + getval_setup(INIVAL_TYPE_CHAR, flags); getval_returns(as_char); } unsigned char ini_getval_uchar(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_UCHAR, flags) + getval_setup(INIVAL_TYPE_UCHAR, flags); getval_returns(as_uchar); } char *ini_getval_char_p(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_STR, flags) + getval_setup(INIVAL_TYPE_STR, flags); getval_returns(as_char_p); } @@ -301,7 +303,7 @@ char *ini_getval_str(struct INIFILE *ini, char *section_name, char *key, int fla } char *ini_getval_char_array_p(struct INIFILE *ini, char *section_name, char *key, int flags, int *state) { - getval_setup(INIVAL_TYPE_STR_ARRAY, flags) + getval_setup(INIVAL_TYPE_STR_ARRAY, flags); getval_returns(as_char_p); } @@ -310,7 +312,7 @@ char *ini_getval_str_array(struct INIFILE *ini, char *section_name, char *key, i } struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char *key, char *tok, int flags, int *state) { - getval_setup(INIVAL_TYPE_STR_ARRAY, flags) + getval_setup(INIVAL_TYPE_STR_ARRAY, flags); struct StrList *list = strlist_init(); strlist_append_tokenize(list, result.as_char_p, tok); guard_free(result.as_char_p); -- cgit From e9ecb44bbd84c2896fcee35ead68baef9b8d1cc3 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:08:30 -0400 Subject: ini_section_create: realloc * Fix sizeof * Remove pointless else * Free on error --- src/lib/core/ini.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 3c52312..07206ac 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -403,12 +403,12 @@ int ini_setval(struct INIFILE **ini, unsigned type, char *section_name, char *ke } int ini_section_create(struct INIFILE **ini, char *key) { - struct INISection **tmp = realloc((*ini)->section, ((*ini)->section_count + 1) * sizeof(**(*ini)->section)); - if (tmp == NULL) { + struct INISection **tmp = realloc((*ini)->section, ((*ini)->section_count + 1) * sizeof (*(*ini)->section)); + if (!tmp) { + ini_free(ini); return 1; - } else { - (*ini)->section = tmp; } + (*ini)->section = tmp; (*ini)->section[(*ini)->section_count] = calloc(1, sizeof(*(*ini)->section[0])); if (!(*ini)->section[(*ini)->section_count]) { -- cgit From df6ccdd5e534f175ba735247880c0d3b24b33bd4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:09:47 -0400 Subject: ini_section_create: reduce the pointer to something human readable * free on error --- src/lib/core/ini.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 07206ac..b761f4d 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -410,13 +410,15 @@ int ini_section_create(struct INIFILE **ini, char *key) { } (*ini)->section = tmp; - (*ini)->section[(*ini)->section_count] = calloc(1, sizeof(*(*ini)->section[0])); - if (!(*ini)->section[(*ini)->section_count]) { + struct INISection **section = &(*ini)->section[(*ini)->section_count]; + //[(*ini)->section_count]; + *section = calloc(1, sizeof(*(*ini)->section[0])); + if (!*section) { return -1; } - (*ini)->section[(*ini)->section_count]->key = strdup(key); - if (!(*ini)->section[(*ini)->section_count]->key) { + (*section)->key = strdup(key); + if (!(*section)->key) { return -1; } -- cgit From 9d37911e194e526fa164dab43a0d4546fa14ddd2 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:16:07 -0400 Subject: ni_free: return on NULL --- src/lib/core/ini.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index b761f4d..ba3ab63 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -516,6 +516,9 @@ char *unquote(char *s) { } void ini_free(struct INIFILE **ini) { + if (!(*ini)) { + return; + } for (size_t section = 0; section < (*ini)->section_count; section++) { for (size_t data = 0; data < (*ini)->section[section]->data_count; data++) { if ((*ini)->section[section]->data[data]) { -- cgit From 8842af477c702f7f9bb5953e152407149e3e1d78 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:16:37 -0400 Subject: ini_open: return on error --- src/lib/core/ini.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index ba3ab63..495ee93 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -545,10 +545,19 @@ struct INIFILE *ini_open(const char *filename) { return NULL; } - ini_section_init(&ini); + ini->section = ini_section_init(&ini); + if (!ini->section) { + ini_free(&ini); + return NULL; + } // Create an implicit section. [default] does not need to be present in the INI config - ini_section_create(&ini, "default"); + if (ini_section_create(&ini, "default")) { + SYSERROR("%s", "unable to create default section"); + ini_free(&ini); + ini = NULL; + return NULL; + } strncpy(current_section, "default", sizeof(current_section) - 1); current_section[sizeof(current_section) - 1] = '\0'; @@ -621,7 +630,11 @@ struct INIFILE *ini_open(const char *filename) { // Create new named section strip(section_name); - ini_section_create(&ini, section_name); + if (ini_section_create(&ini, section_name)) { + SYSERROR("unable to create section: %s", section_name); + ini_free(&ini); + return NULL; + } // Record the name of the section. This is used until another section is found. memset(current_section, 0, sizeof(current_section)); -- cgit From 5f32f35ce9879b46a70b31c8847192d2006ccb4d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:18:13 -0400 Subject: junitxml: fail on allocation errors --- src/lib/core/junitxml.c | 93 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/src/lib/core/junitxml.c b/src/lib/core/junitxml.c index a59cb9d..e590cb5 100644 --- a/src/lib/core/junitxml.c +++ b/src/lib/core/junitxml.c @@ -209,42 +209,78 @@ static int read_xml_data(xmlTextReaderPtr reader, struct JUNIT_Testsuite **tests for (size_t x = 0; x < strlist_count(attrs); x += 2) { char *attr_name = strlist_item(attrs, x); char *attr_value = strlist_item(attrs, x + 1); - if (!strcmp(attr_name, "name")) { - (*testsuite)->name = strdup(attr_value); - } else if (!strcmp(attr_name, "errors")) { - (*testsuite)->errors = (int) strtol(attr_value, NULL, 10); - } else if (!strcmp(attr_name, "failures")) { - (*testsuite)->failures = (int) strtol(attr_value, NULL, 0); - } else if (!strcmp(attr_name, "skipped")) { - (*testsuite)->skipped = (int) strtol(attr_value, NULL, 0); - } else if (!strcmp(attr_name, "tests")) { - (*testsuite)->tests = (int) strtol(attr_value, NULL, 0); - } else if (!strcmp(attr_name, "time")) { - (*testsuite)->time = strtof(attr_value, NULL); - } else if (!strcmp(attr_name, "timestamp")) { - (*testsuite)->timestamp = strdup(attr_value); - } else if (!strcmp(attr_name, "hostname")) { - (*testsuite)->hostname = strdup(attr_value); + if (attr_name && attr_value) { + if (!strcmp(attr_name, "name")) { + (*testsuite)->name = strdup(attr_value); + if (!(*testsuite)->name) { + SYSERROR("%s", "failed to allocate memory for testcase name"); + return -1; + } + } else if (!strcmp(attr_name, "errors")) { + (*testsuite)->errors = (int) strtol(attr_value, NULL, 10); + } else if (!strcmp(attr_name, "failures")) { + (*testsuite)->failures = (int) strtol(attr_value, NULL, 0); + } else if (!strcmp(attr_name, "skipped")) { + (*testsuite)->skipped = (int) strtol(attr_value, NULL, 0); + } else if (!strcmp(attr_name, "tests")) { + (*testsuite)->tests = (int) strtol(attr_value, NULL, 0); + } else if (!strcmp(attr_name, "time")) { + (*testsuite)->time = strtof(attr_value, NULL); + } else if (!strcmp(attr_name, "timestamp")) { + (*testsuite)->timestamp = strdup(attr_value); + if (!(*testsuite)->timestamp) { + SYSERROR("%s", "failed to allocate memory for testcase timestamp"); + return -1; + } + } else if (!strcmp(attr_name, "hostname")) { + (*testsuite)->hostname = strdup(attr_value); + if (!(*testsuite)->hostname) { + SYSERROR("%s", "failed to allocate memory for testcase hostname"); + return -1; + } + } } } } else if (!strcmp(node_name, "testcase")) { struct JUNIT_Testcase *testcase = testcase_from_attributes(attrs); + if (!testcase) { + SYSERROR("%s", "failed to allocate memory for testcase"); + return -1; + } testsuite_append_testcase(testsuite, testcase); } else if (!strcmp(node_name, "failure")) { size_t cur_tc = (*testsuite)->_tc_inuse > 0 ? (*testsuite)->_tc_inuse - 1 : (*testsuite)->_tc_inuse; struct JUNIT_Failure *failure = testcase_failure_from_attributes(attrs); - (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_FAILURE; - (*testsuite)->testcase[cur_tc]->result_state.failure = failure; + if (!failure) { + SYSERROR("%s", "failed to allocate memory for testcase failure"); + return -1; + } + if ((*testsuite)->testcase && (*testsuite)->testcase[cur_tc]) { + (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_FAILURE; + (*testsuite)->testcase[cur_tc]->result_state.failure = failure; + } } else if (!strcmp(node_name, "error")) { size_t cur_tc = (*testsuite)->_tc_inuse > 0 ? (*testsuite)->_tc_inuse - 1 : (*testsuite)->_tc_inuse; struct JUNIT_Error *error = testcase_error_from_attributes(attrs); - (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_ERROR; - (*testsuite)->testcase[cur_tc]->result_state.error = error; + if (!error) { + SYSERROR("%s", "failed to allocate memory for testcase error"); + return -1; + } + if ((*testsuite)->testcase && (*testsuite)->testcase[cur_tc]) { + (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_ERROR; + (*testsuite)->testcase[cur_tc]->result_state.error = error; + } } else if (!strcmp(node_name, "skipped")) { size_t cur_tc = (*testsuite)->_tc_inuse > 0 ? (*testsuite)->_tc_inuse - 1 : (*testsuite)->_tc_inuse; struct JUNIT_Skipped *skipped = testcase_skipped_from_attributes(attrs); - (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_SKIPPED; - (*testsuite)->testcase[cur_tc]->result_state.skipped = skipped; + if (!skipped) { + SYSERROR("%s", "failed to allocate memory for testcase skipped"); + return -1; + } + if ((*testsuite)->testcase && (*testsuite)->testcase[cur_tc]) { + (*testsuite)->testcase[cur_tc]->tc_result_state_type = JUNIT_RESULT_STATE_SKIPPED; + (*testsuite)->testcase[cur_tc]->result_state.skipped = skipped; + } } } (*testsuite)->passed = (*testsuite)->tests - (*testsuite)->failures - (*testsuite)->errors - (*testsuite)->skipped; @@ -255,12 +291,17 @@ static int read_xml_data(xmlTextReaderPtr reader, struct JUNIT_Testsuite **tests static int read_xml_file(const char *filename, struct JUNIT_Testsuite **testsuite) { xmlTextReaderPtr reader = xmlReaderForFile(filename, NULL, 0); if (!reader) { + xmlFreeTextReader(reader); return -1; } int result = xmlTextReaderRead(reader); while (result == 1) { - read_xml_data(reader, testsuite); + if (read_xml_data(reader, testsuite) < 0) { + xmlFreeTextReader(reader); + return -1; + } + result = xmlTextReaderRead(reader); } @@ -279,6 +320,10 @@ struct JUNIT_Testsuite *junitxml_testsuite_read(const char *filename) { if (!result) { return NULL; } - read_xml_file(filename, &result); + + if (read_xml_file(filename, &result)) { + junitxml_testsuite_free(&result); + } + return result; } \ No newline at end of file -- cgit From 9732a6fca438f719eb9e7c9f48e9df726743a9ea Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:18:40 -0400 Subject: write_report_output: fail on allocation errors --- src/cli/stasis_indexer/junitxml_report.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli/stasis_indexer/junitxml_report.c b/src/cli/stasis_indexer/junitxml_report.c index 073bb61..891fe8a 100644 --- a/src/cli/stasis_indexer/junitxml_report.c +++ b/src/cli/stasis_indexer/junitxml_report.c @@ -31,6 +31,10 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x char *bname_tmp = strdup(xmlfilename); char *bname = strdup(path_basename(bname_tmp)); + if (!bname) { + SYSERROR("%s", "unable to allocate bytes for basename"); + return -1; + } if (endswith(bname, ".xml")) { bname[strlen(bname) - 4] = 0; } -- cgit From c8812a2d2c8d0ab5e79ddf374e1c2b2235de9810 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:19:45 -0400 Subject: split: free on error --- src/lib/core/str.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/core/str.c b/src/lib/core/str.c index 501c232..c80666b 100644 --- a/src/lib/core/str.c +++ b/src/lib/core/str.c @@ -93,7 +93,6 @@ char** split(char *_sptr, const char* delim, size_t max) // Duplicate the input string and save a copy of the pointer to be freed later char *orig = _sptr; char *sptr = strdup(orig); - if (!sptr) { return NULL; } @@ -134,6 +133,8 @@ char** split(char *_sptr, const char* delim, size_t max) } result[i] = calloc(STASIS_BUFSIZ, sizeof(char)); if (!result[i]) { + guard_free(sptr); + guard_array_n_free(result, i); return NULL; } strncpy(result[i], token, STASIS_BUFSIZ - 1); @@ -145,6 +146,8 @@ char** split(char *_sptr, const char* delim, size_t max) // append the remaining string contents to array result[i] = calloc(STASIS_BUFSIZ, sizeof(char)); if (!result[i]) { + guard_free(sptr); + guard_array_n_free(result, i); return NULL; } strncpy(result[i], &orig[pos], STASIS_BUFSIZ - 1); @@ -227,7 +230,7 @@ char *join_ex(char *separator, ...) { result = calloc(size + 1, sizeof(char)); for (size_t i = 0; i < argc; i++) { // Append argument to string - strncat(result, argv[i], size - strlen(result)); // no -1 because +1 above + strncat(result, argv[i], size - (result ? strlen(result) - 1 : 0)); // no -1 because +1 above // Do not append a trailing separator when we reach the last argument if (i < (argc - 1)) { -- cgit From 59f63ed5665aee5596ead0e8c79e883c4cb27bf3 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:20:25 -0400 Subject: join: maybe truncate string --- src/lib/core/str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/str.c b/src/lib/core/str.c index c80666b..447fc78 100644 --- a/src/lib/core/str.c +++ b/src/lib/core/str.c @@ -175,7 +175,7 @@ char *join(char **arr, const char *separator) { result = (char *)calloc(total_bytes, sizeof(char)); for (int i = 0; i < records; i++) { - strncat(result, arr[i], total_bytes - strlen(result) - 1); + strncat(result, arr[i], total_bytes - (result ? strlen(result) - 1 : 0)); if (i < (records - 1)) { strncat(result, separator, total_bytes - strlen(result) - 1); } -- cgit From a3c516350bcfdbfca8557a528d20daae5eef6a06 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:21:11 -0400 Subject: git_describe: close pipe on error --- src/lib/core/utils.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 6b689c0..ba847e2 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -415,7 +415,11 @@ char *git_rev_parse(const char *path, char *args) { if (!pp) { return NULL; } - fgets(version, sizeof(version) - 1, pp); + if (fgets(version, sizeof(version) - 1, pp) == NULL) { + pclose(pp); + popd(); + return NULL; + } strip(version); pclose(pp); popd(); -- cgit From eb362846147bea33242c66972493a2fce8ba7053 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:21:44 -0400 Subject: xmkstemp: Simplify tmpdir assignment --- src/lib/core/utils.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index ba847e2..0ba5170 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -504,14 +504,10 @@ void debug_shell() { char *xmkstemp(FILE **fp, const char *mode) { int fd = -1; - char tmpdir[PATH_MAX]; - char t_name[PATH_MAX * 2]; + char tmpdir[PATH_MAX] = {0}; + char t_name[PATH_MAX * 2] = {0}; - if (globals.tmpdir) { - strncpy(tmpdir, globals.tmpdir, sizeof(tmpdir) - 1); - } else { - strncpy(tmpdir, "/tmp/stasis", sizeof(tmpdir) - 1); - } + strncpy(tmpdir, globals.tmpdir ? globals.tmpdir : "/tmp/stasis", sizeof(tmpdir) - 1); tmpdir[sizeof(tmpdir) - 1] = '\0'; if (mkdirs(tmpdir, 0700) < 0) { -- cgit From 9300ecd1b163b0eb057a3b70dfbae713febd00d7 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:22:22 -0400 Subject: xmkstemp: UB, close handles correctly * free tempfile --- src/lib/core/utils.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 0ba5170..35310b4 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -525,23 +525,19 @@ char *xmkstemp(FILE **fp, const char *mode) { } *fp = fdopen(fd, mode); if (!*fp) { - // unable to open, die - if (fd > 0) - close(fd); - *fp = NULL; + close(fd); return NULL; } char *path = strdup(t_name); if (!path) { // strdup failed, die - if (*fp) { - // close the file handle - fclose(*fp); - *fp = NULL; - } - // fall through. path is NULL. + // close the file handle + fclose(*fp); + *fp = NULL; + return NULL; } + return path; } -- cgit From 345becc488f47cd2383dcca3fc08af464ba4f8ff Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:23:17 -0400 Subject: xml_pretty_print_in_place: close file handles and allocations correctly --- src/lib/core/utils.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 35310b4..221d507 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -605,10 +605,7 @@ int path_store(char **destptr, size_t maxlen, const char *base, const char *path int xml_pretty_print_in_place(const char *filename, const char *pretty_print_prog, const char *pretty_print_args) { int status = 0; - char *tempfile = NULL; char *result = NULL; - FILE *fp = NULL; - FILE *tmpfp = NULL; char cmd[PATH_MAX]; if (!find_program(pretty_print_prog)) { // Pretty printing is optional. 99% chance the XML data will @@ -619,11 +616,18 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro snprintf(cmd, sizeof(cmd), "%s %s %s", pretty_print_prog, pretty_print_args, filename); result = shell_output(cmd, &status); if (status || !result) { - goto pretty_print_failed; + return status; } - tempfile = xmkstemp(&tmpfp, "w+"); - if (!tmpfp || !tempfile) { + int clean_up_fp = 0; + FILE *tmpfp = NULL; + char *tempfile = xmkstemp(&tmpfp, "w+"); + if (!tempfile || !tmpfp) { + guard_free(tempfile); + if (tmpfp) { + fclose(tmpfp); + } + status = -1; goto pretty_print_failed; } @@ -631,10 +635,12 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro fflush(tmpfp); fclose(tmpfp); - fp = fopen(filename, "w+"); + FILE *fp = fopen(filename, "w+"); if (!fp) { + status = -1; goto pretty_print_failed; } + clean_up_fp = 1; if (copy2(tempfile, filename, CT_PERM)) { SYSWARN("unable to copy: '%s' -> '%s'", tempfile, filename); @@ -651,15 +657,16 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro return 0; pretty_print_failed: - if (fp) { - fclose(fp); - } - if (tmpfp) { - fclose(tmpfp); - } - guard_free(tempfile); - guard_free(result); - return -1; + if (tempfile && remove(tempfile)) { + SYSERROR("unable to remove temporary file: %s", tempfile); + } + guard_free(tempfile); + guard_free(result); + if (clean_up_fp) { + fclose(fp); + } + + return status; } /** -- cgit From 5561871e9fe902a6787bd13475b94e37831b923a Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:23:43 -0400 Subject: fix_tox_conf: close file handles and allocations correctly --- src/lib/core/utils.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 221d507..78d713d 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -678,12 +678,15 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro */ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { struct INIFILE *toxini; - FILE *fptemp; + FILE *fptemp = NULL; // Create new temporary tox configuration file char *tempfile = xmkstemp(&fptemp, "w+"); if (!tempfile) { SYSERROR("unable to create temporary file"); + if (fptemp) { + fclose(fptemp); + } return -1; } @@ -692,6 +695,9 @@ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { *result = calloc(maxlen, sizeof(**result)); if (!*result) { guard_free(tempfile); + if (fptemp) { + fclose(fptemp); + } return -1; } } @@ -729,6 +735,7 @@ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { strlen(value) + strlen(with_posargs) + 1); guard_free(*result); guard_free(tempfile); + fclose(fptemp); return -1; } value = tmp; -- cgit From 345d8fa8867a37de7493d0bc353a36c6e2680419 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:24:17 -0400 Subject: add non_format_len() function --- src/lib/core/include/utils.h | 7 +++++++ src/lib/core/utils.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/lib/core/include/utils.h b/src/lib/core/include/utils.h index 1a5e97f..5bd037f 100644 --- a/src/lib/core/include/utils.h +++ b/src/lib/core/include/utils.h @@ -484,4 +484,11 @@ int str_to_timeout(char *s); const char *get_random_generator_file(); int get_random_bytes(char *result, size_t maxlen); +/** + * Get length of `s` as if any formatters are not present + * @param s format string + * @return length + */ +int non_format_len(const char *s); + #endif //STASIS_UTILS_H diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 78d713d..5ba10c4 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -1229,3 +1229,23 @@ int get_random_bytes(char *result, size_t maxlen) { result[bytes ? bytes - 1 : 0] = '\0'; return 0; } + +int non_format_len(const char *s) { + int len = 0; + int until_space = 0; + for (size_t i = 0; i < strlen(s); i++) { + if (until_space && isspace(s[i])) { + until_space = 0; + } + if (until_space && !isspace(s[i])) { + continue; + } + if (s[i] == '%') { + until_space = 1; + continue; + } + len++; + } + return len; +} + -- cgit From 14ceedd4d1436de5c0f5e448b71bd6e0a5fa154d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:25:36 -0400 Subject: wheel_parse_metadata: return on error --- src/lib/core/wheel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index ea2089a..64399fd 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -539,6 +539,10 @@ static ssize_t wheel_parse_metadata(struct WheelMetadata * const pkg, const char return -1; } current_extra = pkg->provides_extra[provides_extra_i]; + if (!current_extra) { + SYSERROR("%s", "provides_extra array cannot have a NULL record"); + return -1; + } current_extra->target = strdup(value); if (!current_extra->target) { // memory error -- cgit From 574cb264eaa307bdc8a2ea84a5128b8a1156d97b Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:25:50 -0400 Subject: wheel_parse_metadata: fix sizeof --- src/lib/core/wheel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 64399fd..e5e93b9 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -172,7 +172,7 @@ static ssize_t wheel_parse_metadata(struct WheelMetadata * const pkg, const char return -1; } - pkg->provides_extra = calloc(WHEEL_MAXELEM + 1, sizeof(pkg->provides_extra[0])); + pkg->provides_extra = calloc(WHEEL_MAXELEM + 1, sizeof(*pkg->provides_extra)); if (!pkg->provides_extra) { // memory error return -1; -- cgit From 9227c2526233f6ba0c300afdce21afdcf3dfd9f3 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:26:26 -0400 Subject: wheel_metadata_free: allow meta to be NULL --- src/lib/core/wheel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index e5e93b9..ccdf2c4 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -957,6 +957,9 @@ void wheel_entry_point_free(struct WheelEntryPoint **entry) { } void wheel_metadata_free(struct WheelMetadata *meta) { + if (!meta) { + return; + } guard_free(meta->license); guard_free(meta->license_expression); guard_free(meta->version); -- cgit From bbc45830393375f8b15edffc147c16ab1f946a00 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:26:57 -0400 Subject: wheel_package_free: allow pkg to be NULL --- src/lib/core/wheel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index ccdf2c4..2132818 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -994,6 +994,9 @@ void wheel_metadata_free(struct WheelMetadata *meta) { } void wheel_package_free(struct Wheel **pkg) { + if (!*pkg) { + return; + } guard_free((*pkg)->wheel_version); guard_free((*pkg)->generator); guard_free((*pkg)->root_is_pure_lib); -- cgit From 94f67cb77eacaefbd5e3d47bbf5d99ce03c2dc9e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:27:33 -0400 Subject: wheel_package_free: fix NULL dereference in provides_extra loop --- src/lib/core/wheel.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 2132818..4bd5c64 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -982,13 +982,14 @@ void wheel_metadata_free(struct WheelMetadata *meta) { guard_strlist_free(&meta->requires_dist); guard_strlist_free(&meta->keywords); guard_strlist_free(&meta->license_file); - - for (size_t i = 0; meta->provides_extra[i] != NULL; i++) { - guard_free(meta->provides_extra[i]->target); - guard_strlist_free(&meta->provides_extra[i]->requires_dist); - guard_free(meta->provides_extra[i]); + if (meta->provides_extra) { + for (size_t i = 0; meta->provides_extra[i] != NULL; i++) { + guard_free(meta->provides_extra[i]->target); + guard_strlist_free(&meta->provides_extra[i]->requires_dist); + guard_free(meta->provides_extra[i]); + } + guard_free(meta->provides_extra); } - guard_free(meta->provides_extra); guard_free(meta); } -- cgit From 5c256235b5545f048c493908131a76395f22c38d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:29:56 -0400 Subject: wheel_package_free: free record array --- src/lib/core/wheel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 4bd5c64..4b004ae 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -1008,7 +1008,7 @@ void wheel_package_free(struct Wheel **pkg) { for (size_t i = 0; (*pkg)->record && (*pkg)->record[i] != NULL; i++) { wheel_record_free(&(*pkg)->record[i]); } - guard_free((*pkg)->record); + guard_array_n_free((*pkg)->record, (*pkg)->num_record); for (size_t i = 0; (*pkg)->entry_point && (*pkg)->entry_point[i] != NULL; i++) { wheel_entry_point_free(&(*pkg)->entry_point[i]); -- cgit From c598f2080ee5ae7ebfbfff5ec3eb396ee545dce4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:30:29 -0400 Subject: wheel_package: fix leak on failure --- src/lib/core/wheel.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 4b004ae..2162dae 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -692,8 +692,8 @@ static int wheel_metadata_get(const struct Wheel *pkg, const char *wheel_filenam if (wheel_get_file_contents(wheel_filename, "*.dist-info/METADATA", &data)) { return -1; } - const ssize_t result = wheel_parse_metadata(pkg->metadata, data); char *data_orig = data; + const ssize_t result = wheel_parse_metadata(pkg->metadata, data); guard_free(data_orig); return (int) result; } @@ -1142,6 +1142,7 @@ int wheel_get_entry_point(struct Wheel *pkg, const char *filename) { for (size_t i = 0; i < usable_lines; i++) { pkg->entry_point[i] = calloc(1, sizeof(*pkg->entry_point[0])); if (!pkg->entry_point[i]) { + guard_array_n_free(pkg->entry_point, usable_lines + 1); goto GEP_FAIL; } } @@ -1343,41 +1344,54 @@ int wheel_show_info(const struct Wheel *wheel) { } int wheel_package(struct Wheel **pkg, const char *filename) { + int status = 0; if (!filename) { - return WHEEL_PACKAGE_E_FILENAME; + status = WHEEL_PACKAGE_E_FILENAME; + goto fail; } if (!*pkg) { *pkg = calloc(1, sizeof(**pkg)); if (!*pkg) { - return WHEEL_PACKAGE_E_ALLOC; + status = WHEEL_PACKAGE_E_ALLOC; + goto fail; } (*pkg)->metadata = calloc(1, sizeof(*(*pkg)->metadata)); if (!(*pkg)->metadata) { - guard_free(*pkg); - return WHEEL_PACKAGE_E_ALLOC; + status = WHEEL_PACKAGE_E_ALLOC; + goto fail; } } if (wheel_get(pkg, filename) < 0) { - return WHEEL_PACKAGE_E_GET; + status = WHEEL_PACKAGE_E_GET; + goto fail; } if (wheel_metadata_get(*pkg, filename) < 0) { - return WHEEL_PACKAGE_E_GET_METADATA; + status = WHEEL_PACKAGE_E_GET_METADATA; + goto fail; } if (wheel_get_top_level(*pkg, filename) < 0) { - return WHEEL_PACKAGE_E_GET_TOP_LEVEL; + status = WHEEL_PACKAGE_E_GET_TOP_LEVEL; + goto fail; } if (wheel_get_records(*pkg, filename) < 0) { - return WHEEL_PACKAGE_E_GET_RECORDS; + status = WHEEL_PACKAGE_E_GET_RECORDS; + goto fail; } if (wheel_get_entry_point(*pkg, filename) < 0) { - return WHEEL_PACKAGE_E_GET_ENTRY_POINT; + status = WHEEL_PACKAGE_E_GET_ENTRY_POINT; + goto fail; } // Optional marker wheel_get_zip_safe(*pkg, filename); - return WHEEL_PACKAGE_E_SUCCESS; + status = WHEEL_PACKAGE_E_SUCCESS; + return status; + + fail: + wheel_package_free(pkg); + return status; } -- cgit From 7524ce5fde0cd7bfe7b2adaafec9d509f917e8c1 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 13:34:38 -0400 Subject: strlist: check return value of strlist_item before using it --- src/lib/core/strlist.c | 115 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 17 deletions(-) diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c index 526a1c9..5cd3f4a 100644 --- a/src/lib/core/strlist.c +++ b/src/lib/core/strlist.c @@ -171,6 +171,10 @@ int strlist_contains(struct StrList *pStrList, const char *value, size_t *index_ for (size_t i = 0; i < strlist_count(pStrList); i++) { const char *item = strlist_item(pStrList, i); + if (!item) { + *index_of = 0; + break; + } if (!strcmp(item, value)) { *index_of = i; return 1; @@ -359,9 +363,10 @@ int strlist_cmp(struct StrList *a, struct StrList *b) { return 1; } - for (size_t i = 0; i < strlist_count(a); i++) { - if (strcmp(strlist_item(a, i), strlist_item(b, i)) != 0) { + const char *item_a = strlist_item(a, i); + const char *item_b = strlist_item(b, i); + if ((!item_a || !item_b) || strcmp(item_a, item_b) != 0) { return 1; } } @@ -439,9 +444,8 @@ void strlist_set(struct StrList **pStrList, size_t index, char *value) { if (!tmp) { SYSERROR("strlist_set replacement realloc failed: %s", strerror(errno)); return; - } else if (tmp != (*pStrList)->data[index]) { - (*pStrList)->data[index] = tmp; } + (*pStrList)->data[index] = tmp; const size_t len = strlen(value) + 1; memset((*pStrList)->data[index], '\0', len); @@ -506,7 +510,13 @@ char strlist_item_as_char(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - char result = (char) strtol(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return CHAR_MAX; + } + + char result = (char) strtol(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -525,7 +535,13 @@ unsigned char strlist_item_as_uchar(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - unsigned char result = (unsigned char) strtoul(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return UCHAR_MAX; + } + + unsigned char result = (unsigned char) strtoul(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -544,7 +560,12 @@ short strlist_item_as_short(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - short result = (short) strtol(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return SHRT_MAX; + } + short result = (short) strtol(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -563,7 +584,13 @@ unsigned short strlist_item_as_ushort(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - unsigned short result = (unsigned short) strtoul(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return USHRT_MAX; + } + + unsigned short result = (unsigned short) strtoul(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -582,7 +609,13 @@ int strlist_item_as_int(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - int result = (int) strtol(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return INT_MAX; + } + + int result = (int) strtol(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -601,7 +634,13 @@ unsigned int strlist_item_as_uint(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - unsigned int result = (unsigned int) strtoul(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return UINT_MAX; + } + + unsigned int result = (unsigned int) strtoul(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -620,7 +659,13 @@ long strlist_item_as_long(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - long result = (long) strtol(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return LONG_MAX; + } + + long result = (long) strtol(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -639,7 +684,13 @@ unsigned long strlist_item_as_ulong(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - unsigned long result = (unsigned long) strtoul(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return ULONG_MAX; + } + + unsigned long result = (unsigned long) strtoul(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -658,7 +709,13 @@ long long strlist_item_as_long_long(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - long long result = (long long) strtoll(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return LONG_LONG_MAX; + } + + long long result = (long long) strtoll(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -677,7 +734,13 @@ unsigned long long strlist_item_as_ulong_long(struct StrList *pStrList, size_t i char *error_p; strlist_clear_error(); - unsigned long long result = (unsigned long long) strtol(strlist_item(pStrList, index), &error_p, 10); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return ULONG_LONG_MAX; + } + + unsigned long long result = (unsigned long long) strtol(item, &error_p, 10); if (!result && error_p && *error_p != 0) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -696,7 +759,13 @@ float strlist_item_as_float(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - const float result = strtof(strlist_item(pStrList, index), &error_p); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return HUGE_VALF; + } + + const float result = strtof(item, &error_p); if ((result == FLT_MIN || result == HUGE_VALF) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -715,7 +784,13 @@ double strlist_item_as_double(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - const double result = strtod(strlist_item(pStrList, index), &error_p); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return HUGE_VAL; + } + + const double result = strtod(item, &error_p); if ((result == DBL_MIN || result == HUGE_VAL) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; @@ -734,7 +809,13 @@ long double strlist_item_as_long_double(struct StrList *pStrList, size_t index) char *error_p; strlist_clear_error(); - const long double result = strtold(strlist_item(pStrList, index), &error_p); + char *item = strlist_item(pStrList, index); + if (!item) { + strlist_set_error(STRLIST_E_INVALID_VALUE); + return LDBL_MAX; + } + + const long double result = strtold(item, &error_p); if ((result == DBL_MIN || result == HUGE_VALL) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; -- cgit From 0557219fbfe52cfb284f62b37e0bcce111a57cf0 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 14:28:36 -0400 Subject: Subtract remaining characters in format string --- src/cli/stasis_indexer/stasis_indexer_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index 2bf72fd..86cace5 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -48,9 +48,9 @@ int indexer_combine_rootdirs(const char *dest, char **rootdirs, const size_t roo if (!access(srcdir_with_output, F_OK)) { srcdir = srcdir_with_output; } - snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "'%s'/ ", srcdir); + snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd) - non_format_len("'%s'/ "), "'%s'/ ", srcdir); } - snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), " %s/", destdir); + snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd) - non_format_len(" %s/"), " %s/", destdir); if (globals.verbose) { puts(cmd); -- cgit From 657d1cd403a4d97c73260eae1e689e55ff324895 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 14:29:49 -0400 Subject: maxwidth will fit --- src/cli/stasis/stasis_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index b902a8a..553d275 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -551,12 +551,11 @@ static char *center_text(const char *s, const size_t maxwidth) { } result[i++] = 'v'; strncpy(&result[i], s, maxwidth - middle - 1); - result[maxwidth - 1] = '\0'; + result[maxwidth] = '\0'; return result; } - int main(int argc, char *argv[]) { struct Delivery ctx; struct Process proc = { -- cgit From 5e546365edeb7f9ff92f3fd75fadb19058723813 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 29 Apr 2026 14:32:36 -0400 Subject: return INISection on init --- src/lib/core/ini.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 495ee93..b4674e8 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -14,8 +14,9 @@ struct INIFILE *ini_init() { return ini; } -void ini_section_init(struct INIFILE **ini) { - (*ini)->section = calloc((*ini)->section_count + 1, sizeof(**(*ini)->section)); +struct INISection **ini_section_init(struct INIFILE **ini) { + struct INISection **section = calloc((*ini)->section_count + 1, sizeof(**(*ini)->section)); + return section; } struct INISection *ini_section_search(struct INIFILE **ini, unsigned mode, const char *value) { -- cgit From 79cbdf3b3ea5a38791cad816d650b542df6b4cbc Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Thu, 30 Apr 2026 09:42:06 -0400 Subject: Add message before running micromamba configuration --- src/cli/stasis_indexer/stasis_indexer_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index 86cace5..071057a 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -325,6 +325,7 @@ int main(const int argc, char *argv[]) { mkdirs(ctx.storage.wheel_artifact_dir, 0755); } + msg(STASIS_MSG_L1, "Configure Micromamba\n"); struct MicromambaInfo m; if (micromamba_configure(&ctx, &m)) { SYSERROR("Unable to configure micromamba"); -- cgit From 8f91345c4284ed6c882c38e961be106e72418ec8 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Thu, 30 Apr 2026 09:43:55 -0400 Subject: Move center_text function into utils.c/utils.h * Remove 'v' prefix * Print version the same way in the indexer --- src/cli/stasis_indexer/stasis_indexer_main.c | 12 +++++++++- src/lib/core/include/utils.h | 1 + src/lib/core/utils.c | 33 ++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index 071057a..e87122e 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -304,7 +304,17 @@ int main(const int argc, char *argv[]) { struct Delivery ctx = {0}; - printf(BANNER, VERSION, AUTHOR); + char *version = center_text(VERSION, strlen(STASIS_BANNER_HEADER)); + if (!version) { + SYSERROR("%s", "version too long?"); + version = strdup(VERSION); + if (!version) { + SYSERROR("%s", "unable to allocate uncentered fallback version string"); + exit(1); + } + } + printf(BANNER, version, AUTHOR); + guard_free(version); indexer_init_dirs(&ctx, workdir); diff --git a/src/lib/core/include/utils.h b/src/lib/core/include/utils.h index 5bd037f..194f8e7 100644 --- a/src/lib/core/include/utils.h +++ b/src/lib/core/include/utils.h @@ -491,4 +491,5 @@ int get_random_bytes(char *result, size_t maxlen); */ int non_format_len(const char *s); +char *center_text(const char *s, size_t maxwidth); #endif //STASIS_UTILS_H diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 5ba10c4..72ecfc9 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -1249,3 +1249,36 @@ int non_format_len(const char *s) { return len; } +char *center_text(const char *s, const size_t maxwidth) { + if (maxwidth < 2) { + SYSERROR("%s", "maximum width must be greater than 0"); + return NULL; + } + + if (maxwidth % 2 != 0) { + SYSERROR("maximum width (%zu) must be even", maxwidth); + return NULL; + } + + const size_t s_len = strlen(s); + if (s_len + 1 > maxwidth) { + SYSERROR("length of input string (%zu) exceeds maximum width (%zu)", s_len, maxwidth); + return NULL; + } + + char *result = calloc(maxwidth + 1, sizeof(*result)); + if (!result) { + SYSERROR("%s", "unable to allocate bytes for centered text string"); + return NULL; + } + const size_t middle = (maxwidth / 2) - s_len / 2; + size_t i = 0; + for (; i < middle; i++) { + result[i] = ' '; + } + strncpy(&result[i], s, maxwidth - middle - 1); + result[maxwidth] = '\0'; + + return result; +} + -- cgit From 801f6f3fb6c7a87b689c4c4c478ebb62523931b5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Thu, 30 Apr 2026 09:45:15 -0400 Subject: init: clean up on error --- src/lib/core/ini.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index b4674e8..3c0377f 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -633,6 +633,7 @@ struct INIFILE *ini_open(const char *filename) { strip(section_name); if (ini_section_create(&ini, section_name)) { SYSERROR("unable to create section: %s", section_name); + guard_free(section_name); ini_free(&ini); return NULL; } @@ -652,7 +653,7 @@ struct INIFILE *ini_open(const char *filename) { continue; } - char *operator = strchr(line, '='); + const char *operator = strchr(line, '='); // a value continuation line if (multiline_data && (startswith(line, " ") || startswith(line, "\t"))) { @@ -660,7 +661,7 @@ struct INIFILE *ini_open(const char *filename) { } if (operator) { - size_t key_len = operator - line; + const size_t key_len = operator - line; memset(key, 0, key_size); strncpy(key, line, key_len); -- cgit From 6cf418547c51e885648e028e3ec9e167cc32dec3 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 1 May 2026 18:58:47 -0400 Subject: terminate platform string after copy --- src/lib/delivery/delivery_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index acdddf6..5f1c605 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -222,6 +222,8 @@ int delivery_init_platform(struct Delivery *ctx) { SYSDEBUG("Setting platform"); strncpy(ctx->system.platform[DELIVERY_PLATFORM], uts.sysname, DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; + if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Darwin")) { snprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], DELIVERY_PLATFORM_MAXLEN, "osx-%s", archsuffix); strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "MacOSX", DELIVERY_PLATFORM_MAXLEN - 1); -- cgit From f467de54062fed57c37de53d1e89794b5e9eee2a Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 1 May 2026 19:01:03 -0400 Subject: explicitly check if option name is NULL --- src/cli/stasis/args.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/stasis/args.c b/src/cli/stasis/args.c index e1c49fe..eb096bc 100644 --- a/src/cli/stasis/args.c +++ b/src/cli/stasis/args.c @@ -59,7 +59,7 @@ static int get_option_max_width(struct option option[]) { int i = 0; int max = 0; const int indent = 4; - while (option[i].name != 0) { + while (option[i].name != NULL) { int len = (int) strlen(option[i].name); if (option[i].has_arg) { len += indent; -- cgit From 095793d256f97ef8bd0820ffee78be1f6c8c9349 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 6 May 2026 17:16:44 -0400 Subject: terminate strings --- src/lib/delivery/delivery_install.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index 4d52b82..e699122 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -376,14 +376,16 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha if (INSTALL_PKG_CONDA_DEFERRED & type) { strncat(command_base, " --use-local", sizeof(command_base) - strlen(command_base) - 1); + command_base[sizeof(command_base) - 1] = '\0'; } else if (INSTALL_PKG_PIP_DEFERRED & type) { // Don't change the baseline package set unless we're working with a // new build. Release candidates will need to keep packages as stable // as possible between releases. if (!ctx->meta.based_on) { strncat(command_base, " --upgrade", sizeof(command_base) - strlen(command_base) - 1); + command_base[sizeof(command_base) - 1] = '\0'; } - snprintf(command_base + strlen(command_base), sizeof(command_base), " --extra-index-url 'file://%s'", ctx->storage.wheel_artifact_dir); + snprintf(command_base + strlen(command_base), sizeof(command_base) - strlen(command_base), " --extra-index-url 'file://%s'", ctx->storage.wheel_artifact_dir); } size_t args_alloc_len = STASIS_BUFSIZ; -- cgit From 5ec6f09c2abcc866b4ba34a995d5f61e7851df48 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 6 May 2026 17:17:06 -0400 Subject: Add debug output --- src/lib/delivery/delivery_install.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index e699122..ca41c82 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -404,15 +404,18 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha continue; } if (INSTALL_PKG_PIP_DEFERRED & type) { + SYSDEBUG("Getting requirements for test: %s", name); struct Test *info = requirement_from_test(ctx, name); if (info) { if (!strcmp(info->version, "HEAD") || is_git_sha(info->version)) { + SYSDEBUG("Using version: %s", info->version); struct StrList *tag_data = strlist_init(); if (!tag_data) { SYSERROR("Unable to allocate memory for tag data"); guard_free(args); return -1; } + SYSDEBUG("%s", "Tokenizing repository info tag: %s\n", info->repository_info_tag); strlist_append_tokenize(tag_data, info->repository_info_tag, "-"); struct WheelInfo *whl = NULL; @@ -420,13 +423,16 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha char *hash = NULL; if (strlist_count(tag_data) > 1) { post_commit = strlist_item(tag_data, 1); + SYSDEBUG("post_commit: %s", post_commit); hash = strlist_item(tag_data, 2); + SYSDEBUG("hash: %s", hash); } // We can't match on version here (index 0). The wheel's version is not guaranteed to be // equal to the tag; setuptools_scm auto-increments the value, the user can change it manually, // etc. errno = 0; + SYSDEBUG("%s", "Getting wheel information"); whl = wheelinfo_get(ctx->storage.wheel_artifact_dir, info->name, (char *[]) {ctx->meta.python_compact, ctx->system.arch, "none", "any", @@ -441,8 +447,10 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha SYSERROR("No wheel packages found that match the description of '%s'", info->name); } else { // found, replace the original version with newly detected version + SYSDEBUG("Replacing version: %s", whl->version); guard_free(info->version); info->version = strdup(whl->version); + SYSDEBUG("Version replaced with: %s", whl->version); } guard_strlist_free(&tag_data); wheelinfo_free(&whl); -- cgit From 398c71a07c84312d7438974d178a0358d3713e2b Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 17:04:41 -0400 Subject: Error check --- src/cli/stasis_indexer/junitxml_report.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cli/stasis_indexer/junitxml_report.c b/src/cli/stasis_indexer/junitxml_report.c index 891fe8a..909bf1d 100644 --- a/src/cli/stasis_indexer/junitxml_report.c +++ b/src/cli/stasis_indexer/junitxml_report.c @@ -30,11 +30,17 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x } char *bname_tmp = strdup(xmlfilename); + if (!bname_tmp) { + SYSERROR("%s", "unable to allocate bytes for temporary basename"); + return -1; + } + char *bname = strdup(path_basename(bname_tmp)); if (!bname) { SYSERROR("%s", "unable to allocate bytes for basename"); return -1; } + if (endswith(bname, ".xml")) { bname[strlen(bname) - 4] = 0; } -- cgit From 9df56118210af2ae0af8d735e85b391828b5d289 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 20:10:24 -0400 Subject: How did you get back in there... --- src/cli/stasis/stasis_main.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index 553d275..fb4ed80 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -522,40 +522,6 @@ static void transfer_artifacts(struct Delivery *ctx) { } } -static char *center_text(const char *s, const size_t maxwidth) { - if (maxwidth < 2) { - SYSERROR("maximum width must be greater than 0"); - return NULL; - } - - if (maxwidth % 2 != 0) { - SYSERROR("maximum width (%zu) must be even", maxwidth); - return NULL; - } - - const size_t s_len = strlen(s); - if (s_len + 1 > maxwidth) { - SYSERROR("length of input string (%zu) exceeds maximum width (%zu)", s_len, maxwidth); - return NULL; - } - - char *result = calloc(maxwidth + 1, sizeof(*result)); - if (!result) { - SYSERROR("unable to allocate bytes for centered text string"); - return NULL; - } - const size_t middle = (maxwidth / 2) - s_len / 2; - size_t i = 0; - for (; i < middle; i++) { - result[i] = ' '; - } - result[i++] = 'v'; - strncpy(&result[i], s, maxwidth - middle - 1); - result[maxwidth] = '\0'; - - return result; -} - int main(int argc, char *argv[]) { struct Delivery ctx; struct Process proc = { -- cgit From 69c99be43c918f7f0723fa6632ae1a766ed794e5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 20:33:31 -0400 Subject: Update macro --- src/lib/delivery/delivery_install.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index ca41c82..d39fa3e 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -415,7 +415,7 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha guard_free(args); return -1; } - SYSDEBUG("%s", "Tokenizing repository info tag: %s\n", info->repository_info_tag); + SYSDEBUG("Tokenizing repository info tag: %s\n", info->repository_info_tag); strlist_append_tokenize(tag_data, info->repository_info_tag, "-"); struct WheelInfo *whl = NULL; -- cgit From 98d50a05c62b772a6c391d05f175f44d8764c8a5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:37:13 -0400 Subject: Update SYS_* macros --- src/cli/stasis_indexer/junitxml_report.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/stasis_indexer/junitxml_report.c b/src/cli/stasis_indexer/junitxml_report.c index 909bf1d..a7dcd06 100644 --- a/src/cli/stasis_indexer/junitxml_report.c +++ b/src/cli/stasis_indexer/junitxml_report.c @@ -31,13 +31,13 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x char *bname_tmp = strdup(xmlfilename); if (!bname_tmp) { - SYSERROR("%s", "unable to allocate bytes for temporary basename"); + SYSERROR("unable to allocate bytes for temporary basename"); return -1; } char *bname = strdup(path_basename(bname_tmp)); if (!bname) { - SYSERROR("%s", "unable to allocate bytes for basename"); + SYSERROR("unable to allocate bytes for basename"); return -1; } -- cgit From b5bda9c367d78a28c6523071d6c8c8e7b6551f02 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:42:34 -0400 Subject: Close all file descriptors in child process, except STDIN, STDOUT, STDERR. * Rename fd to redirect so I can remember why this is here --- src/lib/core/multiprocessing.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index f431dd3..2fe02bb 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -85,14 +85,22 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { return -1; } - int fd = -1; - if ((fd = dup2(STDOUT_FILENO, STDERR_FILENO)) < 0) { + const int redirect = dup2(STDOUT_FILENO, STDERR_FILENO); + if (redirect < 0) { SYSERROR("%s", "Unable to redirect stderr to stdout"); SYSERROR("Unable to redirect stderr to stdout"); fclose(fp_log); return -1; } + // Close child file descriptors + for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); fd++) { + if (fd == redirect) { + continue; + } + close(fd); + } + // Generate timestamp for log header const time_t t = time(NULL); char *timebuf = ctime(&t); @@ -114,7 +122,10 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { fflush(stdout); fflush(stderr); char *args[] = {"bash", "--norc", task->parent_script, (char *) NULL}; - return execvp("/bin/bash", args); + semaphore_post(&pool->semaphore); + execvp("bash", args); + SYSERROR("execvp failed (%s)", strerror(errno)); + _exit(127); } int parent(struct MultiProcessingPool *pool, struct MultiProcessingTask *task, pid_t pid, int *child_status) { -- cgit From 3eddcfe9d11e6feba000fab54288124cb24f1899 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:44:15 -0400 Subject: Use semaphore to lock the child process up to the point of execvp --- src/lib/core/multiprocessing.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 2fe02bb..5a6767f 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -62,6 +62,7 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { (void) pool; FILE *fp_log = NULL; + semaphore_wait(&pool->semaphore); // The task starts inside the requested working directory if (chdir(task->working_dir)) { perror(task->working_dir); @@ -77,11 +78,13 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { snprintf(task->log_file + strlen(task->log_file), sizeof(task->log_file) - strlen(task->log_file), "task-%zu-%d.log", mp_global_task_count, task->parent_pid); SYSDEBUG("using log file: %s", task->log_file); + semaphore_post(&pool->semaphore); } fp_log = freopen(task->log_file, "w+", stdout); if (!fp_log) { fprintf(stderr, "unable to open '%s' for writing: %s\n", task->log_file, strerror(errno)); SYSERROR("unable to open '%s' for writing: %s", task->log_file, strerror(errno)); + semaphore_post(&pool->semaphore); return -1; } @@ -90,6 +93,7 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { SYSERROR("%s", "Unable to redirect stderr to stdout"); SYSERROR("Unable to redirect stderr to stdout"); fclose(fp_log); + semaphore_post(&pool->semaphore); return -1; } -- cgit From c594e4632a9125497fc86f2a79dde50c86c514fc Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:45:54 -0400 Subject: Allocate heap instead of mmapping the task's command string --- src/lib/core/multiprocessing.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 5a6767f..f33b38d 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -245,8 +245,12 @@ struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const // Record the command(s) SYSDEBUG("%s", "mmap() slot command"); - slot->cmd_len = (strlen(cmd) * sizeof(*cmd)) + 1; - slot->cmd = mmap(NULL, slot->cmd_len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + slot->cmd_len = strlen(cmd) + 1; + slot->cmd = calloc(slot->cmd_len, sizeof(*slot->cmd)); + if (!slot->cmd) { + SYSERROR("Failed to allocate memory for slot command"); + return NULL; + } memset(slot->cmd, 0, slot->cmd_len); snprintf(slot->cmd, slot->cmd_len, "%s", cmd); @@ -591,14 +595,14 @@ void mp_pool_free(struct MultiProcessingPool **pool) { semaphore_destroy(&(*pool)->semaphore); } - // Unmap all pool tasks + // Free all task commands if ((*pool)->task) { - if ((*pool)->task->cmd) { - if (munmap((*pool)->task->cmd, (*pool)->task->cmd_len) < 0) { - perror("munmap"); - } + for (size_t i = 0; i < (*pool)->num_alloc + 1; i++) { + struct MultiProcessingTask *task = &(*pool)->task[i]; + guard_free(task->cmd); } - if (munmap((*pool)->task, sizeof(*(*pool)->task) * (*pool)->num_alloc) < 0) { + // Unmap the task array + if (munmap((*pool)->task, sizeof(*(*pool)->task) * (*pool)->num_alloc + 1) < 0) { perror("munmap"); } } -- cgit From f319f565a6e4349ef37dd1c01accaf617df75ba4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:47:08 -0400 Subject: Change raw fprintf to SYSERROR --- src/lib/core/multiprocessing.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index f33b38d..d2efe1e 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -82,7 +82,6 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { } fp_log = freopen(task->log_file, "w+", stdout); if (!fp_log) { - fprintf(stderr, "unable to open '%s' for writing: %s\n", task->log_file, strerror(errno)); SYSERROR("unable to open '%s' for writing: %s", task->log_file, strerror(errno)); semaphore_post(&pool->semaphore); return -1; -- cgit From 6babfe77f8e728e8ddb2f2665563673e05f3f433 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:47:47 -0400 Subject: Rename status to child_status to better clarify what we're looking at --- src/lib/core/multiprocessing.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index d2efe1e..9246daa 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -353,7 +353,7 @@ int mp_pool_kill(struct MultiProcessingPool *pool, int signum) { } int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { - int status = 0; + int child_status = 0; int failures = 0; size_t tasks_complete = 0; size_t lower_i = 0; @@ -394,7 +394,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { } // Is the process finished? - pid_t pid = waitpid(slot->pid, &status, WNOHANG | WUNTRACED | WCONTINUED); + const pid_t pid = waitpid(slot->pid, &child_status, WNOHANG | WUNTRACED | WCONTINUED); char progress[1024] = {0}; const double percent = ((double) (tasks_complete + 1) / (double) pool->num_used) * 100; @@ -407,7 +407,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { seconds_to_human_readable(slot->timeout, duration, sizeof(duration)); printf("%s Task timed out after %s (pid: %d)\n", progress, duration, slot->pid); if (kill(slot->pid, SIGKILL) == 0) { - status = SIGKILL; + child_status = SIGKILL; } else { SYSERROR("Timeout reached, however pid %d could not be killed.", slot->pid); return -1; @@ -415,13 +415,13 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { } } - const int task_ended = WIFEXITED(status); - const int task_ended_by_signal = WIFSIGNALED(status); - const int task_stopped = WIFSTOPPED(status); - const int task_continued = WIFCONTINUED(status); - const int status_exit = WEXITSTATUS(status); - const int status_signal = WTERMSIG(status); - const int status_stopped = WSTOPSIG(status); + const int task_ended = WIFEXITED(child_status); + const int task_ended_by_signal = WIFSIGNALED(child_status); + const int task_stopped = WIFSTOPPED(child_status); + const int task_continued = WIFCONTINUED(child_status); + const int status_exit = WEXITSTATUS(child_status); + const int status_signal = WTERMSIG(child_status); + const int status_stopped = WSTOPSIG(child_status); // Update status slot->status = status_exit; @@ -445,7 +445,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { printf("%s Task ended (status: %d)\n", progress, status_exit); tasks_complete++; } else { - SYSWARN("%s Task state is unknown (0x%04X)", progress, status); + SYSWARN("%s Task state is unknown (0x%04X)", progress, child_status); } if (globals.enable_task_logging) { @@ -455,7 +455,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) { } } - if (status >> 8 != 0 || (status & 0xff) != 0) { + if (child_status >> 8 != 0 || (child_status & 0xff) != 0) { semaphore_wait(&pool->semaphore); update_task_elapsed(slot); semaphore_post(&pool->semaphore); -- cgit From b8c85b6743ec7855b07084596535878c1004a2d8 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 21:48:23 -0400 Subject: Handle error for mapping pool --- src/lib/core/multiprocessing.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 9246daa..14a8ae6 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -544,6 +544,10 @@ struct MultiProcessingPool *mp_pool_init(const char *ident, const char *log_root // The pool is shared with children pool = mmap(NULL, sizeof(*pool), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (pool == MAP_FAILED) { + SYSERROR("unable to memory map pool"); + return NULL; + } // Set pool identity string memset(pool->ident, 0, sizeof(pool->ident)); -- cgit From cf7f1916db60a13ed9257ba803bb9d4e1cd29676 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 11 May 2026 09:24:29 -0400 Subject: Remove check for DEBUG define --- src/lib/core/conda.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index f9e2bd2..0be817a 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -207,42 +207,30 @@ int pkg_index_provides(int mode, const char *index, const char *spec, const char return PKG_INDEX_PROVIDES_E_INTERNAL_MODE_UNKNOWN; } -#if defined(DEBUG) - const int debug_log = 1; -#else - const int debug_log = 0; -#endif - // Print errors only when shell() itself throws one // If some day we want to see the errors thrown by pip too, use this // condition instead: (status != 0) - if (debug_log) { - SYSDEBUG("Executing: %s", cmd); - } + SYSDEBUG("Executing: %s", cmd); status = shell(&proc, cmd); - if (debug_log) { - SYSDEBUG("Log file: %s", logfile); - } - if (status < 0 || debug_log) { + SYSDEBUG("Log file: %s", logfile); + if (status < 0) { FILE *fp = fdopen(logfd, "r"); if (!fp) { remove(logfile); return -1; - } else { - char line[STASIS_BUFSIZ] = {0}; - fflush(stdout); - fflush(stderr); - while (fgets(line, sizeof(line) - 1, fp) != NULL) { - if (debug_log) { - SYSDEBUG("%s", strip(line)); - } else { - fprintf(stderr, "%s", line); - } - } - fflush(stderr); - fclose(fp); } + + fflush(stdout); + fflush(stderr); + + char line[STASIS_BUFSIZ] = {0}; + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + SYSDEBUG("%s", strip(line)); + } + + fflush(stderr); + fclose(fp); } remove(logfile); -- cgit From 90e25ccfde6a1f6053587d108d601ab51c8d9766 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 11 May 2026 23:26:47 -0400 Subject: The time has come * Dump the pip log on error --- src/lib/core/conda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 0be817a..6083023 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -214,7 +214,7 @@ int pkg_index_provides(int mode, const char *index, const char *spec, const char status = shell(&proc, cmd); SYSDEBUG("Log file: %s", logfile); - if (status < 0) { + if (status != 0) { FILE *fp = fdopen(logfd, "r"); if (!fp) { remove(logfile); -- cgit From 1944c5281a29fa02d21338129445dba23d01cc52 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 11 May 2026 23:27:19 -0400 Subject: Remove linefeed from warning message --- src/lib/delivery/delivery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index 500bb88..dc9e2ce 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -489,7 +489,7 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { } if (!strlist_count(deferred)) { - SYSWARN("No %s packages were filtered by test definitions\n", mode); + SYSWARN("No %s packages were filtered by test definitions", mode); } else { if (DEFER_CONDA == type) { guard_strlist_free(&ctx->conda.conda_packages); -- cgit From 18ebe00bfcd377bda01e1ce70a339cbd6008658d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 11 May 2026 23:37:51 -0400 Subject: Give log messages variable verbosity * WARN = Show only the preface and message * INFO = Show preface, function, and message * DEBUG = Show preface, source file, line number, function, and message --- src/lib/core/log.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/lib/core/log.c b/src/lib/core/log.c index aea3231..b1cab4c 100644 --- a/src/lib/core/log.c +++ b/src/lib/core/log.c @@ -42,19 +42,38 @@ void log_print_debug(const struct ExecPoint ep, const char *fmt, ...) { int log_msgv(FILE *stream, const struct ExecPoint ep, const char *preface_color, const char *preface, const char *fmt, va_list ap) { char header[STASIS_BUFSIZ] = {0}; + const int no_info = LOG_LEVEL < LOG_LEVEL_INFO; + const int some_info = LOG_LEVEL < LOG_LEVEL_DEBUG; int len = snprintf(header, sizeof(header), STASIS_COLOR_RESET "%s%s: " - STASIS_COLOR_RESET - STASIS_COLOR_WHITE - "%s:%d: %s(): " STASIS_COLOR_RESET, preface_color ? preface_color : STASIS_COLOR_RED, - preface ? preface : "UNKNOWN", - path_basename((char *) ep.file), - ep.line, - ep.function); + preface ? preface : "UNKNOWN"); + + if (no_info) { + len += snprintf(header + strlen(header), sizeof(header) - len, + STASIS_COLOR_WHITE + "" + STASIS_COLOR_RESET); + } else if (some_info) { + len += snprintf(header + strlen(header), sizeof(header) - len, + STASIS_COLOR_WHITE + "%s(): " + STASIS_COLOR_RESET, + ep.function); + } else { + // everything + len += snprintf(header + strlen(header), sizeof(header) - len, + STASIS_COLOR_WHITE + "%s:%d: %s(): " + STASIS_COLOR_RESET, + path_basename((char *) ep.file), + ep.line, + ep.function); + } + if (len >= (int) sizeof(header)) { SYSERROR("header format truncated (%d >= %d)", len, (int) sizeof(header)); return len; -- cgit From 43b9334d4c88c0dcf9e44f5b8a20803effb5ebd5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:32:30 -0400 Subject: Blank warning as new line --- src/lib/delivery/delivery_artifactory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_artifactory.c b/src/lib/delivery/delivery_artifactory.c index 3c1cff3..d7a5457 100644 --- a/src/lib/delivery/delivery_artifactory.c +++ b/src/lib/delivery/delivery_artifactory.c @@ -61,7 +61,8 @@ int delivery_artifact_upload(struct Delivery *ctx) { if (!globals.jfrog.repo) { SYSWARN("Artifactory repository path is not configured!"); - SYSWARN("set STASIS_JF_REPO environment variable...\nOr append to configuration file:\n"); + SYSWARN("set STASIS_JF_REPO environment variable...\nOr append to configuration file:"); + SYSWARN(""); SYSWARN("[deploy:artifactory]\nrepo = example/generic/repo/path\n"); status++; break; -- cgit From c96bee4c1e34fb80453a79ba455ff9eb1c72b6c5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:42:29 -0400 Subject: Remove linefeed from error --- src/lib/delivery/delivery_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index 5f1c605..48124c2 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -202,7 +202,7 @@ int delivery_init_platform(struct Delivery *ctx) { for (size_t i = 0; i < DELIVERY_PLATFORM_MAX; i++) { ctx->system.platform[i] = calloc(DELIVERY_PLATFORM_MAXLEN, sizeof(*ctx->system.platform[0])); if (!ctx->system.platform[i]) { - SYSERROR("Unable to allocate record %zu in platform array\n", i); + SYSERROR("Unable to allocate record %zu in platform array", i); return -1; } } -- cgit From 6d6a6a1c25672b69ed80985b54a5fd8da2125751 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:43:17 -0400 Subject: free platform array on error --- src/lib/delivery/delivery_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index 48124c2..5bc326d 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -203,6 +203,7 @@ int delivery_init_platform(struct Delivery *ctx) { ctx->system.platform[i] = calloc(DELIVERY_PLATFORM_MAXLEN, sizeof(*ctx->system.platform[0])); if (!ctx->system.platform[i]) { SYSERROR("Unable to allocate record %zu in platform array", i); + guard_array_n_free(ctx->system.platform, i); return -1; } } @@ -210,6 +211,8 @@ int delivery_init_platform(struct Delivery *ctx) { ctx->system.arch = strdup(uts.machine); if (!ctx->system.arch) { // memory error + guard_array_n_free(ctx->system.platform, DELIVERY_PLATFORM_MAX); + ctx->system.platform = NULL; return -1; } -- cgit From 48066ec0b4491b6b07d90c4da82dc98f2dc62bff Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:43:38 -0400 Subject: remove linefeed from debug message --- src/lib/delivery/delivery_install.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index d39fa3e..037098d 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -415,7 +415,7 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha guard_free(args); return -1; } - SYSDEBUG("Tokenizing repository info tag: %s\n", info->repository_info_tag); + SYSDEBUG("Tokenizing repository info tag: %s", info->repository_info_tag); strlist_append_tokenize(tag_data, info->repository_info_tag, "-"); struct WheelInfo *whl = NULL; -- cgit From 898044af3a714481ca40d244f92a31296d503d55 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:44:55 -0400 Subject: when no spec is present use the package name instead --- src/lib/delivery/delivery_install.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index 037098d..538ae15 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -235,12 +235,16 @@ int delivery_conda_enforce_package_version(struct Delivery *ctx, const char *env goto cleanup; } if (strstr(item, name)) { - char *spec_tmp = find_version_spec((char *) item); - while (!isalnum(*spec_tmp)) { - spec_tmp++; + const char *spec_tmp = find_version_spec((char *) item); + if (spec_tmp) { + while (!isalnum(*spec_tmp)) { + spec_tmp++; + } + spec_request = strdup(spec_tmp); + } else { + spec_request = strdup(item); } - spec_request = strdup(spec_tmp); if (!spec_request) { SYSERROR("unable to allocate memory for conda package spec request"); status = -1; -- cgit From 95786be9be8c77709c197b8efbcebd13d9ca8049 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:45:24 -0400 Subject: if conda fails, return --- src/lib/delivery/delivery_install.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index 538ae15..efdb819 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -265,9 +265,17 @@ int delivery_conda_enforce_package_version(struct Delivery *ctx, const char *env } snprintf(cmd, PATH_MAX, "remove --name %s %s", env_name, name); - conda_exec(cmd); + if (conda_exec(cmd)) { + SYSERROR("unable to remove package %s from %s", name, env_name); + status = -1; + goto cleanup; + } snprintf(cmd, PATH_MAX, "install --name %s %s=%s", env_name, name, spec_request); - conda_exec(cmd); + if (conda_exec(cmd)) { + SYSERROR("unable to install package %s into %s", name, env_name); + status = -1; + goto cleanup; + } cleanup: guard_free(spec_request); -- cgit From 210bcaf0c8ccaf2ff6dfbb172d6bd3df795caea1 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:45:39 -0400 Subject: make dep_status constant --- src/lib/delivery/delivery_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c index 1ba123a..f59a62e 100644 --- a/src/lib/delivery/delivery_test.c +++ b/src/lib/delivery/delivery_test.c @@ -178,7 +178,7 @@ void delivery_tests_run(struct Delivery *ctx) { if (pushd(destdir)) { COE_CHECK_ABORT(1, "Unable to enter repository directory\n"); } else { - int dep_status = check_python_package_dependencies("."); + const int dep_status = check_python_package_dependencies("."); if (dep_status) { SYSERROR("Please replace all occurrences above with standard package specs:\n" "\n" -- cgit From 4e9fc375be4019578877859e701619f7fa8aa218 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:46:05 -0400 Subject: give a better idea of which munmap failed --- src/lib/core/multiprocessing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 14a8ae6..11add1e 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -606,13 +606,13 @@ void mp_pool_free(struct MultiProcessingPool **pool) { } // Unmap the task array if (munmap((*pool)->task, sizeof(*(*pool)->task) * (*pool)->num_alloc + 1) < 0) { - perror("munmap"); + SYSWARN("munmap pool task failed: %s", strerror(errno)); } } // Unmap the pool if ((*pool)) { if (munmap((*pool), sizeof(*(*pool))) < 0) { - SYSWARN("munmap failed: %s", strerror(errno)); + SYSWARN("munmap pool failed: %s", strerror(errno)); } (*pool) = NULL; } -- cgit From 58ca01047c5da6f244525ca612154d220cef8819 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:51:30 -0400 Subject: Use log_print_error instead of SYSERROR * Add comment so I don't accidentally do it again --- src/lib/core/str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/str.c b/src/lib/core/str.c index 447fc78..c31ce5e 100644 --- a/src/lib/core/str.c +++ b/src/lib/core/str.c @@ -11,7 +11,7 @@ char *strdup_maybe_entry(const char * restrict s, const struct ExecPoint ep, con if (s != NULL) { char *x = strdup(s); if (!x) { - SYSERROR("unable to duplicate string"); + // We want to trace the origin of the allocation so SYSERROR can't be used here. log_print_error(ep, "out of memory"); exit(exit_code); } -- cgit From 99d7e7c5fd5030cd901afe276d73831f734f1428 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:51:47 -0400 Subject: free result on error --- src/lib/core/system.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/core/system.c b/src/lib/core/system.c index f0fd38f..d0956f4 100644 --- a/src/lib/core/system.c +++ b/src/lib/core/system.c @@ -177,6 +177,7 @@ char *shell_output(const char *command, int *status) { current_size += initial_size; char *tmp = realloc(result, sizeof(*result) * current_size); if (!tmp) { + guard_free(result); return NULL; } result = tmp; -- cgit From 8217fc2354f4614ed64f7b5530fbc9d155b697b5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:52:51 -0400 Subject: exit on error --- src/cli/stasis/system_requirements.c | 91 ++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/src/cli/stasis/system_requirements.c b/src/cli/stasis/system_requirements.c index 02889da..b531ae1 100644 --- a/src/cli/stasis/system_requirements.c +++ b/src/cli/stasis/system_requirements.c @@ -3,20 +3,83 @@ void check_system_env_requirements() { msg(STASIS_MSG_L1, "Checking environment\n"); globals.envctl = envctl_init(); - envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "TMPDIR"); - envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_ROOT"); - envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_SYSCONFDIR"); - envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_CPU_COUNT"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED | STASIS_ENVCTL_REDACT, callback_except_gh, "STASIS_GH_TOKEN"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_ARTIFACTORY_URL"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_ACCESS_TOKEN"); - envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_JF_USER"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_PASSWORD"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_KEY_PATH"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_PASSPHRASE"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_CERT_PATH"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_KEY_PATH"); - envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_REPO"); + if (!globals.envctl) { + SYSERROR("envctl_init failed"); + exit(1); + } + + int status = 0; + status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "TMPDIR"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_ROOT"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_SYSCONFDIR"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_CPU_COUNT"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED | STASIS_ENVCTL_REDACT, callback_except_gh, "STASIS_GH_TOKEN"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_ARTIFACTORY_URL"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_ACCESS_TOKEN"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_JF_USER"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_PASSWORD"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_KEY_PATH"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_PASSPHRASE"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_CERT_PATH"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_KEY_PATH"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_REPO"); + if (!status) { + SYSERROR("envctl_register failed"); + exit(1); + } + envctl_do_required(globals.envctl, globals.verbose); } -- cgit From 13bf2ddac70aa3a5da51fa410d9d93e6a24a54b5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:53:10 -0400 Subject: Missing temp file is a warning, not an error --- src/lib/core/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 72ecfc9..66d1511 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -658,7 +658,7 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro pretty_print_failed: if (tempfile && remove(tempfile)) { - SYSERROR("unable to remove temporary file: %s", tempfile); + SYSWARN("unable to remove temporary file: %s", tempfile); } guard_free(tempfile); guard_free(result); -- cgit From 858e86c9140cee951496e0a2ae16c7f323ca8a25 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:53:21 -0400 Subject: Remove linefeed from debug message --- src/lib/core/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 66d1511..9b98639 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -1012,7 +1012,7 @@ int grow(const size_t size_new, size_t *size_orig, char **data) { } if (size_new >= *size_orig) { const size_t new_size = *size_orig + size_new + 1; - SYSDEBUG("template data buffer new size: %zu\n", new_size); + SYSDEBUG("template data buffer new size: %zu", new_size); char *tmp = realloc(*data, new_size); if (!tmp) { -- cgit From 77aedfe62eba8e2d3beca7a3ada7c29aa8d09e09 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 10:53:49 -0400 Subject: One argument for error message string --- src/lib/core/utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 9b98639..d869143 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -1200,7 +1200,7 @@ int get_random_bytes(char *result, size_t maxlen) { if (filename != NULL) { fp = fopen(filename, "rb"); if (!fp) { - SYSERROR("%s", "unable to open random generator"); + SYSERROR("unable to open random generator"); return -1; } } @@ -1213,7 +1213,7 @@ int get_random_bytes(char *result, size_t maxlen) { ch = rand() % 255; } if (fp && ferror(fp)) { - SYSERROR("%s", "unable to read from random generator"); + SYSERROR("unable to read from random generator"); fclose(fp); return -1; } -- cgit From 2dbf196d3147fd87e0539a45e01a98e4d719389f Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 11:01:37 -0400 Subject: Usable lines denote the number of entries * reduce complexity * 'x' should not overflow --- src/lib/core/wheel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 2162dae..e94060a 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -1133,16 +1133,16 @@ int wheel_get_entry_point(struct Wheel *pkg, const char *filename) { usable_lines--; } } + pkg->num_entry_point = usable_lines; - pkg->entry_point = calloc(usable_lines + 1, sizeof(*pkg->entry_point)); + pkg->entry_point = calloc(pkg->num_entry_point + 1, sizeof(*pkg->entry_point)); if (!pkg->entry_point) { goto GEP_FAIL; } - for (size_t i = 0; i < usable_lines; i++) { + for (size_t i = 0; i < pkg->num_entry_point; i++) { pkg->entry_point[i] = calloc(1, sizeof(*pkg->entry_point[0])); if (!pkg->entry_point[i]) { - guard_array_n_free(pkg->entry_point, usable_lines + 1); goto GEP_FAIL; } } @@ -1198,6 +1198,9 @@ int wheel_get_entry_point(struct Wheel *pkg, const char *filename) { return 0; GEP_FAIL: + if (pkg->entry_point) { + guard_array_n_free(pkg->entry_point, pkg->num_entry_point); + } guard_strlist_free(&lines); guard_free(data); return -1; -- cgit From 45d8e2aeb737a5d3b91217a01f81392341f190d2 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 11:14:06 -0400 Subject: Reverse logic on status check --- src/cli/stasis/system_requirements.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/cli/stasis/system_requirements.c b/src/cli/stasis/system_requirements.c index b531ae1..a48c113 100644 --- a/src/cli/stasis/system_requirements.c +++ b/src/cli/stasis/system_requirements.c @@ -10,72 +10,72 @@ void check_system_env_requirements() { int status = 0; status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "TMPDIR"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_ROOT"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_SYSCONFDIR"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_CPU_COUNT"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED | STASIS_ENVCTL_REDACT, callback_except_gh, "STASIS_GH_TOKEN"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_ARTIFACTORY_URL"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_ACCESS_TOKEN"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_PASSTHRU, NULL, "STASIS_JF_USER"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_PASSWORD"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_KEY_PATH"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_SSH_PASSPHRASE"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_CERT_PATH"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REDACT, NULL, "STASIS_JF_CLIENT_CERT_KEY_PATH"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } status = envctl_register(&globals.envctl, STASIS_ENVCTL_REQUIRED, callback_except_jf, "STASIS_JF_REPO"); - if (!status) { + if (status) { SYSERROR("envctl_register failed"); exit(1); } -- cgit From 0c23437108bc5c7c00104345f2a22bd9da607e20 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:02:38 -0400 Subject: Placate FORTIFY_SOURCE warning * The log_root in almost every circumstance will be able to handle the extra slash chracter. It complains because log_file and log_path are both sizeof PATH_MAX --- src/lib/core/multiprocessing.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 11add1e..b17bdc1 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -196,7 +196,9 @@ struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const // Set log file path memset(slot->log_file, 0, sizeof(*slot->log_file)); if (globals.enable_task_logging) { - snprintf(slot->log_file, sizeof(slot->log_file) - strlen(slot->log_file), "%s/", pool->log_root); + snprintf(slot->log_file, sizeof(slot->log_file), "%s", pool->log_root); + // FORTIFY_SOURCE won't leave snprintf alone. The chance for truncation is slim anyway. + strncat(slot->log_file, "/", sizeof(slot->log_file) - strlen(slot->log_file)); } else { snprintf(slot->log_file, sizeof(slot->log_file), "/dev/stdout"); } -- cgit From d89f776c1d55fa6ad41b5dcf870d03256a4f54a7 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:32:18 -0400 Subject: Remove redundant __FUNCTION__ --- src/cli/stasis_indexer/helpers.c | 2 +- src/lib/core/artifactory.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cli/stasis_indexer/helpers.c b/src/cli/stasis_indexer/helpers.c index bf7efee..92e2dd4 100644 --- a/src/cli/stasis_indexer/helpers.c +++ b/src/cli/stasis_indexer/helpers.c @@ -257,7 +257,7 @@ int get_files(struct StrList **out, const char *path, const char *pattern, ...) return -1; } if ((size_t) len > sizeof(userpattern)) { - SYSWARN("%s: userpattern truncated!", __FUNCTION__); + SYSWARN("userpattern truncated!"); } va_end(args); if (!strlen(userpattern)) { diff --git a/src/lib/core/artifactory.c b/src/lib/core/artifactory.c index 669bfff..d4b48fb 100644 --- a/src/lib/core/artifactory.c +++ b/src/lib/core/artifactory.c @@ -38,7 +38,7 @@ int artifactory_download_cli(char *dest, strncpy(os_ident, "linux", sizeof(os_ident) - 1); os_ident[sizeof(os_ident) - 1] = '\0'; } else { - SYSERROR("%s: unknown operating system: %s", __FUNCTION__, os_ident); + SYSERROR("unknown operating system: %s", os_ident); return -1; } @@ -59,7 +59,7 @@ int artifactory_download_cli(char *dest, } else if (!strcmp(arch_ident, "arm64") || !strcmp(arch_ident, "aarch64")) { strncpy(arch_ident, "arm64", sizeof(arch_ident) - 1); } else { - SYSERROR("%s: unknown architecture: %s", __FUNCTION__, arch_ident); + SYSERROR("unknown architecture: %s", arch_ident); return -1; } arch_ident[sizeof(arch_ident) - 1] = '\0'; @@ -79,7 +79,7 @@ int artifactory_download_cli(char *dest, path[sizeof(path) - 1] = '\0'; if (mkdirs(path, 0755)) { - SYSERROR("%s: %s: %s", __FUNCTION__, path, strerror(errno)); + SYSERROR("%s: %s", path, strerror(errno)); return -1; } -- cgit From 9b7a784099f11fa20312a118c74d08a2c25572fc Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:34:30 -0400 Subject: Replace void pointer with pointer to tplfunc_frame structure --- src/lib/core/include/template.h | 7 +++++-- src/lib/core/include/template_func_proto.h | 10 +++++----- src/lib/core/template.c | 2 +- src/lib/core/template_func_proto.c | 10 +++++----- tests/test_template.c | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/lib/core/include/template.h b/src/lib/core/include/template.h index e3d83fb..436fcc6 100644 --- a/src/lib/core/include/template.h +++ b/src/lib/core/include/template.h @@ -40,7 +40,9 @@ char *tpl_render(char *str); */ int tpl_render_to_file(char *str, const char *filename); -typedef int tplfunc(void *frame, void *data_out); +struct tplfunc_frame; + +typedef int tplfunc(struct tplfunc_frame *frame, void *data_out); struct tplfunc_frame { char *key; ///< Name of the function @@ -68,8 +70,9 @@ struct tplfunc_frame { * @param key function name to expose to "func:" interface * @param tplfunc_ptr pointer to function of type tplfunc * @param argc number of function arguments to accept + * @param data_in pointer to function input data */ -void tpl_register_func(char *key, void *tplfunc_ptr, int argc, void *data_in); +void tpl_register_func(char *key, tplfunc *tplfunc_ptr, int argc, void *data_in); /** * Get the function frame associated with a template function diff --git a/src/lib/core/include/template_func_proto.h b/src/lib/core/include/template_func_proto.h index 286ccfb..0f2ad80 100644 --- a/src/lib/core/include/template_func_proto.h +++ b/src/lib/core/include/template_func_proto.h @@ -4,10 +4,10 @@ #include "template.h" -int get_github_release_notes_tplfunc_entrypoint(void *frame, void *data_out); -int get_github_release_notes_auto_tplfunc_entrypoint(void *frame, void *data_out); -int get_junitxml_file_entrypoint(void *frame, void *data_out); -int get_basetemp_dir_entrypoint(void *frame, void *data_out); -int tox_run_entrypoint(void *frame, void *data_out); +int get_github_release_notes_tplfunc_entrypoint(struct tplfunc_frame *frame, void *data_out); +int get_github_release_notes_auto_tplfunc_entrypoint(struct tplfunc_frame *frame, void *data_out); +int get_junitxml_file_entrypoint(struct tplfunc_frame *frame, void *data_out); +int get_basetemp_dir_entrypoint(struct tplfunc_frame *frame, void *data_out); +int tox_run_entrypoint(struct tplfunc_frame *frame, void *data_out); #endif //TEMPLATE_FUNC_PROTO_H \ No newline at end of file diff --git a/src/lib/core/template.c b/src/lib/core/template.c index 00e0058..8396b1e 100644 --- a/src/lib/core/template.c +++ b/src/lib/core/template.c @@ -26,7 +26,7 @@ extern void tpl_reset() { tpl_pool_func_used = 0; } -void tpl_register_func(char *key, void *tplfunc_ptr, int argc, void *data_in) { +void tpl_register_func(char *key, tplfunc *tplfunc_ptr, int argc, void *data_in) { struct tplfunc_frame *frame = calloc(1, sizeof(*frame)); if (!frame) { SYSERROR("unable to allocate memory for function frame"); diff --git a/src/lib/core/template_func_proto.c b/src/lib/core/template_func_proto.c index f28a1eb..54a8860 100644 --- a/src/lib/core/template_func_proto.c +++ b/src/lib/core/template_func_proto.c @@ -2,7 +2,7 @@ #include "delivery.h" #include "github.h" -int get_github_release_notes_tplfunc_entrypoint(void *frame, void *data_out) { +int get_github_release_notes_tplfunc_entrypoint(struct tplfunc_frame *frame, void *data_out) { char **output = (char **) data_out; struct tplfunc_frame *f = (struct tplfunc_frame *) frame; char *api_token = getenv("STASIS_GH_TOKEN"); @@ -17,7 +17,7 @@ int get_github_release_notes_tplfunc_entrypoint(void *frame, void *data_out) { return result; } -int get_github_release_notes_auto_tplfunc_entrypoint(void *frame, void *data_out) { +int get_github_release_notes_auto_tplfunc_entrypoint(struct tplfunc_frame *frame, void *data_out) { int result = 0; char **output = (char **) data_out; struct tplfunc_frame *f = (struct tplfunc_frame *) frame; @@ -68,7 +68,7 @@ int get_github_release_notes_auto_tplfunc_entrypoint(void *frame, void *data_out return result; } -int get_junitxml_file_entrypoint(void *frame, void *data_out) { +int get_junitxml_file_entrypoint(struct tplfunc_frame *frame, void *data_out) { int result = 0; char **output = (char **) data_out; struct tplfunc_frame *f = (struct tplfunc_frame *) frame; @@ -95,7 +95,7 @@ int get_junitxml_file_entrypoint(void *frame, void *data_out) { return result; } -int get_basetemp_dir_entrypoint(void *frame, void *data_out) { +int get_basetemp_dir_entrypoint(struct tplfunc_frame *frame, void *data_out) { int result = 0; char **output = (char **) data_out; struct tplfunc_frame *f = (struct tplfunc_frame *) frame; @@ -121,7 +121,7 @@ int get_basetemp_dir_entrypoint(void *frame, void *data_out) { return result; } -int tox_run_entrypoint(void *frame, void *data_out) { +int tox_run_entrypoint(struct tplfunc_frame *frame, void *data_out) { char **output = (char **) data_out; struct tplfunc_frame *f = (struct tplfunc_frame *) frame; const struct Delivery *ctx = (const struct Delivery *) f->data_in; diff --git a/tests/test_template.c b/tests/test_template.c index e8f0c1d..3efb142 100644 --- a/tests/test_template.c +++ b/tests/test_template.c @@ -95,7 +95,7 @@ void test_tpl_register_func() { struct testcase { const char *key; int argc; - void *func; + tplfunc *func; }; struct testcase tc[] = { {.key = "add", .argc = 2, .func = &adder}, -- cgit From 96bc699d269ff79bf31dad182f1a2b96226e8ce5 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:37:27 -0400 Subject: Replace __FUNCTION__ with __func__ (portable) --- src/lib/core/include/log.h | 2 +- tests/include/testing.h | 6 +++--- tests/test_conda.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/core/include/log.h b/src/lib/core/include/log.h index 18617c4..cad954f 100644 --- a/src/lib/core/include/log.h +++ b/src/lib/core/include/log.h @@ -16,7 +16,7 @@ struct ExecPoint { const char *function; // function of origin }; -#define EXECPOINT (struct ExecPoint) {.line = __LINE__, .file = __FILE__, .function = __FUNCTION__} +#define EXECPOINT (struct ExecPoint) {.line = __LINE__, .file = __FILE__, .function = __func__} void log_print_error(struct ExecPoint ep, const char *fmt, ...); void log_print_warning(struct ExecPoint ep, const char *fmt, ...); diff --git a/tests/include/testing.h b/tests/include/testing.h index 728b6a6..d11398c 100644 --- a/tests/include/testing.h +++ b/tests/include/testing.h @@ -224,7 +224,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_ASSERT(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = (COND), \ .msg_assertion = "ASSERT(" #COND ")", \ @@ -234,7 +234,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_ASSERT_FATAL(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = (COND), \ .msg_assertion = "ASSERT FATAL (" #COND ")", \ @@ -248,7 +248,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_SKIP_IF(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = true, \ .skip = (COND), \ diff --git a/tests/test_conda.c b/tests/test_conda.c index f6ee2f8..bbbef3c 100644 --- a/tests/test_conda.c +++ b/tests/test_conda.c @@ -110,13 +110,13 @@ void test_conda_setup_headless() { void test_conda_env_create_from_uri() { const char *url = "https://ssb.stsci.edu/jhunk/stasis_test/test_conda_env_create_from_uri.yml"; - char *name = strdup(__FUNCTION__); + char *name = strdup(__func__); STASIS_ASSERT(conda_env_create_from_uri(name, (char *) url, "3.11") == 0, "creating an environment from a remote source failed"); free(name); } void test_conda_env_create_export_remove() { - char *name = strdup(__FUNCTION__); + char *name = strdup(__func__); STASIS_ASSERT(conda_env_create(name, "3", "fitsverify") == 0, "unable to create a simple environment"); STASIS_ASSERT(conda_env_export(name, ".", name) == 0, "unable to export an environment"); STASIS_ASSERT(conda_env_remove(name) == 0, "unable to remove an environment"); -- cgit From 9e4a3f4471cfc50d778b50d6999cd957bff62ec0 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:38:00 -0400 Subject: Replace escape sequence '\e' with '\x1b' (portable) --- src/lib/core/include/utils.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/core/include/utils.h b/src/lib/core/include/utils.h index 194f8e7..98b8ae8 100644 --- a/src/lib/core/include/utils.h +++ b/src/lib/core/include/utils.h @@ -210,17 +210,17 @@ int path_store(char **destptr, size_t maxlen, const char *base, const char *path #define STASIS_COLOR_RESET "" #else //! Set output color to red -#define STASIS_COLOR_RED "\e[1;91m" +#define STASIS_COLOR_RED "\x1b[1;91m" //! Set output color to green -#define STASIS_COLOR_GREEN "\e[1;92m" +#define STASIS_COLOR_GREEN "\x1b[1;92m" //! Set output color to yellow -#define STASIS_COLOR_YELLOW "\e[1;93m" +#define STASIS_COLOR_YELLOW "\x1b[1;93m" //! Set output color to blue -#define STASIS_COLOR_BLUE "\e[1;94m" +#define STASIS_COLOR_BLUE "\x1b[1;94m" //! Set output color to white -#define STASIS_COLOR_WHITE "\e[1;97m" +#define STASIS_COLOR_WHITE "\x1b[1;97m" //! Reset output color to terminal default -#define STASIS_COLOR_RESET "\e[0;37m\e[0m" +#define STASIS_COLOR_RESET "\x1b[0;37m\x1b[0m" #endif #define STASIS_MSG_SUCCESS 0 -- cgit From 1d91efc28e30c8501428fec8ff6cd7b13dcdfb95 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 12 May 2026 12:38:24 -0400 Subject: replace for-loop with while-loop since 'i' was unused --- tests/test_ini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ini.c b/tests/test_ini.c index af47ddf..3070806 100644 --- a/tests/test_ini.c +++ b/tests/test_ini.c @@ -205,7 +205,7 @@ void test_ini_getall() { STASIS_ASSERT_FATAL(ini != NULL, "failed to open ini file"); const struct INIData *d = NULL; - for (size_t i = 0; (d = ini_getall(ini, "default")) != NULL; i++) { + while ((d = ini_getall(ini, "default")) != NULL) { STASIS_ASSERT(d->key != NULL, "INIData key should not be NULL"); STASIS_ASSERT(d->value != NULL, "INIData key should not be NULL"); } -- cgit