gout

A static git page generator
git clone https://git.bracken.jp/gout.git
Log | Files | Refs | README | LICENSE

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:
Msrc/format.c | 7++++---
Msrc/writer/gopher/commit.c | 5+++--
Msrc/writer/gopher/fileblob.c | 5+++--
Msrc/writer/gopher/repo_writer.c | 10++++++----
Msrc/writer/html/commit.c | 15+++++++++------
Msrc/writer/html/fileblob.c | 5+++--
Msrc/writer/html/repo_writer.c | 10++++++----
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);