diff --git a/src/htsback.c b/src/htsback.c index 21c72e272..718ec2641 100644 --- a/src/htsback.c +++ b/src/htsback.c @@ -1101,9 +1101,10 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback, strcpybuff(back[p].r.msg, "Empty compressed file"); } } else { - snprintf(back[p].r.msg, sizeof(back[p].r.msg), - "Open error when decompressing (can not create temporary file %s)", - back[p].tmpfile); + htsblk_failf(&back[p].r, + "Open error when decompressing (can not create " + "temporary file %s)", + back[p].tmpfile); back[p].tmpfile[0] = '\0'; back[p].r.statuscode = STATUSCODE_INVALID; } @@ -1188,11 +1189,11 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback, a local write's errno behind, and 0 for a bad stream. */ if (errno != 0) back_report_write_failure(opt, &back[p]); - snprintf(back[p].r.msg, sizeof(back[p].r.msg), - codec == HTS_CODEC_UNSUPPORTED - ? "Unsupported Content-Encoding (%s)" - : "Error when decompressing (%s)", - back[p].r.contentencoding); + htsblk_failf(&back[p].r, + codec == HTS_CODEC_UNSUPPORTED + ? "Unsupported Content-Encoding (%s)" + : "Error when decompressing (%s)", + back[p].r.contentencoding); /* Drop the undecoded body so the writer can't commit the coded bytes as the page; url_sav is left untouched. */ if (!back[p].r.is_write) diff --git a/src/htslib.c b/src/htslib.c index 93c297d9d..294dbbd1f 100644 --- a/src/htslib.c +++ b/src/htslib.c @@ -2326,8 +2326,7 @@ T_SOC newhttp_addr(httrackp *opt, const char *_iadr, htsblk *retour, int port, // a port filter named; an empty "host:" just means the default (#614) if (a[1] != '\0' && !hts_parse_url_port(a + 1, &port)) { if (retour != NULL) { - snprintf(retour->msg, sizeof(retour->msg), "Invalid port: %s", - a + 1); + htsblk_failf(retour, "Invalid port: %s", a + 1); } return INVALID_SOCKET; } @@ -2355,13 +2354,7 @@ T_SOC newhttp_addr(httrackp *opt, const char *_iadr, htsblk *retour, int port, printf("erreur gethostbyname\n"); #endif if (retour != NULL) { -#ifdef _WIN32 - snprintf(retour->msg, sizeof(retour->msg), - "Unable to get server's address: %s", error); -#else - snprintf(retour->msg, sizeof(retour->msg), - "Unable to get server's address: %s", error); -#endif + htsblk_failf(retour, "Unable to get server's address: %s", error); } return INVALID_SOCKET; } @@ -2408,8 +2401,8 @@ T_SOC newhttp_addr(httrackp *opt, const char *_iadr, htsblk *retour, int port, &bind_addr, &error) == NULL || bind(soc, &SOCaddr_sockaddr(bind_addr), SOCaddr_size(bind_addr)) != 0) { - snprintf(retour->msg, sizeof(retour->msg), - "Unable to bind the specificied server address: %s", error); + htsblk_failf( + retour, "Unable to bind the specificied server address: %s", error); deletesoc(soc); return INVALID_SOCKET; } @@ -2430,9 +2423,8 @@ T_SOC newhttp_addr(httrackp *opt, const char *_iadr, htsblk *retour, int port, #endif char errbuf[HTS_STRERROR_SIZE]; - snprintf(retour->msg, sizeof(retour->msg), - "Non-blocking socket failed: %s", - hts_strerror(last_errno, errbuf, sizeof(errbuf))); + htsblk_failf(retour, "Non-blocking socket failed: %s", + hts_strerror(last_errno, errbuf, sizeof(errbuf))); deletesoc(soc); return INVALID_SOCKET; } diff --git a/src/htslib.h b/src/htslib.h index 269c36af6..417c56a9c 100644 --- a/src/htslib.h +++ b/src/htslib.h @@ -709,7 +709,7 @@ HTS_STATIC int strcmpnocase(const char *a, const char *b) { #ifdef _WIN32 #define strcasecmp(a,b) stricmp(a,b) #define strncasecmp(a,b,n) strnicmp(a,b,n) -#define snprintf _snprintf +/* No snprintf alias: _snprintf leaves a truncated string unterminated. */ #endif /* MSVC ships these POSIX functions under other names. Kept out of the installed diff --git a/tests/491_no-legacy-printf-alias.test b/tests/491_no-legacy-printf-alias.test new file mode 100755 index 000000000..a521a3f2a --- /dev/null +++ b/tests/491_no-legacy-printf-alias.test @@ -0,0 +1,51 @@ +#!/bin/bash +# +# No build may give a C99 printf call another implementation under its own +# name. A Linux build cannot see such an alias, so this scan is the only guard. + +set -euo pipefail + +# shellcheck source=tests/testlib.sh +. "${0%"${0##*/}"}./testlib.sh" + +top="${abs_top_srcdir:?not run under make check}" +test -f "$top/src/htslib.h" || fail "no $top/src/htslib.h" + +work=$(mktemp -d "${TMPDIR:-/tmp}/printfalias.XXXXXX") || fail "no tmpdir" +cleanup_push rm -rf "$work" + +family='v?(f|s|sn)?printf|v?asprintf' +# A macro whose name IS the C99 call, so every later use silently changes +# meaning. A wrapper named otherwise, such as htssafe.h's sprintfbuff, is fine. +source_re="^[[:space:]]*#[[:space:]]*define[[:space:]]+($family)[[:space:](]" +# The same alias handed to the compiler instead: -Dsnprintf=_snprintf, or a +# Visual Studio PreprocessorDefinitions entry. +build_re="($family)=" + +sources() { # sources DIR -> the .c and .h files under it + find "$1" \( -name '*.c' -o -name '*.h' \) -print | LC_ALL=C sort +} + +sources "$top/src" >"$work/files" +# A find that silently narrowed would report a clean tree, so floor the count. +test "$(lines_of "$work/files")" -ge 100 || + fail "only $(lines_of "$work/files") sources found under $top/src" +xargs grep -nHE "$source_re" <"$work/files" >"$work/found" || true + +ls "$top"/configure.ac "$top"/*/Makefile.am "$top"/src/*.vcxproj >"$work/builds" +xargs grep -nHE "$build_re" <"$work/builds" >>"$work/found" || true + +# Control: both scans must fire on the lines this test exists to keep out. +mkdir -p "$work/ctl" +printf '#define snprintf _snprintf\n' >"$work/ctl/legacy.h" +printf 'snprintf=_snprintf\n' \ + >"$work/ctl/legacy.vcxproj" +grep -qE "$source_re" "$work/ctl/legacy.h" || + fail "the source scan cannot see a legacy alias, so a clean result proves nothing" +grep -qE "$build_re" "$work/ctl/legacy.vcxproj" || + fail "the build scan cannot see a legacy alias, so a clean result proves nothing" + +test ! -s "$work/found" || + fail_dump "a C99 printf call is aliased to another implementation under its own name. Call the real one, or give the wrapper its own name" "$work/found" + +echo "scanned $(lines_of "$work/files") sources and $(lines_of "$work/builds") build files, aliases: 0"