diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Sort an empty list without handing qsort a null
Every list sorted here is null until its first entry, and C leaves a null base undefined even with nothing to sort. glibc declares it nonnull and its UBSan build aborted the stats page of a repository with no commits in the window, which the Linux matrix caught.
-rw-r--r--source/cgit.c2
-rw-r--r--source/shared.h12
-rw-r--r--source/ui-refs.c12
-rw-r--r--source/ui-repolist.c2
-rw-r--r--source/ui-stats.c2
5 files changed, 21 insertions, 9 deletions
diff --git a/source/cgit.c b/source/cgit.c
index 8a3d8c1..6d663fe 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -335,7 +335,7 @@ static void parse_args(int argc, const char **argv)
}
}
if (scanned) {
- qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), cmp_repos);
+ cgit_qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), cmp_repos);
print_repolist(stdout, &cgit_repolist, 0);
exit(0);
}
diff --git a/source/shared.h b/source/shared.h
index e22eb57..2bf305d 100644
--- a/source/shared.h
+++ b/source/shared.h
@@ -140,4 +140,16 @@ extern int cgit_valid_rev(const char *rev);
*/
extern int cgit_notes_ref_usable(const char *notes_ref);
+/*
+ * qsort for a list that may be empty. C leaves a null base undefined even
+ * with nothing to sort, and glibc declares it nonnull, while the lists here
+ * stay null until their first entry.
+ */
+static inline void cgit_qsort(void *base, size_t n, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+ if (n)
+ qsort(base, n, size, cmp);
+}
+
#endif // CGIT_SHARED_H
diff --git a/source/ui-refs.c b/source/ui-refs.c
index 890a959..38a5773 100644
--- a/source/ui-refs.c
+++ b/source/ui-refs.c
@@ -246,9 +246,9 @@ static void print_branches_page(int pagesize)
print_branch_header();
collect_branches(&list);
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
+ cgit_qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
if (ctx.repo->branch_sort == 0)
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_name);
+ cgit_qsort(list.refs, list.count, sizeof(*list.refs), cmp_name);
page = page_bounds(pagesize, list.count);
@@ -271,7 +271,7 @@ static void print_tags_page(int pagesize)
collect_tags(&list);
if (list.count == 0)
return;
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
+ cgit_qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
page = page_bounds(pagesize, list.count);
@@ -300,9 +300,9 @@ void cgit_print_branches(int maxcount)
// The date sort covers the list, the name sort only the rows about to
// be shown, so the section holds the newest branches rather than the
// first ones by name.
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
+ cgit_qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
if (ctx.repo->branch_sort == 0)
- qsort(list.refs, maxcount, sizeof(*list.refs), cmp_name);
+ cgit_qsort(list.refs, maxcount, sizeof(*list.refs), cmp_name);
for (i = 0; i < maxcount; i++)
print_branch(list.refs[i]);
@@ -322,7 +322,7 @@ void cgit_print_tags(int maxcount)
collect_tags(&list);
if (list.count == 0)
return;
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
+ cgit_qsort(list.refs, list.count, sizeof(*list.refs), cmp_date);
if (maxcount <= 0 || maxcount > list.count)
maxcount = list.count;
print_tag_header();
diff --git a/source/ui-repolist.c b/source/ui-repolist.c
index 58e31ed..6df70e4 100644
--- a/source/ui-repolist.c
+++ b/source/ui-repolist.c
@@ -402,7 +402,7 @@ static int sort_repolist(const char *field)
continue;
if (column->cmp == cmp_idle || column->cmp == cmp_section)
resolve_modtimes();
- qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), column->cmp);
+ cgit_qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), column->cmp);
return 1;
}
return 0;
diff --git a/source/ui-stats.c b/source/ui-stats.c
index f200b63..a332335 100644
--- a/source/ui-stats.c
+++ b/source/ui-stats.c
@@ -450,7 +450,7 @@ void cgit_show_stats(void)
}
if (collect_stats(period, &authors))
return;
- qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits);
+ cgit_qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits);
top = ctx.qry.ofs;
if (!top)