From 87779a8c85eec0b71703ed3090a3949761396a15 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 15 Apr 2026 10:10:15 -0400 Subject: Replace sprintf with snprintf * A few strcpy and strcat changes as well --- src/lib/core/artifactory.c | 8 ++++--- src/lib/core/conda.c | 44 ++++++++++++++++++++++---------------- src/lib/core/docker.c | 4 ++-- src/lib/core/github.c | 8 +++---- src/lib/core/multiprocessing.c | 4 +++- src/lib/core/recipe.c | 6 +++--- src/lib/core/template_func_proto.c | 6 +++--- src/lib/core/utils.c | 36 +++++++++++++++++++------------ src/lib/core/wheelinfo.c | 2 +- 9 files changed, 68 insertions(+), 50 deletions(-) (limited to 'src/lib/core') diff --git a/src/lib/core/artifactory.c b/src/lib/core/artifactory.c index d5457e7..6a01620 100644 --- a/src/lib/core/artifactory.c +++ b/src/lib/core/artifactory.c @@ -60,7 +60,9 @@ int artifactory_download_cli(char *dest, return -1; } - sprintf(path + strlen(path), "/%s", remote_filename); + const char *remote_filename_fmt = "/%s"; + int remote_filename_fmt_len = snprintf(NULL, 0, remote_filename_fmt, remote_filename); + snprintf(path + strlen(path), sizeof(path) - remote_filename_fmt_len, remote_filename_fmt, remote_filename); char *errmsg = NULL; long fetch_status = download(url, path, &errmsg); if (HTTP_ERROR(fetch_status)) { @@ -78,7 +80,7 @@ void jfrt_register_opt_str(char *jfrt_val, const char *opt_name, struct StrList // no data return; } - snprintf(data, sizeof(data) - 1, "--%s=\"%s\"", opt_name, jfrt_val); + snprintf(data, sizeof(data), "--%s=\"%s\"", opt_name, jfrt_val); strlist_append(&*opt_map, data); } @@ -89,7 +91,7 @@ void jfrt_register_opt_bool(bool jfrt_val, const char *opt_name, struct StrList // option will not be used return; } - snprintf(data, sizeof(data) - 1, "--%s", opt_name); + snprintf(data, sizeof(data), "--%s", opt_name); strlist_append(&*opt_map, data); } diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 16483ee..dd336bc 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -18,10 +18,12 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { } char url[PATH_MAX]; - sprintf(url, "https://micro.mamba.pm/api/micromamba/%s-%s/latest", sys.sysname, sys.machine); + const char *url_fmt = "https://micro.mamba.pm/api/micromamba/%s-%s/latest"; + const int url_fmt_len = snprintf(NULL, 0, url_fmt, sys.sysname, sys.machine); + snprintf(url, sizeof(url) - url_fmt_len, url_fmt, sys.sysname, sys.machine); char installer_path[PATH_MAX]; - sprintf(installer_path, "%s/latest", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"); + snprintf(installer_path, sizeof(installer_path), "%s/latest", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"); if (access(installer_path, F_OK)) { char *errmsg = NULL; @@ -34,12 +36,12 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { } char mmbin[PATH_MAX]; - sprintf(mmbin, "%s/micromamba", info->micromamba_prefix); + snprintf(mmbin, sizeof(mmbin), "%s/micromamba", info->micromamba_prefix); if (access(mmbin, F_OK)) { char untarcmd[PATH_MAX * 2]; mkdirs(info->micromamba_prefix, 0755); - sprintf(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; @@ -47,7 +49,7 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { } char cmd[STASIS_BUFSIZ] = {0}; - sprintf(cmd, "%s -r %s -p %s ", mmbin, info->conda_prefix, info->conda_prefix); + snprintf(cmd, sizeof(cmd), "%s -r %s -p %s ", mmbin, info->conda_prefix, info->conda_prefix); va_list args; va_start(args, command); vsprintf(cmd + strlen(cmd), command, args); @@ -56,7 +58,7 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) { mkdirs(info->conda_prefix, 0755); char rcpath[PATH_MAX]; - sprintf(rcpath, "%s/.condarc", info->conda_prefix); + snprintf(rcpath, sizeof(rcpath), "%s/.condarc", info->conda_prefix); touch(rcpath); if (errno == ENOENT) { errno = 0; @@ -321,13 +323,13 @@ int conda_activate(const char *root, const char *env_name) { struct Process proc = {0}; // Where to find conda's init scripts - sprintf(path_conda, "%s%s", root, init_script_conda); - sprintf(path_mamba, "%s%s", root, init_script_mamba); + snprintf(path_conda, sizeof(path_conda), "%s%s", root, init_script_conda); + snprintf(path_mamba, sizeof(path_mamba), "%s%s", root, init_script_mamba); // Set the path to our stdout log // Emulate mktemp()'s behavior. Give us a unique file name, but don't use // the file handle at all. We'll open it as a FILE stream soon enough. - sprintf(logfile, "%s/%s", globals.tmpdir, "shell_XXXXXX"); + snprintf(logfile, sizeof(logfile), "%s/%s", globals.tmpdir, "shell_XXXXXX"); int fd = mkstemp(logfile); if (fd < 0) { @@ -337,7 +339,7 @@ int conda_activate(const char *root, const char *env_name) { close(fd); // Configure our process for output to a log file - strcpy(proc.f_stdout, logfile); + strncpy(proc.f_stdout, logfile, PATH_MAX - 1); // Verify conda's init scripts are available if (access(path_conda, F_OK) < 0) { @@ -478,6 +480,7 @@ int conda_setup_headless() { char cmd[PATH_MAX]; size_t total = 0; + const char *cmd_fmt = "'%s'"; if (globals.conda_packages && strlist_count(globals.conda_packages)) { memset(cmd, 0, sizeof(cmd)); strcpy(cmd, "install "); @@ -488,9 +491,10 @@ int conda_setup_headless() { if (isempty(item)) { continue; } - sprintf(cmd + strlen(cmd), "'%s'", item); + const int cmd_fmt_len = snprintf(NULL, 0, cmd_fmt, item); + snprintf(cmd + strlen(cmd), sizeof(cmd) - cmd_fmt_len, cmd_fmt, item); if (i < total - 1) { - strcat(cmd, " "); + strncat(cmd, " ", sizeof(cmd) - strlen(cmd) - 1); } } @@ -510,9 +514,10 @@ int conda_setup_headless() { if (isempty(item)) { continue; } - sprintf(cmd + strlen(cmd), "'%s'", item); + const int cmd_fmt_len = snprintf(NULL, 0, cmd_fmt, item); + snprintf(cmd + strlen(cmd), sizeof(cmd) - cmd_fmt_len, cmd_fmt, item); if (i < total - 1) { - strcat(cmd, " "); + strncat(cmd, " ", sizeof(cmd) - strlen(cmd) - 1); } } @@ -552,7 +557,7 @@ int conda_env_create_from_uri(char *name, char *uri, char *python_version) { } char tempfile[PATH_MAX] = {0}; - sprintf(tempfile, "%s/remote_XXXXXX", globals.tmpdir); + snprintf(tempfile, sizeof(tempfile), "%s/remote_XXXXXX", globals.tmpdir); // Touch a temporary file int fd = mkstemp(tempfile); @@ -610,13 +615,13 @@ int conda_env_create(char *name, char *python_version, char *packages) { int conda_env_remove(char *name) { char env_command[PATH_MAX]; - sprintf(env_command, "env remove -n %s", name); + snprintf(env_command, sizeof(env_command), "env remove -n %s", name); return conda_exec(env_command); } int conda_env_export(char *name, char *output_dir, char *output_filename) { char env_command[PATH_MAX]; - sprintf(env_command, "env export -n %s -f %s/%s.yml", name, output_dir, output_filename); + snprintf(env_command, sizeof(env_command), "env export -n %s -f %s/%s.yml", name, output_dir, output_filename); return conda_exec(env_command); } @@ -637,12 +642,13 @@ char *conda_get_active_environment() { int conda_index(const char *path) { char command[PATH_MAX]; - sprintf(command, "index %s", path); + snprintf(command, sizeof(command), "index %s", path); return conda_exec(command); } int conda_env_exists(const char *root, const char *name) { char path[PATH_MAX] = {0}; - snprintf(path, sizeof(path) - 1 - 6, "%s/envs/%s", root, name); + const int len = snprintf(NULL, 0, "%s/%s", root, name); + snprintf(path, sizeof(path) - len, "%s/envs/%s", root, name); return access(path, F_OK) == 0; } diff --git a/src/lib/core/docker.c b/src/lib/core/docker.c index 39357ad..fd0a2e2 100644 --- a/src/lib/core/docker.c +++ b/src/lib/core/docker.c @@ -93,9 +93,9 @@ int docker_save(const char *image, const char *destdir, const char *compression_ } else { strncpy(ext, compression_program, sizeof(ext) - 1); } - sprintf(cmd, "save \"%s\" | %s > \"%s/%s.tar.%s\"", image, compression_program, destdir, image, ext); + snprintf(cmd, sizeof(cmd), "save \"%s\" | %s > \"%s/%s.tar.%s\"", image, compression_program, destdir, image, ext); } else { - sprintf(cmd, "save \"%s\" -o \"%s/%s.tar\"", image, destdir, image); + snprintf(cmd, sizeof(cmd), "save \"%s\" -o \"%s/%s.tar\"", image, destdir, image); } return docker_exec(cmd, 0); diff --git a/src/lib/core/github.c b/src/lib/core/github.c index f0c5199..c5281c6 100644 --- a/src/lib/core/github.c +++ b/src/lib/core/github.c @@ -58,9 +58,9 @@ int get_github_release_notes(const char *api_token, const char *repo, const char } // Render the header data - sprintf(endpoint_header_auth, endpoint_header_auth_fmt, api_token); - sprintf(endpoint_post_fields, endpoint_post_fields_fmt, tag, target_commitish); - sprintf(endpoint_url, endpoint_url_fmt, repo); + snprintf(endpoint_header_auth, sizeof(endpoint_header_auth), endpoint_header_auth_fmt, api_token); + snprintf(endpoint_post_fields, sizeof(endpoint_post_fields), endpoint_post_fields_fmt, tag, target_commitish); + snprintf(endpoint_url, sizeof(endpoint_url), endpoint_url_fmt, repo); // Begin curl configuration curl_easy_setopt(curl, CURLOPT_URL, endpoint_url); @@ -77,7 +77,7 @@ int get_github_release_notes(const char *api_token, const char *repo, const char // Set the user-agent (github requires one) char user_agent[20] = {0}; - sprintf(user_agent, "stasis/%s", VERSION); + snprintf(user_agent, sizeof(user_agent), "stasis/%s", VERSION); curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent); // Execute curl request diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c index 7ae23c9..f694ad6 100644 --- a/src/lib/core/multiprocessing.c +++ b/src/lib/core/multiprocessing.c @@ -74,7 +74,9 @@ int child(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) { // Set log file name if (globals.enable_task_logging) { - sprintf(task->log_file + strlen(task->log_file), "task-%zu-%d.log", mp_global_task_count, task->parent_pid); + const char *log_file_fmt = "task-%zu-%d.log"; + const int log_file_len = snprintf(NULL, 0, log_file_fmt, mp_global_task_count, task->parent_pid); + snprintf(task->log_file + strlen(task->log_file), sizeof(task->log_file) - log_file_len, log_file_fmt, mp_global_task_count, task->parent_pid); } fp_log = freopen(task->log_file, "w+", stdout); if (!fp_log) { diff --git a/src/lib/core/recipe.c b/src/lib/core/recipe.c index 99d3fe1..cc96139 100644 --- a/src/lib/core/recipe.c +++ b/src/lib/core/recipe.c @@ -9,14 +9,14 @@ int recipe_clone(char *recipe_dir, char *url, char *gitref, char **result) { memset(destdir, 0, sizeof(destdir)); reponame = path_basename(url); - sprintf(destdir, "%s/%s", recipe_dir, reponame); + snprintf(destdir, sizeof(destdir), "%s/%s", recipe_dir, reponame); if (!*result) { *result = calloc(PATH_MAX, sizeof(*result)); if (!*result) { return -1; } } - strncpy(*result, destdir, PATH_MAX); + strncpy(*result, destdir, PATH_MAX - 1); if (!access(destdir, F_OK)) { if (!strcmp(destdir, "/")) { @@ -52,7 +52,7 @@ int recipe_get_type(char *repopath) { for (size_t i = 0; marker[i] != NULL; i++) { char path[PATH_MAX] = {0}; - sprintf(path, "%s/%s", repopath, marker[i]); + snprintf(path, sizeof(path), "%s/%s", repopath, marker[i]); int result = access(path, F_OK); if (!result) { return type[i]; diff --git a/src/lib/core/template_func_proto.c b/src/lib/core/template_func_proto.c index 52a11b5..d344933 100644 --- a/src/lib/core/template_func_proto.c +++ b/src/lib/core/template_func_proto.c @@ -44,7 +44,7 @@ int get_github_release_notes_auto_tplfunc_entrypoint(void *frame, void *data_out // Using HEAD, GitHub returns the previous tag char *note = NULL; char h1_title[NAME_MAX] = {0}; - sprintf(h1_title, "# %s", test->name); + snprintf(h1_title, sizeof(h1_title), "# %s", test->name); strlist_append(¬es_list, h1_title); result += get_github_release_notes(api_token ? api_token : "anonymous", repository, @@ -88,7 +88,7 @@ int get_junitxml_file_entrypoint(void *frame, void *data_out) { SYSERROR("failed to allocate output string: %s", strerror(errno)); return -1; } - sprintf(*output, "%s/results-%s-%s.xml", ctx->storage.results_dir, name, ctx->info.release_name); + snprintf(*output, PATH_MAX, "%s/results-%s-%s.xml", ctx->storage.results_dir, name, ctx->info.release_name); return result; } @@ -113,7 +113,7 @@ int get_basetemp_dir_entrypoint(void *frame, void *data_out) { SYSERROR("failed to allocate output string: %s", strerror(errno)); return -1; } - sprintf(*output, "%s/truth-%s-%s", ctx->storage.tmpdir, name, ctx->info.release_name); + snprintf(*output, PATH_MAX, "%s/truth-%s-%s", ctx->storage.tmpdir, name, ctx->info.release_name); return result; } diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c index e106193..2722585 100644 --- a/src/lib/core/utils.c +++ b/src/lib/core/utils.c @@ -316,11 +316,13 @@ int git_clone(struct Process *proc, char *url, char *destdir, char *gitref) { } static char command[PATH_MAX] = {0}; - sprintf(command, "%s clone -c advice.detachedHead=false --recursive %s", program, url); + snprintf(command, sizeof(command), "%s clone -c advice.detachedHead=false --recursive %s", program, url); if (destdir && access(destdir, F_OK) < 0) { // Destination directory does not exist - sprintf(command + strlen(command), " %s", destdir); + const char *command_fmt = " %s"; + const int command_fmt_len = snprintf(NULL, 0, command_fmt, destdir); + snprintf(command + strlen(command), sizeof(command) - command_fmt_len, command_fmt, destdir); // Clone the repo result = shell(proc, command); if (result) { @@ -338,7 +340,7 @@ int git_clone(struct Process *proc, char *url, char *destdir, char *gitref) { if (!pushd(chdir_to)) { memset(command, 0, sizeof(command)); - sprintf(command, "%s fetch --all", program); + snprintf(command, sizeof(command), "%s fetch --all", program); result = shell(proc, command); if (result) { goto die_pop; @@ -346,7 +348,7 @@ int git_clone(struct Process *proc, char *url, char *destdir, char *gitref) { if (gitref != NULL) { memset(command, 0, sizeof(command)); - sprintf(command, "%s checkout %s", program, gitref); + snprintf(command, sizeof(command), "%s checkout %s", program, gitref); result = shell(proc, command); if (result) { @@ -403,7 +405,7 @@ char *git_rev_parse(const char *path, char *args) { } // TODO: Use `-C [path]` if the version of git installed supports it - sprintf(cmd, "git rev-parse %s", args); + snprintf(cmd, sizeof(cmd), "git rev-parse %s", args); FILE *pp = popen(cmd, "r"); if (!pp) { return NULL; @@ -453,11 +455,11 @@ void msg(unsigned type, char *fmt, ...) { } if (type & STASIS_MSG_L1) { - sprintf(header, "==>%s" STASIS_COLOR_RESET STASIS_COLOR_WHITE, status); + snprintf(header, sizeof(header), "==>%s" STASIS_COLOR_RESET STASIS_COLOR_WHITE, status); } else if (type & STASIS_MSG_L2) { - sprintf(header, " ->%s" STASIS_COLOR_RESET, status); + snprintf(header, sizeof(header), " ->%s" STASIS_COLOR_RESET, status); } else if (type & STASIS_MSG_L3) { - sprintf(header, STASIS_COLOR_BLUE " ->%s" STASIS_COLOR_RESET, status); + snprintf(header, sizeof(header), STASIS_COLOR_BLUE " ->%s" STASIS_COLOR_RESET, status); } fprintf(stream, "%s", header); @@ -487,7 +489,7 @@ char *xmkstemp(FILE **fp, const char *mode) { strcpy(tmpdir, "/tmp"); } memset(t_name, 0, sizeof(t_name)); - sprintf(t_name, "%s/%s", tmpdir, "STASIS.XXXXXX"); + snprintf(t_name, sizeof(t_name), "%s/%s", tmpdir, "STASIS.XXXXXX"); fd = mkstemp(t_name); *fp = fdopen(fd, mode); @@ -912,13 +914,15 @@ void debug_hexdump(char *data, int len) { char *pos = start; while (pos != end) { if (count == 0) { - sprintf(addr + strlen(addr), "%p", pos); + const char *pos_fmt = "%p"; + const int pos_fmt_len = snprintf(NULL, 0, pos_fmt, pos); + snprintf(addr + strlen(addr), sizeof(addr) - pos_fmt_len, pos_fmt, pos); } if (count == 8) { strcat(bytes, " "); } if (count > 15) { - sprintf(output, "%s | %s | %s", addr, bytes, ascii); + snprintf(output, sizeof(output), "%s | %s | %s", addr, bytes, ascii); puts(output); memset(output, 0, sizeof(output)); memset(addr, 0, sizeof(addr)); @@ -928,8 +932,13 @@ void debug_hexdump(char *data, int len) { continue; } - sprintf(bytes + strlen(bytes), "%02X ", (unsigned char) *pos); - sprintf(ascii + strlen(ascii), "%c", isprint(*pos) ? *pos : '.'); + const char *bytes_fmt = "%02X "; + const int bytes_fmt_len = snprintf(NULL, 0, bytes_fmt, (unsigned char) *pos); + snprintf(bytes + strlen(bytes), sizeof(bytes) - bytes_fmt_len, bytes_fmt, (unsigned char) *pos); + + const char *ascii_fmt = "%c"; + // no need to calculate length for a single character + snprintf(ascii + strlen(ascii), sizeof(ascii) - 1, ascii_fmt, isprint(*pos) ? *pos : '.'); pos++; count++; @@ -1171,4 +1180,3 @@ int get_random_bytes(char *result, size_t maxlen) { result[bytes ? bytes - 1 : 0] = '\0'; return 0; } - diff --git a/src/lib/core/wheelinfo.c b/src/lib/core/wheelinfo.c index 1a93a82..86b71cf 100644 --- a/src/lib/core/wheelinfo.c +++ b/src/lib/core/wheelinfo.c @@ -8,7 +8,7 @@ struct WheelInfo *wheelinfo_get(const char *basepath, const char *name, char *to strcpy(package_name, name); tolower_s(package_name); - sprintf(package_path, "%s/%s", basepath, package_name); + snprintf(package_path, sizeof(package_path), "%s/%s", basepath, package_name); DIR *dp = opendir(package_path); if (!dp) { -- cgit