From 6321fc84ad313bd905d0f8f23d8e8c262d1c8123 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Thu, 23 Apr 2026 16:42:26 -0400 Subject: delivery_format_str: fix snprintf append --- src/lib/delivery/delivery.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index 5403743..a97cc11 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -312,13 +312,13 @@ int delivery_format_str(struct Delivery *ctx, char **dest, size_t maxlen, const strncat(*dest, ctx->meta.mission, maxlen - 1); break; case 'r': // revision - snprintf(*dest + strlen(*dest), maxlen, "%d", ctx->meta.rc); + snprintf(*dest + strlen(*dest), maxlen - strlen(*dest), "%d", ctx->meta.rc); break; case 'R': // "final"-aware revision if (ctx->meta.final) strncat(*dest, "final", maxlen); else - snprintf(*dest + strlen(*dest), maxlen, "%d", ctx->meta.rc); + snprintf(*dest + strlen(*dest), maxlen - strlen(*dest), "%d", ctx->meta.rc); break; case 'v': // version strncat(*dest, ctx->meta.version, maxlen - 1); @@ -336,14 +336,14 @@ int delivery_format_str(struct Delivery *ctx, char **dest, size_t maxlen, const strncat(*dest, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], maxlen - 1); break; case 't': // unix epoch - snprintf(*dest + strlen(*dest), maxlen, "%ld", ctx->info.time_now); + snprintf(*dest + strlen(*dest), maxlen - strlen(*dest), "%ld", ctx->info.time_now); break; default: // unknown formatter, write as-is - snprintf(*dest + strlen(*dest), maxlen, "%c%c", fmt[i - 1], fmt[i]); + snprintf(*dest + strlen(*dest), maxlen - strlen(*dest), "%c%c", fmt[i - 1], fmt[i]); break; } } else { // write non-format text - snprintf(*dest + strlen(*dest), maxlen, "%c", fmt[i]); + snprintf(*dest + strlen(*dest), maxlen - strlen(*dest), "%c", fmt[i]); } } return 0; -- cgit From 8721fca71d83bad253428245f00f60bb74dde23e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Thu, 23 Apr 2026 16:45:37 -0400 Subject: conda_env_create_from_uri: increase size of filesystem path, and fix maxlen --- src/lib/core/conda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 854d56d..4cb7710 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -561,11 +561,11 @@ int conda_env_create_from_uri(char *name, char *uri, char *python_version) { // Convert a bare system path to a file:// path if (!strstr(uri, "://")) { - uri_fs = calloc(strlen(uri) + strlen("file://") + 1, sizeof(*uri_fs)); + uri_fs = calloc(PATH_MAX, sizeof(*uri_fs)); if (!uri_fs) { return -1; } - snprintf(uri_fs, strlen(uri) + strlen("file://") + 1, "%s%s", "file://", uri); + snprintf(uri_fs, PATH_MAX, "%s%s", "file://", uri); } char tempfile[PATH_MAX] = {0}; -- cgit From 347677c3330ece8496b9cd242fd7e4292c2260ae Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 15:55:21 -0400 Subject: NUL terminate after copy --- src/cli/stasis/stasis_main.c | 10 ++++++++++ src/cli/stasis_indexer/helpers.c | 7 +++++++ src/cli/stasis_indexer/junitxml_report.c | 10 +++++++--- src/cli/stasis_indexer/stasis_indexer_main.c | 6 ++++++ src/cli/stasis_indexer/website.c | 3 +++ src/lib/core/artifactory.c | 11 +++++++++++ src/lib/core/conda.c | 13 ++++++++++++- src/lib/core/copy.c | 1 + src/lib/core/docker.c | 9 +++++++++ src/lib/core/environment.c | 1 + src/lib/core/ini.c | 12 ++++++++++++ src/lib/core/multiprocessing.c | 1 - src/lib/core/recipe.c | 1 + src/lib/core/relocation.c | 1 + src/lib/core/str.c | 14 ++++++++++++-- src/lib/core/strlist.c | 12 ++++++++++-- src/lib/core/template.c | 2 ++ src/lib/core/template_func_proto.c | 3 +++ src/lib/core/utils.c | 19 +++++++++++++++---- src/lib/core/wheelinfo.c | 4 ++++ src/lib/delivery/delivery.c | 6 ++++++ src/lib/delivery/delivery_build.c | 11 +++++++++-- src/lib/delivery/delivery_docker.c | 2 ++ src/lib/delivery/delivery_init.c | 8 ++++++++ src/lib/delivery/delivery_install.c | 12 ++++++++++++ src/lib/delivery/delivery_test.c | 6 +++++- 26 files changed, 169 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index 01a126e..252e67e 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -20,6 +20,7 @@ static void setup_sysconfdir() { } else { strncpy(stasis_sysconfdir_tmp, STASIS_SYSCONFDIR, sizeof(stasis_sysconfdir_tmp) - 1); } + stasis_sysconfdir_tmp[sizeof(stasis_sysconfdir_tmp) - 1] = '\0'; globals.sysconfdir = realpath(stasis_sysconfdir_tmp, NULL); if (!globals.sysconfdir) { @@ -521,6 +522,8 @@ static char *center_text(const char *s, const size_t maxwidth) { } result[i++] = 'v'; strncpy(&result[i], s, maxwidth - middle - 1); + result[maxwidth - middle - 1] = '\0'; + return result; } @@ -571,6 +574,7 @@ int main(int argc, char *argv[]) { break; case 'p': strncpy(python_override_version, optarg, sizeof(python_override_version) - 1); + python_override_version[sizeof(python_override_version) - 1] = '\0'; break; case 'l': globals.cpu_limit = strtol(optarg, NULL, 10); @@ -707,8 +711,14 @@ int main(int argc, char *argv[]) { runtime_apply(ctx.runtime.environ); strncpy(env_name, ctx.info.release_name, sizeof(env_name) - 1); + env_name[sizeof(env_name) - 1] = '\0'; + strncpy(env_name_testing, env_name, sizeof(env_name_testing) - 1); + env_name_testing[sizeof(env_name_testing) - 1] = '\0'; + strncat(env_name_testing, "-test", sizeof(env_name_testing) - strlen(env_name_testing) - 1); + env_name_testing[sizeof(env_name_testing) - 1] = '\0'; + char *envs[] = { "release", env_name, "testing", env_name_testing, diff --git a/src/cli/stasis_indexer/helpers.c b/src/cli/stasis_indexer/helpers.c index 23e4f5a..86a20e4 100644 --- a/src/cli/stasis_indexer/helpers.c +++ b/src/cli/stasis_indexer/helpers.c @@ -121,7 +121,11 @@ int pandoc_exec(const char *in_file, const char *out_file, const char *css_file, // Converts a markdown file to html char cmd[STASIS_BUFSIZ] = {0}; strncpy(cmd, "pandoc ", sizeof(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; + strncat(cmd, pandoc_versioned_args, sizeof(cmd) - strlen(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; + if (css_file && strlen(css_file)) { strncat(cmd, "--css ", sizeof(cmd) - strlen(cmd) - 1); strncat(cmd, css_file, sizeof(cmd) - strlen(cmd) - 1); @@ -397,8 +401,11 @@ int write_manifest(const char *path, char **exclude_path, FILE *fp) { } char filepath[PATH_MAX] = {0}; strncpy(filepath, path, PATH_MAX - 1); + filepath[PATH_MAX - 1] = '\0'; + strncat(filepath, "/", sizeof(filepath) - strlen(filepath) - 1); strncat(filepath, rec->d_name, sizeof(filepath) - strlen(filepath) - 1); + if (rec->d_type == DT_DIR) { write_manifest(filepath, exclude_path, fp); continue; diff --git a/src/cli/stasis_indexer/junitxml_report.c b/src/cli/stasis_indexer/junitxml_report.c index d30ee09..4eae7f7 100644 --- a/src/cli/stasis_indexer/junitxml_report.c +++ b/src/cli/stasis_indexer/junitxml_report.c @@ -36,10 +36,15 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x char result_outfile[PATH_MAX] = {0}; char *short_name_pattern = NULL; - asprintf(&short_name_pattern, "-%s", ctx->info.release_name); + if (asprintf(&short_name_pattern, "-%s", ctx->info.release_name) < 0 || !short_name_pattern) { + SYSERROR("%s", "unable to allocate bytes for short name pattern"); + return -1; + } char short_name[PATH_MAX] = {0}; strncpy(short_name, bname, sizeof(short_name) - 1); + short_name[sizeof(short_name) - 1] = '\0'; + replace_text(short_name, short_name_pattern, "", 0); replace_text(short_name, "results-", "", 0); guard_free(short_name_pattern); @@ -52,8 +57,7 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x testsuite->passed, testsuite->failures, testsuite->skipped, testsuite->errors); - snprintf(result_outfile, sizeof(result_outfile) - strlen(bname) - 3, "%s.md", - bname); + snprintf(result_outfile, sizeof(result_outfile) - strlen(bname), "%s.md", bname); guard_free(bname); FILE *resultfp = fopen(result_outfile, "w+"); diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index d475c15..fa28c58 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -14,8 +14,13 @@ int indexer_combine_rootdirs(const char *dest, char **rootdirs, const size_t roo char *destdir = destdir_bare; strncpy(destdir_bare, dest, sizeof(destdir_bare) - 1); + destdir[sizeof(destdir_bare) - 1] = '\0'; + strncpy(destdir_with_output, dest, sizeof(destdir_with_output) - 1); + destdir_with_output[sizeof(destdir_with_output) - 1] = '\0'; + strncat(destdir_with_output, "/output", sizeof(destdir_with_output) - strlen(destdir_with_output) - 1); + destdir_with_output[sizeof(destdir_with_output) - 1] = '\0'; if (!access(destdir_with_output, F_OK)) { destdir = destdir_with_output; @@ -251,6 +256,7 @@ int main(const int argc, char *argv[]) { } else { strncpy(stasis_sysconfdir_tmp, STASIS_SYSCONFDIR, sizeof(stasis_sysconfdir_tmp) - 1); } + stasis_sysconfdir_tmp[sizeof(stasis_sysconfdir_tmp) - 1] = '\0'; globals.sysconfdir = realpath(stasis_sysconfdir_tmp, NULL); if (!globals.sysconfdir) { diff --git a/src/cli/stasis_indexer/website.c b/src/cli/stasis_indexer/website.c index 8a5126d..aa6e2a5 100644 --- a/src/cli/stasis_indexer/website.c +++ b/src/cli/stasis_indexer/website.c @@ -36,6 +36,8 @@ int indexer_make_website(struct Delivery **ctx) { // Replace *.md extension with *.html. strncpy(fullpath_dest, fullpath_src, sizeof(fullpath_dest) - 1); + fullpath_dest[sizeof(fullpath_dest) - 1] = '\0'; + gen_file_extension_str(fullpath_dest, sizeof(fullpath_dest), ".html"); // Convert markdown to html @@ -53,6 +55,7 @@ int indexer_make_website(struct Delivery **ctx) { char link_from[PATH_MAX] = {0}; char link_dest[PATH_MAX] = {0}; strncpy(link_from, "README.html", sizeof(link_from) - 1); + link_dest[sizeof(link_dest) - 1] = '\0'; snprintf(link_dest, sizeof(link_dest), "%s/%s", root, "index.html"); if (symlink(link_from, link_dest)) { SYSERROR("Warning: symlink(%s, %s) failed: %s", link_from, link_dest, strerror(errno)); diff --git a/src/lib/core/artifactory.c b/src/lib/core/artifactory.c index 2490346..54f4ba0 100644 --- a/src/lib/core/artifactory.c +++ b/src/lib/core/artifactory.c @@ -26,14 +26,17 @@ int artifactory_download_cli(char *dest, // convert platform string to lower-case SYSDEBUG("%s", "Set os_ident"); strncpy(os_ident, os, sizeof(os_ident) - 1); + os_ident[sizeof(os_ident) - 1] = '\0'; tolower_s(os_ident); SYSDEBUG("os_ident=%s", os_ident); // translate OS identifier if (!strcmp(os_ident, "darwin") || startswith(os_ident, "macos")) { strncpy(os_ident, "mac", sizeof(os_ident) - 1); + os_ident[sizeof(os_ident) - 1] = '\0'; } else if (!strcmp(os_ident, "linux")) { strncpy(os_ident, "linux", sizeof(os_ident) - 1); + os_ident[sizeof(os_ident) - 1] = '\0'; } else { fprintf(stderr, "%s: unknown operating system: %s\n", __FUNCTION__, os_ident); return -1; @@ -42,7 +45,9 @@ int artifactory_download_cli(char *dest, // translate ARCH identifier SYSDEBUG("%s", "Set arch_ident"); strncpy(arch_ident, arch, sizeof(arch_ident) - 1); + arch_ident[sizeof(arch_ident) - 1] = '\0'; SYSDEBUG("arch_ident=%s", arch_ident); + if (startswith(arch_ident, "i") && endswith(arch_ident, "86")) { strncpy(arch_ident, "386", sizeof(arch_ident) - 1); } else if (!strcmp(arch_ident, "amd64") || !strcmp(arch_ident, "x86_64") || !strcmp(arch_ident, "x64")) { @@ -57,6 +62,8 @@ int artifactory_download_cli(char *dest, fprintf(stderr, "%s: unknown architecture: %s\n", __FUNCTION__, arch_ident); return -1; } + arch_ident[sizeof(arch_ident) - 1] = '\0'; + SYSDEBUG("%s", "Construct URL"); snprintf(url, sizeof(url), "%s/%s/%s/%s/%s-%s-%s/%s", @@ -69,6 +76,7 @@ int artifactory_download_cli(char *dest, arch_ident, // jfrog-cli-linux-x86_64 remote_filename); // jf strncpy(path, dest, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; if (mkdirs(path, 0755)) { fprintf(stderr, "%s: %s: %s", __FUNCTION__, path, strerror(errno)); @@ -265,7 +273,10 @@ int jfrog_cli(struct JFRT_Auth *auth, const char *subsystem, const char *task, c if (!globals.verbose) { strncpy(proc.f_stdout, "/dev/null", sizeof(proc.f_stdout) - 1); + proc.f_stdout[sizeof(proc.f_stdout) - 1] = '\0'; + strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1); + proc.f_stderr[sizeof(proc.f_stderr) - 1] = '\0'; } return shell(&proc, cmd); } diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 4cb7710..1da4d6a 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -11,10 +11,12 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { tolower_s(sys.sysname); if (!strcmp(sys.sysname, "darwin")) { strncpy(sys.sysname, "osx", sizeof(sys.sysname) - 1); + sys.sysname[sizeof(sys.sysname) - 1] = '\0'; } if (!strcmp(sys.machine, "x86_64")) { strncpy(sys.machine, "64", sizeof(sys.machine) - 1); + sys.machine[sizeof(sys.machine) - 1] = '\0'; } char url[PATH_MAX] = {0}; @@ -146,6 +148,7 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { // Normalize the local spec string strncpy(spec_local, spec, sizeof(spec_local) - 1); + spec_local[sizeof(spec_local) - 1] = '\0'; tolower_s(spec_local); lstrip(spec_local); strip(spec_local); @@ -167,12 +170,15 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { // Do an installation in dry-run mode to see if the package exists in the given index. // The --force argument ignores local installation and cache, and actually polls the remote index(es) strncpy(cmd, "python -m pip install --force --dry-run --no-cache --no-deps ", sizeof(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; if (index) { snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "--index-url='%s' ", index); } snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "'%s' ", spec_local); } else if (mode == PKG_USE_CONDA) { strncpy(cmd, "mamba search ", sizeof(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; + if (index) { snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "--channel '%s' ", index); } @@ -247,6 +253,8 @@ int conda_exec(const char *args) { break; } } + conda_as[sizeof(conda_as) - 1] = '\0'; + const char *command_fmt = "%s %s"; const int len = snprintf(NULL, 0, command_fmt, conda_as, args); @@ -352,7 +360,8 @@ int conda_activate(const char *root, const char *env_name) { close(fd); // Configure our process for output to a log file - strncpy(proc.f_stdout, logfile, PATH_MAX - 1); + strncpy(proc.f_stdout, logfile, sizeof(proc.f_stdout) - 1); + proc.f_stdout[sizeof(proc.f_stdout) - 1] = '\0'; // Verify conda's init scripts are available if (access(path_conda, F_OK) < 0) { @@ -497,6 +506,7 @@ int conda_setup_headless() { if (globals.conda_packages && strlist_count(globals.conda_packages)) { memset(cmd, 0, sizeof(cmd)); strncpy(cmd, "install ", sizeof(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; total = strlist_count(globals.conda_packages); for (size_t i = 0; i < total; i++) { @@ -520,6 +530,7 @@ int conda_setup_headless() { if (globals.pip_packages && strlist_count(globals.pip_packages)) { memset(cmd, 0, sizeof(cmd)); strncpy(cmd, "install ", sizeof(cmd) - 1); + cmd[sizeof(cmd) - 1] = '\0'; total = strlist_count(globals.pip_packages); for (size_t i = 0; i < total; i++) { diff --git a/src/lib/core/copy.c b/src/lib/core/copy.c index 5b4e468..6697f59 100644 --- a/src/lib/core/copy.c +++ b/src/lib/core/copy.c @@ -15,6 +15,7 @@ int copy2(const char *src, const char *dest, unsigned int op) { char dname[1024] = {0}; strncpy(dname, dest, sizeof(dname) - 1); + dname[sizeof(dname) - 1] = '\0'; char *dname_endptr = strrchr(dname, '/'); if (dname_endptr != NULL) { diff --git a/src/lib/core/docker.c b/src/lib/core/docker.c index b289e5a..484f476 100644 --- a/src/lib/core/docker.c +++ b/src/lib/core/docker.c @@ -19,9 +19,11 @@ int docker_exec(const char *args, const unsigned flags) { if (final_flags & STASIS_DOCKER_QUIET_STDOUT) { strncpy(proc.f_stdout, "/dev/null", sizeof(proc.f_stdout) - 1); + proc.f_stdout[sizeof(proc.f_stdout) - 1] = '\0'; } if (final_flags & STASIS_DOCKER_QUIET_STDERR) { strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1); + proc.f_stderr[sizeof(proc.f_stderr) - 1] = '\0'; } if (!final_flags) { @@ -74,6 +76,8 @@ int docker_build(const char *dirpath, const char *args, int engine) { if (engine & STASIS_DOCKER_BUILD_X) { strncpy(build, "buildx build", sizeof(build) - 1); } + build[sizeof(build) - 1] = '\0'; + snprintf(cmd, sizeof(cmd), "%s %s %s", build, args, dirpath); return docker_exec(cmd, 0); } @@ -94,6 +98,7 @@ int docker_save(const char *image, const char *destdir, const char *compression_ } else { strncpy(ext, compression_program, sizeof(ext) - 1); } + ext[sizeof(ext) - 1] = '\0'; snprintf(cmd, sizeof(cmd), "save \"%s\" | %s > \"%s/%s.tar.%s\"", image, compression_program, destdir, image, ext); } else { snprintf(cmd, sizeof(cmd), "save \"%s\" -o \"%s/%s.tar\"", image, destdir, image); @@ -122,7 +127,11 @@ static char *docker_ident() { memset(&proc, 0, sizeof(proc)); strncpy(proc.f_stdout, tempfile, sizeof(proc.f_stdout) - 1); + proc.f_stdout[sizeof(proc.f_stdout) - 1] = '\0'; + strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1); + proc.f_stderr[sizeof(proc.f_stderr) - 1] = '\0'; + shell(&proc, "docker --version"); if (!freopen(tempfile, "r", fp)) { diff --git a/src/lib/core/environment.c b/src/lib/core/environment.c index 3c94d33..1bd9d28 100644 --- a/src/lib/core/environment.c +++ b/src/lib/core/environment.c @@ -90,6 +90,7 @@ void runtime_export(RuntimeEnv *env, char **keys) { break; } } + export_command[sizeof(export_command) - 1] = '\0'; for (size_t i = 0; i < strlist_count(env); i++) { char output[STASIS_BUFSIZ] = {0}; diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 6995eb2..16ffc20 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -181,7 +181,9 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, int break; case INIVAL_TYPE_STR_ARRAY: strncpy(tbufp, data_copy, sizeof(tbuf) - 1); + tbuf[sizeof(tbuf) - 1] = '\0'; guard_free(data_copy); + data_copy = calloc(STASIS_BUFSIZ, sizeof(*data_copy)); if (!data_copy) { return -1; @@ -526,6 +528,7 @@ struct INIFILE *ini_open(const char *filename) { // Create an implicit section. [default] does not need to be present in the INI config ini_section_create(&ini, "default"); strncpy(current_section, "default", sizeof(current_section) - 1); + current_section[sizeof(current_section) - 1] = '\0'; // Open the configuration file for reading FILE *fp = fopen(filename, "r"); @@ -600,6 +603,8 @@ struct INIFILE *ini_open(const char *filename) { // Record the name of the section. This is used until another section is found. memset(current_section, 0, sizeof(current_section)); strncpy(current_section, section_name, sizeof(current_section) - 1); + current_section[sizeof(current_section) - 1] = '\0'; + guard_free(section_name); memset(line, 0, sizeof(line)); continue; @@ -621,16 +626,21 @@ struct INIFILE *ini_open(const char *filename) { size_t key_len = operator - line; memset(key, 0, sizeof(inikey[0])); strncpy(key, line, key_len); + key[key_len] = '\0'; lstrip(key); strip(key); + memset(key_last, 0, sizeof(inikey[1])); strncpy(key_last, key, sizeof(inikey[1]) - 1); + key_last[sizeof(inikey[1]) - 1] = '\0'; + reading_value = 1; if (strlen(operator) > 1) { strncpy(value, &operator[1], sizeof(value) - 1); } else { strncpy(value, "", sizeof(value) - 1); } + value[sizeof(value) - 1] = '\0'; if (isempty(value)) { //printf("%s is probably long raw data\n", key); hint = INIVAL_TYPE_STR_ARRAY; @@ -644,7 +654,9 @@ struct INIFILE *ini_open(const char *filename) { strip(value); } else { strncpy(key, key_last, sizeof(inikey[0]) - 1); + key[sizeof(inikey[0]) - 1] = '\0'; strncpy(value, line, sizeof(value) - 1); + value[sizeof(value) - 1] = '\0'; } memset(line, 0, sizeof(line)); diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 7b16af3..8fd8b93 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -261,7 +261,6 @@ void mp_pool_show_summary(struct MultiProcessingPool *pool) { char duration[255] = {0}; seconds_to_human_readable(task->time_data.duration, duration, sizeof(duration)); printf("%-4s %10d %10s %-10s\n", status_str, task->parent_pid, duration, task->ident) ; - //printf("%-4s %10d %7lds %-10s\n", status_str, task->parent_pid, task->elapsed, task->ident) ; } puts(""); } diff --git a/src/lib/core/recipe.c b/src/lib/core/recipe.c index cc96139..72aa6a3 100644 --- a/src/lib/core/recipe.c +++ b/src/lib/core/recipe.c @@ -17,6 +17,7 @@ int recipe_clone(char *recipe_dir, char *url, char *gitref, char **result) { } } strncpy(*result, destdir, PATH_MAX - 1); + *result[PATH_MAX - 1] = '\0'; if (!access(destdir, F_OK)) { if (!strcmp(destdir, "/")) { diff --git a/src/lib/core/relocation.c b/src/lib/core/relocation.c index ea8b9c6..f7dafe8 100644 --- a/src/lib/core/relocation.c +++ b/src/lib/core/relocation.c @@ -85,6 +85,7 @@ int replace_text(char *original, const char *target, const char *replacement, un } // replace original with contents of buffer strncpy(original, buffer, buffer_len + 1); + original[buffer_len] = '\0'; return 0; } diff --git a/src/lib/core/str.c b/src/lib/core/str.c index 368ab49..b04dfed 100644 --- a/src/lib/core/str.c +++ b/src/lib/core/str.c @@ -63,6 +63,7 @@ void strchrdel(char *sptr, const char *chars) { for (size_t i = 0; i < strlen(chars); i++) { char ch[2] = {0}; strncpy(ch, &chars[i], 1); + ch[sizeof(ch) - 1] = '\0'; replace_text(sptr, ch, "", 0); } } @@ -105,7 +106,7 @@ char** split(char *_sptr, const char* delim, size_t max) // Separate the string into individual parts and store them in the result array char *token = NULL; char *sptr_tmp = sptr; - size_t pos = 0; + ptrdiff_t pos = 0; size_t i; for (i = 0; (token = strsep(&sptr_tmp, delim)) != NULL; i++) { // When max is zero, record all tokens @@ -120,6 +121,7 @@ char** split(char *_sptr, const char* delim, size_t max) return NULL; } strncpy(result[i], token, STASIS_BUFSIZ - 1); + result[i][STASIS_BUFSIZ - 1] = '\0'; } // pos is non-zero when maximum split is reached @@ -130,6 +132,7 @@ char** split(char *_sptr, const char* delim, size_t max) return NULL; } strncpy(result[i], &orig[pos], STASIS_BUFSIZ - 1); + result[i][STASIS_BUFSIZ - 1] = '\0'; } guard_free(sptr); @@ -562,7 +565,10 @@ char *normalize_space(char *s) { } // Rewrite the input string - strncpy(result, tmp_orig, strlen(result) + 1); + const size_t result_len = strlen(result) + 1; + strncpy(result, tmp_orig, result_len); + result[result_len] = '\0'; + guard_free(tmp_orig); return result; } @@ -583,6 +589,10 @@ char **strdup_array(char **array) { result = calloc(elems + 1, sizeof(*result)); for (size_t i = 0; i < elems; i++) { result[i] = strdup(array[i]); + if (!result[i]) { + guard_array_free(result); + break; + } } return result; diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c index ff9c098..a9a95e7 100644 --- a/src/lib/core/strlist.c +++ b/src/lib/core/strlist.c @@ -4,6 +4,10 @@ */ #include "download.h" #include "strlist.h" + +#include +#include + #include "utils.h" /** @@ -85,6 +89,8 @@ int strlist_append_file(struct StrList *pStrList, char *_path, ReaderFn *readerF int fd; char tempfile[PATH_MAX] = {0}; strncpy(tempfile, "/tmp/.remote_file.XXXXXX", sizeof(tempfile) - 1); + tempfile[sizeof(tempfile) - 1] = '\0'; + if ((fd = mkstemp(tempfile)) < 0) { retval = -1; goto fatal; @@ -420,8 +426,10 @@ void strlist_set(struct StrList **pStrList, size_t index, char *value) { (*pStrList)->data[index] = tmp; } - memset((*pStrList)->data[index], '\0', strlen(value) + 1); - strncpy((*pStrList)->data[index], value, strlen(value)); + const size_t len = strlen(value) + 1; + memset((*pStrList)->data[index], '\0', len); + strncpy((*pStrList)->data[index], value, len); + (*pStrList)->data[index][len] = '\0'; } } diff --git a/src/lib/core/template.c b/src/lib/core/template.c index 3a1b759..c72c6e5 100644 --- a/src/lib/core/template.c +++ b/src/lib/core/template.c @@ -236,6 +236,8 @@ char *tpl_render(char *str) { } else if (do_func) { // {{ func:NAME(a, ...) }} char func_name_temp[STASIS_NAME_MAX] = {0}; strncpy(func_name_temp, type_stop + 1, sizeof(func_name_temp) - 1); + func_name_temp[sizeof(func_name_temp) - 1] = '\0'; + char *param_begin = strchr(func_name_temp, '('); if (!param_begin) { fprintf(stderr, "At position %zu in %s\nfunction name must be followed by a '('\n", off, key); diff --git a/src/lib/core/template_func_proto.c b/src/lib/core/template_func_proto.c index fc58e33..f28a1eb 100644 --- a/src/lib/core/template_func_proto.c +++ b/src/lib/core/template_func_proto.c @@ -81,6 +81,8 @@ int get_junitxml_file_entrypoint(void *frame, void *data_out) { } char nametmp[PATH_MAX] = {0}; strncpy(nametmp, cwd, sizeof(nametmp) - 1); + nametmp[sizeof(nametmp) - 1] = '\0'; + char *name = path_basename(nametmp); *output = calloc(PATH_MAX, sizeof(**output)); @@ -106,6 +108,7 @@ int get_basetemp_dir_entrypoint(void *frame, void *data_out) { } char nametmp[PATH_MAX] = {0}; strncpy(nametmp, cwd, sizeof(nametmp) - 1); + nametmp[sizeof(nametmp) - 1] = '\0'; char *name = path_basename(nametmp); *output = calloc(PATH_MAX, sizeof(**output)); diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 2b7f0ec..b528add 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -35,9 +35,11 @@ int popd() { int rmtree(char *_path) { int status = 0; char path[PATH_MAX] = {0}; - strncpy(path, _path, sizeof(path) - 1); struct dirent *d_entity; + strncpy(path, _path, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + DIR *dir = opendir(path); if (!dir) { return 1; @@ -106,6 +108,7 @@ char *expandpath(const char *_path) { char *tmphome; if ((tmphome = getenv(homes[i])) != NULL) { strncpy(home, tmphome, PATH_MAX - 1); + home[PATH_MAX - 1] = '\0'; break; } } @@ -285,6 +288,7 @@ char *find_program(const char *name) { continue; } strncpy(result, abspath, sizeof(result) - 1); + result[sizeof(result) - 1] = '\0'; break; } path = path_orig; @@ -451,6 +455,7 @@ void msg(unsigned type, char *fmt, ...) { fprintf(stream, "%s", STASIS_COLOR_GREEN); strncpy(status, " ", sizeof(status) - 1); } + status[sizeof(status) - 1] = '\0'; if (type & STASIS_MSG_L1) { snprintf(header, sizeof(header), "==>%s" STASIS_COLOR_RESET STASIS_COLOR_WHITE, status); @@ -498,6 +503,8 @@ char *xmkstemp(FILE **fp, const char *mode) { } else { strncpy(tmpdir, "/tmp", sizeof(tmpdir) - 1); } + tmpdir[sizeof(tmpdir) - 1] = '\0'; + memset(t_name, 0, sizeof(t_name)); snprintf(t_name, sizeof(t_name), "%s/%s", tmpdir, "STASIS.XXXXXX"); @@ -722,6 +729,7 @@ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { // Store path to modified config strncpy(*result, tempfile, maxlen - 1); + *result[maxlen - 1] = '\0'; guard_free(tempfile); ini_free(&toxini); @@ -766,11 +774,12 @@ char *collapse_whitespace(char **s) { int redact_sensitive(const char **to_redact, size_t to_redact_size, char *src, char *dest, size_t maxlen) { const char *redacted = "***REDACTED***"; - char *tmp = calloc(strlen(redacted) + strlen(src) + 1, sizeof(*tmp)); + char *tmp = calloc(maxlen + 1, sizeof(*tmp)); if (!tmp) { return -1; } - strncpy(tmp, src, strlen(redacted) + strlen(src)); + strncpy(tmp, src, maxlen); + tmp[maxlen] = '\0'; for (size_t i = 0; i < to_redact_size; i++) { if (to_redact[i] && strstr(tmp, to_redact[i])) { @@ -780,7 +789,8 @@ int redact_sensitive(const char **to_redact, size_t to_redact_size, char *src, c } memset(dest, 0, maxlen); - strncpy(dest, tmp, maxlen - 1); + strncpy(dest, tmp, maxlen); + dest[maxlen] = '\0'; guard_free(tmp); return 0; @@ -834,6 +844,7 @@ int mkdirs(const char *_path, mode_t mode) { char *token; char pathbuf[PATH_MAX] = {0}; strncpy(pathbuf, _path, sizeof(pathbuf) - 1); + pathbuf[sizeof(pathbuf) - 1] = '\0'; char *path = pathbuf; errno = 0; diff --git a/src/lib/core/wheelinfo.c b/src/lib/core/wheelinfo.c index ce8ea74..9d8a6af 100644 --- a/src/lib/core/wheelinfo.c +++ b/src/lib/core/wheelinfo.c @@ -7,6 +7,7 @@ struct WheelInfo *wheelinfo_get(const char *basepath, const char *name, char *to char package_name[NAME_MAX]; strncpy(package_name, name, sizeof(package_name) - 1); + package_name[sizeof(package_name) - 1] = '\0'; tolower_s(package_name); snprintf(package_path, sizeof(package_path), "%s/%s", basepath, package_name); @@ -19,8 +20,11 @@ struct WheelInfo *wheelinfo_get(const char *basepath, const char *name, char *to if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) { continue; } + char filename[NAME_MAX]; strncpy(filename, rec->d_name, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + char *ext = strstr(filename, ".whl"); if (ext) { *ext = '\0'; diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index a97cc11..d4fe08c 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -367,6 +367,8 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { SYSERROR("BUG: type %d does not map to a supported package manager!\n", type); exit(1); } + mode[sizeof(mode) - 1] = '\0'; + msg(STASIS_MSG_L2, "Filtering %s packages by test definition...\n", mode); struct StrList *filtered = NULL; @@ -391,8 +393,10 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { spec_end++; } strncpy(package_name, name, spec_begin - name); + package_name[spec_begin - name] = '\0'; } else { strncpy(package_name, name, sizeof(package_name) - 1); + package_name[sizeof(package_name) - 1] = '\0'; } remove_extras(package_name); @@ -404,6 +408,8 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { char nametmp[STASIS_NAME_MAX] = {0}; strncpy(nametmp, package_name, sizeof(nametmp) - 1); + nametmp[sizeof(nametmp) - 1] = '\0'; + // Is the [test:NAME] in the package name? if (!strcmp(nametmp, test->name)) { // Override test->version when a version is provided by the (pip|conda)_package list item diff --git a/src/lib/delivery/delivery_build.c b/src/lib/delivery/delivery_build.c index 3ff5df7..49d2f5b 100644 --- a/src/lib/delivery/delivery_build.c +++ b/src/lib/delivery/delivery_build.c @@ -34,10 +34,11 @@ int delivery_build_recipes(struct Delivery *ctx) { tag[len] = '\0'; } else { strncpy(tag, ctx->tests->test[i]->repository_info_tag, sizeof(tag) - 1); - tag[strlen(ctx->tests->test[i]->repository_info_tag)] = '\0'; + tag[sizeof(tag) - 1] = '\0'; } } else { strncpy(tag, ctx->tests->test[i]->version, sizeof(tag) - 1); + tag[sizeof(tag) - 1] = '\0'; } //sprintf(recipe_version, "{%% set version = GIT_DESCRIBE_TAG ~ \".dev\" ~ GIT_DESCRIBE_NUMBER ~ \"+\" ~ GIT_DESCRIBE_HASH %%}"); @@ -51,6 +52,7 @@ int delivery_build_recipes(struct Delivery *ctx) { snprintf(recipe_version, sizeof(recipe_version), "{%% set version = \"%s\" %%}", tag); snprintf(recipe_git_url, sizeof(recipe_git_url), " url: %s/archive/refs/tags/{{ version }}.tar.gz", ctx->tests->test[i]->repository); strncpy(recipe_git_rev, "", sizeof(recipe_git_rev) - 1); + recipe_git_rev[sizeof(recipe_git_rev) - 1] = '\0'; snprintf(recipe_buildno, sizeof(recipe_buildno), " number: 0"); unsigned flags = REPLACE_TRUNCATE_AFTER_MATCH; @@ -79,14 +81,17 @@ int delivery_build_recipes(struct Delivery *ctx) { memset(platform, 0, sizeof(platform)); strncpy(platform, "osx", sizeof(platform) - 1); } + platform[sizeof(platform) - 1] = '\0'; tolower_s(platform); + if (strstr(ctx->system.arch, "arm64")) { strncpy(arch, "arm64", sizeof(arch) - 1); } else if (strstr(ctx->system.arch, "64")) { strncpy(arch, "64", sizeof(arch) - 1); } else { - strncat(arch, "32", sizeof(arch) - 1); // blind guess + strncat(arch, "32", sizeof(arch) - strlen(arch) - 1); // blind guess } + arch[sizeof(arch) - 1] = '\0'; tolower_s(arch); snprintf(command, sizeof(command), "mambabuild --python=%s -m ../.ci_support/%s_%s_.yaml .", @@ -385,6 +390,7 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) { char name[100] = {0}; char *fullspec = strlist_item(ctx->conda.pip_packages_defer, p); strncpy(name, fullspec, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; remove_extras(name); char *spec = find_version_spec(name); if (spec) { @@ -435,6 +441,7 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) { } strncpy(dname, ctx->tests->test[i]->name, sizeof(dname) - 1); + dname[sizeof(dname) - 1] = '\0'; tolower_s(dname); snprintf(outdir, sizeof(outdir), "%s/%s", ctx->storage.wheel_artifact_dir, dname); if (mkdirs(outdir, 0755)) { diff --git a/src/lib/delivery/delivery_docker.c b/src/lib/delivery/delivery_docker.c index 1178a8c..3177c96 100644 --- a/src/lib/delivery/delivery_docker.c +++ b/src/lib/delivery/delivery_docker.c @@ -45,6 +45,7 @@ int delivery_docker(struct Delivery *ctx) { for (size_t i = 0; i < total_tags; i++) { char *tag_orig = strlist_item(ctx->deploy.docker.tags, i); strncpy(tag, tag_orig, sizeof(tag) - 1); + tag[sizeof(tag) - 1] = '\0'; docker_sanitize_tag(tag); snprintf(args + strlen(args), sizeof(args) - strlen(args), " -t \"%s\" ", tag); } @@ -103,6 +104,7 @@ int delivery_docker(struct Delivery *ctx) { // All tags point back to the same image so test the first one we see // regardless of how many are defined strncpy(tag, strlist_item(ctx->deploy.docker.tags, 0), sizeof(tag) - 1); + tag[sizeof(tag) - 1] = '\0'; docker_sanitize_tag(tag); msg(STASIS_MSG_L2, "Executing image test script for %s\n", tag); diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index ff877f0..a163f01 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -178,22 +178,30 @@ int delivery_init_platform(struct Delivery *ctx) { } else { strncpy(archsuffix, ctx->system.arch, sizeof(archsuffix) - 1); } + archsuffix[sizeof(archsuffix) - 1] = '\0'; SYSDEBUG("%s", "Setting platform"); strncpy(ctx->system.platform[DELIVERY_PLATFORM], uts.sysname, DELIVERY_PLATFORM_MAXLEN - 1); 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); + ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "macos", DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_RELEASE][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; } else if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Linux")) { snprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], DELIVERY_PLATFORM_MAXLEN, "linux-%s", archsuffix); strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "Linux", DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "linux", DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_RELEASE][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; } else { // Not explicitly supported systems strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1); + ctx->system.platform[DELIVERY_PLATFORM_RELEASE][DELIVERY_PLATFORM_MAXLEN - 1] = '\0'; tolower_s(ctx->system.platform[DELIVERY_PLATFORM_RELEASE]); } diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index 22b3752..3d54eaa 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -32,8 +32,10 @@ static char *have_spec_in_config(const struct Delivery *ctx, const char *name) { char package[255] = {0}; if (op) { strncpy(package, config_spec, op - config_spec); + package[op - config_spec] = '\0'; } else { strncpy(package, config_spec, sizeof(package) - 1); + package[sizeof(package) - 1] = '\0'; } remove_extras(package); if (strncmp(package, name, strlen(name)) == 0) { @@ -81,8 +83,10 @@ int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_nam char *op = find_version_spec(spec); if (op) { strncpy(spec_name, spec, op - spec); + spec_name[op - spec] = '\0'; } else { strncpy(spec_name, spec, sizeof(spec_name) - 1); + spec_name[sizeof(spec_name) - 1] = '\0'; } struct Test *test_block = requirement_from_test(ctx, spec_name); @@ -102,8 +106,10 @@ int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_nam // we only care about packages with specs here. if something else arrives, ignore it if (op) { strncpy(frozen_name, frozen_spec, op - frozen_spec); + frozen_name[op - frozen_spec] = '\0'; } else { strncpy(frozen_name, frozen_spec, sizeof(frozen_name) - 1); + frozen_name[sizeof(frozen_name) - 1] = '\0'; } struct Test *test = requirement_from_test(ctx, frozen_name); if (test && strcmp(test->name, frozen_name) == 0) { @@ -151,15 +157,19 @@ int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_ fn = conda_exec; list = ctx->conda.conda_packages_purge; strncpy(package_manager, "conda", sizeof(package_manager) - 1); + package_manager[sizeof(package_manager) - 1] = '\0'; // conda is already configured for "always_yes" strncpy(subcommand, "remove", sizeof(subcommand) - 1); + subcommand[sizeof(subcommand) - 1] = '\0'; break; case PKG_USE_PIP: fn = pip_exec; list = ctx->conda.pip_packages_purge; strncpy(package_manager, "pip", sizeof(package_manager) - 1); + package_manager[sizeof(package_manager) - 1] = '\0'; // avoid user prompt to remove packages strncpy(subcommand, "uninstall -y", sizeof(subcommand) - 1); + subcommand[sizeof(subcommand) - 1] = '\0'; break; default: SYSERROR("Unknown package manager: %d", use_pkg_manager); @@ -300,8 +310,10 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha char req[255] = {0}; if (!strcmp(name, info->name)) { strncpy(req, info->name, sizeof(req) - 1); + req[sizeof(req) - 1] = '\0'; } else { strncpy(req, name, sizeof(req) - 1); + req[sizeof(req) - 1] = '\0'; char *spec = find_version_spec(req); if (spec) { *spec = 0; diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c index a088cd7..5d5a3e8 100644 --- a/src/lib/delivery/delivery_test.c +++ b/src/lib/delivery/delivery_test.c @@ -201,6 +201,7 @@ void delivery_tests_run(struct Delivery *ctx) { memset(&proc, 0, sizeof(proc)); strncpy(cmd, test->script, strlen(test->script) + STASIS_BUFSIZ - 1); + cmd[strlen(test->script) + STASIS_BUFSIZ - 1] = '\0'; char *cmd_rendered = tpl_render(cmd); if (cmd_rendered) { if (strcmp(cmd_rendered, cmd) != 0) { @@ -230,6 +231,7 @@ void delivery_tests_run(struct Delivery *ctx) { selected = SERIAL; memset(pool_name, 0, sizeof(pool_name)); strncpy(pool_name, "serial", sizeof(pool_name) - 1); + pool_name[sizeof(pool_name) - 1] = '\0'; } if (asprintf(&runner_cmd, runner_cmd_fmt, cmd) < 0) { @@ -281,11 +283,13 @@ void delivery_tests_run(struct Delivery *ctx) { } strncpy(cmd, test->script_setup, cmd_len - 1); + cmd[cmd_len - 1] = '\0'; + char *cmd_rendered = tpl_render(cmd); if (cmd_rendered) { if (strcmp(cmd_rendered, cmd) != 0) { strncpy(cmd, cmd_rendered, cmd_len - 1); - cmd[strlen(cmd_rendered) ? strlen(cmd_rendered) - 1 : 0] = 0; + cmd[strlen(cmd_rendered) ? strlen(cmd_rendered) - 1 : 0] = '\0'; } guard_free(cmd_rendered); } else { -- cgit From 8e35f384df1812c980f356417aa24cf97667be55 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 16:14:32 -0400 Subject: Bit shift needs to be unsigned long --- src/lib/core/envctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/envctl.c b/src/lib/core/envctl.c index d8d1b3d..5987616 100644 --- a/src/lib/core/envctl.c +++ b/src/lib/core/envctl.c @@ -53,7 +53,7 @@ size_t envctl_get_index(const struct EnvCtl *envctl, const char *name) { for (size_t i = 0; i < envctl->num_used; i++) { if (!strcmp(envctl->item[i]->name, name)) { // pack state flag, outer (struct) index and inner (name) index - return 1L << 63L | i; + return 1UL << 63UL | i; } } return 0; -- cgit From 32e8aa87ba1f592f31f5a94b2d35bf2159071ae0 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 16:15:40 -0400 Subject: NUL after copy --- src/cli/stasis_indexer/stasis_indexer_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index fa28c58..5a92014 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -32,8 +32,13 @@ int indexer_combine_rootdirs(const char *dest, char **rootdirs, const size_t roo char srcdir_with_output[PATH_MAX] = {0}; char *srcdir = srcdir_bare; strncpy(srcdir_bare, rootdirs[i], sizeof(srcdir_bare) - 1); + srcdir_bare[sizeof(srcdir_bare) - 1] = '\0'; + strncpy(srcdir_with_output, rootdirs[i], sizeof(srcdir_with_output) - 1); + srcdir_with_output[sizeof(srcdir_with_output) - 1] = '\0'; + strncat(srcdir_with_output, "/output", sizeof(srcdir_with_output) - strlen(srcdir_with_output) - 1); + srcdir_with_output[sizeof(srcdir_with_output) - 1] = '\0'; if (access(srcdir_bare, F_OK)) { fprintf(stderr, "%s does not exist\n", srcdir_bare); -- cgit From f074cf9ea6d8ab8f2ad6681e8c2a39bcd32f7f0e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 16:17:05 -0400 Subject: Fix error check for strtof/d/ld calls --- src/lib/core/strlist.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c index a9a95e7..42d5b85 100644 --- a/src/lib/core/strlist.c +++ b/src/lib/core/strlist.c @@ -679,8 +679,8 @@ float strlist_item_as_float(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - float result = (float) strtof(strlist_item(pStrList, index), &error_p); - if (!result && error_p && *error_p != 0) { + const float result = strtof(strlist_item(pStrList, index), &error_p); + if ((result == FLT_MIN || result == HUGE_VALF) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; } @@ -698,8 +698,8 @@ double strlist_item_as_double(struct StrList *pStrList, size_t index) { char *error_p; strlist_clear_error(); - double result = (double) strtod(strlist_item(pStrList, index), &error_p); - if (!result && error_p && *error_p != 0) { + const double result = strtod(strlist_item(pStrList, index), &error_p); + if ((result == DBL_MIN || result == HUGE_VAL) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; } @@ -717,8 +717,8 @@ long double strlist_item_as_long_double(struct StrList *pStrList, size_t index) char *error_p; strlist_clear_error(); - long double result = (long double) strtold(strlist_item(pStrList, index), &error_p); - if (!result && error_p && *error_p != 0) { + const long double result = strtold(strlist_item(pStrList, index), &error_p); + if ((result == DBL_MIN || result == HUGE_VALL) && errno == ERANGE) { strlist_set_error(STRLIST_E_INVALID_VALUE); return 0; } -- cgit From 5570710481e3d2bff5fe914c7720ae62f9725fab Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 16:17:44 -0400 Subject: Close fp_out before execl --- src/lib/core/system.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/lib/core/system.c b/src/lib/core/system.c index 5b47a62..8a6143c 100644 --- a/src/lib/core/system.c +++ b/src/lib/core/system.c @@ -90,6 +90,7 @@ int shell(struct Process *proc, char *args) { } _exit(1); } + fclose(fp_out); } } -- cgit From 97ab5131530148b3ea01716a54e0c39c9f200a84 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 16:18:48 -0400 Subject: Remove incorrect equality check. --- src/lib/core/system.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/system.c b/src/lib/core/system.c index 8a6143c..b00762c 100644 --- a/src/lib/core/system.c +++ b/src/lib/core/system.c @@ -180,9 +180,8 @@ char *shell_output(const char *command, int *status) { char *tmp = realloc(result, sizeof(*result) * current_size); if (!tmp) { return NULL; - } else if (tmp != result) { - result = tmp; } + result = tmp; } strncat(result, line, current_size - strlen(result) - 1); memset(line, 0, sizeof(line)); -- cgit From 51b01cdd30aafb0846263c60334850e0f82118e6 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 19:56:51 -0400 Subject: Fix NUL placement in center text --- src/cli/stasis/stasis_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index 252e67e..c04e88b 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -522,7 +522,7 @@ static char *center_text(const char *s, const size_t maxwidth) { } result[i++] = 'v'; strncpy(&result[i], s, maxwidth - middle - 1); - result[maxwidth - middle - 1] = '\0'; + result[maxwidth - 1] = '\0'; return result; } -- cgit From f1a92821c3019f80357331d087b8ca86745857f9 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 23:26:17 -0400 Subject: Fix NUL termination in double pointer --- src/lib/core/recipe.c | 2 +- src/lib/core/utils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/recipe.c b/src/lib/core/recipe.c index 72aa6a3..e5769bb 100644 --- a/src/lib/core/recipe.c +++ b/src/lib/core/recipe.c @@ -17,7 +17,7 @@ int recipe_clone(char *recipe_dir, char *url, char *gitref, char **result) { } } strncpy(*result, destdir, PATH_MAX - 1); - *result[PATH_MAX - 1] = '\0'; + (*result)[PATH_MAX - 1] = '\0'; if (!access(destdir, F_OK)) { if (!strcmp(destdir, "/")) { diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index b528add..b8049a4 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -729,7 +729,7 @@ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { // Store path to modified config strncpy(*result, tempfile, maxlen - 1); - *result[maxlen - 1] = '\0'; + (*result)[maxlen - 1] = '\0'; guard_free(tempfile); ini_free(&toxini); -- cgit From b90c1e085564c410bddb5f4c9ea796cb41804bd2 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 23:28:05 -0400 Subject: Fix snprintf calls --- src/lib/core/ini.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 16ffc20..12541f5 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -456,15 +456,19 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { return -1; } + size_t len = 0; if (*hint == INIVAL_TYPE_STR_ARRAY) { int leading_space = isspace(*render); if (leading_space) { - snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s" LINE_SEP, render); + len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s" LINE_SEP, render); + snprintf(outvalue + strlen(outvalue), len, "%s" LINE_SEP, render); } else { - snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), " %s" LINE_SEP, render); + len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, " %s" LINE_SEP, render); + snprintf(outvalue + strlen(outvalue), len, " %s" LINE_SEP, render); } } else { - snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s", render); + len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s", render); + snprintf(outvalue + strlen(outvalue), len, "%s", render); } if (mode == INI_WRITE_PRESERVE) { guard_free(render); -- cgit From ec2577ca0875f97a6a89d847b5ac9524f947c79d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 24 Apr 2026 23:51:01 -0400 Subject: Do not close stderr! --- src/lib/core/system.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/system.c b/src/lib/core/system.c index b00762c..06ca7bf 100644 --- a/src/lib/core/system.c +++ b/src/lib/core/system.c @@ -80,7 +80,6 @@ int shell(struct Process *proc, char *args) { fclose(fp_err); _exit(1); } - fclose(fp_err); } else { // redirect stderr to stdout if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) { @@ -90,7 +89,6 @@ int shell(struct Process *proc, char *args) { } _exit(1); } - fclose(fp_out); } } -- cgit From 5e583af9c55a5bdda6d0f699117a9df163f00b21 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 00:23:54 -0400 Subject: Use strncpy in example code --- src/lib/core/relocation.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/relocation.c b/src/lib/core/relocation.c index f7dafe8..16376b3 100644 --- a/src/lib/core/relocation.c +++ b/src/lib/core/relocation.c @@ -8,8 +8,9 @@ * Replace all occurrences of `target` with `replacement` in `original` * * ~~~{.c} - * char *str = calloc(100, sizeof(char)); - * strcpy(str, "This are a test."); + * size_t str_maxlen = 100; + * char *str = calloc(str_maxlen, sizeof(char)); + * strncpy(str, "This are a test.", str_maxlen - 1); * if (replace_text(str, "are", "is")) { * fprintf(stderr, "string replacement failed\n"); * exit(1); -- cgit From 7b7d84b3bea179d607fae2db5de7613adef1a6fd Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 10:15:35 -0400 Subject: delivery_init_tmpdir: reverse error condition to clean up goto logic --- src/lib/delivery/delivery_init.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index a163f01..9a2f6c3 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -12,7 +12,7 @@ int has_mount_flags(const char *mount_point, const unsigned long flags) { int delivery_init_tmpdir(struct Delivery *ctx) { char *tmpdir = NULL; char *x = NULL; - int unusable = 0; + int unusable = 1; errno = 0; x = getenv("TMPDIR"); @@ -25,7 +25,8 @@ int delivery_init_tmpdir(struct Delivery *ctx) { if (!tmpdir) { // memory error - return -1; + SYSERROR("%s", "unable to allocate tmpdir"); + goto l_delivery_init_tmpdir_fatal; } // If the directory doesn't exist, create it @@ -61,15 +62,25 @@ int delivery_init_tmpdir(struct Delivery *ctx) { if (!globals.tmpdir) { globals.tmpdir = strdup(tmpdir); + if (!globals.tmpdir) { + SYSERROR("%s", "unable to allocate globals.tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } } if (!ctx->storage.tmpdir) { ctx->storage.tmpdir = strdup(globals.tmpdir); + if (!ctx->storage.tmpdir) { + SYSERROR("%s", "unable to allocate globals.tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } } - return unusable; + unusable = 0; l_delivery_init_tmpdir_fatal: - unusable = 1; + if (unusable) { + guard_free(tmpdir); + } return unusable; } -- cgit From 237872ae44b1b3debb96e4f96d21c3c06dbdf761 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 10:16:36 -0400 Subject: strdup_array: handle allocation errors --- src/lib/core/str.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/lib/core/str.c b/src/lib/core/str.c index b04dfed..a08bd2b 100644 --- a/src/lib/core/str.c +++ b/src/lib/core/str.c @@ -587,6 +587,10 @@ char **strdup_array(char **array) { // Create new array result = calloc(elems + 1, sizeof(*result)); + if (!result) { + SYSERROR("%s", "could not allocate memory for result array"); + return NULL; + } for (size_t i = 0; i < elems; i++) { result[i] = strdup(array[i]); if (!result[i]) { -- cgit From cb90837b058ea1680ada46752294b992fbf542a4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 10:17:32 -0400 Subject: UB / write "NULL" on NULL --- src/lib/core/template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/template.c b/src/lib/core/template.c index c72c6e5..3b6f58d 100644 --- a/src/lib/core/template.c +++ b/src/lib/core/template.c @@ -98,7 +98,7 @@ void tpl_register(char *key, char **ptr) { item->ptr = ptr; if (!replacing) { - SYSDEBUG("Registered tpl_item at index %u:\n\tkey=%s\n\tptr=%s", tpl_pool_used, item->key, *item->ptr); + SYSDEBUG("Registered tpl_item at index %u:\n\tkey=%s\n\tptr=%s", tpl_pool_used, item->key, *item->ptr ? *item->ptr : "NULL"); tpl_pool[tpl_pool_used] = item; tpl_pool_used++; } -- cgit From 1b86d8fee99fef44671da649cec83356b404328f Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 10:17:56 -0400 Subject: wheel_parse_wheel: handle key allocation error --- src/lib/core/wheel.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 0bc4209..9e656ce 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -69,9 +69,14 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { char **pair = split(line, ":", 1); if (pair) { char *key = strdup(strip(pair[0])); - char *value = strdup(lstrip(pair[1])); + if (!key) { + SYSERROR("%s", "could not allocate memory for pair wheel key"); + return -1; + } - if (!key || !value) { + char *value = strdup(lstrip(pair[1])); + if (value) { + SYSERROR("%s", "could not allocate memory for wheel value"); return -1; } -- cgit From 0d4b95442be1dcb72855a2384744d0e13cc4ee7d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 14:18:37 -0400 Subject: usage: fail on allocation error --- src/cli/stasis_indexer/args.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/cli/stasis_indexer/args.c b/src/cli/stasis_indexer/args.c index 8c9d3fe..e77c0b7 100644 --- a/src/cli/stasis_indexer/args.c +++ b/src/cli/stasis_indexer/args.c @@ -22,6 +22,10 @@ const char *long_options_help[] = { void usage(char *name) { const int maxopts = sizeof(long_options) / sizeof(long_options[0]); char *opts = calloc(maxopts + 1, sizeof(char)); + if (!opts) { + SYSERROR("%s", "Unable to allocate memory for options array"); + exit(1); + } for (int i = 0; i < maxopts; i++) { opts[i] = (char) long_options[i].val; } -- cgit From 8f209a9ab8dfca02ce5c53f50d87919b7202e3f1 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 16:35:28 -0400 Subject: Set starting TMPDIR to /tmp/stasis * Easier to remove leftover files, if any * Now uses setenv() to have better control over external programs * Removes the hack to initialize TMPDIR early --- src/cli/stasis/system_requirements.c | 4 --- src/cli/stasis_indexer/stasis_indexer_main.c | 8 ++++- src/lib/delivery/delivery_init.c | 44 ++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/cli/stasis/system_requirements.c b/src/cli/stasis/system_requirements.c index 0f0aae8..ebfbffc 100644 --- a/src/cli/stasis/system_requirements.c +++ b/src/cli/stasis/system_requirements.c @@ -38,10 +38,6 @@ void check_system_requirements(struct Delivery *ctx) { msg(STASIS_MSG_RESTRICT, "found\n"); } - if (!globals.tmpdir && !ctx->storage.tmpdir) { - delivery_init_tmpdir(ctx); - } - msg(STASIS_MSG_L2, "Docker\n"); if (docker_capable(&ctx->deploy.docker.capabilities)) { struct DockerCapabilities *dcap = &ctx->deploy.docker.capabilities; diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index 5a92014..d71c341 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -274,8 +274,14 @@ int main(const int argc, char *argv[]) { if (system_tmp) { strncat(workdir_template, system_tmp, sizeof(workdir_template) - strlen(workdir_template) - 1); } else { - strncat(workdir_template, "/tmp", sizeof(workdir_template) - strlen(workdir_template) - 1); + strncat(workdir_template, "/tmp/stasis", sizeof(workdir_template) - strlen(workdir_template) - 1); } + + if (mkdirs(workdir_template, 0700)) { + SYSERROR("Unable to create directory '%s': %s", workdir_template, strerror(errno)); + exit(1); + } + strncat(workdir_template, "/stasis-combine.XXXXXX", sizeof(workdir_template) - strlen(workdir_template) - 1); char *workdir = mkdtemp(workdir_template); if (!workdir) { diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index 9a2f6c3..17f3899 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -11,24 +11,43 @@ int has_mount_flags(const char *mount_point, const unsigned long flags) { int delivery_init_tmpdir(struct Delivery *ctx) { char *tmpdir = NULL; - char *x = NULL; int unusable = 1; errno = 0; - x = getenv("TMPDIR"); + int need_setenv = 0; + const char *x = getenv("TMPDIR"); if (x) { guard_free(ctx->storage.tmpdir); tmpdir = strdup(x); + if (!tmpdir) { + // memory error + SYSERROR("%s", "unable to allocate tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } } else { - tmpdir = ctx->storage.tmpdir; + tmpdir = strdup("/tmp/stasis"); + if (!tmpdir) { + SYSERROR("%s", "unable to allocate tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } + need_setenv = 1; } - if (!tmpdir) { - // memory error - SYSERROR("%s", "unable to allocate tmpdir"); - goto l_delivery_init_tmpdir_fatal; + if (!ctx->storage.tmpdir) { + ctx->storage.tmpdir = strdup(tmpdir); + if (!ctx->storage.tmpdir) { + SYSERROR("%s", "unable to allocate ctx->storage.tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } + } else { + // we already have a temp directory to use + guard_free(tmpdir); + tmpdir = strdup(ctx->storage.tmpdir); + if (!tmpdir) { + SYSERROR("%s", "unable to allocate tmpdir"); + goto l_delivery_init_tmpdir_fatal; + } } - // If the directory doesn't exist, create it if (access(tmpdir, F_OK) < 0) { if (mkdirs(tmpdir, 0755) < 0) { @@ -60,7 +79,7 @@ int delivery_init_tmpdir(struct Delivery *ctx) { goto l_delivery_init_tmpdir_fatal; } - if (!globals.tmpdir) { + if (!globals.tmpdir || strcmp(globals.tmpdir, ctx->storage.tmpdir) != 0) { globals.tmpdir = strdup(tmpdir); if (!globals.tmpdir) { SYSERROR("%s", "unable to allocate globals.tmpdir"); @@ -76,11 +95,12 @@ int delivery_init_tmpdir(struct Delivery *ctx) { } } unusable = 0; + if (need_setenv) { + setenv("TMPDIR", ctx->storage.tmpdir, 1); + } l_delivery_init_tmpdir_fatal: - if (unusable) { - guard_free(tmpdir); - } + guard_free(tmpdir); return unusable; } -- cgit From 2057ef8a1b88e97a16f1f7afc7b4b3c350a104bd Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 16:36:54 -0400 Subject: Move system requirement check down so configure_delivery_context can set TMPDIR before getting executed --- src/cli/stasis/stasis_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index c04e88b..78aae0c 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -691,7 +691,6 @@ int main(int argc, char *argv[]) { setup_python_version_override(&ctx, python_override_version); configure_stasis_ini(&ctx, &config_input); check_system_path(); - check_requirements(&ctx); msg(STASIS_MSG_L1, "Setup\n"); @@ -700,6 +699,7 @@ int main(int argc, char *argv[]) { configure_delivery_ini(&ctx, &delivery_input); configure_delivery_context(&ctx); + check_requirements(&ctx); configure_jfrog_cli(&ctx); /* -- cgit From b2e23f78b53091c9db780f2db7eba72b29ac1997 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 16:37:31 -0400 Subject: Colorize SYSERROR and SYSDEBUG output --- src/lib/core/include/core_message.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/include/core_message.h b/src/lib/core/include/core_message.h index 1ffa846..aab7203 100644 --- a/src/lib/core/include/core_message.h +++ b/src/lib/core/include/core_message.h @@ -3,13 +3,13 @@ #define STASIS_CORE_MESSAGE_H #define SYSERROR(MSG, ...) do { \ - fprintf(stderr, "%s:%d:%s():%s - ", path_basename(__FILE__), __LINE__, __FUNCTION__, (errno > 0) ? strerror(errno) : "info"); \ + fprintf(stderr, STASIS_COLOR_RED "ERROR: " STASIS_COLOR_RESET STASIS_COLOR_WHITE "%s:%d:%s()" STASIS_COLOR_RESET ":%s - ", path_basename(__FILE__), __LINE__, __FUNCTION__, (errno > 0) ? strerror(errno) : "info"); \ fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \ } while (0) #ifdef DEBUG #define SYSDEBUG(MSG, ...) do { \ - fprintf(stderr, "DEBUG: %s:%d:%s(): ", path_basename(__FILE__), __LINE__, __FUNCTION__); \ + fprintf(stderr, STASIS_COLOR_BLUE "DEBUG: " STASIS_COLOR_RESET STASIS_COLOR_WHITE "%s:%d:%s()" STASIS_COLOR_RESET ": ", path_basename(__FILE__), __LINE__, __FUNCTION__); \ fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \ } while (0) #else -- cgit From a15dfe9326e32dc3614d2b5d26c33993f3bf741d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 16:47:48 -0400 Subject: Fix broken allocation error check --- src/lib/core/wheel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index 9e656ce..c8c75ca 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -75,7 +75,7 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { } char *value = strdup(lstrip(pair[1])); - if (value) { + if (!value) { SYSERROR("%s", "could not allocate memory for wheel value"); return -1; } -- cgit From b6987fdaadb750a4cf89f4eba58ce8d19ee282c7 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 18:45:34 -0400 Subject: Use /tmp/stasis --- src/lib/core/conda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 1da4d6a..731cf80 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -153,7 +153,7 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { lstrip(spec_local); strip(spec_local); - char logfile[] = "/tmp/STASIS-package_exists.XXXXXX"; + char logfile[] = "/tmp/stasis/STASIS-package_exists.XXXXXX"; int logfd = mkstemp(logfile); if (logfd < 0) { perror(logfile); -- cgit From 011dfefa478f7e280cf64641644dccffe4ae5b1b Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sat, 25 Apr 2026 19:18:33 -0400 Subject: Use /tmp/stasis --- src/lib/core/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index b8049a4..4843e5a 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -501,7 +501,7 @@ char *xmkstemp(FILE **fp, const char *mode) { if (globals.tmpdir) { strncpy(tmpdir, globals.tmpdir, sizeof(tmpdir) - 1); } else { - strncpy(tmpdir, "/tmp", sizeof(tmpdir) - 1); + strncpy(tmpdir, "/tmp/stasis", sizeof(tmpdir) - 1); } tmpdir[sizeof(tmpdir) - 1] = '\0'; -- cgit From d2892e347a619325550fa45cb8da5914bf2a5343 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 26 Apr 2026 01:33:48 -0400 Subject: xmkstemp: create sub-directories if needed --- src/lib/core/utils.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index 4843e5a..90dac1d 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -505,6 +505,11 @@ char *xmkstemp(FILE **fp, const char *mode) { } tmpdir[sizeof(tmpdir) - 1] = '\0'; + if (mkdirs(tmpdir, 0700) < 0) { + SYSERROR("unable to create sub-directories in %s", tmpdir); + return NULL; + } + memset(t_name, 0, sizeof(t_name)); snprintf(t_name, sizeof(t_name), "%s/%s", tmpdir, "STASIS.XXXXXX"); @@ -665,6 +670,7 @@ int fix_tox_conf(const char *filename, char **result, size_t maxlen) { // Create new temporary tox configuration file char *tempfile = xmkstemp(&fptemp, "w+"); if (!tempfile) { + SYSERROR("%s", "unable to create temporary file"); return -1; } -- cgit From 421903a1379353f07a10deb335ed3c0361233064 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 26 Apr 2026 01:49:02 -0400 Subject: Fix file handle leaks --- src/cli/stasis_indexer/readmes.c | 1 + src/lib/delivery/delivery_postprocess.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/cli/stasis_indexer/readmes.c b/src/cli/stasis_indexer/readmes.c index 749b1ee..7357fca 100644 --- a/src/cli/stasis_indexer/readmes.c +++ b/src/cli/stasis_indexer/readmes.c @@ -67,6 +67,7 @@ int indexer_readmes(struct Delivery **ctx, const size_t nelem) { latest_deliveries[i]->info.build_number, strstr((*ctx)->rules.release_fmt, "%p") ? latest_deliveries[i]->meta.python_compact : "" ) < 0) { SYSERROR("%s", "Unable to allocate bytes for pattern"); + fclose(indexfp); return -1; } diff --git a/src/lib/delivery/delivery_postprocess.c b/src/lib/delivery/delivery_postprocess.c index 95bcc0a..3ff1d56 100644 --- a/src/lib/delivery/delivery_postprocess.c +++ b/src/lib/delivery/delivery_postprocess.c @@ -243,6 +243,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) { FILE *bottom_fp = fopen(bottom_index, "w+"); if (!bottom_fp) { closedir(dp); + fclose(top_fp); return -3; } -- cgit From 917df9195011c852a6efffd4f1dc40ff007534c9 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 26 Apr 2026 01:49:22 -0400 Subject: Fix leaks --- src/cli/stasis_indexer/junitxml_report.c | 1 + src/lib/core/wheel.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/cli/stasis_indexer/junitxml_report.c b/src/cli/stasis_indexer/junitxml_report.c index 4eae7f7..c6cf4b0 100644 --- a/src/cli/stasis_indexer/junitxml_report.c +++ b/src/cli/stasis_indexer/junitxml_report.c @@ -38,6 +38,7 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x char *short_name_pattern = NULL; if (asprintf(&short_name_pattern, "-%s", ctx->info.release_name) < 0 || !short_name_pattern) { SYSERROR("%s", "unable to allocate bytes for short name pattern"); + guard_free(bname); return -1; } diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c index c8c75ca..9f3b3c8 100644 --- a/src/lib/core/wheel.c +++ b/src/lib/core/wheel.c @@ -77,6 +77,7 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { char *value = strdup(lstrip(pair[1])); if (!value) { SYSERROR("%s", "could not allocate memory for wheel value"); + guard_free(key); return -1; } @@ -95,6 +96,8 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { pkg->wheel_version = strdup(value); if (!pkg->wheel_version) { // memory error + guard_free(key); + guard_free(value); wheel_package_free(&pkg); return -1; } @@ -104,6 +107,8 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { pkg->generator = strdup(value); if (!pkg->generator) { // memory error + guard_free(key); + guard_free(value); wheel_package_free(&pkg); return -1; } @@ -113,6 +118,8 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { pkg->root_is_pure_lib = strdup(value); if (!pkg->root_is_pure_lib) { // memory error + guard_free(key); + guard_free(value); wheel_package_free(&pkg); return -1; } @@ -122,6 +129,8 @@ static ssize_t wheel_parse_wheel(struct Wheel * pkg, const char * data) { if (!pkg->tag) { pkg->tag = strlist_init(); if (!pkg->tag) { + guard_free(key); + guard_free(value); wheel_package_free(&pkg); return -1; } -- cgit From f4bccc6b21c8eec58bb08bc22115a93a2352868d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 26 Apr 2026 01:49:48 -0400 Subject: Add allocation checks --- src/cli/stasis_indexer/stasis_indexer_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c index d71c341..ed938b7 100644 --- a/src/cli/stasis_indexer/stasis_indexer_main.c +++ b/src/cli/stasis_indexer/stasis_indexer_main.c @@ -212,6 +212,10 @@ int main(const int argc, char *argv[]) { if (optind < argc) { rootdirs_total = argc - current_index; rootdirs = calloc(rootdirs_total + 1, sizeof(*rootdirs)); + if (!rootdirs) { + SYSERROR("%s", "unable to allocate memory for rootdirs array"); + exit(1); + } int i = 0; while (optind < argc) { @@ -223,6 +227,10 @@ int main(const int argc, char *argv[]) { } // use first positional argument rootdirs[i] = realpath(argv[optind], NULL); + if (!rootdirs[i]) { + SYSERROR("%s", "Unable to allocate memory for root directory"); + exit(1); + } optind++; break; } -- cgit From 6df309db7afa3f2c44d5f7069534484da7523cfd Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 26 Apr 2026 21:59:00 -0400 Subject: pkg_index_provides: When in debug mode show log data regardless --- src/lib/core/conda.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 731cf80..2a76c30 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -187,11 +187,24 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { return PKG_INDEX_PROVIDES_E_INTERNAL_MODE_UNKNOWN; } +#if defined(DEBUG) + const int debug_log = 1; +#else + const 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); + } status = shell(&proc, cmd); - if (status < 0) { + + if (debug_log) { + SYSDEBUG("Log file: %s", logfile); + } + if (status < 0 || debug_log) { FILE *fp = fdopen(logfd, "r"); if (!fp) { remove(logfile); @@ -201,7 +214,11 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { fflush(stdout); fflush(stderr); while (fgets(line, sizeof(line) - 1, fp) != NULL) { - fprintf(stderr, "%s", line); + if (debug_log) { + SYSDEBUG("%s", strip(line)); + } else { + fprintf(stderr, "%s", line); + } } fflush(stderr); fclose(fp); -- cgit From 4d3edd67c28116bdd337f5b3b2f456329a269bdb Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 01:55:14 -0400 Subject: pkg_index_provides: Add logdir argument * mkdirs() the logdir --- src/lib/core/conda.c | 11 +++++++++-- src/lib/core/include/conda.h | 3 ++- src/lib/delivery/delivery.c | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 2a76c30..d15b6a6 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -137,7 +137,7 @@ const char *pkg_index_provides_strerror(int code) { return PKG_ERROR_STR[code]; } -int pkg_index_provides(int mode, const char *index, const char *spec) { +int pkg_index_provides(int mode, const char *index, const char *spec, const char *logdir) { char cmd[PATH_MAX] = {0}; char spec_local[255] = {0}; @@ -153,7 +153,14 @@ int pkg_index_provides(int mode, const char *index, const char *spec) { lstrip(spec_local); strip(spec_local); - char logfile[] = "/tmp/stasis/STASIS-package_exists.XXXXXX"; + if (mkdirs(logdir, 0700) < 0) { + SYSERROR("Unable to create log directory: %s", logdir ? logdir : "NULL"); + return -1; + } + const char logfile_template[] = "STASIS-package_exists.XXXXXX"; + char logfile[PATH_MAX] = {0}; + snprintf(logfile, sizeof(logfile), "%s/%s", logdir, logfile_template); + int logfd = mkstemp(logfile); if (logfd < 0) { perror(logfile); diff --git a/src/lib/core/include/conda.h b/src/lib/core/include/conda.h index f3d481c..ccab060 100644 --- a/src/lib/core/include/conda.h +++ b/src/lib/core/include/conda.h @@ -219,12 +219,13 @@ int conda_index(const char *path); * @param mode USE_CONDA * @param index a file system path or url pointing to a simple index or conda channel * @param spec a pip package specification (e.g. `name==1.2.3`) + * @param logdir the directory to store the output log * @param spec a conda package specification (e.g. `name=1.2.3`) * @return PKG_NOT_FOUND, if not found * @return PKG_FOUND, if found * @return PKG_E_INDEX_PROVIDES_{ERROR}, on error (see conda.h) */ -int pkg_index_provides(int mode, const char *index, const char *spec); +int pkg_index_provides(int mode, const char *index, const char *spec, const char *logdir); const char *pkg_index_provides_strerror(int code); char *conda_get_active_environment(); diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c index d4fe08c..45b3b35 100644 --- a/src/lib/delivery/delivery.c +++ b/src/lib/delivery/delivery.c @@ -453,9 +453,9 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { int upstream_exists = 0; if (DEFER_PIP == type) { - upstream_exists = pkg_index_provides(PKG_USE_PIP, PYPI_INDEX_DEFAULT, name); + upstream_exists = pkg_index_provides(PKG_USE_PIP, PYPI_INDEX_DEFAULT, name, ctx->storage.tmpdir); } else if (DEFER_CONDA == type) { - upstream_exists = pkg_index_provides(PKG_USE_CONDA, NULL, name); + upstream_exists = pkg_index_provides(PKG_USE_CONDA, NULL, name, ctx->storage.tmpdir); } if (PKG_INDEX_PROVIDES_FAILED(upstream_exists)) { -- cgit From 11bc498b5bca18662a582a163d3e9aaed1a17b79 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 09:20:06 -0400 Subject: Add download_dir member to MicroMambaInfo struct. * TMPDIR and hardcoded path is too unpredictable. --- src/cli/stasis_indexer/helpers.c | 1 + src/lib/core/conda.c | 19 ++++++++++++++++--- src/lib/core/include/conda.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cli/stasis_indexer/helpers.c b/src/cli/stasis_indexer/helpers.c index 86a20e4..425d209 100644 --- a/src/cli/stasis_indexer/helpers.c +++ b/src/cli/stasis_indexer/helpers.c @@ -156,6 +156,7 @@ int micromamba_configure(const struct Delivery *ctx, struct MicromambaInfo *m) { } m->conda_prefix = globals.conda_install_prefix; m->micromamba_prefix = micromamba_prefix; + m->download_dir = ctx->storage.tmpdir; const size_t pathvar_len = strlen(getenv("PATH")) + strlen(m->micromamba_prefix) + strlen(m->conda_prefix) + 3 + 4 + 1; // ^^^^^^^^^^^^^^^^^^ diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index d15b6a6..4557c5c 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -19,11 +19,22 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { sys.machine[sizeof(sys.machine) - 1] = '\0'; } + if (!info->download_dir || isempty(info->download_dir)) { + SYSERROR("%s", "micromamba inf->download_dir is NULL, or empty"); + return -1; + } + + if (mkdirs(info->download_dir, 0755) < 0) { + SYSERROR("Unable to create info->download_dir: %s", info->download_dir); + return -1; + } + char url[PATH_MAX] = {0}; snprintf(url, sizeof(url), "https://micro.mamba.pm/api/micromamba/%s-%s/latest", sys.sysname, sys.machine); - char installer_path[PATH_MAX]; - snprintf(installer_path, sizeof(installer_path), "%s/latest", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"); + const char installer_name[] = "mm_latest"; + char installer_path[PATH_MAX] = {0}; + snprintf(installer_path, sizeof(installer_path), "%s/%s", info->download_dir, installer_name); if (access(installer_path, F_OK)) { char *errmsg = NULL; @@ -41,7 +52,9 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { if (access(mmbin, F_OK)) { char untarcmd[PATH_MAX * 2]; mkdirs(info->micromamba_prefix, 0755); - snprintf(untarcmd, sizeof(untarcmd), "tar -xvf %s -C %s --strip-components=1 bin/micromamba 1>/dev/null", installer_path, info->micromamba_prefix); + snprintf(untarcmd, sizeof(untarcmd), + "tar -xvf %s -C %s --strip-components=1 bin/micromamba 1>/dev/null", + installer_path, info->micromamba_prefix); int untarcmd_status = system(untarcmd); if (untarcmd_status) { return -1; diff --git a/src/lib/core/include/conda.h b/src/lib/core/include/conda.h index ccab060..cc9426d 100644 --- a/src/lib/core/include/conda.h +++ b/src/lib/core/include/conda.h @@ -29,6 +29,7 @@ struct MicromambaInfo { char *micromamba_prefix; //!< Path to write micromamba binary char *conda_prefix; //!< Path to install conda base tree + char *download_dir; //!< Path to store micromamba installer }; /** -- cgit From a54a712ab47a4a5b99cc6c8fc8fbfcb6c5c995f3 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 10:42:38 -0400 Subject: delivery_export_configuration: Add debug statements --- src/lib/delivery/delivery_export.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/lib/delivery/delivery_export.c b/src/lib/delivery/delivery_export.c index c12a365..e67fdfb 100644 --- a/src/lib/delivery/delivery_export.c +++ b/src/lib/delivery/delivery_export.c @@ -2,26 +2,44 @@ static void delivery_export_configuration(const struct Delivery *ctx) { msg(STASIS_MSG_L2, "Exporting delivery configuration\n"); + + SYSDEBUG("Entering configuration directory: %s", ctx->storage.delivery_dir); if (!pushd(ctx->storage.cfgdump_dir)) { char filename[PATH_MAX] = {0}; + SYSDEBUG("%s", "Populating filename"); snprintf(filename, sizeof(filename), "%s.ini", ctx->info.release_name); + SYSDEBUG("filename: %s", filename); + + SYSDEBUG("%s: opening", filename); FILE *spec = fopen(filename, "w+"); if (!spec) { msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "failed %s\n", filename); exit(1); } + SYSDEBUG("%s: writing", filename); ini_write(ctx->_stasis_ini_fp.delivery, &spec, INI_WRITE_RAW); + SYSDEBUG("%s: writing done", filename); fclose(spec); + SYSDEBUG("%s: closing", filename); + SYSDEBUG("%s", "Zeroing filename"); memset(filename, 0, sizeof(filename)); + SYSDEBUG("%s", "Populating rendered filename"); snprintf(filename, sizeof(filename), "%s-rendered.ini", ctx->info.release_name); + SYSDEBUG("filename: %s", filename); + + SYSDEBUG("%s: opening", filename); spec = fopen(filename, "w+"); if (!spec) { msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "failed %s\n", filename); exit(1); } + SYSDEBUG("%s: writing", filename); ini_write(ctx->_stasis_ini_fp.delivery, &spec, INI_WRITE_PRESERVE); + SYSDEBUG("%s: writing done", filename); + SYSDEBUG("%s: closing", filename); fclose(spec); + SYSDEBUG("Returning from %s", ctx->storage.cfgdump_dir); popd(); } else { SYSERROR("Failed to enter directory: %s", ctx->storage.delivery_dir); -- cgit From d9ed9eb3e5ac9f822c09fd17080d1848d95df7de Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 11:13:57 -0400 Subject: ini_write: Add debug statements --- src/lib/core/ini.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 12541f5..77f4094 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -431,6 +431,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { char *value = data->value; unsigned *hint = &data->type_hint; memset(outvalue, 0, sizeof(outvalue)); + SYSDEBUG("%s", "outvalue zeroed"); if (key && value) { int err = 0; @@ -458,15 +459,19 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { size_t len = 0; if (*hint == INIVAL_TYPE_STR_ARRAY) { + SYSDEBUG("%s", "array hint."); int leading_space = isspace(*render); if (leading_space) { len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s" LINE_SEP, render); + SYSDEBUG("has leading space. buffer remaining=%zu", len); snprintf(outvalue + strlen(outvalue), len, "%s" LINE_SEP, render); } else { len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, " %s" LINE_SEP, render); + SYSDEBUG("no leading space. buffer remaining=%zu", len); snprintf(outvalue + strlen(outvalue), len, " %s" LINE_SEP, render); } } else { + SYSDEBUG("string hint. buffer remaining=%zu", len); len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s", render); snprintf(outvalue + strlen(outvalue), len, "%s", render); } @@ -476,7 +481,11 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { } guard_array_free(parts); strip(outvalue); - strncat(outvalue, LINE_SEP, sizeof(outvalue) - strlen(outvalue) - 1); + + SYSDEBUG("%s", "appending line separator to buffer"); + snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s", LINE_SEP); + SYSDEBUG("buffer final length: %zu", strlen(outvalue)); + fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, *hint == INIVAL_TYPE_STR_ARRAY ? LINE_SEP : "", outvalue); guard_free(value); } else { -- cgit From 062b0dc23ac67a4e8311d8db998f97a60ad1c506 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 11:41:15 -0400 Subject: ini_write: Add debug statements --- src/lib/core/ini.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 77f4094..a9d8fab 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -422,6 +422,8 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { for (size_t x = 0; x < ini->section_count; x++) { struct INISection *section = ini->section[x]; char *section_name = section->key; + + SYSDEBUG("section name: %s", section_name); fprintf(*stream, "[%s]" LINE_SEP, section_name); for (size_t y = 0; y < ini->section[x]->data_count; y++) { @@ -430,6 +432,9 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { char *key = data->key; char *value = data->value; unsigned *hint = &data->type_hint; + + SYSDEBUG("%s: %s = %s", section_name, key, value); + memset(outvalue, 0, sizeof(outvalue)); SYSDEBUG("%s", "outvalue zeroed"); @@ -447,8 +452,10 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { for (size_t p = 0; parts && parts[p] != NULL; p++) { char *render = NULL; if (mode == INI_WRITE_PRESERVE) { + SYSDEBUG("Rendering %zu", p); render = tpl_render(parts[p]); } else { + SYSDEBUG("Not rendering %zu", p); render = parts[p]; } @@ -476,6 +483,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { snprintf(outvalue + strlen(outvalue), len, "%s", render); } if (mode == INI_WRITE_PRESERVE) { + SYSDEBUG("%s", "freeing rendered value"); guard_free(render); } } @@ -487,6 +495,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { SYSDEBUG("buffer final length: %zu", strlen(outvalue)); fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, *hint == INIVAL_TYPE_STR_ARRAY ? LINE_SEP : "", outvalue); + SYSDEBUG("%s", "freeing value"); guard_free(value); } else { fprintf(*stream, "%s = %s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->value); @@ -494,6 +503,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { } fprintf(*stream, LINE_SEP); } + SYSDEBUG("%s", "returning"); return 0; } -- cgit From 9a39dd3fb2cace355aab7dd5881e5f11adf3b2f8 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 12:25:19 -0400 Subject: ini_write: Make inikey buffer sizes less impossible to understand --- src/lib/core/ini.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index a9d8fab..7249ee2 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -478,8 +478,8 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { snprintf(outvalue + strlen(outvalue), len, " %s" LINE_SEP, render); } } else { - SYSDEBUG("string hint. buffer remaining=%zu", len); len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s", render); + SYSDEBUG("string hint. buffer remaining=%zu", len); snprintf(outvalue + strlen(outvalue), len, "%s", render); } if (mode == INI_WRITE_PRESERVE) { @@ -564,15 +564,15 @@ struct INIFILE *ini_open(const char *filename) { unsigned hint = 0; int multiline_data = 0; int no_data = 0; - char inikey[2][255]; + char inikey[2][255] = {0}; char *key = inikey[0]; char *key_last = inikey[1]; char value[STASIS_BUFSIZ] = {0}; - memset(inikey, 0, sizeof(inikey)); - // Read file for (size_t i = 0; fgets(line, sizeof(line), fp) != NULL; i++) { + const size_t key_last_size = sizeof(inikey[1]); + const size_t key_size = sizeof(inikey[0]); if (no_data && multiline_data) { if (!isempty(line)) { no_data = 0; @@ -581,7 +581,7 @@ struct INIFILE *ini_open(const char *filename) { } memset(value, 0, sizeof(value)); } else { - memset(key, 0, sizeof(inikey[0])); + memset(key, 0, key_size); } // Find pointer to first comment character char *comment = strpbrk(line, ";#"); @@ -605,7 +605,7 @@ struct INIFILE *ini_open(const char *filename) { // Test for section header: [string] if (startswith(line, "[")) { // The previous key is irrelevant now - memset(key_last, 0, sizeof(inikey[1])); + memset(key_last, 0, key_last_size); char *section_name = substring_between(line, "[]"); if (!section_name) { @@ -647,15 +647,15 @@ struct INIFILE *ini_open(const char *filename) { if (operator) { size_t key_len = operator - line; - memset(key, 0, sizeof(inikey[0])); + memset(key, 0, key_size); strncpy(key, line, key_len); - key[key_len] = '\0'; + key[key_size - 1] = '\0'; lstrip(key); strip(key); - memset(key_last, 0, sizeof(inikey[1])); - strncpy(key_last, key, sizeof(inikey[1]) - 1); - key_last[sizeof(inikey[1]) - 1] = '\0'; + memset(key_last, 0, key_last_size); + strncpy(key_last, key, key_last_size - 1); + key_last[key_last_size - 1] = '\0'; reading_value = 1; if (strlen(operator) > 1) { @@ -676,8 +676,8 @@ struct INIFILE *ini_open(const char *filename) { } strip(value); } else { - strncpy(key, key_last, sizeof(inikey[0]) - 1); - key[sizeof(inikey[0]) - 1] = '\0'; + strncpy(key, key_last, key_size - 1); + key[key_size - 1] = '\0'; strncpy(value, line, sizeof(value) - 1); value[sizeof(value) - 1] = '\0'; } -- cgit From aca0b00cfe3f7c5b0359f7269fc8fdfe013b1226 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 12:34:14 -0400 Subject: ini_write: Add debug statements --- src/lib/core/ini.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 7249ee2..1434681 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -648,14 +648,19 @@ struct INIFILE *ini_open(const char *filename) { if (operator) { size_t key_len = operator - line; memset(key, 0, key_size); + + SYSDEBUG("%s", "operator reached"); + SYSDEBUG("in: '%s'", line); strncpy(key, line, key_len); key[key_size - 1] = '\0'; lstrip(key); strip(key); + SYSDEBUG("key is: %s", key); memset(key_last, 0, key_last_size); strncpy(key_last, key, key_last_size - 1); key_last[key_last_size - 1] = '\0'; + SYSDEBUG("last key is: %s", key_last); reading_value = 1; if (strlen(operator) > 1) { @@ -664,13 +669,17 @@ struct INIFILE *ini_open(const char *filename) { strncpy(value, "", sizeof(value) - 1); } value[sizeof(value) - 1] = '\0'; + SYSDEBUG("value: %s", value); + if (isempty(value)) { //printf("%s is probably long raw data\n", key); + SYSDEBUG("%s", "multiline data encountered"); hint = INIVAL_TYPE_STR_ARRAY; multiline_data = 1; no_data = 1; } else { //printf("%s is probably short data\n", key); + SYSDEBUG("%s", "string data encountered"); hint = INIVAL_TYPE_STR; multiline_data = 0; } @@ -678,8 +687,10 @@ struct INIFILE *ini_open(const char *filename) { } else { strncpy(key, key_last, key_size - 1); key[key_size - 1] = '\0'; + SYSDEBUG("updated key (%s) with key_last (%s)", key, key_last); strncpy(value, line, sizeof(value) - 1); value[sizeof(value) - 1] = '\0'; + SYSDEBUG("wrote value: %s", value); } memset(line, 0, sizeof(line)); @@ -699,5 +710,6 @@ struct INIFILE *ini_open(const char *filename) { } fclose(fp); + SYSDEBUG("%s", "returning"); return ini; } \ No newline at end of file -- cgit From daa5a35004bd4a39a730a01b4ed6faf554fabad8 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 13:14:11 -0400 Subject: ini_data_append: Add debug statements --- src/lib/core/ini.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 1434681..6809051 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -347,6 +347,10 @@ int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *v section->data_count++; } else { struct INIData *data = ini_data_get(*ini, section_name, key); + if (!data) { + SYSERROR("%s:%s: key does not exist", section_name, key); + return -1; + } size_t value_len_old = strlen(data->value); size_t value_len = strlen(value); size_t value_len_new = value_len_old + value_len; @@ -355,10 +359,12 @@ int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *v if (!value_tmp) { SYSERROR("Unable to increase data->value size to %zu bytes", value_len_new + 2); return -1; - } else { - data->value = value_tmp; } + data->value = value_tmp; + + SYSDEBUG("%s", "writing value"); strncat(data->value, value, value_len_new - strlen(data->value)); + SYSDEBUG("%s", "value written"); } return 0; } @@ -701,9 +707,11 @@ struct INIFILE *ini_open(const char *filename) { unquote(value); if (!multiline_data) { reading_value = 0; + SYSDEBUG("appending multiline (%s): %s", key, value); ini_data_append(&ini, current_section, key, value, hint); continue; } + SYSDEBUG("appending (%s): %s", key, value); ini_data_append(&ini, current_section, key, value, hint); reading_value = 1; } -- cgit From 6a9f076f69d233f75ec78e74b77fefa5e9ed92db Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Mon, 27 Apr 2026 18:12:21 -0400 Subject: disable setting TMPDIR --- src/lib/delivery/delivery_init.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c index 17f3899..ec05a0f 100644 --- a/src/lib/delivery/delivery_init.c +++ b/src/lib/delivery/delivery_init.c @@ -14,7 +14,7 @@ int delivery_init_tmpdir(struct Delivery *ctx) { int unusable = 1; errno = 0; - int need_setenv = 0; + //int need_setenv = 0; const char *x = getenv("TMPDIR"); if (x) { guard_free(ctx->storage.tmpdir); @@ -30,7 +30,7 @@ int delivery_init_tmpdir(struct Delivery *ctx) { SYSERROR("%s", "unable to allocate tmpdir"); goto l_delivery_init_tmpdir_fatal; } - need_setenv = 1; + //need_setenv = 1; } if (!ctx->storage.tmpdir) { @@ -95,9 +95,10 @@ int delivery_init_tmpdir(struct Delivery *ctx) { } } unusable = 0; - if (need_setenv) { - setenv("TMPDIR", ctx->storage.tmpdir, 1); - } + // TODO: Figure out why this breaks EVERYTHING + //if (need_setenv) { + // setenv("TMPDIR", ctx->storage.tmpdir, 1); + //} l_delivery_init_tmpdir_fatal: guard_free(tmpdir); -- cgit From 05e48deff2c974911e876b753dfc12614ecbb25e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 28 Apr 2026 09:05:35 -0400 Subject: Possibly fix buffer overflow reported by stack protector --- src/lib/core/ini.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index 6809051..c166487 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -454,6 +454,9 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { xvalue = ini_getval_str(ini, section_name, key, (int) mode, &err); value = xvalue; } + + const size_t buf_size = sizeof(outvalue); + size_t buf_len = 0; char **parts = split(value, LINE_SEP, 0); for (size_t p = 0; parts && parts[p] != NULL; p++) { char *render = NULL; @@ -470,38 +473,30 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { return -1; } - size_t len = 0; + buf_len = strlen(outvalue); if (*hint == INIVAL_TYPE_STR_ARRAY) { - SYSDEBUG("%s", "array hint."); - int leading_space = isspace(*render); + const int leading_space = isspace(*render); if (leading_space) { - len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s" LINE_SEP, render); - SYSDEBUG("has leading space. buffer remaining=%zu", len); - snprintf(outvalue + strlen(outvalue), len, "%s" LINE_SEP, render); + snprintf(outvalue + buf_len, buf_size - buf_len, "%s" LINE_SEP, render); } else { - len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, " %s" LINE_SEP, render); - SYSDEBUG("no leading space. buffer remaining=%zu", len); - snprintf(outvalue + strlen(outvalue), len, " %s" LINE_SEP, render); + snprintf(outvalue + buf_len, buf_size - buf_len, " %s" LINE_SEP, render); } } else { - len = sizeof(outvalue) - (size_t) snprintf(NULL, 0, "%s", render); - SYSDEBUG("string hint. buffer remaining=%zu", len); - snprintf(outvalue + strlen(outvalue), len, "%s", render); + snprintf(outvalue + buf_len, buf_size - buf_len, "%s", render); } if (mode == INI_WRITE_PRESERVE) { - SYSDEBUG("%s", "freeing rendered value"); guard_free(render); } } guard_array_free(parts); strip(outvalue); - SYSDEBUG("%s", "appending line separator to buffer"); - snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s", LINE_SEP); - SYSDEBUG("buffer final length: %zu", strlen(outvalue)); + // update length of outvalue + buf_len = strlen(outvalue); + + snprintf(outvalue + buf_len, buf_size - buf_len, "%s", LINE_SEP); fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, *hint == INIVAL_TYPE_STR_ARRAY ? LINE_SEP : "", outvalue); - SYSDEBUG("%s", "freeing value"); guard_free(value); } else { fprintf(*stream, "%s = %s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->value); -- cgit From d761cc976a8d645e61d23f6e43dcfec1a7fdb061 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Tue, 28 Apr 2026 09:20:29 -0400 Subject: Remove debug statements --- src/lib/core/ini.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'src') diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c index c166487..c37030c 100644 --- a/src/lib/core/ini.c +++ b/src/lib/core/ini.c @@ -362,9 +362,7 @@ int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *v } data->value = value_tmp; - SYSDEBUG("%s", "writing value"); strncat(data->value, value, value_len_new - strlen(data->value)); - SYSDEBUG("%s", "value written"); } return 0; } @@ -429,7 +427,6 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { struct INISection *section = ini->section[x]; char *section_name = section->key; - SYSDEBUG("section name: %s", section_name); fprintf(*stream, "[%s]" LINE_SEP, section_name); for (size_t y = 0; y < ini->section[x]->data_count; y++) { @@ -439,10 +436,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { char *value = data->value; unsigned *hint = &data->type_hint; - SYSDEBUG("%s: %s = %s", section_name, key, value); - memset(outvalue, 0, sizeof(outvalue)); - SYSDEBUG("%s", "outvalue zeroed"); if (key && value) { int err = 0; @@ -461,10 +455,8 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { for (size_t p = 0; parts && parts[p] != NULL; p++) { char *render = NULL; if (mode == INI_WRITE_PRESERVE) { - SYSDEBUG("Rendering %zu", p); render = tpl_render(parts[p]); } else { - SYSDEBUG("Not rendering %zu", p); render = parts[p]; } @@ -504,7 +496,6 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { } fprintf(*stream, LINE_SEP); } - SYSDEBUG("%s", "returning"); return 0; } @@ -519,12 +510,9 @@ char *unquote(char *s) { void ini_free(struct INIFILE **ini) { for (size_t section = 0; section < (*ini)->section_count; section++) { - SYSDEBUG("freeing section: %s", (*ini)->section[section]->key); for (size_t data = 0; data < (*ini)->section[section]->data_count; data++) { if ((*ini)->section[section]->data[data]) { - SYSDEBUG("freeing data key: %s", (*ini)->section[section]->data[data]->key); guard_free((*ini)->section[section]->data[data]->key); - SYSDEBUG("freeing data value: %s", (*ini)->section[section]->data[data]->value); guard_free((*ini)->section[section]->data[data]->value); guard_free((*ini)->section[section]->data[data]); } @@ -650,18 +638,14 @@ struct INIFILE *ini_open(const char *filename) { size_t key_len = operator - line; memset(key, 0, key_size); - SYSDEBUG("%s", "operator reached"); - SYSDEBUG("in: '%s'", line); strncpy(key, line, key_len); key[key_size - 1] = '\0'; lstrip(key); strip(key); - SYSDEBUG("key is: %s", key); memset(key_last, 0, key_last_size); strncpy(key_last, key, key_last_size - 1); key_last[key_last_size - 1] = '\0'; - SYSDEBUG("last key is: %s", key_last); reading_value = 1; if (strlen(operator) > 1) { @@ -670,17 +654,14 @@ struct INIFILE *ini_open(const char *filename) { strncpy(value, "", sizeof(value) - 1); } value[sizeof(value) - 1] = '\0'; - SYSDEBUG("value: %s", value); if (isempty(value)) { //printf("%s is probably long raw data\n", key); - SYSDEBUG("%s", "multiline data encountered"); hint = INIVAL_TYPE_STR_ARRAY; multiline_data = 1; no_data = 1; } else { //printf("%s is probably short data\n", key); - SYSDEBUG("%s", "string data encountered"); hint = INIVAL_TYPE_STR; multiline_data = 0; } @@ -688,10 +669,8 @@ struct INIFILE *ini_open(const char *filename) { } else { strncpy(key, key_last, key_size - 1); key[key_size - 1] = '\0'; - SYSDEBUG("updated key (%s) with key_last (%s)", key, key_last); strncpy(value, line, sizeof(value) - 1); value[sizeof(value) - 1] = '\0'; - SYSDEBUG("wrote value: %s", value); } memset(line, 0, sizeof(line)); @@ -702,17 +681,14 @@ struct INIFILE *ini_open(const char *filename) { unquote(value); if (!multiline_data) { reading_value = 0; - SYSDEBUG("appending multiline (%s): %s", key, value); ini_data_append(&ini, current_section, key, value, hint); continue; } - SYSDEBUG("appending (%s): %s", key, value); ini_data_append(&ini, current_section, key, value, hint); reading_value = 1; } } fclose(fp); - SYSDEBUG("%s", "returning"); return ini; } \ No newline at end of file -- cgit