4 ms·
The pointer isn't guaranteed to point into `environ` directly. `getenv()` could copy the value to a thread-local, (dynamically-allocated?) buffer while holding
by Sprocklem 3y ago
The 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
- Sprocklem 3y agoOf course, *_r is a better option, but the existing API is used so pervasively that it needs to be made thread-safe to actually avoid thread-unsafe code in, e.g, libraries.
- lokar 3y agoI don’t see how you can make: - return a pointer - the library owns the allocation - the state is global and mutable Thread safe
- Sprocklem 3y agoA number of libc functions return a pointer to an internal thread-local buffer, which is invalidated on subsequent calls. If the function copies the environment variable's value to such a buffer while holding the mutex controlling access to the global state, then the returned value is guaranteed to remain unaffected by other threads. There are, however, other problems (discussed elsewhere in this thread) that complicate such an API in the context of getenv().
- harerazer 3y agoThen don't do that. Of all the footguns in POSIX/C programming, having to remember to free this is really not as bad as you seem to imply.
- thayne 3y agoAnd how would you free it? The current posix API doesn't have any way to reliably free the result returned by `getenv`.
- alexey-salmin 3y agoYou miss the point. If you have full control over when and how getenv is called, there's no issue to begin with. The problem is that you don't, as OP demonstrates. It's perfectly natural to call getaddrinfo in a loop. We need a new API which is not broken like in NetBSD, and a multi-year migration of all core libraries to it. Well a pity it wasn't started years ago though, could've been 95% done by now.
- lokar 3y agoLibc and much of posix predate threads. There was no way to fix everything without changing the APIs, which they did in many cases but not all.