diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 7a7faa8ed..ef4ae8b88 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -336,7 +336,10 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { parser.libdata().transient_commandlines.push_back(do_complete_param); cleanup_t remove_transient([&] { parser.libdata().transient_commandlines.pop_back(); }); - if (parser.libdata().builtin_complete_recursion_level < 1) { + // Allow a limited number of recursive calls to complete (#3474). + if (parser.libdata().builtin_complete_recursion_level >= 1) { + streams.err.append_format(L"%ls: maximum recursive depth reached\n", cmd); + } else { parser.libdata().builtin_complete_recursion_level++; std::vector comp; diff --git a/tests/checks/complete.fish b/tests/checks/complete.fish index a232fb589..733f78c3a 100644 --- a/tests/checks/complete.fish +++ b/tests/checks/complete.fish @@ -59,3 +59,9 @@ complete # CHECK: complete {{.*}} # CHECK: complete {{.*}} # CHECK: complete {{.*}} + +# Recursive calls to complete (see #3474) +complete -c complete_test_recurse1 -xa '(echo recursing 1>&2; complete -C"complete_test_recurse1 ")' +complete -C'complete_test_recurse1 ' +# CHECKERR: recursing +# CHECKERR: complete: maximum recursive depth reached diff --git a/tests/checks/wraps.fish b/tests/checks/wraps.fish index 5ffc9edb5..14d223977 100644 --- a/tests/checks/wraps.fish +++ b/tests/checks/wraps.fish @@ -26,4 +26,6 @@ complete -c testcommand2 -x -a "(testcommand2_complete)" complete -c testcommand2 --wraps "testcommand2 from_wraps " complete -C'testcommand2 explicit ' # CHECKERR: explicit +# CHECKERR: complete: maximum recursive depth reached # CHECKERR: from_wraps explicit +# CHECKERR: complete: maximum recursive depth reached