Bug 15946 - ash: command substitution hangs indefinitely inside `command_not_found_handle`
Summary: ash: command substitution hangs indefinitely inside `command_not_found_handle`
Status: NEW
Alias: None
Product: Busybox
Classification: Unclassified
Component: Standard Compliance (show other bugs)
Version: 1.37.x
Hardware: Other Linux
: P5 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-02-16 17:55 UTC by jyn
Modified: 2024-02-16 17:55 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
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;
                }
```