3 ms·
I agree with you, its not so peculiar as one might think. (Disclaimer: been writing software for Unix since before POSIX...) This design choice reflects the P
by aa-jv 1y ago
I agree with you, its not so peculiar as one might think. (Disclaimer: been writing software for Unix since before POSIX...)
This design choice reflects the POSIX philosophy of minimizing overhead and maximizing flexibility for system programming. Frequent calls to write(), for example, would be hindered by having to reset errno with each call/check of write() return value - especially in cases where a lot of write()'s are queued.
Or .. a library function like fopen() might internally call multiple system calls (e.g., open(), stat(), etc.). If one of these calls sets errno but the overall fopen() operation succeeds, the library doesn’t need to clear errno. For instance, fopen() might try to open a file in one mode, fail with an errno of EACCES (permission denied), then retry in another mode and succeed. The final errno value is irrelevant since the call succeeded.
This mechanism minimizes overhead by not requiring errno to be reset on success.
It allows flexible, efficient implementations of library and system calls and encourages robust programming practices by mandating return-value checks before inspecting errno.
It supports complex, retry-based logic in libraries without unnecessary state management - and it preserves potentially useful debugging information.
You only care about errno when you know an actual error occurred. Until then, ignore it.
This is similar to other systems-level things that can occur in such environments, for example when setting a hard Reset-Reason or Fail-Reason register in static/non-volatile memory somewhere, for later assessment.
IMHO, the thing thats most peculiar about this is that folks these days think of it as weird/quaint - when in fact, it makes a lot of sense if you think about it.
- amelius 1y agoDoes Valgrind give a warning when you do check errno after a successful system call?
- aa-jv 1y agoValgrind doesn't specifically (although it might catch side-effects of this bug), but Coverity would, under most conditions (such as having MISRA or CERT checkers enabled), catch it. If its important to you to find these cases, use clang's static analyzer to perform deep source code analysis via scan-build. See also cppcheck and pc-lint, or PVS-Studio, each of which have means by which you can catch this error.
- saagarjha 1y agoI mean, it definitely sucks. It's cute if you look at it as a product of its time but it makes no sense to do things this way anymore.
- aa-jv 1y agoI don't agree with you at all that 'it sucks'. I think it makes perfect sense and works as intended. Plus, we're talking about POSIX here. You don't have a time machine. Shall we argue about just how much POSIX software is out there, working perfectly fine with this technique? Sure, in New Fangled Language De Jour™, return as many tuples as your heart desires. But don't expect POSIX to play along ..
- saagarjha 1y agoIt sucks because people miss error codes, or they overwrite them, or misunderstand what they mean. You read the blog post right? That’s what I’m talking about. I deal with that all the time (maybe more than the average person, to be fair, but still it’s a lot). I don’t really blame the people in 1970 for coming up with this design but it’s 2025 now; we can agree that it has problems. Tape recorders were also a neat idea but I can record a thousand times more on my phone now, often at higher quality. By modern standards, they suck.
- aa-jv 1y ago>It sucks because people miss error codes, or they overwrite them, or misunderstand what they mean. "Pointers suck", for the same reason. In any case, its the 21st century - if you're shipping C code that hasn't been statically analyzed with 100% code coverage, you're doing it wrong. Besides which, this is an abstraction which, once done properly once, in a library or framework, can be ignored at higher levels of abstraction, or even language runtime/execution environments, with some degree of comfort .. /ducks
- MangoToupe 1y ago> Plus, we're talking about POSIX here. You don't have a time machine. Shall we argue about just how much POSIX software is out there, working perfectly fine with this technique? I'd argue this is in spite of choosing a path that makes maintainable software more difficult than it needs to be. Constraints change over time, and the thought process that made this practice rational no longer coheres with modern-day constraints. Maintaining software is now (much, much) more expensive than the performance minutae that led to this cost. > Sure, in New Fangled Language De Jour™, return as many tuples as your heart desires. This isn't related to language at all—C may not have tuples, but structs are an equivalent.
- norir 1y agoI once worked on a project that had openssl as a dependency. We found that about 90 seconds in, the connection would drop a high percentage of the time. I laboriously worked through both the openssl and dependency code until finding that the bug was due to some code in the dependency not manually clearing out errno for openssl which caused a later read to hard fail when it should have soft failed with ewouldblock (or whatever). Global errno is a bad design that is a consequence of bad design in c. If c supported tagged unions and pattern matching, there would be no way to access the result or error value without first checking what type of value it is. But since c doesn't support this, all these apis require programmer discipline that cannot be relied upon. As a consequence, it becomes almost inevitable that you encounter some inscrutable bug that someone else wrote due to their lack of skill and/or discipline. That doesn't make sense to me though I do understand why it is the way it is.
- boffinAudio 1y ago>programmer discipline that cannot be relied upon This is the crux of all computerization and will never be eradicated.