aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2026-04-21 12:15:11 -0400
committerGitHub <noreply@github.com>2026-04-21 12:15:11 -0400
commite05702d1818088439fd017786a036103062db358 (patch)
tree379773aaaae0193d1a53583646b48e23edd817a5
parent2258cd05bcded0125136c17d51568831ac421bf7 (diff)
parent577912ff0e1996b9846db00247648abd828a8f43 (diff)
downloadstasis-e05702d1818088439fd017786a036103062db358.tar.gz
Merge pull request #134 from jhunkeler/sprintf-to-snprintf
String safety
-rw-r--r--.github/workflows/cmake-multi-platform.yml10
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/cli/stasis/args.c20
-rw-r--r--src/cli/stasis/stasis_main.c20
-rw-r--r--src/cli/stasis_indexer/args.c2
-rw-r--r--src/cli/stasis_indexer/helpers.c48
-rw-r--r--src/cli/stasis_indexer/junitxml_report.c4
-rw-r--r--src/cli/stasis_indexer/readmes.c10
-rw-r--r--src/cli/stasis_indexer/stasis_indexer_main.c35
-rw-r--r--src/cli/stasis_indexer/website.c12
-rw-r--r--src/lib/core/artifactory.c50
-rw-r--r--src/lib/core/conda.c103
-rw-r--r--src/lib/core/copy.c2
-rw-r--r--src/lib/core/docker.c30
-rw-r--r--src/lib/core/environment.c6
-rw-r--r--src/lib/core/github.c8
-rw-r--r--src/lib/core/include/utils.h5
-rw-r--r--src/lib/core/ini.c30
-rw-r--r--src/lib/core/multiprocessing.c25
-rw-r--r--src/lib/core/recipe.c6
-rw-r--r--src/lib/core/relocation.c10
-rw-r--r--src/lib/core/str.c14
-rw-r--r--src/lib/core/strlist.c4
-rw-r--r--src/lib/core/system.c2
-rw-r--r--src/lib/core/template.c4
-rw-r--r--src/lib/core/template_func_proto.c12
-rw-r--r--src/lib/core/utils.c110
-rw-r--r--src/lib/core/wheelinfo.c6
-rw-r--r--src/lib/delivery/delivery.c39
-rw-r--r--src/lib/delivery/delivery_artifactory.c14
-rw-r--r--src/lib/delivery/delivery_build.c34
-rw-r--r--src/lib/delivery/delivery_conda.c27
-rw-r--r--src/lib/delivery/delivery_docker.c28
-rw-r--r--src/lib/delivery/delivery_export.c4
-rw-r--r--src/lib/delivery/delivery_init.c34
-rw-r--r--src/lib/delivery/delivery_install.c22
-rw-r--r--src/lib/delivery/delivery_populate.c10
-rw-r--r--src/lib/delivery/delivery_postprocess.c24
-rw-r--r--src/lib/delivery/delivery_test.c12
-rw-r--r--src/lib/delivery/include/delivery.h6
-rw-r--r--tests/test_artifactory.c12
-rw-r--r--tests/test_conda.c4
-rw-r--r--tests/test_environment.c2
-rw-r--r--tests/test_junitxml.c4
-rw-r--r--tests/test_multiprocessing.c4
-rw-r--r--tests/test_recipe.c2
-rw-r--r--tests/test_relocation.c5
-rw-r--r--tests/test_str.c12
-rw-r--r--tests/test_system.c2
-rw-r--r--tests/test_template.c49
-rw-r--r--tests/test_utils.c24
-rw-r--r--tests/test_wheel.c2
52 files changed, 546 insertions, 422 deletions
diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml
index e3f0ce7..e2315f7 100644
--- a/.github/workflows/cmake-multi-platform.yml
+++ b/.github/workflows/cmake-multi-platform.yml
@@ -64,6 +64,7 @@ jobs:
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
+ -DASAN=ON
-DTESTS=ON
-DTESTS_VERBOSE=ON
-DTESTS_RT=ON
@@ -77,6 +78,13 @@ jobs:
- name: Test
working-directory: ${{ steps.strings.outputs.build-output-dir }}
- run: ctest --build-config ${{ matrix.build_type }} --output-on-failure --output-junit results.xml --test-output-size-passed 65536 --test-output-size-failed 65536
+ run: |
+ export ASAN_OPTIONS="verify_asan_link_order=0 strict_string_checks=1 detect_stack_use_after_return=1"
+ if [[ "$RUNNER_OS" == "macOS" ]]; then
+ ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=0"
+ else
+ ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=1"
+ fi
+ ctest --build-config ${{ matrix.build_type }} --output-on-failure --output-junit results.xml --test-output-size-passed 65536 --test-output-size-failed 65536
env:
STASIS_SYSCONFDIR: ../../..
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 71e310b..fc403ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,9 +10,13 @@ find_package(CURL)
option(ASAN "Address Analyzer" OFF)
set(ASAN_OPTIONS "-fsanitize=address,null,undefined")
+message(CHECK_START "Enable Address Analyzer (ASAN)")
if (ASAN)
+ message(CHECK_PASS "Yes")
add_compile_options(${ASAN_OPTIONS} -fno-omit-frame-pointer -g -O0)
add_link_options(${ASAN_OPTIONS})
+else()
+ message(CHECK_FAIL "No")
endif()
pkg_check_modules(ZIP libzip)
diff --git a/src/cli/stasis/args.c b/src/cli/stasis/args.c
index dbc9c2f..98b4479 100644
--- a/src/cli/stasis/args.c
+++ b/src/cli/stasis/args.c
@@ -85,28 +85,30 @@ void usage(char *progname) {
int width = get_option_max_width(long_options);
for (int x = 0; long_options[x].name != 0; x++) {
char tmp[STASIS_NAME_MAX] = {0};
- char output[sizeof(tmp)] = {0};
+ char output[STASIS_NAME_MAX] = {0};
char opt_long[50] = {0}; // --? [ARG]?
char opt_short[50] = {0}; // -? [ARG]?
- strcat(opt_long, "--");
- strcat(opt_long, long_options[x].name);
+ strncat(opt_long, "--", sizeof(opt_long) - strlen(opt_long) - 1);
+ strncat(opt_long, long_options[x].name, sizeof(opt_long) - strlen(opt_long) - 1);
if (long_options[x].has_arg) {
- strcat(opt_long, " ARG");
+ strncat(opt_long, " ARG", sizeof(opt_long) - strlen(opt_long) - 1);
}
if (long_options[x].val <= 'z') {
- strcat(opt_short, "-");
+ strncat(opt_short, "-", sizeof(opt_short) - strlen(opt_short) - 1);
opt_short[1] = (char) long_options[x].val;
if (long_options[x].has_arg) {
- strcat(opt_short, " ARG");
+ strncat(opt_short, " ARG", sizeof(opt_short) - strlen(opt_short) - 1);
}
} else {
- strcat(opt_short, " ");
+ strncat(opt_short, " ", sizeof(opt_short) - strlen(opt_short) - 1);
}
- sprintf(tmp, " %%-%ds\t%%s\t\t%%s", width + 4);
- sprintf(output, tmp, opt_long, opt_short, long_options_help[x]);
+ const char *opt_fmt = " %%-%ds\t%%s\t\t%%s";
+ size_t opt_fmt_len = snprintf(NULL, 0, opt_fmt, width);
+ snprintf(tmp, sizeof(tmp) - opt_fmt_len, opt_fmt, width + 4);
+ snprintf(output, sizeof(output), tmp, opt_long, opt_short, long_options_help[x]);
puts(output);
}
}
diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c
index 44efc4a..328d825 100644
--- a/src/cli/stasis/stasis_main.c
+++ b/src/cli/stasis/stasis_main.c
@@ -45,7 +45,7 @@ static void configure_stasis_ini(struct Delivery *ctx, char **config_input) {
if (!*config_input) {
SYSDEBUG("%s", "No configuration passed by argument. Using basic config.");
char cfgfile[PATH_MAX * 2];
- sprintf(cfgfile, "%s/%s", globals.sysconfdir, "stasis.ini");
+ snprintf(cfgfile, sizeof(cfgfile), "%s/%s", globals.sysconfdir, "stasis.ini");
SYSDEBUG("cfgfile: %s", cfgfile);
if (!access(cfgfile, F_OK | R_OK)) {
*config_input = strdup(cfgfile);
@@ -161,9 +161,9 @@ static void check_conda_prefix_length(const struct Delivery *ctx) {
}
}
-static void setup_conda(struct Delivery *ctx, char *installer_url) {
+static void setup_conda(struct Delivery *ctx, char *installer_url, const size_t maxlen) {
msg(STASIS_MSG_L1, "Conda setup\n");
- delivery_get_conda_installer_url(ctx, installer_url);
+ delivery_get_conda_installer_url(ctx, installer_url, maxlen);
msg(STASIS_MSG_L2, "Downloading: %s\n", installer_url);
if (delivery_get_conda_installer(ctx, installer_url)) {
msg(STASIS_MSG_ERROR, "download failed: %s\n", installer_url);
@@ -429,7 +429,7 @@ static void build_docker(struct Delivery *ctx, const int disabled) {
msg(STASIS_MSG_L1 | STASIS_MSG_WARN, "Docker image building is disabled by CLI argument\n");
} else {
char dockerfile[PATH_MAX] = {0};
- sprintf(dockerfile, "%s/%s", ctx->storage.build_docker_dir, "Dockerfile");
+ snprintf(dockerfile, sizeof(dockerfile), "%s/%s", ctx->storage.build_docker_dir, "Dockerfile");
if (globals.enable_docker) {
if (!access(dockerfile, F_OK)) {
msg(STASIS_MSG_L1, "Building Docker image\n");
@@ -461,7 +461,7 @@ static void generate_release(struct Delivery *ctx, char *env_name, char *env_nam
delivery_export(ctx, (char *[]) {env_name, env_name_testing, NULL});
char specfile[PATH_MAX];
- sprintf(specfile, "%s/%s.yml", ctx->storage.delivery_dir, env_name);
+ snprintf(specfile, sizeof(specfile), "%s/%s.yml", ctx->storage.delivery_dir, env_name);
delivery_rewrite_stage1(ctx, specfile);
build_docker(ctx, disable_docker);
@@ -532,7 +532,7 @@ int main(int argc, char *argv[]) {
globals.continue_on_error = true;
break;
case 'p':
- strcpy(python_override_version, optarg);
+ strncpy(python_override_version, optarg, sizeof(python_override_version) - 1);
break;
case 'l':
globals.cpu_limit = strtol(optarg, NULL, 10);
@@ -652,9 +652,9 @@ int main(int argc, char *argv[]) {
configure_jfrog_cli(&ctx);
runtime_apply(ctx.runtime.environ);
- strcpy(env_name, ctx.info.release_name);
- strcpy(env_name_testing, env_name);
- strcat(env_name_testing, "-test");
+ strncpy(env_name, ctx.info.release_name, sizeof(env_name) - 1);
+ strncpy(env_name_testing, env_name, sizeof(env_name_testing) - 1);
+ strncat(env_name_testing, "-test", sizeof(env_name_testing) - strlen(env_name_testing) - 1);
char *envs[] = {
"release", env_name,
"testing", env_name_testing,
@@ -666,7 +666,7 @@ int main(int argc, char *argv[]) {
check_conda_install_prefix(&ctx);
check_conda_prefix_length(&ctx);
- setup_conda(&ctx, installer_url);
+ setup_conda(&ctx, installer_url, sizeof(installer_url));
configure_conda_base(&ctx, envs);
configure_conda_purge(&ctx, envs);
setup_activate_test_env(&ctx, env_name_testing);
diff --git a/src/cli/stasis_indexer/args.c b/src/cli/stasis_indexer/args.c
index 2d92ab0..8c9d3fe 100644
--- a/src/cli/stasis_indexer/args.c
+++ b/src/cli/stasis_indexer/args.c
@@ -30,7 +30,7 @@ void usage(char *name) {
for (int i = 0; i < maxopts - 1; i++) {
char line[255] = {0};
- sprintf(line, " --%s -%c %-20s", long_options[i].name, long_options[i].val, long_options_help[i]);
+ snprintf(line, sizeof(line), " --%s -%c %-20s", long_options[i].name, long_options[i].val, long_options_help[i]);
puts(line);
}
diff --git a/src/cli/stasis_indexer/helpers.c b/src/cli/stasis_indexer/helpers.c
index 6dc653d..0debfe4 100644
--- a/src/cli/stasis_indexer/helpers.c
+++ b/src/cli/stasis_indexer/helpers.c
@@ -96,44 +96,44 @@ int pandoc_exec(const char *in_file, const char *out_file, const char *css_file,
if (!get_pandoc_version(&pandoc_version)) {
// < 2.19
if (pandoc_version < 0x02130000) {
- strcat(pandoc_versioned_args, "--self-contained ");
+ strncat(pandoc_versioned_args, "--self-contained ", sizeof(pandoc_versioned_args) - strlen(pandoc_versioned_args) - 1);
} else {
// >= 2.19
- strcat(pandoc_versioned_args, "--embed-resources ");
+ strncat(pandoc_versioned_args, "--embed-resources ", sizeof(pandoc_versioned_args) - strlen(pandoc_versioned_args) - 1);
}
// >= 1.15.0.4
if (pandoc_version >= 0x010f0004) {
- strcat(pandoc_versioned_args, "--standalone ");
+ strncat(pandoc_versioned_args, "--standalone ", sizeof(pandoc_versioned_args) - strlen(pandoc_versioned_args) - 1);
}
// >= 1.10.0.1
if (pandoc_version >= 0x010a0001) {
- strcat(pandoc_versioned_args, "-f gfm+autolink_bare_uris ");
+ strncat(pandoc_versioned_args, "-f gfm+autolink_bare_uris ", sizeof(pandoc_versioned_args) - strlen(pandoc_versioned_args) - 1);
}
// > 3.1.9
if (pandoc_version > 0x03010900) {
- strcat(pandoc_versioned_args, "-f gfm+alerts ");
+ strncat(pandoc_versioned_args, "-f gfm+alerts ", sizeof(pandoc_versioned_args) - strlen(pandoc_versioned_args) - 1);
}
}
// Converts a markdown file to html
char cmd[STASIS_BUFSIZ] = {0};
- strcpy(cmd, "pandoc ");
- strcat(cmd, pandoc_versioned_args);
+ strncpy(cmd, "pandoc ", sizeof(cmd) - 1);
+ strncat(cmd, pandoc_versioned_args, sizeof(cmd) - strlen(cmd) - 1);
if (css_file && strlen(css_file)) {
- strcat(cmd, "--css ");
- strcat(cmd, css_file);
+ strncat(cmd, "--css ", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, css_file, sizeof(cmd) - strlen(cmd) - 1);
}
- strcat(cmd, " ");
- strcat(cmd, "--metadata title=\"");
- strcat(cmd, title);
- strcat(cmd, "\" ");
- strcat(cmd, "-o ");
- strcat(cmd, out_file);
- strcat(cmd, " ");
- strcat(cmd, in_file);
+ strncat(cmd, " ", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, "--metadata title=\"", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, title, sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, "\" ", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, "-o ", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, out_file, sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, " ", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, in_file, sizeof(cmd) - strlen(cmd) - 1);
if (globals.verbose) {
puts(cmd);
@@ -243,7 +243,15 @@ int get_files(struct StrList **out, const char *path, const char *pattern, ...)
va_list args;
va_start(args, pattern);
char userpattern[PATH_MAX] = {0};
- vsprintf(userpattern, pattern, args);
+ const int len = vsnprintf(userpattern, sizeof(userpattern), pattern, args);
+ if (len < 0) {
+ SYSERROR("%s", "vsnprintf failed\n");
+ va_end(args);
+ return -1;
+ }
+ if ((size_t) len > sizeof(userpattern)) {
+ fprintf(stderr, "WARNING: %s: userpattern truncated!\n", __FUNCTION__);
+ }
va_end(args);
if (!strlen(userpattern)) {
userpattern[0] = '*';
@@ -377,8 +385,8 @@ int write_manifest(const char *path, char **exclude_path, FILE *fp) {
}
char filepath[PATH_MAX] = {0};
strncpy(filepath, path, PATH_MAX - 1);
- strcat(filepath, "/");
- strcat(filepath, rec->d_name);
+ 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 21cf729..d30ee09 100644
--- a/src/cli/stasis_indexer/junitxml_report.c
+++ b/src/cli/stasis_indexer/junitxml_report.c
@@ -98,7 +98,7 @@ static int write_report_output(struct Delivery *ctx, FILE *destfp, const char *x
int indexer_junitxml_report(struct Delivery **ctx, const size_t nelem) {
char indexfile[PATH_MAX] = {0};
- sprintf(indexfile, "%s/README.md", (*ctx)->storage.results_dir);
+ snprintf(indexfile, sizeof(indexfile), "%s/README.md", (*ctx)->storage.results_dir);
struct StrList *file_listing = listdir((*ctx)->storage.results_dir);
if (!file_listing) {
@@ -117,7 +117,7 @@ int indexer_junitxml_report(struct Delivery **ctx, const size_t nelem) {
int current_rc = (*ctx)->meta.rc;
for (size_t d = 0; d < nelem; d++) {
char pattern[PATH_MAX] = {0};
- snprintf(pattern, sizeof(pattern) - 1, "*%s*", ctx[d]->info.release_name);
+ snprintf(pattern, sizeof(pattern), "*%s*", ctx[d]->info.release_name);
// if the result directory contains tests for this release name, print them
if (!is_file_in_listing(file_listing, pattern)) {
diff --git a/src/cli/stasis_indexer/readmes.c b/src/cli/stasis_indexer/readmes.c
index edc6312..91c936f 100644
--- a/src/cli/stasis_indexer/readmes.c
+++ b/src/cli/stasis_indexer/readmes.c
@@ -12,7 +12,7 @@ int indexer_readmes(struct Delivery **ctx, const size_t nelem) {
}
char indexfile[PATH_MAX] = {0};
- sprintf(indexfile, "%s/README.md", (*ctx)->storage.delivery_dir);
+ snprintf(indexfile, sizeof(indexfile), "%s/README.md", (*ctx)->storage.delivery_dir);
FILE *indexfp = fopen(indexfile, "w+");
if (!indexfp) {
@@ -52,10 +52,10 @@ int indexer_readmes(struct Delivery **ctx, const size_t nelem) {
if (!latest_deliveries[i]->meta.name) {
continue;
}
- sprintf(link_name, "latest-py%s-%s-%s.yml", latest_deliveries[i]->meta.python_compact, latest_deliveries[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest_deliveries[i]->system.arch);
- sprintf(readme_name, "README-py%s-%s-%s.md", latest_deliveries[i]->meta.python_compact, latest_deliveries[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest_deliveries[i]->system.arch);
- sprintf(conf_name, "%s.ini", latest_deliveries[i]->info.release_name);
- sprintf(conf_name_relative, "../config/%s.ini", latest_deliveries[i]->info.release_name);
+ snprintf(link_name, sizeof(link_name), "latest-py%s-%s-%s.yml", latest_deliveries[i]->meta.python_compact, latest_deliveries[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest_deliveries[i]->system.arch);
+ snprintf(readme_name, sizeof(readme_name), "README-py%s-%s-%s.md", latest_deliveries[i]->meta.python_compact, latest_deliveries[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest_deliveries[i]->system.arch);
+ snprintf(conf_name, sizeof(conf_name), "%s.ini", latest_deliveries[i]->info.release_name);
+ snprintf(conf_name_relative, sizeof(conf_name_relative), "../config/%s.ini", latest_deliveries[i]->info.release_name);
if (strstr(link_name, platform) && strstr(link_name, arch)) {
fprintf(indexfp, "- Python %s\n", latest_deliveries[i]->meta.python);
fprintf(indexfp, " - Info: [README](%s)\n", readme_name);
diff --git a/src/cli/stasis_indexer/stasis_indexer_main.c b/src/cli/stasis_indexer/stasis_indexer_main.c
index 840e897..d475c15 100644
--- a/src/cli/stasis_indexer/stasis_indexer_main.c
+++ b/src/cli/stasis_indexer/stasis_indexer_main.c
@@ -13,9 +13,9 @@ int indexer_combine_rootdirs(const char *dest, char **rootdirs, const size_t roo
char destdir_with_output[PATH_MAX] = {0};
char *destdir = destdir_bare;
- strcpy(destdir_bare, dest);
- strcpy(destdir_with_output, dest);
- strcat(destdir_with_output, "/output");
+ strncpy(destdir_bare, dest, sizeof(destdir_bare) - 1);
+ strncpy(destdir_with_output, dest, sizeof(destdir_with_output) - 1);
+ strncat(destdir_with_output, "/output", sizeof(destdir_with_output) - strlen(destdir_with_output) - 1);
if (!access(destdir_with_output, F_OK)) {
destdir = destdir_with_output;
@@ -26,9 +26,9 @@ int indexer_combine_rootdirs(const char *dest, char **rootdirs, const size_t roo
char srcdir_bare[PATH_MAX] = {0};
char srcdir_with_output[PATH_MAX] = {0};
char *srcdir = srcdir_bare;
- strcpy(srcdir_bare, rootdirs[i]);
- strcpy(srcdir_with_output, rootdirs[i]);
- strcat(srcdir_with_output, "/output");
+ strncpy(srcdir_bare, rootdirs[i], sizeof(srcdir_bare) - 1);
+ strncpy(srcdir_with_output, rootdirs[i], sizeof(srcdir_with_output) - 1);
+ strncat(srcdir_with_output, "/output", sizeof(srcdir_with_output) - strlen(srcdir_with_output) - 1);
if (access(srcdir_bare, F_OK)) {
fprintf(stderr, "%s does not exist\n", srcdir_bare);
@@ -80,11 +80,11 @@ int indexer_symlinks(struct Delivery **ctx, const size_t nelem) {
if (!data[i]->meta.name) {
continue;
}
- sprintf(link_name_spec, "latest-py%s-%s-%s.yml", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
- sprintf(file_name_spec, "%s.yml", data[i]->info.release_name);
+ snprintf(link_name_spec, sizeof(link_name_spec), "latest-py%s-%s-%s.yml", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
+ snprintf(file_name_spec, sizeof(file_name_spec), "%s.yml", data[i]->info.release_name);
- sprintf(link_name_readme, "README-py%s-%s-%s.md", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
- sprintf(file_name_readme, "README-%s.md", data[i]->info.release_name);
+ snprintf(link_name_readme, sizeof(link_name_readme), "README-py%s-%s-%s.md", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
+ snprintf(file_name_readme, sizeof(file_name_readme), "README-%s.md", data[i]->info.release_name);
if (!access(link_name_spec, F_OK)) {
if (unlink(link_name_spec)) {
@@ -151,7 +151,7 @@ void indexer_init_dirs(struct Delivery *ctx, const char *workdir) {
char newpath[PATH_MAX] = {0};
if (getenv("PATH")) {
- sprintf(newpath, "%s/bin:%s", ctx->storage.tools_dir, getenv("PATH"));
+ snprintf(newpath, sizeof(newpath), "%s/bin:%s", ctx->storage.tools_dir, getenv("PATH"));
setenv("PATH", newpath, 1);
} else {
SYSERROR("%s", "environment variable PATH is undefined. Unable to continue.");
@@ -261,11 +261,11 @@ int main(const int argc, char *argv[]) {
char workdir_template[PATH_MAX] = {0};
const char *system_tmp = getenv("TMPDIR");
if (system_tmp) {
- strcat(workdir_template, system_tmp);
+ strncat(workdir_template, system_tmp, sizeof(workdir_template) - strlen(workdir_template) - 1);
} else {
- strcat(workdir_template, "/tmp");
+ strncat(workdir_template, "/tmp", sizeof(workdir_template) - strlen(workdir_template) - 1);
}
- strcat(workdir_template, "/stasis-combine.XXXXXX");
+ strncat(workdir_template, "/stasis-combine.XXXXXX", sizeof(workdir_template) - strlen(workdir_template) - 1);
char *workdir = mkdtemp(workdir_template);
if (!workdir) {
SYSERROR("Unable to create temporary directory: %s", workdir_template);
@@ -320,6 +320,11 @@ int main(const int argc, char *argv[]) {
msg(STASIS_MSG_L1, "Loading metadata\n");
struct StrList *metafiles = NULL;
get_files(&metafiles, ctx.storage.meta_dir, "*.stasis");
+ if (!metafiles || !strlist_count(metafiles)) {
+ SYSERROR("%s: No metadata!", ctx.storage.meta_dir);
+ delivery_free(&ctx);
+ exit(1);
+ }
strlist_sort(metafiles, STASIS_SORT_LEN_ASCENDING);
struct Delivery **local = calloc(strlist_count(metafiles) + 1, sizeof(*local));
@@ -411,7 +416,7 @@ int main(const int argc, char *argv[]) {
msg(STASIS_MSG_L1, "Copying indexed delivery to '%s'\n", destdir);
char cmd[PATH_MAX] = {0};
- sprintf(cmd, "rsync -ah%s --delete --exclude 'tmp/' --exclude 'tools/' '%s/' '%s/'", globals.verbose ? "v" : "q", workdir, destdir);
+ snprintf(cmd, sizeof(cmd), "rsync -ah%s --delete --exclude 'tmp/' --exclude 'tools/' '%s/' '%s/'", globals.verbose ? "v" : "q", workdir, destdir);
guard_free(destdir);
if (globals.verbose) {
diff --git a/src/cli/stasis_indexer/website.c b/src/cli/stasis_indexer/website.c
index 966391e..8a5126d 100644
--- a/src/cli/stasis_indexer/website.c
+++ b/src/cli/stasis_indexer/website.c
@@ -8,7 +8,7 @@ int indexer_make_website(struct Delivery **ctx) {
return -1;
}
- sprintf(css_filename, "%s/%s", globals.sysconfdir, "stasis_pandoc.css");
+ snprintf(css_filename, PATH_MAX, "%s/%s", globals.sysconfdir, "stasis_pandoc.css");
const int have_css = access(css_filename, F_OK | R_OK) == 0;
struct StrList *dirs = strlist_init();
@@ -29,14 +29,14 @@ int indexer_make_website(struct Delivery **ctx) {
char *filename = path_basename(strlist_item(inputs, x));
char fullpath_src[PATH_MAX] = {0};
char fullpath_dest[PATH_MAX] = {0};
- sprintf(fullpath_src, "%s/%s", root, filename);
+ snprintf(fullpath_src, sizeof(fullpath_src), "%s/%s", root, filename);
if (access(fullpath_src, F_OK)) {
continue;
}
// Replace *.md extension with *.html.
- strcpy(fullpath_dest, fullpath_src);
- gen_file_extension_str(fullpath_dest, ".html");
+ strncpy(fullpath_dest, fullpath_src, sizeof(fullpath_dest) - 1);
+ gen_file_extension_str(fullpath_dest, sizeof(fullpath_dest), ".html");
// Convert markdown to html
if (pandoc_exec(fullpath_src, fullpath_dest, have_css ? css_filename : NULL, "STASIS")) {
@@ -52,8 +52,8 @@ int indexer_make_website(struct Delivery **ctx) {
if (!strcmp(filename, "README.md")) {
char link_from[PATH_MAX] = {0};
char link_dest[PATH_MAX] = {0};
- strcpy(link_from, "README.html");
- sprintf(link_dest, "%s/%s", root, "index.html");
+ strncpy(link_from, "README.html", sizeof(link_from) - 1);
+ 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 d5457e7..9e41046 100644
--- a/src/lib/core/artifactory.c
+++ b/src/lib/core/artifactory.c
@@ -14,37 +14,37 @@ int artifactory_download_cli(char *dest,
char arch_ident[STASIS_NAME_MAX] = {0};
// convert platform string to lower-case
- strcpy(os_ident, os);
+ strncpy(os_ident, os, sizeof(os_ident) - 1);
tolower_s(os_ident);
// translate OS identifier
if (!strcmp(os_ident, "darwin") || startswith(os_ident, "macos")) {
- strcpy(os_ident, "mac");
+ strncpy(os_ident, "mac", sizeof(os_ident) - 1);
} else if (!strcmp(os_ident, "linux")) {
- strcpy(os_ident, "linux");
+ strncpy(os_ident, "linux", sizeof(os_ident) - 1);
} else {
fprintf(stderr, "%s: unknown operating system: %s\n", __FUNCTION__, os_ident);
return -1;
}
// translate ARCH identifier
- strcpy(arch_ident, arch);
+ strncpy(arch_ident, arch, sizeof(arch_ident) - 1);
if (startswith(arch_ident, "i") && endswith(arch_ident, "86")) {
- strcpy(arch_ident, "386");
+ strncpy(arch_ident, "386", sizeof(arch_ident) - 1);
} else if (!strcmp(arch_ident, "amd64") || !strcmp(arch_ident, "x86_64") || !strcmp(arch_ident, "x64")) {
if (!strcmp(os_ident, "mac")) {
- strcpy(arch_ident, "386");
+ strncpy(arch_ident, "386", sizeof(arch_ident) - 1);
} else {
- strcpy(arch_ident, "amd64");
+ strncpy(arch_ident, "amd64", sizeof(arch_ident) - 1);
}
} else if (!strcmp(arch_ident, "arm64") || !strcmp(arch_ident, "aarch64")) {
- strcpy(arch_ident, "arm64");
+ strncpy(arch_ident, "arm64", sizeof(arch_ident) - 1);
} else {
fprintf(stderr, "%s: unknown architecture: %s\n", __FUNCTION__, arch_ident);
return -1;
}
- snprintf(url, sizeof(url) - 1, "%s/%s/%s/%s/%s-%s-%s/%s",
+ snprintf(url, sizeof(url), "%s/%s/%s/%s/%s-%s-%s/%s",
jfrog_artifactory_base_url, // https://releases.jfrog.io/artifactory
jfrog_artifactory_product, // jfrog-cli
cli_major_ver, // v\d+(-jf)?
@@ -53,14 +53,16 @@ int artifactory_download_cli(char *dest,
os_ident, // ...
arch_ident, // jfrog-cli-linux-x86_64
remote_filename); // jf
- strcpy(path, dest);
+ strncpy(path, dest, sizeof(path) - 1);
if (mkdirs(path, 0755)) {
fprintf(stderr, "%s: %s: %s", __FUNCTION__, path, strerror(errno));
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);
}
@@ -100,7 +102,7 @@ void jfrt_register_opt_int(int jfrt_val, const char *opt_name, struct StrList **
// option will not be used
return;
}
- snprintf(data, sizeof(data) - 1, "--%s=%d", opt_name, jfrt_val);
+ snprintf(data, sizeof(data), "--%s=%d", opt_name, jfrt_val);
strlist_append(&*opt_map, data);
}
@@ -111,7 +113,7 @@ void jfrt_register_opt_long(long jfrt_val, const char *opt_name, struct StrList
// option will not be used
return;
}
- snprintf(data, sizeof(data) - 1, "--%s=%ld", opt_name, jfrt_val);
+ snprintf(data, sizeof(data), "--%s=%ld", opt_name, jfrt_val);
strlist_append(&*opt_map, data);
}
@@ -230,7 +232,7 @@ int jfrog_cli(struct JFRT_Auth *auth, const char *subsystem, const char *task, c
auth->client_cert_path,
auth->password,
};
- snprintf(cmd, sizeof(cmd) - 1, "jf %s %s %s %s", subsystem, task, auth_args, args ? args : "");
+ snprintf(cmd, sizeof(cmd), "jf %s %s %s %s", subsystem, task, auth_args, args ? args : "");
redact_sensitive(redactable, sizeof(redactable) / sizeof (*redactable), cmd, cmd_redacted, sizeof(cmd_redacted) - 1);
guard_free(auth_args);
@@ -242,8 +244,8 @@ int jfrog_cli(struct JFRT_Auth *auth, const char *subsystem, const char *task, c
}
if (!globals.verbose) {
- strcpy(proc.f_stdout, "/dev/null");
- strcpy(proc.f_stderr, "/dev/null");
+ strncpy(proc.f_stdout, "/dev/null", sizeof(proc.f_stdout) - 1);
+ strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1);
}
return shell(&proc, cmd);
}
@@ -254,13 +256,13 @@ static int jfrog_cli_rt(struct JFRT_Auth *auth, char *task, char *args) {
int jfrog_cli_rt_build_collect_env(struct JFRT_Auth *auth, char *build_name, char *build_number) {
char cmd[STASIS_BUFSIZ] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "\"%s\" \"%s\"", build_name, build_number);
+ snprintf(cmd, sizeof(cmd), "\"%s\" \"%s\"", build_name, build_number);
return jfrog_cli(auth, "rt", "build-collect-env", cmd);
}
int jfrog_cli_rt_build_publish(struct JFRT_Auth *auth, char *build_name, char *build_number) {
char cmd[STASIS_BUFSIZ] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "\"%s\" \"%s\"", build_name, build_number);
+ snprintf(cmd, sizeof(cmd), "\"%s\" \"%s\"", build_name, build_number);
return jfrog_cli(auth, "rt", "build-publish", cmd);
}
@@ -326,7 +328,7 @@ int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, cha
return -1;
}
- snprintf(cmd, sizeof(cmd) - 1, "%s '%s' '%s'", args, repo_path, dest ? dest : "");
+ snprintf(cmd, sizeof(cmd), "%s '%s' '%s'", args, repo_path, dest ? dest : "");
guard_free(args);
guard_strlist_free(&arg_map);
@@ -411,12 +413,12 @@ int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *s
if (base) {
src = base;
} else {
- strcat(src, "/");
+ strncat(src, "/", sizeof(src) - strlen(src) - 1);
}
pushd(new_src);
}
- snprintf(cmd, sizeof(cmd) - 1, "%s '%s' \"%s\"", args, src, repo_path);
+ snprintf(cmd, sizeof(cmd), "%s '%s' \"%s\"", args, src, repo_path);
guard_free(args);
guard_strlist_free(&arg_map);
@@ -475,7 +477,7 @@ int jfrog_cli_rt_search(struct JFRT_Auth *auth, struct JFRT_Search *ctx, char *r
return -1;
}
- snprintf(cmd, sizeof(cmd) - 1, "%s '%s/%s'", args, repo_path, pattern ? pattern: "");
+ snprintf(cmd, sizeof(cmd), "%s '%s/%s'", args, repo_path, pattern ? pattern: "");
guard_free(args);
guard_strlist_free(&arg_map);
diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c
index 16483ee..90c6ba1 100644
--- a/src/lib/core/conda.c
+++ b/src/lib/core/conda.c
@@ -10,18 +10,20 @@ int micromamba(const struct MicromambaInfo *info, char *command, ...) {
tolower_s(sys.sysname);
if (!strcmp(sys.sysname, "darwin")) {
- strcpy(sys.sysname, "osx");
+ strncpy(sys.sysname, "osx", sizeof(sys.sysname) - 1);
}
if (!strcmp(sys.machine, "x86_64")) {
- strcpy(sys.machine, "64");
+ strncpy(sys.machine, "64", sizeof(sys.machine) - 1);
}
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,16 +49,37 @@ 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);
va_list args;
+ int cmd_len = snprintf(cmd, sizeof(cmd), "%s -r %s -p %s ", mmbin, info->conda_prefix, info->conda_prefix);
+ if (cmd_len < 0) {
+ SYSERROR("%s", "Unable to build argument list for micromamba");
+ va_end(args);
+ return -1;
+ }
+ if ((size_t) cmd_len > sizeof(cmd)) {
+ SYSERROR("%s", "micromamba command truncated");
+ va_end(args);
+ return -1;
+ }
+
va_start(args, command);
- vsprintf(cmd + strlen(cmd), command, args);
+ cmd_len = vsnprintf(cmd + strlen(cmd), sizeof(cmd) - cmd_len, command, args);
+ if (cmd_len < 0) {
+ SYSERROR("%s", "Unable to append arguments to micromamba command");
+ va_end(args);
+ return -1;
+ }
+ if ((size_t) cmd_len > sizeof(cmd)) {
+ SYSERROR("%s", "micromamba command truncated while appending arguments");
+ va_end(args);
+ return -1;
+ }
va_end(args);
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;
@@ -147,22 +170,22 @@ int pkg_index_provides(int mode, const char *index, const char *spec) {
int status = 0;
struct Process proc = {0};
proc.redirect_stderr = 1;
- strcpy(proc.f_stdout, logfile);
+ strncpy(proc.f_stdout, logfile, sizeof(proc.f_stdout) - 1);
if (mode == PKG_USE_PIP) {
// 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);
if (index) {
- snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "--index-url='%s' ", index);
+ snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "--index-url='%s' ", index);
}
- snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "'%s' ", spec_local);
+ snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "'%s' ", spec_local);
} else if (mode == PKG_USE_CONDA) {
strncpy(cmd, "mamba search ", sizeof(cmd) - 1);
if (index) {
- snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "--channel '%s' ", index);
+ snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "--channel '%s' ", index);
}
- snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "'%s' ", spec_local);
+ snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), "'%s' ", spec_local);
} else {
return PKG_INDEX_PROVIDES_E_INTERNAL_MODE_UNKNOWN;
}
@@ -224,12 +247,12 @@ int conda_exec(const char *args) {
"deactivate",
NULL
};
- char conda_as[6] = {0};
+ char conda_as[10] = {0};
- strcpy(conda_as, "conda");
+ strncpy(conda_as, "conda", sizeof(conda_as) - 1);
for (size_t i = 0; mamba_commands[i] != NULL; i++) {
if (startswith(args, mamba_commands[i])) {
- strcpy(conda_as, "mamba");
+ strncpy(conda_as, "mamba", sizeof(conda_as) - 1);
break;
}
}
@@ -321,13 +344,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 +360,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) {
@@ -417,15 +440,15 @@ int conda_check_required() {
// Construct a "conda list" command that searches for all required packages
// using conda's (python's) regex matching
- strcat(cmd, "conda list '");
+ strncat(cmd, "conda list '", sizeof(cmd) - strlen(cmd) - 1);
for (size_t i = 0; conda_minimum_viable_tools[i] != NULL; i++) {
- strcat(cmd, "^");
- strcat(cmd, conda_minimum_viable_tools[i]);
+ strncat(cmd, "^", sizeof(cmd) - strlen(cmd) - 1);
+ strncat(cmd, conda_minimum_viable_tools[i], sizeof(cmd) - strlen(cmd) - 1);
if (conda_minimum_viable_tools[i + 1] != NULL) {
- strcat(cmd, "|");
+ strncat(cmd, "|", sizeof(cmd) - strlen(cmd) - 1);
}
}
- strcat(cmd, "' | cut -d ' ' -f 1");
+ strncat(cmd, "' | cut -d ' ' -f 1", sizeof(cmd) - strlen(cmd) - 1);
// Verify all required packages are installed
char *cmd_out = shell_output(cmd, &status);
@@ -478,9 +501,10 @@ 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 ");
+ strncpy(cmd, "install ", sizeof(cmd) - 1);
total = strlist_count(globals.conda_packages);
for (size_t i = 0; i < total; i++) {
@@ -488,9 +512,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);
}
}
@@ -502,7 +527,7 @@ int conda_setup_headless() {
if (globals.pip_packages && strlist_count(globals.pip_packages)) {
memset(cmd, 0, sizeof(cmd));
- strcpy(cmd, "install ");
+ strncpy(cmd, "install ", sizeof(cmd) - 1);
total = strlist_count(globals.pip_packages);
for (size_t i = 0; i < total; i++) {
@@ -510,9 +535,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 +578,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);
@@ -560,7 +586,7 @@ int conda_env_create_from_uri(char *name, char *uri, char *python_version) {
unlink(tempfile);
// We'll create a new file with the same random bits, ending with .yml
- strcat(tempfile, ".yml");
+ strncat(tempfile, ".yml", sizeof(tempfile) - strlen(tempfile) - 1);
char *errmsg = NULL;
const long http_code = download(uri_fs ? uri_fs : uri, tempfile, &errmsg);
if (HTTP_ERROR(http_code)) {
@@ -610,13 +636,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 +663,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/copy.c b/src/lib/core/copy.c
index 25eede3..ba52507 100644
--- a/src/lib/core/copy.c
+++ b/src/lib/core/copy.c
@@ -14,7 +14,7 @@ int copy2(const char *src, const char *dest, unsigned int op) {
}
char dname[1024] = {0};
- strcpy(dname, dest);
+ strncpy(dname, dest, sizeof(dname) - 1);
char *dname_endptr = strrchr(dname, '/');
if (dname_endptr != NULL) {
diff --git a/src/lib/core/docker.c b/src/lib/core/docker.c
index 39357ad..52599d3 100644
--- a/src/lib/core/docker.c
+++ b/src/lib/core/docker.c
@@ -7,7 +7,7 @@ int docker_exec(const char *args, const unsigned flags) {
memset(&proc, 0, sizeof(proc));
memset(cmd, 0, sizeof(cmd));
- snprintf(cmd, sizeof(cmd) - 1, "docker %s", args);
+ snprintf(cmd, sizeof(cmd), "docker %s", args);
unsigned final_flags = 0;
if (flags & STASIS_DOCKER_QUIET) {
@@ -18,10 +18,10 @@ int docker_exec(const char *args, const unsigned flags) {
}
if (final_flags & STASIS_DOCKER_QUIET_STDOUT) {
- strcpy(proc.f_stdout, "/dev/null");
+ strncpy(proc.f_stdout, "/dev/null", sizeof(proc.f_stdout) - 1);
}
if (final_flags & STASIS_DOCKER_QUIET_STDERR) {
- strcpy(proc.f_stderr, "/dev/null");
+ strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1);
}
if (!final_flags) {
@@ -36,7 +36,7 @@ int docker_script(const char *image, char *args, char *data, const unsigned flag
(void)flags; // TODO: placeholder
char cmd[PATH_MAX] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "docker run -i %s \"%s\" /bin/sh -", args ? args : "", image);
+ snprintf(cmd, sizeof(cmd), "docker run -i %s \"%s\" /bin/sh -", args ? args : "", image);
FILE *outfile = popen(cmd, "w");
if (!outfile) {
@@ -68,12 +68,12 @@ int docker_build(const char *dirpath, const char *args, int engine) {
memset(cmd, 0, sizeof(cmd));
if (engine & STASIS_DOCKER_BUILD) {
- strcpy(build, "build");
+ strncpy(build, "build", sizeof(build) - 1);
}
if (engine & STASIS_DOCKER_BUILD_X) {
- strcpy(build, "buildx build");
+ strncpy(build, "buildx build", sizeof(build) - 1);
}
- snprintf(cmd, sizeof(cmd) - 1, "%s %s %s", build, args, dirpath);
+ snprintf(cmd, sizeof(cmd), "%s %s %s", build, args, dirpath);
return docker_exec(cmd, 0);
}
@@ -83,19 +83,19 @@ int docker_save(const char *image, const char *destdir, const char *compression_
if (compression_program && strlen(compression_program)) {
char ext[255] = {0};
if (startswith(compression_program, "zstd")) {
- strcpy(ext, "zst");
+ strncpy(ext, "zst", sizeof(ext) - 1);
} else if (startswith(compression_program, "xz")) {
- strcpy(ext, "xz");
+ strncpy(ext, "xz", sizeof(ext) - 1);
} else if (startswith(compression_program, "gzip")) {
- strcpy(ext, "gz");
+ strncpy(ext, "gz", sizeof(ext) - 1);
} else if (startswith(compression_program, "bzip2")) {
- strcpy(ext, "bz2");
+ strncpy(ext, "bz2", sizeof(ext) - 1);
} 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);
@@ -120,8 +120,8 @@ static char *docker_ident() {
}
memset(&proc, 0, sizeof(proc));
- strcpy(proc.f_stdout, tempfile);
- strcpy(proc.f_stderr, "/dev/null");
+ strncpy(proc.f_stdout, tempfile, sizeof(proc.f_stdout) - 1);
+ strncpy(proc.f_stderr, "/dev/null", sizeof(proc.f_stderr) - 1);
shell(&proc, "docker --version");
if (!freopen(tempfile, "r", fp)) {
diff --git a/src/lib/core/environment.c b/src/lib/core/environment.c
index 7ece5e6..3c94d33 100644
--- a/src/lib/core/environment.c
+++ b/src/lib/core/environment.c
@@ -70,7 +70,7 @@ void runtime_export(RuntimeEnv *env, char **keys) {
NULL,
};
- char export_command[7]; // export=6 and setenv=6... convenient
+ char export_command[10]; // export=6 and setenv=6... convenient
char *_sh = getenv("SHELL");
char *sh = path_basename(_sh);
if (sh == NULL) {
@@ -80,13 +80,13 @@ void runtime_export(RuntimeEnv *env, char **keys) {
for (size_t i = 0; borne[i] != NULL; i++) {
if (strcmp(sh, borne[i]) == 0) {
- strcpy(export_command, "export");
+ strncpy(export_command, "export", sizeof(export_command) - 1);
break;
}
}
for (size_t i = 0; unborne[i] != NULL; i++) {
if (strcmp(sh, unborne[i]) == 0) {
- strcpy(export_command, "setenv");
+ strncpy(export_command, "setenv", sizeof(export_command) - 1);
break;
}
}
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/include/utils.h b/src/lib/core/include/utils.h
index 335a7e4..c1ee513 100644
--- a/src/lib/core/include/utils.h
+++ b/src/lib/core/include/utils.h
@@ -293,9 +293,10 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro
* Applies STASIS fixups to a tox ini config
* @param filename path to tox.ini
* @param result path to processed configuration
+ * @param maxlen
* @return 0 on success, -1 on error
*/
-int fix_tox_conf(const char *filename, char **result);
+int fix_tox_conf(const char *filename, char **result, size_t maxlen);
char *collapse_whitespace(char **s);
@@ -420,7 +421,7 @@ int env_manipulate_pathstr(const char *key, char *path, int mode);
/**
* Append or replace a file extension
*/
-int gen_file_extension_str(char *filename, const char *extension);
+int gen_file_extension_str(char *filename, size_t maxlen, const char *extension);
/**
* Remove [extra]s from a spec string
diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c
index cf6f670..1ecff17 100644
--- a/src/lib/core/ini.c
+++ b/src/lib/core/ini.c
@@ -177,7 +177,7 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, int
}
break;
case INIVAL_TYPE_STR_ARRAY:
- strcpy(tbufp, data_copy);
+ strncpy(tbufp, data_copy, sizeof(tbuf) - 1);
guard_free(data_copy);
data_copy = calloc(STASIS_BUFSIZ, sizeof(*data_copy));
if (!data_copy) {
@@ -186,8 +186,8 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, int
while ((token = strsep(&tbufp, "\n")) != NULL) {
//lstrip(token);
if (!isempty(token)) {
- strcat(data_copy, token);
- strcat(data_copy, "\n");
+ strncat(data_copy, token, BUFSIZ - strlen(data_copy) - 1);
+ strncat(data_copy, "\n", BUFSIZ - strlen(data_copy) - 1);
}
}
strip(data_copy);
@@ -353,7 +353,7 @@ int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *v
} else {
data->value = value_tmp;
}
- strcat(data->value, value);
+ strncat(data->value, value, value_len_new - strlen(data->value));
}
return 0;
}
@@ -454,12 +454,12 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) {
if (*hint == INIVAL_TYPE_STR_ARRAY) {
int leading_space = isspace(*render);
if (leading_space) {
- sprintf(outvalue + strlen(outvalue), "%s" LINE_SEP, render);
+ snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s" LINE_SEP, render);
} else {
- sprintf(outvalue + strlen(outvalue), " %s" LINE_SEP, render);
+ snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), " %s" LINE_SEP, render);
}
} else {
- sprintf(outvalue + strlen(outvalue), "%s", render);
+ snprintf(outvalue + strlen(outvalue), sizeof(outvalue) - strlen(outvalue), "%s", render);
}
if (mode == INI_WRITE_PRESERVE) {
guard_free(render);
@@ -467,7 +467,7 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) {
}
guard_array_free(parts);
strip(outvalue);
- strcat(outvalue, LINE_SEP);
+ strncat(outvalue, LINE_SEP, sizeof(outvalue) - strlen(outvalue) - 1);
fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, *hint == INIVAL_TYPE_STR_ARRAY ? LINE_SEP : "", outvalue);
guard_free(value);
} else {
@@ -522,7 +522,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");
- strcpy(current_section, "default");
+ strncpy(current_section, "default", sizeof(current_section) - 1);
// Open the configuration file for reading
FILE *fp = fopen(filename, "r");
@@ -596,7 +596,7 @@ 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));
- strcpy(current_section, section_name);
+ strncpy(current_section, section_name, sizeof(current_section) - 1);
guard_free(section_name);
memset(line, 0, sizeof(line));
continue;
@@ -621,12 +621,12 @@ struct INIFILE *ini_open(const char *filename) {
lstrip(key);
strip(key);
memset(key_last, 0, sizeof(inikey[1]));
- strcpy(key_last, key);
+ strncpy(key_last, key, sizeof(inikey[1]) - 1);
reading_value = 1;
if (strlen(operator) > 1) {
- strcpy(value, &operator[1]);
+ strncpy(value, &operator[1], sizeof(value) - 1);
} else {
- strcpy(value, "");
+ strncpy(value, "", sizeof(value) - 1);
}
if (isempty(value)) {
//printf("%s is probably long raw data\n", key);
@@ -640,8 +640,8 @@ struct INIFILE *ini_open(const char *filename) {
}
strip(value);
} else {
- strcpy(key, key_last);
- strcpy(value, line);
+ strncpy(key, key_last, sizeof(inikey[0]) - 1);
+ strncpy(value, line, sizeof(value) - 1);
}
memset(line, 0, sizeof(line));
diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c
index 7ae23c9..92970f0 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) {
@@ -171,17 +173,17 @@ struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const
// Set log file path
memset(slot->log_file, 0, sizeof(*slot->log_file));
if (globals.enable_task_logging) {
- strcat(slot->log_file, pool->log_root);
- strcat(slot->log_file, "/");
+ strncat(slot->log_file, pool->log_root, sizeof(slot->log_file) - strlen(slot->log_file) - 1);
+ strncat(slot->log_file, "/", sizeof(slot->log_file) - strlen(slot->log_file) - 1);
} else {
- strcpy(slot->log_file, "/dev/stdout");
+ strncpy(slot->log_file, "/dev/stdout", sizeof(slot->log_file) - 1);
}
// Set working directory
if (isempty(working_dir)) {
- strcpy(slot->working_dir, ".");
+ strncpy(slot->working_dir, ".", sizeof(slot->working_dir) - 1);
} else {
- strncpy(slot->working_dir, working_dir, PATH_MAX - 1);
+ strncpy(slot->working_dir, working_dir, sizeof(slot->working_dir) - 1);
}
// Create a temporary file to act as our intermediate command script
@@ -234,14 +236,13 @@ void mp_pool_show_summary(struct MultiProcessingPool *pool) {
if (task->status == MP_POOL_TASK_STATUS_INITIAL && task->pid == MP_POOL_PID_UNUSED) {
// You will only see this label if the task pool is killed by
// MP_POOL_FAIL_FAST and tasks are still queued for execution
- strcpy(status_str, "HOLD");
+ strncpy(status_str, "HOLD", sizeof(status_str) - 1);
} else if (!task->status && !task->signaled_by) {
-
- strcpy(status_str, "DONE");
+ strncpy(status_str, "DONE", sizeof(status_str) - 1);
} else if (task->signaled_by) {
- strcpy(status_str, "TERM");
+ strncpy(status_str, "TERM", sizeof(status_str) - 1);
} else {
- strcpy(status_str, "FAIL");
+ strncpy(status_str, "FAIL", sizeof(status_str) - 1);
}
char duration[255] = {0};
@@ -362,7 +363,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
char progress[1024] = {0};
const double percent = ((double) (tasks_complete + 1) / (double) pool->num_used) * 100;
- snprintf(progress, sizeof(progress) - 1, "[%s:%s] [%3.1f%%]", pool->ident, slot->ident, percent);
+ snprintf(progress, sizeof(progress), "[%s:%s] [%3.1f%%]", pool->ident, slot->ident, percent);
int task_timed_out = false;
if (slot->timeout) {
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/relocation.c b/src/lib/core/relocation.c
index 58b829d..bd5504b 100644
--- a/src/lib/core/relocation.c
+++ b/src/lib/core/relocation.c
@@ -50,18 +50,18 @@ int replace_text(char *original, const char *target, const char *replacement, un
// replacement is shorter than the target
if (rep_len < target_len) {
// shrink the string
- strcat(buffer, replacement);
+ strncat(buffer, replacement, sizeof(buffer) - strlen(buffer) - 1);
memmove(pos, pos + target_len, strlen(pos) - target_len);
memset(pos + (strlen(pos) - target_len), 0, target_len);
} else { // replacement is longer than the target
// write the replacement value to the buffer
- strcat(buffer, replacement);
+ strncat(buffer, replacement, sizeof(buffer) - strlen(buffer) - 1);
// target consumed. jump to the end of the substring.
pos += target_len;
}
if (flags & REPLACE_TRUNCATE_AFTER_MATCH) {
if (strstr(pos, LINE_SEP)) {
- strcat(buffer, LINE_SEP);
+ strncat(buffer, LINE_SEP, sizeof(buffer) - strlen(buffer) - 1);
}
break;
}
@@ -69,7 +69,7 @@ int replace_text(char *original, const char *target, const char *replacement, un
if (!((match = strstr(pos, target)))) {
// no more matches
// append whatever remains to the buffer
- strcat(buffer, pos);
+ strncat(buffer, pos, sizeof(buffer) - strlen(buffer) - 1);
// stop
break;
}
@@ -84,7 +84,7 @@ int replace_text(char *original, const char *target, const char *replacement, un
memset(original + buffer_len, 0, original_len - buffer_len);
}
// replace original with contents of buffer
- strcpy(original, buffer);
+ strncpy(original, buffer, buffer_len + 1);
return 0;
}
diff --git a/src/lib/core/str.c b/src/lib/core/str.c
index 9524886..368ab49 100644
--- a/src/lib/core/str.c
+++ b/src/lib/core/str.c
@@ -119,7 +119,7 @@ char** split(char *_sptr, const char* delim, size_t max)
if (!result[i]) {
return NULL;
}
- strcpy(result[i], token);
+ strncpy(result[i], token, STASIS_BUFSIZ - 1);
}
// pos is non-zero when maximum split is reached
@@ -129,7 +129,7 @@ char** split(char *_sptr, const char* delim, size_t max)
if (!result[i]) {
return NULL;
}
- strcpy(result[i], &orig[pos]);
+ strncpy(result[i], &orig[pos], STASIS_BUFSIZ - 1);
}
guard_free(sptr);
@@ -153,9 +153,9 @@ char *join(char **arr, const char *separator) {
result = (char *)calloc(total_bytes, sizeof(char));
for (int i = 0; i < records; i++) {
- strcat(result, arr[i]);
+ strncat(result, arr[i], total_bytes - strlen(result) - 1);
if (i < (records - 1)) {
- strcat(result, separator);
+ strncat(result, separator, total_bytes - strlen(result) - 1);
}
}
return result;
@@ -207,11 +207,11 @@ char *join_ex(char *separator, ...) {
result = calloc(size + 1, sizeof(char));
for (size_t i = 0; i < argc; i++) {
// Append argument to string
- strcat(result, argv[i]);
+ strncat(result, argv[i], size - strlen(result)); // no -1 because +1 above
// Do not append a trailing separator when we reach the last argument
if (i < (argc - 1)) {
- strcat(result, separator);
+ strncat(result, separator, size - strlen(result)); // no -1 because +1 above
}
guard_free(argv[i]);
}
@@ -562,7 +562,7 @@ char *normalize_space(char *s) {
}
// Rewrite the input string
- strcpy(result, tmp_orig);
+ strncpy(result, tmp_orig, strlen(result) + 1);
guard_free(tmp_orig);
return result;
}
diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c
index f3754c3..ff9c098 100644
--- a/src/lib/core/strlist.c
+++ b/src/lib/core/strlist.c
@@ -84,7 +84,7 @@ int strlist_append_file(struct StrList *pStrList, char *_path, ReaderFn *readerF
if (is_url) {
int fd;
char tempfile[PATH_MAX] = {0};
- strcpy(tempfile, "/tmp/.remote_file.XXXXXX");
+ strncpy(tempfile, "/tmp/.remote_file.XXXXXX", sizeof(tempfile) - 1);
if ((fd = mkstemp(tempfile)) < 0) {
retval = -1;
goto fatal;
@@ -421,7 +421,7 @@ void strlist_set(struct StrList **pStrList, size_t index, char *value) {
}
memset((*pStrList)->data[index], '\0', strlen(value) + 1);
- strcpy((*pStrList)->data[index], value);
+ strncpy((*pStrList)->data[index], value, strlen(value));
}
}
diff --git a/src/lib/core/system.c b/src/lib/core/system.c
index 9eff64a..6c18cc2 100644
--- a/src/lib/core/system.c
+++ b/src/lib/core/system.c
@@ -161,7 +161,7 @@ char *shell_output(const char *command, int *status) {
result = tmp;
}
}
- strcat(result, line);
+ strncat(result, line, current_size - strlen(result) - 1);
memset(line, 0, sizeof(line));
}
*status = pclose(pp);
diff --git a/src/lib/core/template.c b/src/lib/core/template.c
index dd3c7a2..623b811 100644
--- a/src/lib/core/template.c
+++ b/src/lib/core/template.c
@@ -218,7 +218,7 @@ char *tpl_render(char *str) {
value = strdup(env_val ? env_val : "");
} else if (do_func) { // {{ func:NAME(a, ...) }}
char func_name_temp[STASIS_NAME_MAX] = {0};
- strcpy(func_name_temp, type_stop + 1);
+ strncpy(func_name_temp, type_stop + 1, sizeof(func_name_temp) - 1);
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);
@@ -272,7 +272,7 @@ char *tpl_render(char *str) {
// Append replacement value
grow(z, &output_bytes, &output);
- strcat(output, value);
+ strncat(output, value, output_bytes - strlen(output) - 1);
guard_free(value);
output[z] = 0;
}
diff --git a/src/lib/core/template_func_proto.c b/src/lib/core/template_func_proto.c
index 52a11b5..fc58e33 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(&notes_list, h1_title);
result += get_github_release_notes(api_token ? api_token : "anonymous",
repository,
@@ -80,7 +80,7 @@ int get_junitxml_file_entrypoint(void *frame, void *data_out) {
return -1;
}
char nametmp[PATH_MAX] = {0};
- strcpy(nametmp, cwd);
+ strncpy(nametmp, cwd, sizeof(nametmp) - 1);
char *name = path_basename(nametmp);
*output = calloc(PATH_MAX, sizeof(**output));
@@ -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;
}
@@ -105,7 +105,7 @@ int get_basetemp_dir_entrypoint(void *frame, void *data_out) {
return -1;
}
char nametmp[PATH_MAX] = {0};
- strcpy(nametmp, cwd);
+ strncpy(nametmp, cwd, sizeof(nametmp) - 1);
char *name = path_basename(nametmp);
*output = calloc(PATH_MAX, sizeof(**output));
@@ -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;
}
@@ -126,7 +126,7 @@ int tox_run_entrypoint(void *frame, void *data_out) {
// Apply workaround for tox positional arguments
char *toxconf = NULL;
if (!access("tox.ini", F_OK)) {
- if (!fix_tox_conf("tox.ini", &toxconf)) {
+ if (!fix_tox_conf("tox.ini", &toxconf, PATH_MAX)) {
msg(STASIS_MSG_L3, "Fixing tox positional arguments\n");
*output = calloc(STASIS_BUFSIZ, sizeof(**output));
if (!*output) {
diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c
index e106193..f65a1d8 100644
--- a/src/lib/core/utils.c
+++ b/src/lib/core/utils.c
@@ -45,9 +45,9 @@ int rmtree(char *_path) {
while ((d_entity = readdir(dir)) != NULL) {
char abspath[PATH_MAX] = {0};
- strcat(abspath, path);
- strcat(abspath, DIR_SEP);
- strcat(abspath, d_entity->d_name);
+ strncat(abspath, path, sizeof(abspath) - strlen(abspath) - 1);
+ strncat(abspath, DIR_SEP, sizeof(abspath) - strlen(abspath) - 1);
+ strncat(abspath, d_entity->d_name, sizeof(abspath) - strlen(abspath) - 1);
if (!strcmp(d_entity->d_name, ".") || !strcmp(d_entity->d_name, "..") || !strcmp(abspath, path)) {
continue;
@@ -278,13 +278,13 @@ char *find_program(const char *name) {
result[0] = '\0';
while ((path_elem = strsep(&path, PATH_SEP))) {
char abspath[PATH_MAX] = {0};
- strcat(abspath, path_elem);
- strcat(abspath, DIR_SEP);
- strcat(abspath, name);
+ strncat(abspath, path_elem, sizeof(abspath) - strlen(abspath) - 1);
+ strncat(abspath, DIR_SEP, sizeof(abspath) - strlen(abspath) - 1);
+ strncat(abspath, name, sizeof(abspath) - strlen(abspath) - 1);
if (access(abspath, F_OK) < 0) {
continue;
}
- strncpy(result, abspath, sizeof(result));
+ strncpy(result, abspath, sizeof(result) - 1);
break;
}
path = path_orig;
@@ -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;
@@ -442,27 +444,39 @@ void msg(unsigned type, char *fmt, ...) {
// for error output
stream = stderr;
fprintf(stream, "%s", STASIS_COLOR_RED);
- strcpy(status, " ERROR: ");
+ strncpy(status, " ERROR: ", sizeof(status) - 1);
} else if (type & STASIS_MSG_WARN) {
stream = stderr;
fprintf(stream, "%s", STASIS_COLOR_YELLOW);
- strcpy(status, " WARNING: ");
+ strncpy(status, " WARNING: ", sizeof(status) - 1);
} else {
fprintf(stream, "%s", STASIS_COLOR_GREEN);
- strcpy(status, " ");
+ strncpy(status, " ", sizeof(status) - 1);
}
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);
- vfprintf(stream, fmt, args);
- fprintf(stream, "%s", STASIS_COLOR_RESET);
+ if (fprintf(stream, "%s", header) < 0) {
+ SYSERROR("%s", "unable to write message header to stream");
+ return;
+ }
+
+ const int len = vfprintf(stream, fmt, args);
+ if (len < 0) {
+ SYSERROR("%s", "unable to write message to stream");
+ return;
+ }
+
+ if (fprintf(stream, "%s", STASIS_COLOR_RESET) < 0) {
+ SYSERROR("%s", "unable to write message footer to stream");
+ return;
+ }
va_end(args);
}
@@ -482,12 +496,12 @@ char *xmkstemp(FILE **fp, const char *mode) {
char t_name[PATH_MAX * 2];
if (globals.tmpdir) {
- strcpy(tmpdir, globals.tmpdir);
+ strncpy(tmpdir, globals.tmpdir, sizeof(tmpdir) - 1);
} else {
- strcpy(tmpdir, "/tmp");
+ strncpy(tmpdir, "/tmp", sizeof(tmpdir) - 1);
}
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);
@@ -587,7 +601,7 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro
return 0;
}
memset(cmd, 0, sizeof(cmd));
- snprintf(cmd, sizeof(cmd) - 1, "%s %s %s", pretty_print_prog, pretty_print_args, filename);
+ snprintf(cmd, sizeof(cmd), "%s %s %s", pretty_print_prog, pretty_print_args, filename);
result = shell_output(cmd, &status);
if (status || !result) {
goto pretty_print_failed;
@@ -636,9 +650,10 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro
*
* @param filename /path/to/tox.ini
* @param result path of replacement tox.ini configuration
+ * @param maxlen
* @return 0 on success, -1 on error
*/
-int fix_tox_conf(const char *filename, char **result) {
+int fix_tox_conf(const char *filename, char **result, size_t maxlen) {
struct INIFILE *toxini;
FILE *fptemp;
@@ -650,7 +665,7 @@ int fix_tox_conf(const char *filename, char **result) {
// If the result pointer is NULL, allocate enough to store a filesystem path
if (!*result) {
- *result = calloc(PATH_MAX, sizeof(**result));
+ *result = calloc(maxlen, sizeof(**result));
if (!*result) {
guard_free(tempfile);
return -1;
@@ -692,7 +707,7 @@ int fix_tox_conf(const char *filename, char **result) {
return -1;
}
value = tmp;
- strcat(value, with_posargs);
+ strncat(value, with_posargs, (strlen(value) + strlen(with_posargs)) - strlen(value) - 1);
ini_setval(&toxini, INI_SETVAL_REPLACE, section_name, key, value);
}
}
@@ -707,7 +722,7 @@ int fix_tox_conf(const char *filename, char **result) {
fclose(fptemp);
// Store path to modified config
- strcpy(*result, tempfile);
+ strncpy(*result, tempfile, maxlen - 1);
guard_free(tempfile);
ini_free(&toxini);
@@ -756,7 +771,7 @@ int redact_sensitive(const char **to_redact, size_t to_redact_size, char *src, c
if (!tmp) {
return -1;
}
- strcpy(tmp, src);
+ strncpy(tmp, src, strlen(redacted) + strlen(src));
for (size_t i = 0; i < to_redact_size; i++) {
if (to_redact[i] && strstr(tmp, to_redact[i])) {
@@ -819,16 +834,15 @@ long get_cpu_count() {
int mkdirs(const char *_path, mode_t mode) {
char *token;
char pathbuf[PATH_MAX] = {0};
- char *path;
- path = pathbuf;
- strcpy(path, _path);
+ strncpy(pathbuf, _path, sizeof(pathbuf) - 1);
+ char *path = pathbuf;
errno = 0;
char result[PATH_MAX] = {0};
int status = 0;
while ((token = strsep(&path, "/")) != NULL && !status) {
- strcat(result, token);
- strcat(result, "/");
+ strncat(result, token, sizeof result - strlen(result) - 1);
+ strncat(result, "/", sizeof result - strlen(result) - 1);
status = mkdir(result, mode);
if (status && errno == EEXIST) {
status = 0;
@@ -884,10 +898,10 @@ int env_manipulate_pathstr(const char *key, char *path, int mode) {
return 0;
}
-int gen_file_extension_str(char *filename, const char *extension) {
+int gen_file_extension_str(char *filename, const size_t maxlen, const char *extension) {
char *ext_orig = strrchr(filename, '.');
if (!ext_orig) {
- strcat(filename, extension);
+ strncat(filename, extension, maxlen - strlen(filename) - 1);
return 0;
}
@@ -912,13 +926,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, " ");
+ strncat(bytes, " ", sizeof(bytes) - strlen(bytes) - 1);
}
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 +944,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) - strlen(ascii), ascii_fmt, isprint(*pos) ? *pos : '.');
pos++;
count++;
@@ -937,11 +958,11 @@ void debug_hexdump(char *data, int len) {
if (count <= 8) {
// Add group padding
- strcat(bytes, " ");
+ strncat(bytes, " ", sizeof(bytes) - strlen(bytes) - 1);
}
const int padding = 16 - count;
for (int i = 0; i < padding; i++) {
- strcat(bytes, " ");
+ strncat(bytes, " ", sizeof(bytes) - strlen(bytes) - 1);
}
snprintf(output, DEBUG_HEXDUMP_FMT_BYTES + sizeof(addr) + sizeof(bytes) + sizeof(ascii), "%s | %s | %s", addr, bytes, ascii);
puts(output);
@@ -1171,4 +1192,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..ce8ea74 100644
--- a/src/lib/core/wheelinfo.c
+++ b/src/lib/core/wheelinfo.c
@@ -6,9 +6,9 @@ struct WheelInfo *wheelinfo_get(const char *basepath, const char *name, char *to
char package_path[PATH_MAX];
char package_name[NAME_MAX];
- strcpy(package_name, name);
+ strncpy(package_name, name, sizeof(package_name) - 1);
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) {
@@ -20,7 +20,7 @@ struct WheelInfo *wheelinfo_get(const char *basepath, const char *name, char *to
continue;
}
char filename[NAME_MAX];
- strcpy(filename, rec->d_name);
+ strncpy(filename, rec->d_name, sizeof(filename) - 1);
char *ext = strstr(filename, ".whl");
if (ext) {
*ext = '\0';
diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c
index be6e8ff..7d78878 100644
--- a/src/lib/delivery/delivery.c
+++ b/src/lib/delivery/delivery.c
@@ -265,8 +265,11 @@ void delivery_free(struct Delivery *ctx) {
guard_free(ctx->_stasis_ini_fp.mission_path);
}
-int delivery_format_str(struct Delivery *ctx, char **dest, const char *fmt) {
- size_t fmt_len = strlen(fmt);
+int delivery_format_str(struct Delivery *ctx, char **dest, size_t maxlen, const char *fmt) {
+ const size_t fmt_len = strlen(fmt);
+ if (maxlen < 1) {
+ maxlen = 1;
+ }
if (!*dest) {
*dest = calloc(STASIS_NAME_MAX, sizeof(**dest));
@@ -280,47 +283,47 @@ int delivery_format_str(struct Delivery *ctx, char **dest, const char *fmt) {
i++;
switch (fmt[i]) {
case 'n': // name
- strcat(*dest, ctx->meta.name);
+ strncat(*dest, ctx->meta.name, maxlen - 1);
break;
case 'c': // codename
- strcat(*dest, ctx->meta.codename);
+ strncat(*dest, ctx->meta.codename, maxlen - 1);
break;
case 'm': // mission
- strcat(*dest, ctx->meta.mission);
+ strncat(*dest, ctx->meta.mission, maxlen - 1);
break;
case 'r': // revision
- sprintf(*dest + strlen(*dest), "%d", ctx->meta.rc);
+ snprintf(*dest + strlen(*dest), maxlen, "%d", ctx->meta.rc);
break;
case 'R': // "final"-aware revision
if (ctx->meta.final)
- strcat(*dest, "final");
+ strncat(*dest, "final", maxlen);
else
- sprintf(*dest + strlen(*dest), "%d", ctx->meta.rc);
+ snprintf(*dest + strlen(*dest), maxlen, "%d", ctx->meta.rc);
break;
case 'v': // version
- strcat(*dest, ctx->meta.version);
+ strncat(*dest, ctx->meta.version, maxlen - 1);
break;
case 'P': // python version
- strcat(*dest, ctx->meta.python);
+ strncat(*dest, ctx->meta.python, maxlen - 1);
break;
case 'p': // python version major/minor
- strcat(*dest, ctx->meta.python_compact);
+ strncat(*dest, ctx->meta.python_compact, maxlen - 1);
break;
case 'a': // system architecture name
- strcat(*dest, ctx->system.arch);
+ strncat(*dest, ctx->system.arch, maxlen - 1);
break;
case 'o': // system platform (OS) name
- strcat(*dest, ctx->system.platform[DELIVERY_PLATFORM_RELEASE]);
+ strncat(*dest, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], maxlen - 1);
break;
case 't': // unix epoch
- sprintf(*dest + strlen(*dest), "%ld", ctx->info.time_now);
+ snprintf(*dest + strlen(*dest), maxlen, "%ld", ctx->info.time_now);
break;
default: // unknown formatter, write as-is
- sprintf(*dest + strlen(*dest), "%c%c", fmt[i - 1], fmt[i]);
+ snprintf(*dest + strlen(*dest), maxlen, "%c%c", fmt[i - 1], fmt[i]);
break;
}
} else { // write non-format text
- sprintf(*dest + strlen(*dest), "%c", fmt[i]);
+ snprintf(*dest + strlen(*dest), maxlen, "%c", fmt[i]);
}
}
return 0;
@@ -335,11 +338,11 @@ void delivery_defer_packages(struct Delivery *ctx, int type) {
if (DEFER_CONDA == type) {
dataptr = ctx->conda.conda_packages;
deferred = ctx->conda.conda_packages_defer;
- strcpy(mode, "conda");
+ strncpy(mode, "conda", sizeof(mode) - 1);
} else if (DEFER_PIP == type) {
dataptr = ctx->conda.pip_packages;
deferred = ctx->conda.pip_packages_defer;
- strcpy(mode, "pip");
+ strncpy(mode, "pip", sizeof(mode) - 1);
} else {
SYSERROR("BUG: type %d does not map to a supported package manager!\n", type);
exit(1);
diff --git a/src/lib/delivery/delivery_artifactory.c b/src/lib/delivery/delivery_artifactory.c
index 97db752..0a74241 100644
--- a/src/lib/delivery/delivery_artifactory.c
+++ b/src/lib/delivery/delivery_artifactory.c
@@ -4,8 +4,8 @@ int delivery_init_artifactory(struct Delivery *ctx) {
int status = 0;
char dest[PATH_MAX] = {0};
char filepath[PATH_MAX] = {0};
- snprintf(dest, sizeof(dest) - 1, "%s/bin", ctx->storage.tools_dir);
- snprintf(filepath, sizeof(dest) - 1, "%s/bin/jf", ctx->storage.tools_dir);
+ snprintf(dest, sizeof(dest), "%s/bin", ctx->storage.tools_dir);
+ snprintf(filepath, sizeof(dest), "%s/bin/jf", ctx->storage.tools_dir);
if (!access(filepath, F_OK)) {
// already have it
@@ -32,7 +32,7 @@ int delivery_init_artifactory(struct Delivery *ctx) {
// JFROG_CLI_HOME_DIR is where .jfrog is stored
char path[PATH_MAX] = {0};
- snprintf(path, sizeof(path) - 1, "%s/.jfrog", ctx->storage.build_dir);
+ snprintf(path, sizeof(path), "%s/.jfrog", ctx->storage.build_dir);
setenv("JFROG_CLI_HOME_DIR", path, 1);
// JFROG_CLI_TEMP_DIR is where the obvious is stored
@@ -84,8 +84,8 @@ int delivery_artifact_upload(struct Delivery *ctx) {
for (size_t f = 0; f < strlist_count(ctx->deploy.jfrog[i].files); f++) {
char dest[PATH_MAX] = {0};
char files[PATH_MAX] = {0};
- snprintf(dest, sizeof(dest) - 1, "%s/%s", ctx->deploy.jfrog[i].repo, ctx->deploy.jfrog[i].dest);
- snprintf(files, sizeof(files) - 1, "%s", strlist_item(ctx->deploy.jfrog[i].files, f));
+ snprintf(dest, sizeof(dest), "%s/%s", ctx->deploy.jfrog[i].repo, ctx->deploy.jfrog[i].dest);
+ snprintf(files, sizeof(files), "%s", strlist_item(ctx->deploy.jfrog[i].files, f));
status += jfrog_cli_rt_upload(&ctx->deploy.jfrog_auth, &ctx->deploy.jfrog[i].upload_ctx, files, dest);
}
}
@@ -134,7 +134,7 @@ int delivery_mission_render_files(struct Delivery *ctx) {
guard_free(data.src);
return 1;
}
- sprintf(data.src, "%s/%s/%s", ctx->storage.mission_dir, ctx->meta.mission, val.as_char_p);
+ snprintf(data.src, PATH_MAX, "%s/%s/%s", ctx->storage.mission_dir, ctx->meta.mission, val.as_char_p);
msg(STASIS_MSG_L2, "%s\n", data.src);
int err = 0;
@@ -210,7 +210,7 @@ int delivery_series_sync(struct Delivery *ctx) {
}
char *release_pattern = NULL;
- if (delivery_format_str(ctx, &release_pattern, r_fmt) < 0) {
+ if (delivery_format_str(ctx, &release_pattern, STASIS_NAME_MAX, r_fmt) < 0) {
SYSERROR("Unable to render delivery format string: %s", r_fmt);
guard_free(r_fmt);
return -1;
diff --git a/src/lib/delivery/delivery_build.c b/src/lib/delivery/delivery_build.c
index 0a86ec4..3ff5df7 100644
--- a/src/lib/delivery/delivery_build.c
+++ b/src/lib/delivery/delivery_build.c
@@ -37,7 +37,7 @@ int delivery_build_recipes(struct Delivery *ctx) {
tag[strlen(ctx->tests->test[i]->repository_info_tag)] = '\0';
}
} else {
- strcpy(tag, ctx->tests->test[i]->version);
+ strncpy(tag, ctx->tests->test[i]->version, sizeof(tag) - 1);
}
//sprintf(recipe_version, "{%% set version = GIT_DESCRIBE_TAG ~ \".dev\" ~ GIT_DESCRIBE_NUMBER ~ \"+\" ~ GIT_DESCRIBE_HASH %%}");
@@ -48,15 +48,15 @@ int delivery_build_recipes(struct Delivery *ctx) {
// Perhaps we can key it to the recipe type, because the archive is a requirement imposed
// by conda-forge. Hmm.
- sprintf(recipe_version, "{%% set version = \"%s\" %%}", tag);
- sprintf(recipe_git_url, " url: %s/archive/refs/tags/{{ version }}.tar.gz", ctx->tests->test[i]->repository);
- strcpy(recipe_git_rev, "");
- sprintf(recipe_buildno, " number: 0");
+ 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);
+ snprintf(recipe_buildno, sizeof(recipe_buildno), " number: 0");
unsigned flags = REPLACE_TRUNCATE_AFTER_MATCH;
//file_replace_text("meta.yaml", "{% set version = ", recipe_version);
if (ctx->meta.final) { // remove this. i.e. statis cannot deploy a release to conda-forge
- sprintf(recipe_version, "{%% set version = \"%s\" %%}", ctx->tests->test[i]->version);
+ snprintf(recipe_version, sizeof(recipe_version), "{%% set version = \"%s\" %%}", ctx->tests->test[i]->version);
// TODO: replace sha256 of tagged archive
// TODO: leave the recipe unchanged otherwise. in theory this should produce the same conda package hash as conda forge.
// For now, remove the sha256 requirement
@@ -74,25 +74,25 @@ int delivery_build_recipes(struct Delivery *ctx) {
char arch[STASIS_NAME_MAX] = {0};
char platform[STASIS_NAME_MAX] = {0};
- strcpy(platform, ctx->system.platform[DELIVERY_PLATFORM]);
+ strncpy(platform, ctx->system.platform[DELIVERY_PLATFORM], sizeof(platform) - 1);
if (strstr(platform, "Darwin")) {
memset(platform, 0, sizeof(platform));
- strcpy(platform, "osx");
+ strncpy(platform, "osx", sizeof(platform) - 1);
}
tolower_s(platform);
if (strstr(ctx->system.arch, "arm64")) {
- strcpy(arch, "arm64");
+ strncpy(arch, "arm64", sizeof(arch) - 1);
} else if (strstr(ctx->system.arch, "64")) {
- strcpy(arch, "64");
+ strncpy(arch, "64", sizeof(arch) - 1);
} else {
- strcat(arch, "32"); // blind guess
+ strncat(arch, "32", sizeof(arch) - 1); // blind guess
}
tolower_s(arch);
- sprintf(command, "mambabuild --python=%s -m ../.ci_support/%s_%s_.yaml .",
+ snprintf(command, sizeof(command), "mambabuild --python=%s -m ../.ci_support/%s_%s_.yaml .",
ctx->meta.python, platform, arch);
} else {
- sprintf(command, "mambabuild --python=%s .", ctx->meta.python);
+ snprintf(command, sizeof(command), "mambabuild --python=%s .", ctx->meta.python);
}
int status = conda_exec(command);
if (status) {
@@ -131,7 +131,7 @@ int filter_repo_tags(char *repo, struct StrList *patterns) {
int match = fnmatch(pattern, tag, 0);
if (!match) {
char cmd[PATH_MAX] = {0};
- sprintf(cmd, "git tag -d %s", tag);
+ snprintf(cmd, sizeof(cmd), "git tag -d %s", tag);
result += system(cmd);
break;
}
@@ -398,7 +398,7 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) {
memset(srcdir, 0, sizeof(srcdir));
memset(wheeldir, 0, sizeof(wheeldir));
- sprintf(srcdir, "%s/%s", ctx->storage.build_sources_dir, ctx->tests->test[i]->name);
+ snprintf(srcdir, sizeof(srcdir), "%s/%s", ctx->storage.build_sources_dir, ctx->tests->test[i]->name);
if (git_clone(&proc, ctx->tests->test[i]->repository, srcdir, ctx->tests->test[i]->version)) {
SYSERROR("Unable to checkout tag '%s' for package '%s' from repository '%s'\n",
ctx->tests->test[i]->version, ctx->tests->test[i]->name, ctx->tests->test[i]->repository);
@@ -434,9 +434,9 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) {
COE_CHECK_ABORT(dep_status, "Unreproducible delivery");
}
- strcpy(dname, ctx->tests->test[i]->name);
+ strncpy(dname, ctx->tests->test[i]->name, sizeof(dname) - 1);
tolower_s(dname);
- sprintf(outdir, "%s/%s", ctx->storage.wheel_artifact_dir, dname);
+ snprintf(outdir, sizeof(outdir), "%s/%s", ctx->storage.wheel_artifact_dir, dname);
if (mkdirs(outdir, 0755)) {
fprintf(stderr, "failed to create output directory: %s\n", outdir);
guard_strlist_free(&result);
diff --git a/src/lib/delivery/delivery_conda.c b/src/lib/delivery/delivery_conda.c
index 191d93f..d6898a4 100644
--- a/src/lib/delivery/delivery_conda.c
+++ b/src/lib/delivery/delivery_conda.c
@@ -1,21 +1,32 @@
#include "delivery.h"
-void delivery_get_conda_installer_url(struct Delivery *ctx, char *result) {
+void delivery_get_conda_installer_url(struct Delivery *ctx, char *result, size_t maxlen) {
+ int len = 0;
if (ctx->conda.installer_version) {
// Use version specified by configuration file
- sprintf(result, "%s/%s-%s-%s-%s.sh", ctx->conda.installer_baseurl,
+ len = snprintf(NULL, 0, ctx->conda.installer_baseurl,
+ ctx->conda.installer_name,
+ ctx->conda.installer_version,
+ ctx->conda.installer_platform,
+ ctx->conda.installer_arch);
+
+ snprintf(result, maxlen - len, "%s/%s-%s-%s-%s.sh", ctx->conda.installer_baseurl,
ctx->conda.installer_name,
ctx->conda.installer_version,
ctx->conda.installer_platform,
ctx->conda.installer_arch);
} else {
// Use latest installer
- sprintf(result, "%s/%s-%s-%s.sh", ctx->conda.installer_baseurl,
+ len = snprintf(NULL, 0, "%s/%s-%s-%s.sh", ctx->conda.installer_baseurl,
ctx->conda.installer_name,
ctx->conda.installer_platform,
ctx->conda.installer_arch);
- }
+ snprintf(result, maxlen - len, "%s/%s-%s-%s.sh", ctx->conda.installer_baseurl,
+ ctx->conda.installer_name,
+ ctx->conda.installer_platform,
+ ctx->conda.installer_arch);
+ }
}
int delivery_get_conda_installer(struct Delivery *ctx, char *installer_url) {
@@ -23,7 +34,7 @@ int delivery_get_conda_installer(struct Delivery *ctx, char *installer_url) {
char *installer = path_basename(installer_url);
memset(script_path, 0, sizeof(script_path));
- sprintf(script_path, "%s/%s", ctx->storage.tmpdir, installer);
+ snprintf(script_path, sizeof(script_path), "%s/%s", ctx->storage.tmpdir, installer);
if (access(script_path, F_OK)) {
// Script doesn't exist
char *errmsg = NULL;
@@ -61,7 +72,7 @@ void delivery_install_conda(char *install_script, char *conda_install_dir) {
// Proceed with the installation
// -b = batch mode (non-interactive)
char cmd[PATH_MAX] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "%s %s -b -p %s",
+ snprintf(cmd, sizeof(cmd), "%s %s -b -p %s",
find_program("bash"),
install_script,
conda_install_dir);
@@ -73,7 +84,7 @@ void delivery_install_conda(char *install_script, char *conda_install_dir) {
// Proceed with the installation
// -b = batch mode (non-interactive)
char cmd[PATH_MAX] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "%s %s -b -p %s",
+ snprintf(cmd, sizeof(cmd), "%s %s -b -p %s",
find_program("bash"),
install_script,
conda_install_dir);
@@ -97,7 +108,7 @@ void delivery_conda_enable(struct Delivery *ctx, char *conda_install_dir) {
// way to make sure the file is used. Not setting this variable leads to strange
// behavior, especially if a conda environment is already active when STASIS is loaded.
char rcpath[PATH_MAX];
- sprintf(rcpath, "%s/%s", conda_install_dir, ".condarc");
+ snprintf(rcpath, sizeof(rcpath), "%s/%s", conda_install_dir, ".condarc");
setenv("CONDARC", rcpath, 1);
if (runtime_replace(&ctx->runtime.environ, __environ)) {
perror("unable to replace runtime environment after activating conda");
diff --git a/src/lib/delivery/delivery_docker.c b/src/lib/delivery/delivery_docker.c
index 2c43caf..e5f1c2f 100644
--- a/src/lib/delivery/delivery_docker.c
+++ b/src/lib/delivery/delivery_docker.c
@@ -19,7 +19,7 @@ int delivery_docker(struct Delivery *ctx) {
msg(STASIS_MSG_WARN | STASIS_MSG_L2, "No docker tags defined by configuration. Generating default tag(s).\n");
// generate local tag
memset(default_tag, 0, sizeof(default_tag));
- sprintf(default_tag, "%s:%s-py%s", ctx->meta.name, ctx->info.build_name, ctx->meta.python_compact);
+ snprintf(default_tag, sizeof(default_tag), "%s:%s-py%s", ctx->meta.name, ctx->info.build_name, ctx->meta.python_compact);
tolower_s(default_tag);
// Add tag
@@ -29,7 +29,7 @@ int delivery_docker(struct Delivery *ctx) {
if (has_registry) {
// generate tag for target registry
memset(default_tag, 0, sizeof(default_tag));
- sprintf(default_tag, "%s/%s:%s-py%s", ctx->deploy.docker.registry, ctx->meta.name, ctx->info.build_number, ctx->meta.python_compact);
+ snprintf(default_tag, sizeof(default_tag), "%s/%s:%s-py%s", ctx->deploy.docker.registry, ctx->meta.name, ctx->info.build_number, ctx->meta.python_compact);
tolower_s(default_tag);
// Add tag
@@ -44,9 +44,12 @@ int delivery_docker(struct Delivery *ctx) {
// Append image tags to command
for (size_t i = 0; i < total_tags; i++) {
char *tag_orig = strlist_item(ctx->deploy.docker.tags, i);
- strcpy(tag, tag_orig);
+ strncpy(tag, tag_orig, sizeof(tag) - 1);
docker_sanitize_tag(tag);
- sprintf(args + strlen(args), " -t \"%s\" ", tag);
+
+ const char *tag_fmt = " -t \"%s\" ";
+ const int tag_fmt_len = snprintf(NULL, 0, tag_fmt, tag);
+ snprintf(args + strlen(args), tag_fmt_len, tag_fmt, tag);
}
// Append build arguments to command (i.e. --build-arg "key=value"
@@ -55,7 +58,10 @@ int delivery_docker(struct Delivery *ctx) {
if (!build_arg) {
break;
}
- sprintf(args + strlen(args), " --build-arg \"%s\" ", build_arg);
+
+ const char *build_arg_fmt = " --build-arg \"%s\" ";
+ const int build_arg_fmt_len = snprintf(NULL, 0, build_arg_fmt, build_arg);
+ snprintf(args + strlen(args), sizeof(args) - build_arg_fmt_len, build_arg_fmt, build_arg);
}
// Build the image
@@ -65,24 +71,24 @@ int delivery_docker(struct Delivery *ctx) {
memset(delivery_file, 0, sizeof(delivery_file));
memset(dest, 0, sizeof(dest));
- sprintf(delivery_file, "%s/%s.yml", ctx->storage.delivery_dir, ctx->info.release_name);
+ snprintf(delivery_file, sizeof(delivery_file), "%s/%s.yml", ctx->storage.delivery_dir, ctx->info.release_name);
if (access(delivery_file, F_OK) < 0) {
fprintf(stderr, "docker build cannot proceed without delivery file: %s\n", delivery_file);
return -1;
}
- sprintf(dest, "%s/%s.yml", ctx->storage.build_docker_dir, ctx->info.release_name);
+ snprintf(dest, sizeof(dest), "%s/%s.yml", ctx->storage.build_docker_dir, ctx->info.release_name);
if (copy2(delivery_file, dest, CT_PERM)) {
fprintf(stderr, "Failed to copy delivery file to %s: %s\n", dest, strerror(errno));
return -1;
}
memset(dest, 0, sizeof(dest));
- sprintf(dest, "%s/packages", ctx->storage.build_docker_dir);
+ snprintf(dest, sizeof(dest), "%s/packages", ctx->storage.build_docker_dir);
msg(STASIS_MSG_L2, "Copying conda packages\n");
memset(rsync_cmd, 0, sizeof(rsync_cmd));
- sprintf(rsync_cmd, "rsync -avi --progress '%s' '%s'", ctx->storage.conda_artifact_dir, dest);
+ snprintf(rsync_cmd, sizeof(rsync_cmd), "rsync -avi --progress '%s' '%s'", ctx->storage.conda_artifact_dir, dest);
if (system(rsync_cmd)) {
fprintf(stderr, "Failed to copy conda artifacts to docker build directory\n");
return -1;
@@ -90,7 +96,7 @@ int delivery_docker(struct Delivery *ctx) {
msg(STASIS_MSG_L2, "Copying wheel packages\n");
memset(rsync_cmd, 0, sizeof(rsync_cmd));
- sprintf(rsync_cmd, "rsync -avi --progress '%s' '%s'", ctx->storage.wheel_artifact_dir, dest);
+ snprintf(rsync_cmd, sizeof(rsync_cmd), "rsync -avi --progress '%s' '%s'", ctx->storage.wheel_artifact_dir, dest);
if (system(rsync_cmd)) {
fprintf(stderr, "Failed to copy wheel artifacts to docker build directory\n");
}
@@ -102,7 +108,7 @@ int delivery_docker(struct Delivery *ctx) {
// Test the image
// All tags point back to the same image so test the first one we see
// regardless of how many are defined
- strcpy(tag, strlist_item(ctx->deploy.docker.tags, 0));
+ strncpy(tag, strlist_item(ctx->deploy.docker.tags, 0), sizeof(tag) - 1);
docker_sanitize_tag(tag);
msg(STASIS_MSG_L2, "Executing image test script for %s\n", tag);
diff --git a/src/lib/delivery/delivery_export.c b/src/lib/delivery/delivery_export.c
index d982ad5..c12a365 100644
--- a/src/lib/delivery/delivery_export.c
+++ b/src/lib/delivery/delivery_export.c
@@ -4,7 +4,7 @@ static void delivery_export_configuration(const struct Delivery *ctx) {
msg(STASIS_MSG_L2, "Exporting delivery configuration\n");
if (!pushd(ctx->storage.cfgdump_dir)) {
char filename[PATH_MAX] = {0};
- sprintf(filename, "%s.ini", ctx->info.release_name);
+ snprintf(filename, sizeof(filename), "%s.ini", ctx->info.release_name);
FILE *spec = fopen(filename, "w+");
if (!spec) {
msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "failed %s\n", filename);
@@ -14,7 +14,7 @@ static void delivery_export_configuration(const struct Delivery *ctx) {
fclose(spec);
memset(filename, 0, sizeof(filename));
- sprintf(filename, "%s-rendered.ini", ctx->info.release_name);
+ snprintf(filename, sizeof(filename), "%s-rendered.ini", ctx->info.release_name);
spec = fopen(filename, "w+");
if (!spec) {
msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "failed %s\n", filename);
diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c
index 1666f0a..ff877f0 100644
--- a/src/lib/delivery/delivery_init.c
+++ b/src/lib/delivery/delivery_init.c
@@ -174,26 +174,26 @@ int delivery_init_platform(struct Delivery *ctx) {
}
if (!strcmp(ctx->system.arch, "x86_64")) {
- strcpy(archsuffix, "64");
+ strncpy(archsuffix, "64", sizeof(archsuffix) - 1);
} else {
- strcpy(archsuffix, ctx->system.arch);
+ strncpy(archsuffix, ctx->system.arch, sizeof(archsuffix) - 1);
}
SYSDEBUG("%s", "Setting platform");
- strcpy(ctx->system.platform[DELIVERY_PLATFORM], uts.sysname);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM], uts.sysname, DELIVERY_PLATFORM_MAXLEN - 1);
if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Darwin")) {
- sprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], "osx-%s", archsuffix);
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "MacOSX");
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "macos");
+ 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);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "macos", DELIVERY_PLATFORM_MAXLEN - 1);
} else if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Linux")) {
- sprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], "linux-%s", archsuffix);
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "Linux");
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "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);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "linux", DELIVERY_PLATFORM_MAXLEN - 1);
} else {
// Not explicitly supported systems
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], ctx->system.platform[DELIVERY_PLATFORM]);
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], ctx->system.platform[DELIVERY_PLATFORM]);
- strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.platform[DELIVERY_PLATFORM]);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1);
+ strncpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.platform[DELIVERY_PLATFORM], DELIVERY_PLATFORM_MAXLEN - 1);
tolower_s(ctx->system.platform[DELIVERY_PLATFORM_RELEASE]);
}
@@ -203,7 +203,7 @@ int delivery_init_platform(struct Delivery *ctx) {
cpu_count = 1;
}
char ncpus[100] = {0};
- sprintf(ncpus, "%ld", cpu_count);
+ snprintf(ncpus, sizeof(ncpus), "%ld", cpu_count);
// Declare some important bits as environment variables
setenv("CPU_COUNT", ncpus, 1);
@@ -252,16 +252,16 @@ int delivery_init(struct Delivery *ctx, int render_mode) {
delivery_init_dirs_stage1(ctx);
char config_local[PATH_MAX];
- sprintf(config_local, "%s/%s", ctx->storage.tmpdir, "config");
+ snprintf(config_local, sizeof(config_local), "%s/%s", ctx->storage.tmpdir, "config");
setenv("XDG_CONFIG_HOME", config_local, 1);
char cache_local[PATH_MAX];
- sprintf(cache_local, "%s/%s", ctx->storage.tmpdir, "cache");
+ snprintf(cache_local, sizeof(cache_local), "%s/%s", ctx->storage.tmpdir, "cache");
setenv("XDG_CACHE_HOME", cache_local, 1);
// add tools to PATH
char pathvar_tmp[STASIS_BUFSIZ];
- sprintf(pathvar_tmp, "%s/bin:%s", ctx->storage.tools_dir, getenv("PATH"));
+ snprintf(pathvar_tmp, sizeof(pathvar_tmp), "%s/bin:%s", ctx->storage.tools_dir, getenv("PATH"));
setenv("PATH", pathvar_tmp, 1);
// Prevent git from paginating output
@@ -336,7 +336,7 @@ int bootstrap_build_info(struct Delivery *ctx) {
int delivery_exists(struct Delivery *ctx) {
int release_exists = DELIVERY_NOT_FOUND;
char release_pattern[PATH_MAX] = {0};
- sprintf(release_pattern, "*%s*", ctx->info.release_name);
+ snprintf(release_pattern, sizeof(release_pattern), "*%s*", ctx->info.release_name);
if (globals.enable_artifactory) {
if (jfrt_auth_init(&ctx->deploy.jfrog_auth)) {
diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c
index 2de80cf..1e2b82c 100644
--- a/src/lib/delivery/delivery_install.c
+++ b/src/lib/delivery/delivery_install.c
@@ -145,16 +145,16 @@ int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_
case PKG_USE_CONDA:
fn = conda_exec;
list = ctx->conda.conda_packages_purge;
- strcpy(package_manager, "conda");
+ strncpy(package_manager, "conda", sizeof(package_manager) - 1);
// conda is already configured for "always_yes"
- strcpy(subcommand, "remove");
+ strncpy(subcommand, "remove", sizeof(subcommand) - 1);
break;
case PKG_USE_PIP:
fn = pip_exec;
list = ctx->conda.pip_packages_purge;
- strcpy(package_manager, "pip");
+ strncpy(package_manager, "pip", sizeof(package_manager) - 1);
// avoid user prompt to remove packages
- strcpy(subcommand, "uninstall -y");
+ strncpy(subcommand, "uninstall -y", sizeof(subcommand) - 1);
break;
default:
SYSERROR("Unknown package manager: %d", use_pkg_manager);
@@ -203,7 +203,7 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
memset(command_base, 0, sizeof(command_base));
- strcat(command_base, "install");
+ strncat(command_base, "install", sizeof(command_base) - strlen(command_base) - 1);
typedef int (*Runner)(const char *);
Runner runner = NULL;
@@ -214,15 +214,17 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
}
if (INSTALL_PKG_CONDA_DEFERRED & type) {
- strcat(command_base, " --use-local");
+ strncat(command_base, " --use-local", sizeof(command_base) - strlen(command_base) - 1);
} else if (INSTALL_PKG_PIP_DEFERRED & type) {
// Don't change the baseline package set unless we're working with a
// new build. Release candidates will need to keep packages as stable
// as possible between releases.
if (!ctx->meta.based_on) {
- strcat(command_base, " --upgrade");
+ strncat(command_base, " --upgrade", sizeof(command_base) - strlen(command_base) - 1);
}
- sprintf(command_base + strlen(command_base), " --extra-index-url 'file://%s'", ctx->storage.wheel_artifact_dir);
+ const char *command_base_fmt = " --extra-index-url 'file://%s'";
+ const int len = snprintf(NULL, 0, command_base_fmt, ctx->storage.wheel_artifact_dir);
+ snprintf(command_base + strlen(command_base), sizeof(command_base) - len, command_base_fmt, ctx->storage.wheel_artifact_dir);
}
size_t args_alloc_len = STASIS_BUFSIZ;
@@ -287,9 +289,9 @@ int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, cha
char req[255] = {0};
if (!strcmp(name, info->name)) {
- strcpy(req, info->name);
+ strncpy(req, info->name, sizeof(req) - 1);
} else {
- strcpy(req, name);
+ strncpy(req, name, sizeof(req) - 1);
char *spec = find_version_spec(req);
if (spec) {
*spec = 0;
diff --git a/src/lib/delivery/delivery_populate.c b/src/lib/delivery/delivery_populate.c
index d41e3a4..3ce29e9 100644
--- a/src/lib/delivery/delivery_populate.c
+++ b/src/lib/delivery/delivery_populate.c
@@ -256,16 +256,16 @@ int populate_delivery_ini(struct Delivery *ctx, int render_mode) {
return -1;
}
- if (delivery_format_str(ctx, &ctx->info.release_name, ctx->rules.release_fmt)) {
+ if (delivery_format_str(ctx, &ctx->info.release_name, STASIS_NAME_MAX, ctx->rules.release_fmt)) {
fprintf(stderr, "Failed to generate release name. Format used: %s\n", ctx->rules.release_fmt);
return -1;
}
if (!ctx->info.build_name) {
- delivery_format_str(ctx, &ctx->info.build_name, ctx->rules.build_name_fmt);
+ delivery_format_str(ctx, &ctx->info.build_name, STASIS_NAME_MAX, ctx->rules.build_name_fmt);
}
if (!ctx->info.build_number) {
- delivery_format_str(ctx, &ctx->info.build_number, ctx->rules.build_number_fmt);
+ delivery_format_str(ctx, &ctx->info.build_number, STASIS_NAME_MAX, ctx->rules.build_number_fmt);
}
// Best I can do to make output directories unique. Annoying.
@@ -376,10 +376,10 @@ int populate_mission_ini(struct Delivery **ctx, int render_mode) {
// Now populate the rules
char missionfile[PATH_MAX] = {0};
if (getenv("STASIS_SYSCONFDIR")) {
- sprintf(missionfile, "%s/%s/%s/%s.ini",
+ snprintf(missionfile, sizeof(missionfile), "%s/%s/%s/%s.ini",
getenv("STASIS_SYSCONFDIR"), "mission", (*ctx)->meta.mission, (*ctx)->meta.mission);
} else {
- sprintf(missionfile, "%s/%s/%s/%s.ini",
+ snprintf(missionfile, sizeof(missionfile), "%s/%s/%s/%s.ini",
globals.sysconfdir, "mission", (*ctx)->meta.mission, (*ctx)->meta.mission);
}
diff --git a/src/lib/delivery/delivery_postprocess.c b/src/lib/delivery/delivery_postprocess.c
index a7bb2b4..8cb4e65 100644
--- a/src/lib/delivery/delivery_postprocess.c
+++ b/src/lib/delivery/delivery_postprocess.c
@@ -11,7 +11,7 @@ char *delivery_get_release_header(struct Delivery *ctx) {
char output[STASIS_BUFSIZ];
char stamp[100];
strftime(stamp, sizeof(stamp) - 1, "%c", ctx->info.time_info);
- sprintf(output, release_header,
+ snprintf(output, sizeof(output), release_header,
ctx->info.release_name,
ctx->rules.release_fmt,
stamp,
@@ -22,7 +22,7 @@ char *delivery_get_release_header(struct Delivery *ctx) {
int delivery_dump_metadata(struct Delivery *ctx) {
char filename[PATH_MAX];
- sprintf(filename, "%s/meta-%s.stasis", ctx->storage.meta_dir, ctx->info.release_name);
+ snprintf(filename, sizeof(filename), "%s/meta-%s.stasis", ctx->storage.meta_dir, ctx->info.release_name);
FILE *fp = fopen(filename, "w+");
if (!fp) {
return -1;
@@ -143,7 +143,7 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
file_replace_text(filename, "@CONDA_CHANNEL@", ctx->storage.conda_staging_url, 0);
} else if (globals.jfrog.repo) {
SYSDEBUG("%s", "Will replace conda channel with artifactory repo packages/conda url");
- sprintf(output, "%s/%s/%s/%s/packages/conda", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
+ snprintf(output, sizeof(output), "%s/%s/%s/%s/packages/conda", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@CONDA_CHANNEL@", output, 0);
} else {
SYSDEBUG("%s", "Will replace conda channel with local conda artifact directory");
@@ -153,16 +153,16 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
if (ctx->storage.wheel_staging_url) {
SYSDEBUG("%s", "Will replace pip arguments with wheel staging url");
- sprintf(output, "--extra-index-url %s/%s/%s/packages/wheels", ctx->storage.wheel_staging_url, ctx->meta.mission, ctx->info.build_name);
+ snprintf(output, sizeof(output), "--extra-index-url %s/%s/%s/packages/wheels", ctx->storage.wheel_staging_url, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@PIP_ARGUMENTS@", ctx->storage.wheel_staging_url, 0);
} else if (globals.enable_artifactory && globals.jfrog.url && globals.jfrog.repo) {
SYSDEBUG("%s", "Will replace pip arguments with artifactory repo packages/wheel url");
- sprintf(output, "--extra-index-url %s/%s/%s/%s/packages/wheels", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
+ snprintf(output, sizeof(output), "--extra-index-url %s/%s/%s/%s/packages/wheels", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@PIP_ARGUMENTS@", output, 0);
} else {
SYSDEBUG("%s", "Will replace pip arguments with local wheel artifact directory");
msg(STASIS_MSG_WARN, "wheel_staging_dir is not configured. Using fallback: '%s'\n", ctx->storage.wheel_artifact_dir);
- sprintf(output, "--extra-index-url file://%s", ctx->storage.wheel_artifact_dir);
+ snprintf(output, sizeof(output), "--extra-index-url file://%s", ctx->storage.wheel_artifact_dir);
file_replace_text(filename, "@PIP_ARGUMENTS@", output, 0);
}
}
@@ -177,7 +177,7 @@ int delivery_copy_conda_artifacts(struct Delivery *ctx) {
memset(conda_build_dir, 0, sizeof(conda_build_dir));
memset(subdir, 0, sizeof(subdir));
- sprintf(conda_build_dir, "%s/%s", ctx->storage.conda_install_prefix, "conda-bld");
+ snprintf(conda_build_dir, sizeof(conda_build_dir), "%s/%s", ctx->storage.conda_install_prefix, "conda-bld");
// One must run conda build at least once to create the "conda-bld" directory.
// When this directory is missing there can be no build artifacts.
if (access(conda_build_dir, F_OK) < 0) {
@@ -186,7 +186,7 @@ int delivery_copy_conda_artifacts(struct Delivery *ctx) {
return 0;
}
- snprintf(cmd, sizeof(cmd) - 1, "rsync -avi --progress %s/%s %s",
+ snprintf(cmd, sizeof(cmd), "rsync -avi --progress %s/%s %s",
conda_build_dir,
ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR],
ctx->storage.conda_artifact_dir);
@@ -200,7 +200,7 @@ int delivery_index_conda_artifacts(struct Delivery *ctx) {
int delivery_copy_wheel_artifacts(struct Delivery *ctx) {
char cmd[PATH_MAX] = {0};
- snprintf(cmd, sizeof(cmd) - 1, "rsync -avi --progress %s/*/dist/*.whl %s",
+ snprintf(cmd, sizeof(cmd), "rsync -avi --progress %s/*/dist/*.whl %s",
ctx->storage.build_sources_dir,
ctx->storage.wheel_artifact_dir);
return system(cmd);
@@ -217,7 +217,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
// Generate a "dumb" local pypi index that is compatible with:
// pip install --extra-index-url
char top_index[PATH_MAX] = {0};
- sprintf(top_index, "%s/index.html", ctx->storage.wheel_artifact_dir);
+ snprintf(top_index, sizeof(top_index),"%s/index.html", ctx->storage.wheel_artifact_dir);
SYSDEBUG("Opening top-level index for writing: %s", top_index);
FILE *top_fp = fopen(top_index, "w+");
if (!top_fp) {
@@ -232,7 +232,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
}
char bottom_index[PATH_MAX * 2] = {0};
- sprintf(bottom_index, "%s/%s/index.html", ctx->storage.wheel_artifact_dir, rec->d_name);
+ snprintf(bottom_index, sizeof(bottom_index), "%s/%s/index.html", ctx->storage.wheel_artifact_dir, rec->d_name);
SYSDEBUG("Opening bottom-level for writing: %s", bottom_index);
FILE *bottom_fp = fopen(bottom_index, "w+");
if (!bottom_fp) {
@@ -248,7 +248,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
fprintf(top_fp, "<a href=\"%s/\">%s</a><br/>\n", rec->d_name, rec->d_name);
char dpath[PATH_MAX * 2] = {0};
- sprintf(dpath, "%s/%s", ctx->storage.wheel_artifact_dir, rec->d_name);
+ snprintf(dpath, sizeof(dpath), "%s/%s", ctx->storage.wheel_artifact_dir, rec->d_name);
struct StrList *packages = listdir(dpath);
if (!packages) {
closedir(dp);
diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c
index 96dbb10..a088cd7 100644
--- a/src/lib/delivery/delivery_test.c
+++ b/src/lib/delivery/delivery_test.c
@@ -156,7 +156,7 @@ void delivery_tests_run(struct Delivery *ctx) {
}
char destdir[PATH_MAX];
- sprintf(destdir, "%s/%s", ctx->storage.build_sources_dir, path_basename(test->repository));
+ snprintf(destdir, sizeof(destdir), "%s/%s", ctx->storage.build_sources_dir, path_basename(test->repository));
if (!access(destdir, F_OK)) {
msg(STASIS_MSG_L3, "Purging repository %s\n", destdir);
@@ -200,11 +200,11 @@ void delivery_tests_run(struct Delivery *ctx) {
msg(STASIS_MSG_L3, "Queuing task for %s\n", test->name);
memset(&proc, 0, sizeof(proc));
- strcpy(cmd, test->script);
+ strncpy(cmd, test->script, strlen(test->script) + STASIS_BUFSIZ - 1);
char *cmd_rendered = tpl_render(cmd);
if (cmd_rendered) {
if (strcmp(cmd_rendered, cmd) != 0) {
- strcpy(cmd, cmd_rendered);
+ strncpy(cmd, cmd_rendered, strlen(test->script) + STASIS_BUFSIZ - 1);
cmd[strlen(cmd_rendered) ? strlen(cmd_rendered) - 1 : 0] = 0;
}
guard_free(cmd_rendered);
@@ -229,7 +229,7 @@ void delivery_tests_run(struct Delivery *ctx) {
if (!globals.enable_parallel || !test->parallel) {
selected = SERIAL;
memset(pool_name, 0, sizeof(pool_name));
- strcpy(pool_name, "serial");
+ strncpy(pool_name, "serial", sizeof(pool_name) - 1);
}
if (asprintf(&runner_cmd, runner_cmd_fmt, cmd) < 0) {
@@ -267,7 +267,7 @@ void delivery_tests_run(struct Delivery *ctx) {
const struct Test *test = ctx->tests->test[i];
if (test->script_setup) {
char destdir[PATH_MAX];
- sprintf(destdir, "%s/%s", ctx->storage.build_sources_dir, path_basename(test->repository));
+ snprintf(destdir, sizeof(destdir), "%s/%s", ctx->storage.build_sources_dir, path_basename(test->repository));
if (access(destdir, F_OK)) {
SYSERROR("%s: %s", destdir, strerror(errno));
exit(1);
@@ -382,7 +382,7 @@ int delivery_fixup_test_results(struct Delivery *ctx) {
continue;
}
- sprintf(path, "%s/%s", ctx->storage.results_dir, rec->d_name);
+ snprintf(path, sizeof(path), "%s/%s", ctx->storage.results_dir, rec->d_name);
msg(STASIS_MSG_L3, "%s\n", rec->d_name);
if (xml_pretty_print_in_place(path, STASIS_XML_PRETTY_PRINT_PROG, STASIS_XML_PRETTY_PRINT_ARGS)) {
msg(STASIS_MSG_L3 | STASIS_MSG_WARN, "Failed to rewrite file '%s'\n", rec->d_name);
diff --git a/src/lib/delivery/include/delivery.h b/src/lib/delivery/include/delivery.h
index 68f4b14..e524f4d 100644
--- a/src/lib/delivery/include/delivery.h
+++ b/src/lib/delivery/include/delivery.h
@@ -321,9 +321,10 @@ int delivery_get_conda_installer(struct Delivery *ctx, char *installer_url);
* Generate URL based on Delivery context
* @param ctx pointer to Delivery context
* @param result pointer to char
+ * @param maxlen
* @return in result
*/
-void delivery_get_conda_installer_url(struct Delivery *ctx, char *result);
+void delivery_get_conda_installer_url(struct Delivery *ctx, char *result, size_t maxlen);
/**
* Install packages based on Delivery context
@@ -394,10 +395,11 @@ void delivery_install_conda(char *install_script, char *conda_install_dir);
*
* @param ctx pointer to Delivery context
* @param dest NULL pointer to string, or initialized string
+ * @param maxlen
* @param fmt release format string
* @return 0 on success, -1 on error
*/
-int delivery_format_str(struct Delivery *ctx, char **dest, const char *fmt);
+int delivery_format_str(struct Delivery *ctx, char **dest, size_t maxlen, const char *fmt);
// helper function
int delivery_gather_tool_versions(struct Delivery *ctx);
diff --git a/tests/test_artifactory.c b/tests/test_artifactory.c
index 202a67c..fadc9f1 100644
--- a/tests/test_artifactory.c
+++ b/tests/test_artifactory.c
@@ -15,14 +15,14 @@ const char *gbuild_num = "1";
static int jfrog_cli_rt_build_delete(struct JFRT_Auth *auth, char *build_name, char *build_num) {
char cmd[STASIS_BUFSIZ];
memset(cmd, 0, sizeof(cmd));
- snprintf(cmd, sizeof(cmd) - 1, "--build \"%s/%s\"", build_name, build_num);
+ snprintf(cmd, sizeof(cmd), "--build \"%s/%s\"", build_name, build_num);
return jfrog_cli(auth, "rt", "delete", cmd);
}
static int jfrog_cli_rt_delete(struct JFRT_Auth *auth, char *pattern) {
char cmd[STASIS_BUFSIZ];
memset(cmd, 0, sizeof(cmd));
- snprintf(cmd, sizeof(cmd) - 1, "\"%s\"", pattern);
+ snprintf(cmd, sizeof(cmd), "\"%s\"", pattern);
return jfrog_cli(auth, "rt", "delete", cmd);
}
@@ -60,7 +60,7 @@ void test_jfrog_cli_rt_download() {
char *filename = "empty_file_upload.txt";
char path[PATH_MAX] = {0};
- sprintf(path, "%s/%s", getenv("STASIS_JF_REPO"), filename);
+ snprintf(path, sizeof(path), "%s/%s", getenv("STASIS_JF_REPO"), filename);
STASIS_ASSERT(jfrog_cli_rt_download(&gauth, &dl, filename, ".") == 0, "jf download failed");
STASIS_ASSERT(jfrog_cli_rt_delete(&gauth, path) == 0, "jf delete test artifact failed");
}
@@ -93,15 +93,15 @@ int main(int argc, char *argv[]) {
}
char path[PATH_MAX] = {0};
- sprintf(path, "%s/bin:%s", ctx.storage.tools_dir, getenv("PATH"));
+ snprintf(path, sizeof(path), "%s/bin:%s", ctx.storage.tools_dir, getenv("PATH"));
setenv("PATH", path, 1);
// The default config contains the URL information to download jfrog-cli
char cfg_path[PATH_MAX] = {0};
if (strstr(sysconfdir, "..")) {
- sprintf(cfg_path, "%s/%s/stasis.ini", basedir, sysconfdir);
+ snprintf(cfg_path, sizeof(cfg_path), "%s/%s/stasis.ini", basedir, sysconfdir);
} else {
- sprintf(cfg_path, "%s/stasis.ini", sysconfdir);
+ snprintf(cfg_path, sizeof(cfg_path), "%s/stasis.ini", sysconfdir);
}
ctx._stasis_ini_fp.cfg = ini_open(cfg_path);
if (!ctx._stasis_ini_fp.cfg) {
diff --git a/tests/test_conda.c b/tests/test_conda.c
index 1d05e7e..9f0e718 100644
--- a/tests/test_conda.c
+++ b/tests/test_conda.c
@@ -40,7 +40,7 @@ struct Delivery ctx;
void test_conda_installation() {
char *install_url = calloc(255, sizeof(install_url));
- delivery_get_conda_installer_url(&ctx, install_url);
+ delivery_get_conda_installer_url(&ctx, install_url, PATH_MAX);
delivery_get_conda_installer(&ctx, install_url);
delivery_install_conda(ctx.conda.installer_path, ctx.storage.conda_install_prefix);
@@ -92,7 +92,7 @@ void test_conda_exec() {
void test_python_exec() {
const char *python_system_path = find_program("python3");
char python_path[PATH_MAX];
- sprintf(python_path, "%s/bin/python3", ctx.storage.conda_install_prefix);
+ snprintf(python_path, sizeof(python_path), "%s/bin/python3", ctx.storage.conda_install_prefix);
STASIS_ASSERT(strcmp(python_path, python_system_path ? python_system_path : "/not/found") == 0, "conda is not configured correctly.");
STASIS_ASSERT(python_exec("-V") == 0, "python is broken");
diff --git a/tests/test_environment.c b/tests/test_environment.c
index 4f36883..9a503c0 100644
--- a/tests/test_environment.c
+++ b/tests/test_environment.c
@@ -58,7 +58,7 @@ void test_runtime() {
char output_truth[BUFSIZ] = {0};
char *your_path = runtime_get(env, "PATH");
- sprintf(output_truth, "Your PATH is '%s'.", your_path);
+ snprintf(output_truth, sizeof(output_truth), "Your PATH is '%s'.", your_path);
guard_free(your_path);
char *output_expanded = runtime_expand_var(env, "Your PATH is '${PATH}'.");
diff --git a/tests/test_junitxml.c b/tests/test_junitxml.c
index 362cb32..0bbbefb 100644
--- a/tests/test_junitxml.c
+++ b/tests/test_junitxml.c
@@ -4,7 +4,7 @@
void test_junitxml_testsuite_read() {
struct JUNIT_Testsuite *testsuite;
char datafile[PATH_MAX] = {0};
- snprintf(datafile, sizeof(datafile) - 1, "%s/result.xml", TEST_DATA_DIR);
+ snprintf(datafile, sizeof(datafile), "%s/result.xml", TEST_DATA_DIR);
STASIS_ASSERT_FATAL((testsuite = junitxml_testsuite_read(datafile)) != NULL, "failed to load testsuite data");
STASIS_ASSERT(testsuite->name != NULL, "Test suite must be named");
@@ -48,7 +48,7 @@ void test_junitxml_testsuite_read() {
void test_junitxml_testsuite_read_error() {
struct JUNIT_Testsuite *testsuite;
char datafile[PATH_MAX] = {0};
- snprintf(datafile, sizeof(datafile) - 1, "%s/result_error.xml", TEST_DATA_DIR);
+ snprintf(datafile, sizeof(datafile), "%s/result_error.xml", TEST_DATA_DIR);
STASIS_ASSERT_FATAL((testsuite = junitxml_testsuite_read(datafile)) != NULL, "failed to load testsuite data");
STASIS_ASSERT(testsuite->name != NULL, "test suite must be named");
diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c
index 3a462f1..767a9e0 100644
--- a/tests/test_multiprocessing.c
+++ b/tests/test_multiprocessing.c
@@ -65,7 +65,7 @@ void test_mp_task() {
for (size_t i = 0; i < sizeof(commands) / sizeof(*commands); i++) {
struct MultiProcessingTask *task;
char task_name[100] = {0};
- sprintf(task_name, "mytask%zu", i);
+ snprintf(task_name, sizeof(task_name), "mytask%zu", i);
STASIS_ASSERT_FATAL((task = mp_pool_task(pool, task_name, NULL, commands[i])) != NULL, "Task should not be NULL");
STASIS_ASSERT(task->pid == MP_POOL_PID_UNUSED, "PID should be non-zero at this point");
STASIS_ASSERT(task->parent_pid == MP_POOL_PID_UNUSED, "Parent PID should be non-zero");
@@ -137,7 +137,7 @@ void test_mp_fail_fast() {
for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) {
char *command = commands_ff[i];
char taskname[100] = {0};
- snprintf(taskname, sizeof(taskname) - 1, "task_%03zu", i);
+ snprintf(taskname, sizeof(taskname), "task_%03zu", i);
STASIS_ASSERT(mp_pool_task(p, taskname, NULL, (char *) command) != NULL, "Failed to queue task");
}
diff --git a/tests/test_recipe.c b/tests/test_recipe.c
index fc7cc78..3ea21ce 100644
--- a/tests/test_recipe.c
+++ b/tests/test_recipe.c
@@ -4,7 +4,7 @@
static void make_local_recipe(const char *localdir) {
char path[PATH_MAX] = {0};
- sprintf(path, "./%s", localdir);
+ snprintf(path, sizeof(path), "./%s", localdir);
mkdir(path, 0755);
if (!pushd(path)) {
touch("meta.yaml");
diff --git a/tests/test_relocation.c b/tests/test_relocation.c
index a6c33f2..69142dc 100644
--- a/tests/test_relocation.c
+++ b/tests/test_relocation.c
@@ -14,9 +14,12 @@ void test_replace_text() {
const char *target = targets[i];
const char *expected = targets[i + 1];
char input[BUFSIZ] = {0};
- strcpy(input, test_string);
+ strncpy(input, test_string, sizeof(input) - 1);
+ printf("input: %s\n", input);
+ printf("target: %s\n", target);
STASIS_ASSERT(replace_text(input, target, "^^^", 0) == 0, "string replacement failed");
+ printf("result: %s\n\n", input);
STASIS_ASSERT(strcmp(input, expected) == 0, "unexpected replacement");
}
diff --git a/tests/test_str.c b/tests/test_str.c
index a98a34d..aac5d71 100644
--- a/tests/test_str.c
+++ b/tests/test_str.c
@@ -37,7 +37,7 @@ void test_tolower_s() {
for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
char input[100] = {0};
- strcpy(input, tc[i].data);
+ strncpy(input, tc[i].data, sizeof(input) - 1);
tolower_s(input);
STASIS_ASSERT(strcmp(input, tc[i].expected) == 0, "unexpected result");
}
@@ -317,9 +317,8 @@ void test_lstrip() {
STASIS_ASSERT(lstrip(NULL) == NULL, "incorrect return type");
for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
char *buf = calloc(255, sizeof(*buf));
- char *result;
- strcpy(buf, tc[i].data);
- result = lstrip(buf);
+ strncpy(buf, tc[i].data, 254);
+ char *result = lstrip(buf);
STASIS_ASSERT(strcmp(result ? result : "", tc[i].expected) == 0, "incorrect strip-from-left");
guard_free(buf);
}
@@ -342,9 +341,8 @@ void test_strip() {
STASIS_ASSERT(strip(NULL) == NULL, "incorrect return type");
for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
char *buf = calloc(255, sizeof(*buf));
- char *result;
- strcpy(buf, tc[i].data);
- result = strip(buf);
+ strncpy(buf, tc[i].data, 254);
+ char *result = strip(buf);
STASIS_ASSERT(strcmp(result ? result : "", tc[i].expected) == 0, "incorrect strip-from-right");
guard_free(buf);
}
diff --git a/tests/test_system.c b/tests/test_system.c
index 2271e13..9e4a862 100644
--- a/tests/test_system.c
+++ b/tests/test_system.c
@@ -54,7 +54,7 @@ void test_shell_safe_verify_restrictions() {
char cmd[PATH_MAX] = {0};
memset(&proc, 0, sizeof(proc));
- sprintf(cmd, "true%c false", invalid_chars[i]);
+ snprintf(cmd, sizeof(cmd), "true%c false", invalid_chars[i]);
shell_safe(&proc, cmd);
STASIS_ASSERT(proc.returncode == -1, "expected a negative result due to intentional error");
}
diff --git a/tests/test_template.c b/tests/test_template.c
index 596c2b7..e8f0c1d 100644
--- a/tests/test_template.c
+++ b/tests/test_template.c
@@ -10,8 +10,9 @@ static int adder(struct tplfunc_frame *frame, void *result) {
int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10);
int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10);
char **ptr = (char **) result;
- *ptr = calloc(100, sizeof(*ptr));
- sprintf(*ptr, "%d", a + b);
+ const size_t sz = 100;
+ *ptr = calloc(sz, sizeof(*ptr));
+ snprintf(*ptr, sz, "%d", a + b);
return 0;
}
@@ -19,8 +20,9 @@ static int subtractor(struct tplfunc_frame *frame, void *result) {
int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10);
int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10);
char **ptr = (char **) result;
- *ptr = calloc(100, sizeof(*ptr));
- sprintf(*ptr, "%d", a - b);
+ const size_t sz = 100;
+ *ptr = calloc(sz, sizeof(*ptr));
+ snprintf(*ptr, sz, "%d", a - b);
return 0;
}
@@ -28,8 +30,9 @@ static int multiplier(struct tplfunc_frame *frame, void *result) {
int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10);
int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10);
char **ptr = (char **) result;
- *ptr = calloc(100, sizeof(*ptr));
- sprintf(*ptr, "%d", a * b);
+ const size_t sz = 100;
+ *ptr = calloc(sz, sizeof(*ptr));
+ snprintf(*ptr, sz, "%d", a * b);
return 0;
}
@@ -37,8 +40,9 @@ static int divider(struct tplfunc_frame *frame, void *result) {
int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10);
int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10);
char **ptr = (char **) result;
- *ptr = calloc(100, sizeof(*ptr));
- sprintf(*ptr, "%d", a / b);
+ size_t sz = 100;
+ *ptr = calloc(sz, sizeof(*ptr));
+ snprintf(*ptr, sz, "%d", a / b);
return 0;
}
@@ -57,6 +61,19 @@ void test_tpl_workflow() {
STASIS_ASSERT(strcmp(result, "Hello environment!") == 0, "environment variable content mismatch");
guard_free(result);
unsetenv("HELLO");
+
+ const char *message_file = "message.txt";
+ char message_fmt[] = "They wanted a {{ hello_message }} "
+ "So we gave them a {{ hello_message }}";
+ const char *message_expected = "They wanted a Hello world! "
+ "So we gave them a Hello world!";
+ const int state = tpl_render_to_file(message_fmt, message_file);
+ STASIS_ASSERT_FATAL(state == 0, "failed to write rendered string to file");
+ char *message_contents = stasis_testing_read_ascii(message_file);
+ STASIS_ASSERT(strcmp(message_contents, message_expected) == 0, "message in file does not match original message");
+ guard_free(message_contents);
+ remove(message_file);
+
guard_free(data);
}
@@ -68,6 +85,8 @@ void test_tpl_register() {
STASIS_ASSERT(tpl_pool_used == (used_before_register + 1), "tpl_register did not increment allocation counter");
STASIS_ASSERT(tpl_pool[used_before_register] != NULL, "register did not allocate a tpl_item record in the pool");
+ const char *message = tpl_getval("hello_message");
+ STASIS_ASSERT(strcmp(message, "Hello world!") == 0, "stored message corrupt");
free(data);
}
@@ -92,25 +111,25 @@ void test_tpl_register_func() {
char *result = NULL;
result = tpl_render("{{ func:add(0,3) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "add: Answer was not 3");
guard_free(result);
result = tpl_render("{{ func:add(1,2) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "add: Answer was not 3");
guard_free(result);
result = tpl_render("{{ func:sub(6,3) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "sub: was not 3");
guard_free(result);
result = tpl_render("{{ func:sub(4,1) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "sub: Answer was not 3");
guard_free(result);
result = tpl_render("{{ func:mul(1, 3) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "mul: Answer was not 3");
guard_free(result);
result = tpl_render("{{ func:div(6,2) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "div: Answer was not 3");
guard_free(result);
result = tpl_render("{{ func:div(3,1) }}");
- STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "div: Answer was not 3");
guard_free(result);
}
diff --git a/tests/test_utils.c b/tests/test_utils.c
index cfe79e0..7361139 100644
--- a/tests/test_utils.c
+++ b/tests/test_utils.c
@@ -65,7 +65,7 @@ void test_fix_tox_conf() {
if (fp) {
fprintf(fp, "%s", data);
fclose(fp);
- STASIS_ASSERT(fix_tox_conf(filename, &result) == 0, "fix_tox_conf failed");
+ STASIS_ASSERT(fix_tox_conf(filename, &result, PATH_MAX) == 0, "fix_tox_conf failed");
} else {
STASIS_ASSERT(false, "writing mock tox.ini failed");
}
@@ -129,7 +129,7 @@ void test_isempty_dir() {
STASIS_ASSERT(isempty_dir(dname) > 0, "empty directory went undetected");
char path[PATH_MAX];
- sprintf(path, "%s/file.txt", dname);
+ snprintf(path, sizeof(path), "%s/file.txt", dname);
touch(path);
STASIS_ASSERT(isempty_dir(dname) == 0, "populated directory went undetected");
@@ -147,7 +147,9 @@ void test_xmkstemp() {
char buf[100] = {0};
tempfp = fopen(tempfile, "r");
- fgets(buf, sizeof(buf) - 1, tempfp);
+ const char *line = fgets(buf, sizeof(buf) - 1, tempfp);
+ STASIS_ASSERT_FATAL(line != NULL, "file should contain data written earlier");
+ STASIS_ASSERT(strcmp(line, buf) == 0, "file should contain the correct data");
fclose(tempfp);
STASIS_ASSERT(strcmp(buf, data) == 0, "data written to temp file is incorrect");
@@ -193,7 +195,7 @@ void test_git_clone_and_describe() {
// initialize a bare repo so we can clone it
char init_cmd[PATH_MAX];
- sprintf(init_cmd, "git init --bare %s", repo_git);
+ snprintf(init_cmd, sizeof(init_cmd), "git init --bare %s", repo_git);
system(init_cmd);
// clone the bare repo
@@ -308,7 +310,7 @@ void test_path_dirname() {
const char *input = data[i];
const char *expected = data[i + 1];
char tmp[PATH_MAX] = {0};
- strcpy(tmp, input);
+ strncpy(tmp, input, sizeof(tmp) - 1);
char *result = path_dirname(tmp);
STASIS_ASSERT(strcmp(expected, result) == 0, NULL);
@@ -329,8 +331,7 @@ void test_path_basename() {
}
void test_expandpath() {
- char *home;
-
+ char *home = NULL;
const char *homes[] = {
"HOME",
"USERPROFILE",
@@ -341,10 +342,11 @@ void test_expandpath() {
break;
}
}
+ STASIS_ASSERT_FATAL(home != NULL, "cannot expand without knowing the user's home directory path");
char path[PATH_MAX] = {0};
- strcat(path, "~");
- strcat(path, DIR_SEP);
+ strncat(path, "~", sizeof(path) - strlen(path) - 1);
+ strncat(path, DIR_SEP, sizeof(path) - strlen(path) - 1);
char *expanded = expandpath(path);
STASIS_ASSERT(startswith(expanded, home) > 0, expanded);
@@ -366,8 +368,8 @@ void test_rmtree() {
for (size_t i = 0; i < sizeof(tree) / sizeof(*tree); i++) {
char path[PATH_MAX];
char mockfile[PATH_MAX + 10];
- sprintf(path, "%s/%s", root, tree[i]);
- sprintf(mockfile, "%s/%zu.txt", path, i);
+ snprintf(path, sizeof(path), "%s/%s", root, tree[i]);
+ snprintf(mockfile, sizeof(mockfile), "%s/%zu.txt", path, i);
if (mkdir(path, 0755)) {
perror(path);
STASIS_ASSERT(false, NULL);
diff --git a/tests/test_wheel.c b/tests/test_wheel.c
index 1eabb1b..531e4b7 100644
--- a/tests/test_wheel.c
+++ b/tests/test_wheel.c
@@ -171,7 +171,7 @@ int main(int argc, char *argv[]) {
}
char *install_url = calloc(255, sizeof(install_url));
- delivery_get_conda_installer_url(&ctx, install_url);
+ delivery_get_conda_installer_url(&ctx, install_url, PATH_MAX);
delivery_get_conda_installer(&ctx, install_url);
delivery_install_conda(ctx.conda.installer_path, ctx.storage.conda_install_prefix);
guard_free(install_url);