commit 9976affb503011ab063f1de78688b26414d8ec9a from: Mark Jamsek via: Thomas Adam date: Fri Jan 03 10:46:48 2025 UTC fix NULL deref when scrolling small tog tree views down In the rare case a tree view is smaller than four lines in height, the last_displayed_entry is NULL. Check this condition on a scroll down event with j/down arrow or ^f/pgdn to guard a NULL got_tree_entry from being passed to got_tree_entry_get_next() where it is dereferenced. And add a test case covering this path. ok stsp@ commit - eb7ebd1cb08a207935fadc4f17e8c31cb6dca13b commit + 9976affb503011ab063f1de78688b26414d8ec9a blob - 0fcbbd78a8afe17bd2f12a187cecec268453d4ea blob + 381950ee222f7b284d4a41b67b5b08dde376678a --- regress/tog/tree.sh +++ regress/tog/tree.sh @@ -340,10 +340,43 @@ test_tree_commit_keywords() fi test_done "$testroot" "$ret" } + +test_tree_insufficient_height() +{ + test_init tree_insufficient_height 120 3 + + local id=$(git_show_head $testroot/repo) + + # Cover the path that guards a NULL dereference when scrolling + # down in a tree view too small to display any tree entries. + cat <<-EOF >$TOG_TEST_SCRIPT + j attempt to scroll down + f + SCREENDUMP + EOF + cat <<-EOF >$testroot/view.expected + commit $id + [1/4] / + + EOF + + cd $testroot/repo && tog tree + cmp -s $testroot/view.expected $testroot/view + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/view.expected $testroot/view + test_done "$testroot" "$ret" + return 1 + fi + + test_done "$testroot" "$ret" +} + test_parseargs "$@" run_test test_tree_basic run_test test_tree_vsplit_blame run_test test_tree_hsplit_blame run_test test_tree_symlink run_test test_tree_commit_keywords +run_test test_tree_insufficient_height blob - c76a5f2663c1570b0f625e29396a6d50df6fa6a9 blob + 879259f6229b008b4113a82b1138cd2193670ee0 --- tog/tog.c +++ tog/tog.c @@ -9675,7 +9675,8 @@ input_tree_view(struct tog_view **new_view, struct tog s->selected++; break; } - if (got_tree_entry_get_next(s->tree, s->last_displayed_entry) + if (s->last_displayed_entry == NULL || + got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further */ view->count = 0; @@ -9691,7 +9692,8 @@ input_tree_view(struct tog_view **new_view, struct tog case CTRL('f'): case 'f': case ' ': - if (got_tree_entry_get_next(s->tree, s->last_displayed_entry) + if (s->last_displayed_entry == NULL || + got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further; move cursor down */ if (s->selected < s->ndisplayed - 1)