commit 5cdcd66c829a38c1a527ea8b1d83b0b32806915c
parent a034a1756ab0e3b427da010f77eb6d3a06e4813c
Author: Chris Bracken <chris@bracken.jp>
Date: Tue, 17 Feb 2026 19:08:58 +0900
writers: check snprintf calls for truncation
Previously we checked for negative return values in snprintf
invocations, but we didn't check for cases where a string doesn't
fit in the output buffer and is truncated.
Diffstat:
7 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/src/format.c b/src/format.c
@@ -29,9 +29,10 @@ void print_time(FILE* out, time_t time, int timezone_offset) {
int timezone_hours = (timezone_offset < 0 ? -1 : 1) * timezone_offset / 60;
int timezone_mins = (timezone_offset < 0 ? -1 : 1) * timezone_offset % 60;
char out_str[64];
- if (snprintf(out_str, sizeof(out_str), "%s %c%02d%02d", formatted_time,
- timezone_sign, timezone_hours, timezone_mins) < 0) {
- err(1, "snprintf");
+ int r = snprintf(out_str, sizeof(out_str), "%s %c%02d%02d", formatted_time,
+ timezone_sign, timezone_hours, timezone_mins);
+ if (r < 0 || (size_t)r >= sizeof(out_str)) {
+ errx(1, "snprintf: time string truncated or error");
}
fprintf(out, "%s", out_str);
}
diff --git a/src/writer/gopher/commit.c b/src/writer/gopher/commit.c
@@ -36,8 +36,9 @@ GopherCommit* gopher_commit_create(const GitRepo* repo,
const char* title) {
GopherCommit* commit = ecalloc(1, sizeof(GopherCommit));
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.gph", oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.gph", oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
commit->out = efopen(path, "w");
diff --git a/src/writer/gopher/fileblob.c b/src/writer/gopher/fileblob.c
@@ -27,8 +27,9 @@ GopherFileBlob* gopher_fileblob_create(const GitRepo* repo, const char* path) {
// Create directories.
char filename_buffer[PATH_MAX];
- if (snprintf(filename_buffer, sizeof(filename_buffer), "%s.gph", path) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename_buffer, sizeof(filename_buffer), "%s.gph", path);
+ if (r < 0 || (size_t)r >= sizeof(filename_buffer)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* out_path = path_concat("file", filename_buffer);
diff --git a/src/writer/gopher/repo_writer.c b/src/writer/gopher/repo_writer.c
@@ -85,8 +85,9 @@ void gopher_repowriter_begin(GopherRepoWriter* writer) {
void gopher_repowriter_add_commit(GopherRepoWriter* writer,
const GitCommit* git_commit) {
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.gph", git_commit->oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.gph", git_commit->oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
atom_add_commit(writer->atom, git_commit, path, "", "");
@@ -109,8 +110,9 @@ void gopher_repowriter_add_reference(GopherRepoWriter* writer,
if (ref->type == kReftypeTag) {
GitCommit* commit = ref->commit;
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.gph", commit->oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.gph", commit->oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
atom_add_commit(writer->tags, commit, path, "", ref->shorthand);
diff --git a/src/writer/html/commit.c b/src/writer/html/commit.c
@@ -39,8 +39,9 @@ HtmlCommit* html_commit_create(const GitRepo* repo,
const char* title) {
HtmlCommit* commit = ecalloc(1, sizeof(HtmlCommit));
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.html", oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.html", oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
commit->out = efopen(path, "w");
@@ -233,8 +234,9 @@ void html_commit_write_diff_hunk(HtmlCommit* commit,
// Output header. e.g. @@ -0,0 +1,3 @@
char hdr_id[32];
size_t hunkid = hunk->id;
- if (snprintf(hdr_id, sizeof(hdr_id), "h%zu-%zu", file_num, hunkid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(hdr_id, sizeof(hdr_id), "h%zu-%zu", file_num, hunkid);
+ if (r < 0 || (size_t)r >= sizeof(hdr_id)) {
+ errx(1, "snprintf: hunk ID truncated");
}
fprintf(out, "<a href=\"#%s\" id=\"%s\" class=\"h\">", hdr_id, hdr_id);
const char* header = hunk->header;
@@ -247,8 +249,9 @@ void html_commit_write_diff_hunk(HtmlCommit* commit,
const GitHunkLine* line = hunk->lines[i];
size_t hunklineid = line->id;
char line_id[64];
- if (snprintf(line_id, sizeof(line_id), "%s-%zu", hdr_id, hunklineid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(line_id, sizeof(line_id), "%s-%zu", hdr_id, hunklineid);
+ if (r < 0 || (size_t)r >= sizeof(line_id)) {
+ errx(1, "snprintf: line ID truncated");
}
const char* content = line->content;
size_t content_len = line->content_len;
diff --git a/src/writer/html/fileblob.c b/src/writer/html/fileblob.c
@@ -27,8 +27,9 @@ HtmlFileBlob* html_fileblob_create(const GitRepo* repo, const char* path) {
// Create directories.
char filename_buffer[PATH_MAX];
- if (snprintf(filename_buffer, sizeof(filename_buffer), "%s.html", path) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename_buffer, sizeof(filename_buffer), "%s.html", path);
+ if (r < 0 || (size_t)r >= sizeof(filename_buffer)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* out_path = path_concat("file", filename_buffer);
diff --git a/src/writer/html/repo_writer.c b/src/writer/html/repo_writer.c
@@ -84,8 +84,9 @@ void html_repowriter_begin(HtmlRepoWriter* writer) {
void html_repowriter_add_commit(HtmlRepoWriter* writer,
const GitCommit* git_commit) {
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.html", git_commit->oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.html", git_commit->oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
atom_add_commit(writer->atom, git_commit, path, "text/html", "");
@@ -108,8 +109,9 @@ void html_repowriter_add_reference(HtmlRepoWriter* writer,
if (ref->type == kReftypeTag) {
GitCommit* commit = ref->commit;
char filename[PATH_MAX];
- if (snprintf(filename, sizeof(filename), "%s.html", commit->oid) < 0) {
- err(1, "snprintf");
+ int r = snprintf(filename, sizeof(filename), "%s.html", commit->oid);
+ if (r < 0 || (size_t)r >= sizeof(filename)) {
+ errx(1, "snprintf: filename truncated or error");
}
char* path = path_concat("commit", filename);
atom_add_commit(writer->tags, commit, path, "text/html", ref->shorthand);