Skip to content

Commit

Permalink
Generate crash reports on die in fast-import
Browse files Browse the repository at this point in the history
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 <spearce@spearce.org>
  • Loading branch information
Shawn O. Pearce committed Aug 19, 2007
1 parent ac053c0 commit 8acb329
Showing 1 changed file with 93 additions and 0 deletions.
93 changes: 93 additions & 0 deletions fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 8acb329

Please sign in to comment.