bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

command_not_found_handle() flaw


From: Phi Debian
Subject: command_not_found_handle() flaw
Date: Tue, 10 Mar 2020 18:37:24 +0100

Hi All,

While trying to implement  an function autoload feature, with a lazier
function loading and invocation than the example provided in bash doc, I
bumped into this bash bug (or feature, you let me know).

I asked stackoverflow for some ideas, one pointed me to
command_not_found_handle() that I was not aware off and looked promising
for what I wanted to achieve.

This SO post is quite big, so I will report here a shorter version.

In a nutshell to implement a function autoloading I want to plug into
command_not_found_handle(), but I need command_not_found_handle()be
evaluated in the shell context, not in a subshell.

At the moment BASH_VERSION='5.0.16(14)-release' (and all way back) the is
wrongly called as a sub-shell, that doesn't hurt the command-not-found
packages found in many distro as at this point they don't care about
setting things in the shell instance, so their implementation is good
enough.

To demonstrate the bug, suffice to do this


function command_not_found_handle
{ echo $$ ; sh -c 'echo $PPID'
}

When run in shell context we got the correct answer
$ function command_not_found_handle
> { echo $$ ; sh -c 'echo $PPID'
> }
$
$  command_not_found_handle
11370
11370

But when called from 'not found' context we got
$ ddd # dd not found on my system then call command_not_found_handle
11779
11783
$

As we see here, $$ lies pretend to be the shell PID 11779 while it real $$
is 11783, so a child.

This is a real problem because then there is nothing I can do in
command_not_found_handle) to setup things in the shell context, i.e not new
alias setup, no new functin define, etc...

I propose a fix, yet bear in mind hacking bash is not my day to day job :)
so it must be reviewed by gurus. I send the proposed [atch separatly.

With this fix I got this run
PW$ PS1='$ '
$ function command_not_found_handle
> { echo $$ ; sh -c 'echo $PPID'
> }
$ ddd
12165
12165

$ function command_not_found_handle
> { echo in cnf
>   A="cnf-was-called"
>  return 127
> }
$ A=''
$ ddd
in cnf
$ echo $A
cnf-was-called
$

Meaning now command_not_found_handle() is a real function called from the
shel context, shell context can then be touch (vars, alias, functions,
etc..) what I need to implement my autoload mechanism.

Not that it is indeed possible to chain the handlers, so assuming a
command-not-found package installed I got this on ubuntu.
$ declare -f command_not_found_handle
command_not_found_handle ()
{
    if [ -x /usr/lib/command-not-found ]; then
        /usr/lib/command-not-found -- "$1";
        return $?;
    else
        if [ -x /usr/share/command-not-found/command-not-found ]; then
            /usr/share/command-not-found/command-not-found -- "$1";
            return $?;
        else
            printf "%s: command not found\n" "$1" 1>&2;
            return 127;
        fi;
    fi
}

And a run gives

$ ddd

Command 'ddd' not found, but can be installed with:

sudo apt install ddd


If I now want to install my handler I rename the current handler
# Rename current command_not_found_handle
_cnf_body=$(declare -f command_not_found_handle | tail -n +2)
eval "function _cnf_prev $_cnf_body"

Then I create mine chaining to the prev one

function command_not_found_handle
{ echo in cnf
  A="cnf-was-called"
  _cnf_prev "$@"
}

 $ unset A
$ ddd
in cnf

Command 'ddd' not found, but can be installed with:

sudo apt install ddd

$ echo $A
cnf-was-called

This shows that my handler was called, on failure to find a function, it
forward to the previous handler, then it shows that it ran in the shell
contect as A= is set correfctly.

I got no memory leak detected with this patch, but again review thouroughly.

Hope this helps.

Cheers,
Phi


reply via email to

[Prev in Thread] Current Thread [Next in Thread]