Commit ae99e6979b9c2e65c4b9d40f5e32372014fff6a8

Edward Thomson 2020-09-17T11:19:49

Merge pull request #5619 from ddevault/diffstat-segfault diff stats: fix segfaults with new files

diff --git a/src/diff_stats.c b/src/diff_stats.c
index 1028b01..f5fda79 100644
--- a/src/diff_stats.c
+++ b/src/diff_stats.c
@@ -53,7 +53,7 @@ static int diff_file_stats_full_to_buf(
 	const git_diff_stats *stats,
 	size_t width)
 {
-	const char *old_path = NULL, *new_path = NULL;
+	const char *old_path = NULL, *new_path = NULL, *adddel_path = NULL;
 	size_t padding;
 	git_object_size_t old_size, new_size;
 
@@ -62,7 +62,7 @@ static int diff_file_stats_full_to_buf(
 	old_size = delta->old_file.size;
 	new_size = delta->new_file.size;
 
-	if (strcmp(old_path, new_path) != 0) {
+	if (old_path && new_path && strcmp(old_path, new_path) != 0) {
 		size_t common_dirlen;
 		int error;
 
@@ -82,10 +82,11 @@ static int diff_file_stats_full_to_buf(
 		if (error < 0)
 			goto on_error;
 	} else {
-		if (git_buf_printf(out, " %s", old_path) < 0)
+		adddel_path = new_path ? new_path : old_path;
+		if (git_buf_printf(out, " %s", adddel_path) < 0)
 			goto on_error;
 
-		padding = stats->max_name - strlen(old_path);
+		padding = stats->max_name - strlen(adddel_path);
 
 		if (stats->renames > 0)
 			padding += strlen(DIFF_RENAME_FILE_SEPARATOR);
@@ -211,7 +212,7 @@ int git_diff_get_stats(
 
 		/* TODO ugh */
 		namelen = strlen(delta->new_file.path);
-		if (strcmp(delta->old_file.path, delta->new_file.path) != 0) {
+		if (delta->old_file.path && strcmp(delta->old_file.path, delta->new_file.path) != 0) {
 			namelen += strlen(delta->old_file.path);
 			stats->renames++;
 		}
diff --git a/tests/diff/stats.c b/tests/diff/stats.c
index 1503556..520a859 100644
--- a/tests/diff/stats.c
+++ b/tests/diff/stats.c
@@ -343,3 +343,38 @@ void test_diff_stats__mode_change(void)
 	cl_assert_equal_s(stat, git_buf_cstr(&buf));
 	git_buf_dispose(&buf);
 }
+
+void test_diff_stats__new_file(void)
+{
+	git_diff *diff;
+	git_buf buf = GIT_BUF_INIT;
+
+	const char *input =
+	"---\n"
+	" Gurjeet Singh | 1 +\n"
+	" 1 file changed, 1 insertion(+)\n"
+	" create mode 100644 Gurjeet Singh\n"
+	"\n"
+	"diff --git a/Gurjeet Singh b/Gurjeet Singh\n"
+	"new file mode 100644\n"
+	"index 0000000..6d0ecfd\n"
+	"--- /dev/null\n"
+	"+++ b/Gurjeet Singh	\n"
+	"@@ -0,0 +1 @@\n"
+	"+I'm about to try git send-email\n"
+	"-- \n"
+	"2.21.0\n";
+
+	const char *stat =
+	" Gurjeet Singh | 1 +\n"
+	" 1 file changed, 1 insertion(+)\n"
+	" create mode 100644 Gurjeet Singh\n";
+
+	cl_git_pass(git_diff_from_buffer(&diff, input, strlen(input)));
+	cl_git_pass(git_diff_get_stats(&_stats, diff));
+	cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY, 0));
+	cl_assert_equal_s(stat, git_buf_cstr(&buf));
+
+	git_buf_dispose(&buf);
+	git_diff_free(diff);
+}