can you still recover if all three functions are marked readonly?
Yes, usually you can, though that does not mean you should.
Just as you can unset readonly variables by attaching a debugger and calling
unbind_variable as shown in anishsane's answer to that question, you can also unset readonly functions passing their names to
unbind_func using a debugger.
This is not a reasonable approach when they aren't readonly (if it indeed ever is). In that situation you should use cuonglm's solution, which takes advantage of how
unset is treated in POSIX mode. That solution is something you might actually use in real life.
Since there's no actual guarantee that your shell will behave reasonably after you circumvent
readonly with a debugger, I suggest avoiding it whenever a more reasonable alternative, like quitting and restarting your shell or replacing your shell with a new one using
exec, is available.
With that said, here's anishsane's method adapted to unset functions instead of a variable:
cat <<EOF | sudo gdb
$$ is expanded into the shell's process ID, because no part of
<<EOF is quoted.
I tested this on Bash 4.3.48(1)-release on Ubuntu 16.04 LTS, and it worked. You need
gdb for this, though it could be adapted to other debuggers. As anishsane commented, piping from
cat is intended to avoid a deadlock where the process that gives input to
gdb is the one that
gdb has stopped. I believe it achieves that goal, because in a pipeline of two or more commands, Bash runs each command in a subshell. But I am unsure if it is the most robust way. Ultimately, however, there's no actual guarantee that this works anyway, since it's entirely reasonable for Bash to assume readonly variables and functions won't change. In practice, my guess is that this does virtually always work.
To use this technique as written, you need
sudo installed and you need to be able to
sudo to root. You can, of course, replace it with another privilege-elevation method. Depending on what OS you are running and how it is configured, you might be able to omit
sudo altogether and run
gdb as yourself instead of root. For example, the Linux kernel will consult the value of
/proc/sys/kernel/yama/ptrace_scope, which you can set through sysctl and may read or (as root) write, to determine what processes may debug other processes. If the value is
1, then only a process's direct parent--or any process running as root--may debug it. Most recent GNU/Linux systems have it set to
1, which is why I included
That description of Linux kernel behavior is somewhat oversimplified, in that other
ptrace_scope values are allowed and in that the relationship required by
1 can be adjusted. See the relevant documentation for full details.