4 ms·
Hey, don't lump C++ in with this. If you write code in the STL weenie style or the Pretend It's Java style there aren't any idioms I know of that would ever vio
by bcoates 14y ago
Hey, don't lump C++ in with this. If you write code in the STL weenie style or the Pretend It's Java style there aren't any idioms I know of that would ever violate the rules he mentions (out-of-range pointers, signed overflow, invalid aliasing). I don't do those things and the C++ programmers I work with don't do those things, at least not habitually. I don't see violations of undefined behavior rules, or the use of idioms that come close to it, very often in our code. Not nearly as often as the sort of mundane errors that no language can prevent.
These are not problems of a language per se, but the original sins of neo-vaxocentrism and confusing "I understand how this might work, at some random abstraction layer" and "I can depend on what happens when I do something stupid". Free your mind of these and the rest will follow.
These low-level bit banging errors are vastly less common than shared-memory concurrency issues, which as far as I can tell are endemic to all code that attempts shared-memory concurrency, in any language. If you want to have an axe to grind about languages that aren't future proof, look there.
- betterunix 14y ago"If you write code in the STL weenie style or the Pretend It's Java style there aren't any idioms I know of that would ever violate the rules he mentions (out-of-range pointers, signed overflow, invalid aliasing)." What does the STL do about signed overflow? As for out of range pointers, that is an easy one to get with the STL: vector<int> somevector(100); somevector[200] = 5; "These are not problems of a language per se" Yes they are: the default numeric type is fixed-width, pointers pop up all over the place and pointer dereferences are unchecked by default. Personally, though, I would have chosen (as the article's author did) the more severe deficiencies in the standard, like the lack of any requirement that a function with a non-void return type have a return statement along every control path or the fact that there is no reliable way to signal errors that occur in destructors. "These low-level bit banging errors are vastly less common" Not in my experience, and not judging by the number of bug reports and vulnerabilities I have seen that stem from low-level mechanics.
- bcoates 14y agoI'm not saying the language is some sort of security barrier that prevents any error, I'm saying sanely styled code does not have these issues in practice. The solution is "don't do that, and cultivate habits that will not cause you to do that by accident", not having the compiler make up semantics for broken code or putting in checks everywhere. Just because someone, somewhere does it wrong, doesn't mean it's impossible to do it right. this: vector<int> somevector(100); somevector[200] = 5; Is a C idiom translated by cut-and-paste. The unmotivated poking of arbitrary magic-number offsets into a magic-number sized vector is not proper. It's the kind of thing that sets off alarm bells on even the most casual of review.
- betterunix 14y ago"I'm saying sanely styled code does not have these issues in practice" Otherwise known as the "just do it right" argument. This is an argument that goes all the way back to the days of writing everything in assembly language, and it was just as wrong then as it is today. If only a restricted subset of a language can ensure that basic issues do not become serious problems, then the language should be restricted to that subset. "not having the compiler make up semantics for broken code or putting in checks everywhere" Really? I would rather have the compiler put in run time checks whenever it cannot infer that no input will cause the program's behavior to be undefined. Thus, the compiler might insert a check here: for(i = 0; i < input.length(); i++) some_vector[i]++; but not here: for(i = 0; i < min(input.length(), some_vector.length()); i++) some_vector[i]++; nor here: if(input.length() > some_vector.length()) { throw some_exception(); } for(i = 0; i < input.length(); i++) some_vector[i]++; At the very least, requiring bounds checks on array access would create a definition for out-of-bounds pointers: program termination (or perhaps an exception being thrown). A reasonably good compiler can detect when a bounds check is unnecessary and can remote the bounds check as an optimization. Why shouldn't this be something that compilers do -- out-of-bounds array access is never a good thing (oh, wait, you might be dereferencing some arbitrary pointer that you got by some means other than allocating memory with "new" -- OK, fine, but that is what type systems are for; this sort of separation is not unheard of, I see it in Lisp with SBCL's FFI)? "The unmotivated poking of arbitrary magic-number offsets into a magic-number sized vector is not proper. It's the kind of thing that sets off alarm bells on even the most casual of review." Perhaps so, but then the answer is not simply "just use the STL." As with most things C++, it requires a long list of things to make code work right, and even people who have been writing C++ code for many years are sometimes surprised to discover that something they thought was fine is actually bad. C++ makes it pretty easy for programmers to do the wrong thing and needlessly difficult to do the right thing, which is why years of expertise are needed to write remotely reliable C++ code.