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:
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);
+}