From: Shawn O. Pearce Date: Fri, 3 Aug 2007 06:00:37 +0000 (-0400) Subject: Generate crash reports on die in fast-import X-Git-Tag: v1.5.3-rc6~16 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=8acb3297f34fd04bb8f3a35ace3667b59236286e;p=git.git Generate crash reports on die in fast-import As fast-import is quite strict about its input and die()'s anytime something goes wrong it can be difficult for a frontend developer to troubleshoot why fast-import rejected their input, or to even determine what input command it rejected. This change introduces a custom handler for Git's die() routine. When we receive a die() for any reason (fast-import or a lower level core Git routine we called) the error is first dumped onto stderr and then a more extensive crash report file is prepared in GIT_DIR. Finally we exit the process with status 128, just like the stock builtin die handler. An internal flag is set to prevent any further die()'s that may be invoked during the crash report generator from causing us to enter into an infinite loop. We shouldn't die() from our crash report handler, but just in case someone makes a future code change we are prepared to gaurd against small mistakes turning into huge problems for the end-user. Signed-off-by: Shawn O. Pearce --- diff --git a/fast-import.c b/fast-import.c index 429ab491b..71b89e203 100644 --- a/fast-import.c +++ b/fast-import.c @@ -338,6 +338,98 @@ static int unread_command_buf; static uintmax_t next_mark; static struct dbuf new_data; +static void write_branch_report(FILE *rpt, struct branch *b) +{ + fprintf(rpt, "%s:\n", b->name); + + fprintf(rpt, " status :"); + if (b->active) + fputs(" active", rpt); + if (b->branch_tree.tree) + fputs(" loaded", rpt); + if (is_null_sha1(b->branch_tree.versions[1].sha1)) + fputs(" dirty", rpt); + fputc('\n', rpt); + + fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1)); + fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1)); + fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1)); + fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit); + + fputs(" last pack : ", rpt); + if (b->pack_id < MAX_PACK_ID) + fprintf(rpt, "%u", b->pack_id); + fputc('\n', rpt); + + fputc('\n', rpt); +} + +static void write_crash_report(const char *err, va_list params) +{ + char *loc = git_path("fast_import_crash_%d", getpid()); + FILE *rpt = fopen(loc, "w"); + struct branch *b; + unsigned long lu; + + if (!rpt) { + error("can't write crash report %s: %s", loc, strerror(errno)); + return; + } + + fprintf(stderr, "fast-import: dumping crash report to %s\n", loc); + + fprintf(rpt, "fast-import crash report:\n"); + fprintf(rpt, " fast-import process: %d\n", getpid()); + fprintf(rpt, " parent process : %d\n", getppid()); + fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); + fputc('\n', rpt); + + fputs("fatal: ", rpt); + vfprintf(rpt, err, params); + fputc('\n', rpt); + + fputc('\n', rpt); + fputs("Active Branch LRU\n", rpt); + fputs("-----------------\n", rpt); + fprintf(rpt, " active_branches = %lu cur, %lu max\n", + cur_active_branches, + max_active_branches); + fputc('\n', rpt); + fputs(" pos clock name\n", rpt); + fputs(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt); + for (b = active_branches, lu = 0; b; b = b->active_next_branch) + fprintf(rpt, " %2lu) %6" PRIuMAX" %s\n", + ++lu, b->last_commit, b->name); + + fputc('\n', rpt); + fputs("Inactive Branches\n", rpt); + fputs("-----------------\n", rpt); + for (lu = 0; lu < branch_table_sz; lu++) { + for (b = branch_table[lu]; b; b = b->table_next_branch) + write_branch_report(rpt, b); + } + + fputc('\n', rpt); + fputs("-------------------\n", rpt); + fputs("END OF CRASH REPORT\n", rpt); + fclose(rpt); +} + +static NORETURN void die_nicely(const char *err, va_list params) +{ + static int zombie; + + fputs("fatal: ", stderr); + vfprintf(stderr, err, params); + fputc('\n', stderr); + + if (!zombie) { + zombie = 1; + write_crash_report(err, params); + } + + exit(128); +} static void alloc_objects(unsigned int cnt) { @@ -2233,6 +2325,7 @@ int main(int argc, const char **argv) prepare_packed_git(); start_packfile(); + set_die_routine(die_nicely); for (;;) { read_next_command(); if (command_buf.eof)