Skip to content

Commit d819374

Browse files
peffgitster
authored andcommitted
usage.c: add BUG() function
There's a convention in Git's code base to write assertions as: if (...some_bad_thing...) die("BUG: the terrible thing happened"); with the idea that users should never see a "BUG:" message (but if they, it at least gives a clue what happened). We use die() here because it's convenient, but there are a few draw-backs: 1. Without parsing the messages, it's hard for callers to distinguish BUG assertions from regular errors. For instance, it would be nice if the test suite could check that we don't hit any assertions, but test_must_fail will pass BUG deaths as OK. 2. It would be useful to add more debugging features to BUG assertions, like file/line numbers or dumping core. 3. The die() handler can be replaced, and might not actually exit the whole program (e.g., it may just pthread_exit()). This is convenient for normal errors, but for an assertion failure (which is supposed to never happen), we're probably better off taking down the whole process as quickly and cleanly as possible. We could address these by checking in die() whether the error message starts with "BUG", and behaving appropriately. But there's little advantage at that point to sharing the die() code, and only downsides (e.g., we can't change the BUG() interface independently). Moreover, converting all of the existing BUG calls reveals that the test suite does indeed trigger a few of them. Instead, this patch introduces a new BUG() function, which prints an error before dying via SIGABRT. This gives us test suite checking and core dumps. The function is actually a macro (when supported) so that we can show the file/line number. We can convert die("BUG") invocations to BUG() in further patches, dealing with any test fallouts individually. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent b06d364 commit d819374

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

git-compat-util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,15 @@ static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size,
10641064
#define HAVE_VARIADIC_MACROS 1
10651065
#endif
10661066

1067+
#ifdef HAVE_VARIADIC_MACROS
1068+
__attribute__((format (printf, 3, 4))) NORETURN
1069+
void BUG_fl(const char *file, int line, const char *fmt, ...);
1070+
#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)
1071+
#else
1072+
__attribute__((format (printf, 1, 2))) NORETURN
1073+
void BUG(const char *fmt, ...);
1074+
#endif
1075+
10671076
/*
10681077
* Preserves errno, prints a message, but gives no warning for ENOENT.
10691078
* Returns 0 on success, which includes trying to unlink an object that does

usage.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,35 @@ void warning(const char *warn, ...)
201201
warn_routine(warn, params);
202202
va_end(params);
203203
}
204+
205+
static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
206+
{
207+
char prefix[256];
208+
209+
/* truncation via snprintf is OK here */
210+
if (file)
211+
snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
212+
else
213+
snprintf(prefix, sizeof(prefix), "BUG: ");
214+
215+
vreportf(prefix, fmt, params);
216+
abort();
217+
}
218+
219+
#ifdef HAVE_VARIADIC_MACROS
220+
void BUG_fl(const char *file, int line, const char *fmt, ...)
221+
{
222+
va_list ap;
223+
va_start(ap, fmt);
224+
BUG_vfl(file, line, fmt, ap);
225+
va_end(ap);
226+
}
227+
#else
228+
void BUG(const char *fmt, ...)
229+
{
230+
va_list ap;
231+
va_start(ap, fmt);
232+
BUG_vfl(NULL, 0, fmt, ap);
233+
va_end(ap);
234+
}
235+
#endif

0 commit comments

Comments
 (0)