4 ms·
But getenv/setenv syscall could still be under lock, which I think most of the people would use. Walking over memory could be without lock and the program could
by YetAnotherNick 3y ago
But getenv/setenv syscall could still be under lock, which I think most of the people would use. Walking over memory could be without lock and the program could see inconsistent values as is the current behaviour.
- aaronmdjones 3y agoIt's a library call, not a system call. You're right though, they could implement locking.
- asveikau 3y agoI think in libc, there's a lot of stuff where an interface is kind of broken from a thread perspective, and it could be implemented better without changing the interface, but often people generally do not. I can't think of any examples offhand, but I often think it about thread-local storage. Eg. lots of interfaces have an _r() equivalent where you provide the buffer, but many people still call the unsafe one which is broken when there are threads... In my mind, the best way to do this would be to use static thread-local storage in the non-_r() one, and have it call the _r() one ... Sure that has overhead and isn't a perfect solution, but it's better than "bad". But a lot of these old functions don't necessarily get love.
- Gibbon1 3y agoAn a sane world creating a thread would set a global that causes non thread safe library functions to seg fault. Or maybe calling them from two different threads causes a seg fault. But just make it really obvious you're doing bad stuff.
- asveikau 3y agoI think that sounds completely insane. The unsafety is an emergent property of what's done in the function, and entirely dependent on usage. If you were doing very disciplined use of an unsafe call, it's harmless. Perhaps this would be a good feature of an assert, or something that breaks in a debugger if it's attached. But I don't think that is reasonable for production.
- lokar 3y agoThat won’t help. The APi is broken. It returns a pointer.
- Sprocklem 3y agoThe pointer isn't guaranteed to point into `environ` directly. `getenv()` could copy the value to a thread-local, (dynamically-allocated?) buffer while holding the lock. Edit: In hindsight, a dynamic buffer would require returning ENOMEM errors (which might lead to some unexpected failures), while a static buffer would limit the value length. I think you might be right about the API being broken.
- alexey-salmin 3y agoCall getenv() in a loop and you run out of memory.
- Sprocklem 3y agoI was suggesting that the buffer be invalidated by each subsequent call – like some other libc functions' internal buffers – although, as I noted in the edit this would need `getenv()` to be able to indicate errors (specifically ENOMEM). It currently cannot do this as currently described, because NULL is used to indicate an absent variable. You could also require callers free the returned memory when they're done, but that would be another change of API.
- alexey-salmin 3y ago> I was suggesting that the buffer be invalidated by each subsequent call This would break very simple single-threaded programs that e.g. print two env vars in one printf call.
- lokar 3y agoThe solution to all problems like this was decided years ago: _r You provide the storage and free it The problem is these non-direct uses. They each need to switch to •_r and manage the buffer, or offer _r versions themselves and sort of pass through the problem
- cryptonector 3y agoIt should never use locks. Solaris/Illumos' getenv() is lock-less. Every C library should copy that pattern.