Check for unexpected events
assert()
- abort the program if assertion is falseThe assert()
macro can help programmers find bugs in their programs, or
handle exceptional cases via a crash that will produce limited debugging output.
It’s a useful tool, but it has some limitations when used in NeoMutt:
ASSERT()
- stop the program if assertion is falseNeoMutt now has an upgraded ASSERT()
macro.
endwin()
to reset the screen modeASSERT()
Inspiration from Chris Wellons’ https://nullprogram.com/blog/2022/06/26/
ASSERT()
To use the ASSERT()
macro:
#include "mutt/lib.h"
void function(const char *str)
{
ASSERT(str);
}
To disable the macro at build time, define NDEBUG
, e.g.
./configure OPTIONS...
make "EXTRA_CFLAGS="-DNDEBUG"
When combined with configure --debug-backtrace
the output may look like:
NeoMutt 20240425-37-55fed8
Backtrace
assertion_dump() ip = 21, sp = 7ffd651127a0
op_print() ip = 4c, sp = 7ffd651127d0
index_function_dispatcher() ip = 14e, sp = 7ffd65112820
dlg_index() ip = b70, sp = 7ffd65112890
main() ip = 2a41, sp = 7ffd65112950
index/functions.c:2080:op_print() -- assertion failed ((priv->menu->current % 2) == 1)
Illegal instruction (core dumped)
When the assertion fails, the debugger will stop immediately on the ASSERT()
line.
This gives you a chance to examine the variables, and even step over the problem.
2075│ /**
2076│ * op_print - Print the current entry - Implements ::index_function_t - @ingroup index_function_api
2077│ */
2078│ static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2079│ {
2080├─> ASSERT((priv->menu->current % 2) == 1);
2081│ struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2082│ ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2083│ mutt_print_message(shared->mailbox, &ea);
2084│ ARRAY_FREE(&ea);
2085│
2086│ /* in an IMAP folder index with imap_peek=no, printing could change
2087│ * new or old messages status to read. Redraw what's needed. */
2088│ const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2089│ if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2090│ {
2091│ menu_queue_redraw(priv->menu, (priv->tag_prefix ? MENU_REDRAW_INDEX : MENU_REDRAW_CURRENT));
2092│ }
2093│
2094│ return FR_SUCCESS;
2095│ }
In gdb
, you can step over this problem by jumping to a new line, e.g. j 2094
NeoMutt will continue running and at the next refresh repaint the entire screen.