3 ms·
> As far as I'm concerned, the environment is a read-only input parameter set on process creation like argv. Mutating argv is actually quite popular, or at lea
by Joker_vD 2y ago
> As far as I'm concerned, the environment is a read-only input parameter set on process creation like argv.
Mutating argv is actually quite popular, or at least it used to be.
- eqvinox 2y agoYes, and if there were "setargv()" or "getargv()" functions, they'd have the same issues ;) … but argv is a function parameter to main()¹, and only that. ¹ or technically whatever your ELF entry point is, _start in crt0 or your poison of choice.
- gpm 2y ago> but argv is a function parameter to main()¹, and only that. > ¹ or technically whatever your ELF entry point is, _start in crt0 or your poison of choice. Once you include the footnote, at least on linux/macos (not sure about Windows), you could take the same perspective with regards to envp and the auxiliary array. It's libc that decided to store a pointer to these before calling your `main`, not the abi. At the time of the ELF entry point these are all effectively stack local variables.
- eqvinox 2y agoI mean, yes, we're in "violent agreement" there. It's nice that libc squirrels away a copy and gives you a `getenv()` function with a string lookup, but… setenv… that was just a horrible idea. It's not really wrong to view it as a tool that allows you to muck around with main()'s local variables. Which to me sounds like one should take a shower after using it ;D (Ed.: the man page should say "you are required to take a shower after writing code that uses setenv(), both to get off the dirt, but also to give you time to think about what you are doing" :D)
- gpm 2y agoOops, didn't mean to come across as disagreeing at all, more of a "yes, and <once you include the footnote>".
- eqvinox 2y agoAh, after rereading I think I accidentally read that in, sorry
- fch42 2y ago+1 on the "horrible idea" part. Thing is, the (history of the) UNIX APIs - call'em "libc" if you like - is littered with the undead corpses of horrible ideas. Who thought that having global file write offsets are great ? Append-only writes ? Global working directories ? The ability to write the password db via putpwent() ? Modifying your own envp or argv ? Why have a horribly-scaling hack like fcntl-based file locking even in the standard ? "Today", were one to start from scratch, the userspace API of even unix-ish operating systems would be done much differently. After all, systems designers and implementors are intelligent people and learn, and there's 50y+ of history to learn from. But the warts are there, and sometimes, there to "program around" them.
- Joker_vD 2y agoAppend-only writes are actually amazing, having several processes writing into the same file and have their writes interleaved instead of destroying each other is almost impossible to re-create in the user space. And I still don't understand why processes "modifying their own envp or argv" are met with such revulsion in this comment thread except from the "I dislike that on ideological grounds" reason. Now, the ability to modify envp and/or argv of other processes while those are running, yes, that's a horrible idea. But modifying your own internal process state? Oh, and fcntl file locks are horrible for the historical reasons: basically, when POSIX (or its predecessor?) were trying to decide on a portable interface, the representative of one of the vendors cobbled together this API and its implementation in a week or two, and then showed to the meeting with it. To his surprise, instead of arguing everyone else basically said "eh, looks fine", and that was it, we now have broken "why on earth does close()/fork()/exec() interact with locks like that" behaviour.
- fch42 2y agoI had to smirk at the sarcasm (intended or no). I merely included "processes modifying their env" amongst all these historical warts. I consider doing so as inevitably necessary as append writes, the advantages of which you aptly described. That's my opinion, underpinned by the history of those interfaces. I hope we can agree that the breakage is by-and-large in an (old, historical) interface that allows braindead usage, not in either the implementor or the user ?
- skissane 2y agoOn Linux, a privileged process can change the memory address which the kernel (/proc filesystem) reads argv/etc from... prctl(PR_SET_MM) with the PR_SET_MM_ARG_START/PR_SET_MM_ARG_END arguments. Likewise, with PR_SET_MM_ENV_START/PR_SET_MM_ENV_END. The API is ugly, and since it needs CAP_SYS_RESOURCE many programs can't use it... but systemd does: https://github.com/systemd/systemd/blob/2635b5dc4a96157c257536b1e4ad769d565c82a6/src/basic/argv-util.c#L118 https://github.com/systemd/systemd/blob/2635b5dc4a96157c2575... This shouldn't cause the kind of race conditions we are talking about here, since it isn't changing a single arg, it is changing the whole argv all at once. However, the fact that PR_SET_MM_ARG_START/PR_SET_MM_ARG_END are two separate prctl syscalls potentially introduces a different race condition. If Linux would only provide a prctl to set both at once, that would fix that. The reason it was done this way, is the API was originally designed for checkpoint-restore, in which case the process will be effectively suspended while these calls are made.
- GuB-42 2y agoMutating argv is fine for how it is usually done. That is, to permute the arguments in a getopt() call so that all nonoptions are at the end. It is fine because it is usually done during the initialization phase, before starting any other thread. setenv() can be used here too, though I prefer to avoid doing that in any case. I also prefer not to touch argv, but since that's how GNU getopt() works, I just go with it. Once the program is running and has started its threads, I consider setenv() is a big no no. The Rust documentation agrees with me: "In multi-threaded programs on other operating systems, the only safe option is to not use set_var or remove_var at all.". Note: here, "other operating systems" means "not Windows".
- saagarjha 2y agoA big reason to mutate argv is to change the process's name for tools like top.
- GoblinSlayer 2y agoFor that you write to /proc/self/comm, that's where top gets it from.
- saagarjha 2y agoHmm, htop then? Whatever is reading /proc/self/cmdline
- gobblegobble2 2y agoIt may work for top, but not ps among others. The only reliable way is clobbering argv. That's just the way it is. In my opinion, glibc should finally provide setproctitle(), so programs like postgresql or chrome (https://source.chromium.org/chromium/chromium/src/+/main:base/process/set_process_title_linux.cc;l=77 https://source.chromium.org/chromium/chromium/src/+/main:bas...) don't have to resort to argv hacks.
- GoblinSlayer 2y agoThere's prctl https://man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html https://man7.org/linux/man-pages/man2/PR_SET_NAME.2const.htm... that writes to /proc/self/comm