7 ms·
This is absolutely not true. I work with many C and C++ programmers, and we ship very large amounts of C and C++ code with a very high adherence to the standard
by jjnoakes 11y ago
This is absolutely not true. I work with many C and C++ programmers, and we ship very large amounts of C and C++ code with a very high adherence to the standards.
- pdw 11y agoCan you name an open-source C or C++ project that you believe avoids undefined behavior? Because some people have spend serious time looking without success. E.g. http://blog.regehr.org/archives/1292 http://blog.regehr.org/archives/1292
- necessity 11y agoI cannot see the language being at fault in cases such as the ones pointed out by the article: > SQLite’s vdbe struct has a member called aMem that uses 1-based array indexing. To avoid wasting an element, this array is initialized like this: p->aMem = allocSpace(...); p->aMem--;
- dzdt 11y agoIn its deep history, the C language was defined by what the implementations did. Only later was it standardized, with an attempt to permit existing implementations be viewed as conforming or easily updated to be. Even decades later, though, the culture of developers tends to the view that something which has always worked in every important implementation should be allowed and continue to work in new implementations. This is such an example. Only a new generation of compiler writers are challenging this, trying to shift to a language-lawyer interpretation of the standards.
- kps 11y ago> the culture of developers tends to the view that something which has > always worked in every important implementation should be allowed and > continue to work in new implementations Yes, and X3J11 stated as its first guiding principle, > Existing code is important, existing implementations are not. But then they committed the original sin against “simple C” by inventing ‘volatile’, breaking systems code written when p[0]=x was expected to write to location p. Unlike ‘const’, with which the programmer grants additional license to the compiler, C89 granted the non-‘volatile’ license to the compiler by default. In retrospect, I think C would have been better off retaining do-what-I-wrote as the default, and requiring the programmer to grant the compiler license to do otherwise. C already had the ‘register’ keyword to indicate that a variable should be compiled for speed and need not be literally preserved according to a naïve reading of the code.
- jjnoakes 11y agoI don't think many open source projects do, no. Most of them aren't extremely quality-focused, and don't spend the money to develop or purchase some of the static analysis and formal verification tools that help a code base reach the level of quality I'm referring to. But if I tried hard enough, I'm sure I could find a few that have been run through some sort of formal verification tool. Whether I could or not doesn't change my assertion at all though.
- Someone 11y agoVery high adherence < follows the standard to the letter. => You need stronger arguments to make the "absolutely not true" claim.
- jjnoakes 11y ago"Very high adherence" means we pass UBSAN, we pass our in-house static analysis tool, we've never been miscompiled by any compiler (modern, old, bleeding-edge, on multiple platforms) unless it was due to a compiler bug, ... By all practical definitions, and by any measurable way to declare a codebase free of undefined behavior, ours is. And I bet others out there are too. There are formal verifiers for C programs that are used in industries. Unless there's a bug in the verifier, the program that it verifies is, by definition, free of undefined behavior. Just because you, or the open source projects you use, don't code to the standards, or don't have or use the tools that help you do so, doesn't mean there aren't industries out there who can, and do.
- jcranmer 11y agoI would assert that virtually every non-trivial C/C++ program (>100KLOC) contains undefined behavior. Here's a list of undefined behaviors that's almost impossible to get rid of: * Data race. This is particularly fun for anyone who started doing multithreaded code pre-C11/C++11, since volatile does not let you use code across multiple threads without locking. * Signed integer overflow. Are you sure that there is absolutely no input to your program that would not cause one of your thousands of signed arithmetic operations to overflow? * Buffer overflow. This is something like 90% of all security vulnerabilities. * Uninitialized variables. Note that -Wuninitialized doesn't catch all cases, although this is relatively easy to mitigate with a paranoid style guide. * Strict aliasing rules. Better yet, if you have any sort of custom memory allocation scheme, you're pretty much guaranteed to break this, since the only way you can access an object with a dynamic type of bytes (signed/unsigned char) is via signed/unsigned char. Functions like memcpy or malloc cannot legally be written in C without breaking this behavior. Also, there is not (to my knowledge) any dynamic checker for violations of this property, unlike the other things in this list. Your program probably has undefined behavior. You just don't know it yet, and your compiler hasn't figured out how to squeak out a 0.5% speedup from screwing you over because of it yet.
- qwyxzy 11y ago> Functions like memcpy or malloc cannot legally be written in C without breaking this behavior Sorry, I don't understand this. Does this mean that these C standard library functions cannot be written in C without breaking the ISO C standard?
- PeCaN 11y agoParent is wrong. char, signed char, unsigned char, and void pointers can all legally alias anything. Those functions can be written in standard ISO C.
- corysama 11y agoStrict aliasing is the only item on your list that I could see leading someone to get upset with the optimizer. And, maaaaaaybe signed integer overflow. With strict aliasing, I don't think your examples are correct. They all involve typecasting pointers, but don't involve interacting with the original type later. So, memcpy uses a void* as char* and MyAllocator uses char* as MyType*, but in both cases they never go back and expect predictible new values in the original types. The rest are clearly taught in CS100 to be doorways to chaos. In particular, complaining that volatile doesn't get rid of the need for locks is just making noise. Might as well complain that auto doesn't get rid of the need for locks. They are both unrelated to threading.