|
|
Message-ID: <20251119170935.GS1827@brightrain.aerifal.cx> Date: Wed, 19 Nov 2025 12:09:35 -0500 From: Rich Felker <dalias@...c.org> To: Markus Wichmann <nullplan@....net> Cc: musl@...ts.openwall.com, Mike Hilgendorf <mike@...gram.dev> Subject: Re: `unsetenv()` does not always work when run in an `__attribute__((constructor))` function On Wed, Nov 19, 2025 at 05:50:17PM +0100, Markus Wichmann wrote: > Hi all, > > it's been a while since this thread, but I still want to get back to it: > Is it sensible to pass __environ as third argument to main(), rather > than the original envp? > > Reason I ask is that I recently checked out what the current POSIX says > about this third argument, and I found it doesn't say anything at all. > According to POSIX, this argument is a pure extension. So basically, we > can do what we want there. I seem to remember that earlier versions had > something to say about it, though, but it has been dropped from the > current description of exec(). > > Then I also checked out the bad actor in this thread, namely bash. I > wondered whether they are somehow testing for the presence of the third > arg. I struggle to think of a way to do so, however. If the third arg is > not given, then declaring one will in practice give garbage values that > can be anything. And there is absolutely no way to detect this before > runtime, making it a poor option for configure testing, since it isn't > cross-compilation compatible. > > But anyway, what bash is doing is just detecting the platforms it knows > not to give that argument (namely OpenNT and MVS), and then it adds the > macro to switch the behavior to the command line. And in the code > itself, while it uses the NO_MAIN_ENV_ARG macro to select the behavior > in two places, in a third it just uses the platform macros directly. So > this whole thing just doesn't work if any implementation ever decides to > change its behavior (e.g. to align with POSIX). > > Anyway, back to musl: Since it is currently giving a third arg to main, > stopping doing so would be an ABI breakage. But nobody said the third > argument has to be the original envp. If we pass __environ instead, then > the effects of constructors modifying the environment will show up in > main(). And __environ is definitely a valid environment (i.e. a vector > of pointers to strings, each being of the form "key=value"). So there's > no violation of any expectations. I'm not strongly against making a change here, but also question whether we want to be making changes to facilitate what's clearly "doing something in a way that's clearly gratuitously nonportable and wrong". Bash should be fixed to use environ whenever it exists and only use the legacy envp arg to main on systems that somehow lack environ. It's not that it would be wrong to make this work, but changing something to make it work, in my mind, implies some obligation to *care that it works*, and in particular to deal with any fallout of the change or other unexpected aspects of the functionality that's now "intended to be well supported". That's something I think we'd be better off not getting into without good motivation. BTW note that, on implementations where C++ global ctors are implemented via the C++ compiler emitting a call to the top of main, the behavior will match what musl currently does: receiving the original environment pointer from prior to ctor execution. So I think applications using this need to be prepared for either behavior -- or better yet, stop using it. Rich
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.