gout

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

commit d0ff6f6ced5c7d330536644517596a5814b14918
parent 573d74cb9c9b09003bb8fec0ab0a48ca1e0fe1ac
Author: Chris Bracken <chris@bracken.jp>
Date:   Sat,  6 Jun 2026 14:52:04 +0900

writer/atom: fix RFC 4287 violation

Emit an empty title in atom_add_commit when a commit's summary is NULL
or empty to comply with RFC 4287 which requires a <title> tag.

Also fix a potential use-after-free issue with baseurl. Given the
current implementation gets this from Options (i.e. the command-line)
this shouldn't be an issue, but it avoids making assumptions about
implementation details.

Diffstat:
Msrc/writer/atom/atom.c | 26+++++++++++++++-----------
Msrc/writer/atom/atom_tests.c | 29++++++++++++++++++++++++++++-
2 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/src/writer/atom/atom.c b/src/writer/atom/atom.c @@ -12,7 +12,7 @@ struct Atom { const GitRepo* repo; - const char* baseurl; + char* baseurl; FILE* out; size_t remaining_commits; }; @@ -22,7 +22,7 @@ Atom* atom_create(const GitRepo* repo, FILE* out) { assert(out != NULL); Atom* atom = ecalloc(1, sizeof(Atom)); atom->repo = repo; - atom->baseurl = ""; + atom->baseurl = estrdup(""); atom->out = out; atom->remaining_commits = 100; return atom; @@ -32,6 +32,7 @@ void atom_free(Atom* atom) { if (!atom) { return; } + free(atom->baseurl); atom->out = NULL; free(atom); } @@ -39,7 +40,8 @@ void atom_free(Atom* atom) { void atom_set_baseurl(Atom* atom, const char* baseurl) { assert(atom != NULL); assert(baseurl != NULL); - atom->baseurl = baseurl; + free(atom->baseurl); + atom->baseurl = estrdup(baseurl); } void atom_begin(Atom* atom) { @@ -90,16 +92,18 @@ void atom_add_commit(Atom* atom, print_time_z(out, commit->commit_time); fprintf(out, "</updated>\n"); - if (commit->summary) { - fprintf(out, "<title>"); - if (tag && tag[0] != '\0') { - fprintf(out, "["); - print_xml_encoded(out, tag); - fprintf(out, "]"); - } + fprintf(out, "<title>"); + if (tag && tag[0] != '\0') { + fprintf(out, "["); + print_xml_encoded(out, tag); + fprintf(out, "] "); + } + if (commit->summary && commit->summary[0] != '\0') { print_xml_encoded(out, commit->summary); - fprintf(out, "</title>\n"); + } else { + fprintf(out, "Commit %.7s", commit->oid); } + fprintf(out, "</title>\n"); fprintf(out, "<link rel=\"alternate\" "); if (strlen(content_type) > 0) { fprintf(out, "type=\"%s\" ", content_type); diff --git a/src/writer/atom/atom_tests.c b/src/writer/atom/atom_tests.c @@ -68,7 +68,7 @@ UTEST(atom, add_commit) { "<id>abc1234567890</id>", // "<published>2023-12-08T10:30:00Z</published>", // "<updated>2023-12-08T11:30:00Z</updated>", // - "<title>[v1.0]Fix a bug</title>", // + "<title>[v1.0] Fix a bug</title>", // "<link rel=\"alternate\" type=\"text/html\" " "href=\"https://example.com/commit/abc.html\" />", // "<author>", // @@ -201,3 +201,30 @@ UTEST(atom, url_concatenation) { free(buf); } } + +UTEST(atom, empty_summary) { + char* buf = NULL; + size_t size = 0; + FILE* out = open_memstream(&buf, &size); + ASSERT_NE(NULL, out); + + GitRepo repo = {.short_name = "test-repo"}; + Atom* atom = atom_create(&repo, out); + + GitCommit commit = { + .oid = "1234567890abcdef", + .summary = NULL, + .author_name = "Test User", + .author_email = "test@example.com", + }; + + atom_add_commit(atom, &commit, "commit/abc.html", "text/html", ""); + atom_free(atom); + fflush(out); + fclose(out); + + ASSERT_NE(NULL, buf); + EXPECT_TRUE(strstr(buf, "<title>Commit 1234567</title>") != NULL); + + free(buf); +}