Shells don't generally use the libc environment; this would be too limited to implement even standard POSIX shell functions with local variables, or non-exported variables. It's much easier to set up purpose-built data structures to track variables, and construct an argument for execve().
(Edit: removed unneeded pointing out execve)
Also shells generally have their own program search anyway since they need to support built-in commands. It's not particularly hard to implement PATH search.
Once again, the OP asked why setenv is even needed, which implies they likely don’t have much experience with spawning processes in low level languages, so I used the more familiar shell script setting as an illustrative example, as setenv is analogous to export in POSIX sh. I never said export is implemented with setenv, or shell script exports aren’t thread safe. Unfortunately, replies hung up on shell scripts.
As for I’m not aware of execve etc… You need to re-read my comment which clearly mentions execve, execvep, posix_spawn, as well as implementing PATH search on your own.
> Once again, the OP asked why setenv is even needed, which implies they likely don’t have much experience with spawning processes in low level languages
I am the OP and your assumption is incorrect. You may consider why the post ends with:
"export" in shells has to change the environ before they start the new process. It may not be "at runtime" for the new process, but it would be for the shell.
Wrong, export does not have to change the shell's environment at all. There are plenty of exec variants that accept a different environment pointer, same for posix_spawn.
(Edit: removed unneeded pointing out execve)
Also shells generally have their own program search anyway since they need to support built-in commands. It's not particularly hard to implement PATH search.