Bug 15946

Summary: ash: command substitution hangs indefinitely inside `command_not_found_handle`
Product: Busybox Reporter: jyn <jyn514>
Component: Standard ComplianceAssignee: unassigned
Status: NEW ---    
Severity: normal CC: busybox-cvs
Priority: P5    
Version: 1.37.x   
Target Milestone: ---   
Hardware: Other   
OS: Linux   
Host: Target:
Build:

Description jyn 2024-02-16 17:55:45 UTC
```
-bash>git rev-parse HEAD
2d4a3d9e6c1493a9520b907e07a41aca90cdfd94
-bash>./busybox ash
+ ./busybox ash
ash>command_not_found_handle() { echo "entered handle"; x=$(true); echo "finished handle"; }
ash>set -x
ash>does_not_exist
+ does_not_exist
+ echo 'entered handle'
entered handle
+ true
/* ... */
```

i am on alpine linux. i first ran into this with the 1.33.1 release of busybox, but it's also present on 1.36.0 and the latest master commit.
```
-bash>uname -a
Linux linode-static 5.10.176-0-virt #1-Alpine SMP Thu, 23 Mar 2023 10:33:44 +0000 x86_64 Linux
```

for some reason this only happens if `command_not_found_handle` is executed *in the context* of a missing command. if i run it directly, it works fine:
```
ash>command_not_found_handle
entered handle
finished handle
```

i glanced around `shell/ash.c` and i wonder if `find_command` needs to check the return code of `evalfun` so it can longjmp to exception_handler? at least, that patch seems to work for me locally:
```diff
diff --git a/shell/ash.c b/shell/ash.c
index 5f8c8ea19..a65773876 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -13920,7 +13920,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
                        argv[0] = (char*) "command_not_found_handle";
                        argv[1] = name;
                        argv[2] = NULL;
-                       evalfun(hookp->param.func, 2, argv, 0);
+                       if (evalfun(hookp->param.func, 2, argv, 0)) {
+                               longjmp(exception_handler->loc, 1);
+                       }
                        entry->cmdtype = CMDUNKNOWN;
                        return;
                }
```