A script without shebang is meant to be interpreted by a POSIX-compliant sh interpreter. That's actually the POSIX way to write POSIX scripts, POSIX doesn't specify shebangs, though in practice using shebangs is more portable / reliable, and here is a good example why.
The bash shell is such a POSIX sh interpreter. bash (some versions and in some custom builds and in some environments) is actually the only FLOSS shell that I know that has been certified as compliant when running as sh (not when running as bash).
When executing a shebang-less script, bash, when execve() returns ENOEXEC and after having checked that it doesn't look like a binary file, interprets it in a child of his, simulating an execution by attempting to reset its state to the default.
That means however that that script when run from bash is interpreted as a bash script instead of a POSIX sh script unless bash is running in POSIX mode itself (such as when invoked as sh itself).
$ cat a alias uname='echo hi' uname $ zsh -c ./a hi $ sh ./a hi $ bash -c ./a Linux $ (exec -a sh bash -c ./a) hi
See how a was interpreted as bash language (ignoring aliases) instead of the sh languages when invoked by bash.
~$ strace -qqfe execve bash -c ./a execve("/usr/bin/bash", ["bash", "-c", "./a"], 0x7fff0081a820 /* 66 vars */) = 0 execve("./a", ["./a"], 0x55b18b3a4660 /* 66 vars */) = -1 ENOEXEC (Exec format error) [pid 123559] execve("/usr/bin/uname", ["uname"], 0x55b18b3a4660 /* 66 vars */) = 0 Linux --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=123559, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
See how bash didn't execute sh to interpret the script.
The fact that you get that warning: execute_coproc: coproc [147878:COPROC] still exists is a bug whereby bash fails to reset its state properly.
In any case, coproc is not a sh keyword so doesn't have its place in a shebang-less script. coproc is from zsh (while coprocesses are from ksh), though bash's implementation is completely different, so you should have a #! /bin/bash - shebang here.
With bash ./inner.sh or with a shebang, there is a proper execution of a new interpreter instance, and execve() completely and correctly wipes the process memory.