From 19d75948ef7abe9066efa4462108827d70565ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:32 +0200 Subject: [PATCH 1/6] common-main.c: move non-trace2 exit() behavior out of trace2.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the exit() wrapper added in ee4512ed481 (trace2: create new combined trace facility, 2019-02-22) so that we'll split up the trace2 logging concerns from wanting to wrap the "exit()" function itself for other purposes. This makes more sense structurally, as we won't seem to conflate non-trace2 behavior with the trace2 code. I'd previously added an explanation for this in 368b5843158 (common-main.c: call exit(), don't return, 2021-12-07), that comment is being adjusted here. Now the only thing we'll do if we're not using trace2 is to truncate the "code" argument to the lowest 8 bits. We only need to do that truncation on non-POSIX systems, but in ee4512ed481 that "if defined(__MINGW32__)" code added in 47e3de0e796 (MinGW: truncate exit()'s argument to lowest 8 bits, 2009-07-05) was made to run everywhere. It might be good for clarify to narrow that down by an "ifdef" again, but I'm not certain that in the interim we haven't had some other non-POSIX systems rely the behavior. On a POSIX system taking the lowest 8 bits is implicit, see exit(3)[1] and wait(2)[2]. Let's leave a comment about that instead. 1. https://man7.org/linux/man-pages/man3/exit.3.html 2. https://man7.org/linux/man-pages/man2/wait.2.html Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- common-main.c | 22 +++++++++++++++++----- git-compat-util.h | 4 ++-- trace2.c | 8 ++------ trace2.h | 8 +------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/common-main.c b/common-main.c index 29fb7452f8..b6124dd2c2 100644 --- a/common-main.c +++ b/common-main.c @@ -55,10 +55,22 @@ int main(int argc, const char **argv) result = cmd_main(argc, argv); - /* - * We define exit() to call trace2_cmd_exit_fl() in - * git-compat-util.h. Whether we reach this or exit() - * elsewhere we'll always run our trace2 exit handler. - */ + /* Not exit(3), but a wrapper calling our common_exit() */ exit(result); } + +/* We wrap exit() to call common_exit() in git-compat-util.h */ +int common_exit(const char *file, int line, int code) +{ + /* + * For non-POSIX systems: Take the lowest 8 bits of the "code" + * to e.g. turn -1 into 255. On a POSIX system this is + * redundant, see exit(3) and wait(2), but as it doesn't harm + * anything there we don't need to guard this with an "ifdef". + */ + code &= 0xff; + + trace2_cmd_exit_fl(file, line, code); + + return code; +} diff --git a/git-compat-util.h b/git-compat-util.h index 96293b6c43..1227ff80ca 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1451,8 +1451,8 @@ int cmd_main(int, const char **); * Intercept all calls to exit() and route them to trace2 to * optionally emit a message before calling the real exit(). */ -int trace2_cmd_exit_fl(const char *file, int line, int code); -#define exit(code) exit(trace2_cmd_exit_fl(__FILE__, __LINE__, (code))) +int common_exit(const char *file, int line, int code); +#define exit(code) exit(common_exit(__FILE__, __LINE__, (code))) /* * You can mark a stack variable with UNLEAK(var) to avoid it being diff --git a/trace2.c b/trace2.c index e01cf77f1a..0c0a11e07d 100644 --- a/trace2.c +++ b/trace2.c @@ -202,17 +202,15 @@ void trace2_cmd_start_fl(const char *file, int line, const char **argv) argv); } -int trace2_cmd_exit_fl(const char *file, int line, int code) +void trace2_cmd_exit_fl(const char *file, int line, int code) { struct tr2_tgt *tgt_j; int j; uint64_t us_now; uint64_t us_elapsed_absolute; - code &= 0xff; - if (!trace2_enabled) - return code; + return; trace_git_fsync_stats(); trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT); @@ -226,8 +224,6 @@ int trace2_cmd_exit_fl(const char *file, int line, int code) if (tgt_j->pfn_exit_fl) tgt_j->pfn_exit_fl(file, line, us_elapsed_absolute, code); - - return code; } void trace2_cmd_error_va_fl(const char *file, int line, const char *fmt, diff --git a/trace2.h b/trace2.h index 1b109f57d0..88d906ea83 100644 --- a/trace2.h +++ b/trace2.h @@ -101,14 +101,8 @@ void trace2_cmd_start_fl(const char *file, int line, const char **argv); /* * Emit an 'exit' event. - * - * Write the exit-code that will be passed to exit() or returned - * from main(). - * - * Use this prior to actually calling exit(). - * See "#define exit()" in git-compat-util.h */ -int trace2_cmd_exit_fl(const char *file, int line, int code); +void trace2_cmd_exit_fl(const char *file, int line, int code); #define trace2_cmd_exit(code) (trace2_cmd_exit_fl(__FILE__, __LINE__, (code))) From 0cc05b044fd690f37565262a5b09f60c203c5218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:33 +0200 Subject: [PATCH 2/6] usage.c: add a non-fatal bug() function to go with BUG() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a bug() function to use in cases where we'd like to indicate a runtime BUG(), but would like to defer the BUG() call because we're possibly accumulating more bug() callers to exhaustively indicate what went wrong. We already have this sort of facility in various parts of the codebase, just in the form of ad-hoc re-inventions of the functionality that this new API provides. E.g. this will be used to replace optbug() in parse-options.c, and the 'error("BUG:[...]' we do in a loop in builtin/receive-pack.c. Unlike the code this replaces we'll log to trace2 with this new bug() function (as with other usage.c functions, including BUG()), we'll also be able to avoid calls to xstrfmt() in some cases, as the bug() function itself accepts variadic sprintf()-like arguments. Any caller to bug() can follow up such calls with BUG_if_bug(), which will BUG() out (i.e. abort()) if there were any preceding calls to bug(), callers can also decide not to call BUG_if_bug() and leave the resulting BUG() invocation until exit() time. There are currently no bug() API users that don't call BUG_if_bug() themselves after a for-loop, but allowing for not calling BUG_if_bug() keeps the API flexible. As the tests and documentation here show we'll catch missing BUG_if_bug() invocations in our exit() wrapper. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- .../technical/api-error-handling.txt | 24 +++++- Documentation/technical/api-trace2.txt | 4 +- common-main.c | 8 ++ git-compat-util.h | 10 +++ t/helper/test-trace2.c | 29 ++++++- t/t0210-trace2-normal.sh | 76 +++++++++++++++++++ usage.c | 33 ++++++-- 7 files changed, 174 insertions(+), 10 deletions(-) diff --git a/Documentation/technical/api-error-handling.txt b/Documentation/technical/api-error-handling.txt index 8be4f4d0d6..70bf1d3e52 100644 --- a/Documentation/technical/api-error-handling.txt +++ b/Documentation/technical/api-error-handling.txt @@ -1,12 +1,34 @@ Error reporting in git ====================== -`BUG`, `die`, `usage`, `error`, and `warning` report errors of +`BUG`, `bug`, `die`, `usage`, `error`, and `warning` report errors of various kinds. - `BUG` is for failed internal assertions that should never happen, i.e. a bug in git itself. +- `bug` (lower-case, not `BUG`) is supposed to be used like `BUG` but + prints a "BUG" message instead of calling `abort()`. ++ +A call to `bug()` will then result in a "real" call to the `BUG()` +function, either explicitly by invoking `BUG_if_bug()` after call(s) +to `bug()`, or implicitly at `exit()` time where we'll check if we +encountered any outstanding `bug()` invocations. ++ +If there were no prior calls to `bug()` before invoking `BUG_if_bug()` +the latter is a NOOP. The `BUG_if_bug()` function takes the same +arguments as `BUG()` itself. Calling `BUG_if_bug()` explicitly isn't +necessary, but ensures that we die as soon as possible. ++ +If you know you had prior calls to `bug()` then calling `BUG()` itself +is equivalent to calling `BUG_if_bug()`, the latter being a wrapper +calling `BUG()` if we've set a flag indicating that we've called +`bug()`. ++ +This is for the convenience of APIs who'd like to potentially report +more than one "bug", such as the optbug() validation in +parse-options.c. + - `die` is for fatal application errors. It prints a message to the user and exits with status 128. diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt index f4a8a69087..77a150b30e 100644 --- a/Documentation/technical/api-trace2.txt +++ b/Documentation/technical/api-trace2.txt @@ -465,8 +465,8 @@ completed.) ------------ `"error"`:: - This event is emitted when one of the `BUG()`, `error()`, `die()`, - `warning()`, or `usage()` functions are called. + This event is emitted when one of the `BUG()`, `bug()`, `error()`, + `die()`, `warning()`, or `usage()` functions are called. + ------------ { diff --git a/common-main.c b/common-main.c index b6124dd2c2..c531372f3f 100644 --- a/common-main.c +++ b/common-main.c @@ -59,6 +59,13 @@ int main(int argc, const char **argv) exit(result); } +static void check_bug_if_BUG(void) +{ + if (!bug_called_must_BUG) + return; + BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()"); +} + /* We wrap exit() to call common_exit() in git-compat-util.h */ int common_exit(const char *file, int line, int code) { @@ -70,6 +77,7 @@ int common_exit(const char *file, int line, int code) */ code &= 0xff; + check_bug_if_BUG(); trace2_cmd_exit_fl(file, line, code); return code; diff --git a/git-compat-util.h b/git-compat-util.h index 1227ff80ca..ce007102f7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1320,9 +1320,19 @@ static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size, /* usage.c: only to be used for testing BUG() implementation (see test-tool) */ extern int BUG_exit_code; +/* usage.c: if bug() is called we should have a BUG_if_bug() afterwards */ +extern int bug_called_must_BUG; + __attribute__((format (printf, 3, 4))) NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...); #define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__) +__attribute__((format (printf, 3, 4))) +void bug_fl(const char *file, int line, const char *fmt, ...); +#define bug(...) bug_fl(__FILE__, __LINE__, __VA_ARGS__) +#define BUG_if_bug(...) do { \ + if (bug_called_must_BUG) \ + BUG_fl(__FILE__, __LINE__, __VA_ARGS__); \ +} while (0) #ifdef __APPLE__ #define FSYNC_METHOD_DEFAULT FSYNC_METHOD_WRITEOUT_ONLY diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c index 59b124bb5f..180c7f53f3 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -198,7 +198,7 @@ static int ut_006data(int argc, const char **argv) return 0; } -static int ut_007bug(int argc, const char **argv) +static int ut_007BUG(int argc, const char **argv) { /* * Exercise BUG() to ensure that the message is printed to trace2. @@ -206,6 +206,28 @@ static int ut_007bug(int argc, const char **argv) BUG("the bug message"); } +static int ut_008bug(int argc, const char **argv) +{ + bug("a bug message"); + bug("another bug message"); + BUG_if_bug("an explicit BUG_if_bug() following bug() call(s) is nice, but not required"); + return 0; +} + +static int ut_009bug_BUG(int argc, const char **argv) +{ + bug("a bug message"); + bug("another bug message"); + /* The BUG_if_bug(...) isn't here, but we'll spot bug() calls on exit()! */ + return 0; +} + +static int ut_010bug_BUG(int argc, const char **argv) +{ + bug("a bug message"); + BUG("a BUG message"); +} + /* * Usage: * test-tool trace2 @@ -222,7 +244,10 @@ static struct unit_test ut_table[] = { { ut_004child, "004child", "[]" }, { ut_005exec, "005exec", "" }, { ut_006data, "006data", "[ ]+" }, - { ut_007bug, "007bug", "" }, + { ut_007BUG, "007bug", "" }, + { ut_008bug, "008bug", "" }, + { ut_009bug_BUG, "009bug_BUG","" }, + { ut_010bug_BUG, "010bug_BUG","" }, }; /* clang-format on */ diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh index 37c359bd5a..80e76a4695 100755 --- a/t/t0210-trace2-normal.sh +++ b/t/t0210-trace2-normal.sh @@ -168,6 +168,82 @@ test_expect_success 'BUG messages are written to trace2' ' test_cmp expect actual ' +test_expect_success 'bug messages with BUG_if_bug() are written to trace2' ' + test_when_finished "rm trace.normal actual expect" && + test_expect_code 99 env GIT_TRACE2="$(pwd)/trace.normal" \ + test-tool trace2 008bug 2>err && + cat >expect <<-\EOF && + a bug message + another bug message + an explicit BUG_if_bug() following bug() call(s) is nice, but not required + EOF + sed "s/^.*: //" actual && + test_cmp expect actual && + + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 008bug + cmd_name trace2 (trace2) + error a bug message + error another bug message + error an explicit BUG_if_bug() following bug() call(s) is nice, but not required + exit elapsed:_TIME_ code:99 + atexit elapsed:_TIME_ code:99 + EOF + test_cmp expect actual +' + +test_expect_success 'bug messages without explicit BUG_if_bug() are written to trace2' ' + test_when_finished "rm trace.normal actual expect" && + test_expect_code 99 env GIT_TRACE2="$(pwd)/trace.normal" \ + test-tool trace2 009bug_BUG 2>err && + cat >expect <<-\EOF && + a bug message + another bug message + had bug() call(s) in this process without explicit BUG_if_bug() + EOF + sed "s/^.*: //" actual && + test_cmp expect actual && + + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 009bug_BUG + cmd_name trace2 (trace2) + error a bug message + error another bug message + error on exit(): had bug() call(s) in this process without explicit BUG_if_bug() + exit elapsed:_TIME_ code:99 + atexit elapsed:_TIME_ code:99 + EOF + test_cmp expect actual +' + +test_expect_success 'bug messages followed by BUG() are written to trace2' ' + test_when_finished "rm trace.normal actual expect" && + test_expect_code 99 env GIT_TRACE2="$(pwd)/trace.normal" \ + test-tool trace2 010bug_BUG 2>err && + cat >expect <<-\EOF && + a bug message + a BUG message + EOF + sed "s/^.*: //" actual && + test_cmp expect actual && + + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 010bug_BUG + cmd_name trace2 (trace2) + error a bug message + error a BUG message + exit elapsed:_TIME_ code:99 + atexit elapsed:_TIME_ code:99 + EOF + test_cmp expect actual +' + sane_unset GIT_TRACE2_BRIEF # Now test without environment variables and get all Trace2 settings diff --git a/usage.c b/usage.c index b738dd178b..79900d0287 100644 --- a/usage.c +++ b/usage.c @@ -290,18 +290,24 @@ void warning(const char *warn, ...) /* Only set this, ever, from t/helper/, when verifying that bugs are caught. */ int BUG_exit_code; -static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params) +static void BUG_vfl_common(const char *file, int line, const char *fmt, + va_list params) { char prefix[256]; - va_list params_copy; - static int in_bug; - - va_copy(params_copy, params); /* truncation via snprintf is OK here */ snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line); vreportf(prefix, fmt, params); +} + +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params) +{ + va_list params_copy; + static int in_bug; + + va_copy(params_copy, params); + BUG_vfl_common(file, line, fmt, params); if (in_bug) abort(); @@ -317,11 +323,28 @@ static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_lis NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...) { va_list ap; + + bug_called_must_BUG = 0; + va_start(ap, fmt); BUG_vfl(file, line, fmt, ap); va_end(ap); } +int bug_called_must_BUG; +void bug_fl(const char *file, int line, const char *fmt, ...) +{ + va_list ap, cp; + + bug_called_must_BUG = 1; + + va_copy(cp, ap); + va_start(ap, fmt); + BUG_vfl_common(file, line, fmt, ap); + va_end(ap); + trace2_cmd_error_va(fmt, cp); +} + #ifdef SUPPRESS_ANNOTATED_LEAKS void unleak_memory(const void *ptr, size_t len) { From 53ca569419aed9706b052c48656715ab0b5f14fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:34 +0200 Subject: [PATCH 3/6] parse-options.c: use new bug() API for optbug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we run into bugs in parse-options.c usage it's good to be able to note all the issues we ran into before dying. This use-case is why we have the optbug() function introduced in 1e5ce570ca3 (parse-options: clearer reporting of API misuse, 2010-12-02) Let's change this code to use the new bug() API introduced in the preceding commit, which cuts down on the verbosity of parse_options_check(). There are existing uses of BUG() in adjacent code that should have been using optbug() that aren't being changed here. That'll be done in a subsequent commit. This only changes the optbug() callers. Since this will invoke BUG() the previous exit(128) code will be changed, but in this case that's what we want, i.e. to have encountering a BUG() return the specific "BUG" exit code. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- parse-options.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/parse-options.c b/parse-options.c index 6e57744fd2..78b46ae969 100644 --- a/parse-options.c +++ b/parse-options.c @@ -14,15 +14,15 @@ enum opt_parsed { OPT_UNSET = 1<<1, }; -static int optbug(const struct option *opt, const char *reason) +static void optbug(const struct option *opt, const char *reason) { - if (opt->long_name) { - if (opt->short_name) - return error("BUG: switch '%c' (--%s) %s", - opt->short_name, opt->long_name, reason); - return error("BUG: option '%s' %s", opt->long_name, reason); - } - return error("BUG: switch '%c' %s", opt->short_name, reason); + if (opt->long_name && opt->short_name) + bug("switch '%c' (--%s) %s", opt->short_name, + opt->long_name, reason); + else if (opt->long_name) + bug("option '%s' %s", opt->long_name, reason); + else + bug("switch '%c' %s", opt->short_name, reason); } static const char *optname(const struct option *opt, enum opt_parsed flags) @@ -441,28 +441,27 @@ static void check_typos(const char *arg, const struct option *options) static void parse_options_check(const struct option *opts) { - int err = 0; char short_opts[128]; memset(short_opts, '\0', sizeof(short_opts)); for (; opts->type != OPTION_END; opts++) { if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) && (opts->flags & PARSE_OPT_OPTARG)) - err |= optbug(opts, "uses incompatible flags " - "LASTARG_DEFAULT and OPTARG"); + optbug(opts, "uses incompatible flags " + "LASTARG_DEFAULT and OPTARG"); if (opts->short_name) { if (0x7F <= opts->short_name) - err |= optbug(opts, "invalid short name"); + optbug(opts, "invalid short name"); else if (short_opts[opts->short_name]++) - err |= optbug(opts, "short name already used"); + optbug(opts, "short name already used"); } if (opts->flags & PARSE_OPT_NODASH && ((opts->flags & PARSE_OPT_OPTARG) || !(opts->flags & PARSE_OPT_NOARG) || !(opts->flags & PARSE_OPT_NONEG) || opts->long_name)) - err |= optbug(opts, "uses feature " - "not supported for dashless options"); + optbug(opts, "uses feature " + "not supported for dashless options"); switch (opts->type) { case OPTION_COUNTUP: case OPTION_BIT: @@ -471,7 +470,7 @@ static void parse_options_check(const struct option *opts) case OPTION_NUMBER: if ((opts->flags & PARSE_OPT_OPTARG) || !(opts->flags & PARSE_OPT_NOARG)) - err |= optbug(opts, "should not accept an argument"); + optbug(opts, "should not accept an argument"); break; case OPTION_CALLBACK: if (!opts->callback && !opts->ll_callback) @@ -494,10 +493,9 @@ static void parse_options_check(const struct option *opts) } if (opts->argh && strcspn(opts->argh, " _") != strlen(opts->argh)) - err |= optbug(opts, "multi-word argh should use dash to separate words"); + optbug(opts, "multi-word argh should use dash to separate words"); } - if (err) - exit(128); + BUG_if_bug("invalid 'struct option'"); } static void parse_options_start_1(struct parse_opt_ctx_t *ctx, From 5b2f5d92ca5afc118d3fb798c1f25863a5011a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:35 +0200 Subject: [PATCH 4/6] parse-options.c: use optbug() instead of BUG() "opts" check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the assertions added in bf3ff338a25 (parse-options: stop abusing 'callback' for lowlevel callbacks, 2019-01-27) to use optbug() instead of BUG(). At this point we're looping over individual options, so if we encounter any issues we'd like to report the offending option. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- parse-options.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/parse-options.c b/parse-options.c index 78b46ae969..edf55d3ef5 100644 --- a/parse-options.c +++ b/parse-options.c @@ -474,20 +474,21 @@ static void parse_options_check(const struct option *opts) break; case OPTION_CALLBACK: if (!opts->callback && !opts->ll_callback) - BUG("OPTION_CALLBACK needs one callback"); - if (opts->callback && opts->ll_callback) - BUG("OPTION_CALLBACK can't have two callbacks"); + optbug(opts, "OPTION_CALLBACK needs one callback"); + else if (opts->callback && opts->ll_callback) + optbug(opts, "OPTION_CALLBACK can't have two callbacks"); break; case OPTION_LOWLEVEL_CALLBACK: if (!opts->ll_callback) - BUG("OPTION_LOWLEVEL_CALLBACK needs a callback"); + optbug(opts, "OPTION_LOWLEVEL_CALLBACK needs a callback"); if (opts->callback) - BUG("OPTION_LOWLEVEL_CALLBACK needs no high level callback"); + optbug(opts, "OPTION_LOWLEVEL_CALLBACK needs no high level callback"); break; case OPTION_ALIAS: - BUG("OPT_ALIAS() should not remain at this point. " - "Are you using parse_options_step() directly?\n" - "That case is not supported yet."); + optbug(opts, "OPT_ALIAS() should not remain at this point. " + "Are you using parse_options_step() directly?\n" + "That case is not supported yet."); + break; default: ; /* ok. (usually accepts an argument) */ } From 07b1d8f184e126eef8223757844587cf91d6e14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:36 +0200 Subject: [PATCH 5/6] receive-pack: use bug() and BUG_if_bug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amend code added in a6a84319686 (receive-pack.c: shorten the execute_commands loop over all commands, 2015-01-07) and amended to hard die in b6a4788586d (receive-pack.c: die instead of error in case of possible future bug, 2015-01-07) to use the new bug() function instead. Let's also rename the warn_if_*() function that code is in to BUG_if_*(), its name became outdated in b6a4788586d. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- builtin/receive-pack.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index daa153d044..4a62327dee 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1810,21 +1810,17 @@ static int should_process_cmd(struct command *cmd) return !cmd->error_string && !cmd->skip_update; } -static void warn_if_skipped_connectivity_check(struct command *commands, +static void BUG_if_skipped_connectivity_check(struct command *commands, struct shallow_info *si) { struct command *cmd; - int checked_connectivity = 1; for (cmd = commands; cmd; cmd = cmd->next) { - if (should_process_cmd(cmd) && si->shallow_ref[cmd->index]) { - error("BUG: connectivity check has not been run on ref %s", - cmd->ref_name); - checked_connectivity = 0; - } + if (should_process_cmd(cmd) && si->shallow_ref[cmd->index]) + bug("connectivity check has not been run on ref %s", + cmd->ref_name); } - if (!checked_connectivity) - BUG("connectivity check skipped???"); + BUG_if_bug("connectivity check skipped???"); } static void execute_commands_non_atomic(struct command *commands, @@ -2005,7 +2001,7 @@ static void execute_commands(struct command *commands, execute_commands_non_atomic(commands, si); if (shallow_update) - warn_if_skipped_connectivity_check(commands, si); + BUG_if_skipped_connectivity_check(commands, si); } static struct command **queue_command(struct command **tail, From 6d40f0ad15e72daab6524988c9c4b4a3460488f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 2 Jun 2022 14:25:37 +0200 Subject: [PATCH 6/6] cache-tree.c: use bug() and BUG_if_bug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change "BUG" output originally added in a97e4075a16 (Keep rename/rename conflicts of intermediate merges while doing recursive merge, 2007-03-31), and later made to say it was a "BUG" in 19c6a4f8369 (merge-recursive: do not return NULL only to cause segfault, 2010-01-21) to use the new bug() function. This gets the same job done with slightly less code, as we won't need to prefix lines with "BUG: ". More importantly we'll now log the full set of messages via trace2, before this we'd only log the one BUG() invocation. We don't replace the last "BUG()" invocation with "BUG_if_bug()", as in this case we're sure that we called bug() earlier, so there's no need to make it a conditional. While we're at it let's replace "There" with "there" in the message, i.e. not start a message with a capital letter, per the CodingGuidelines. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- cache-tree.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cache-tree.c b/cache-tree.c index 6752f69d51..04d85810e1 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -692,14 +692,14 @@ struct tree* write_in_core_index_as_tree(struct repository *repo) { ret = write_index_as_tree_internal(&o, index_state, was_valid, 0, NULL); if (ret == WRITE_TREE_UNMERGED_INDEX) { int i; - fprintf(stderr, "BUG: There are unmerged index entries:\n"); + bug("there are unmerged index entries:"); for (i = 0; i < index_state->cache_nr; i++) { const struct cache_entry *ce = index_state->cache[i]; if (ce_stage(ce)) - fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce), - (int)ce_namelen(ce), ce->name); + bug("%d %.*s", ce_stage(ce), + (int)ce_namelen(ce), ce->name); } - BUG("unmerged index entries when writing inmemory index"); + BUG("unmerged index entries when writing in-core index"); } return lookup_tree(repo, &index_state->cache_tree->oid);