As I have repeatedly stated, I neither advocate for or against undefined behavior usage. I do my best to avoid it whenever possible, or deal with it (ala' race conditions in hashing) when the only solution to avoid the race is too expensive (acquiring/clearing a lock).wgarvin wrote:I think you are wrong to the extent that you are trying to assign blame to Apple (or the glibc maintainers, or whoever). There was an explicit contract about how strcpy would behave; you and the authors of all those other broken programs that other people are whining about, were 100% in the wrong by using strcpy in an illegal manner. The behavior of strcpy when used that way has been undefined for 25 years, and there is no possible justification--none--for using it in that undefined fashion anyway.bob wrote:WHAT am I "wrong" about?simon wrote:You're probably the only person who is surprised.wgarvin wrote: Okay, we get that you're still annoyed about it, although I'm surprised that two weeks have passed and you still haven't admitted yet that you're completely wrong!
Certainly not my original point, namely that Apple broke something that did not need to be broken. That Apple, in doing so, caused a lot of debugging effort on my part, and on the part of many others, unnecessarily.
I'm neither supporting OR railing against using undefined behavior if one is careful. I do believe the compiler should "do the best thing" as opposed to "let's be anal and break the code..."
Is it annoying to have programs broken by a change by somebody else? Sure.
Was it a dick move for them to start enforcing the requirement by adding this explicit check and abort? Perhaps. I'm actually quite sympathetic to that argument, but neither you nor I knows exactly what their motivation was and it doesn't matter, their freedom to do that was explicitly reserved by the standard 25 years ago.
So we need to apportion blame for the broken programs. You seem to think some, most, or perhaps even all of the blame belongs to glibc/Apple. If so, you are completely wrong. 100% of the blame here belongs to the programmers who didn't write code that followed the standard. In each case, that incorrect code was always a time-bomb waiting to blow up their programs. In your case you got away with it for at least 25 years, which perhaps was extremely lucky. But finally your luck ran out.
So to be clear, I think you are wrong in that you think your experience this week was somebody else's fault when an impartial review of the facts makes clear that it was 100% your fault. Only one party here was violating their obligations under the language contract. Glibc was 100% entitled to do what they did (although they will still take some flak for it because of the "dick move" angle).
When a program invokes undefined behavior according to the spec, there is no other possible outcome. The implementation can do anything it wants, no matter how ludicrous or unintuitive. The implementor might change their mind from one week to the next, and whatever happens is still 100% the programmer's fault.
As programmers we might find this to be more than a little unfair, but its the way the language works. Undefined behavior exists to preserve optimization freedoms for implementors and/or to simplify some parts of their task, and the programmers just have to avoid it as best they can. As long as we avoid invoking undefined behavior, we get to rely on the program semantics promised by the standard. But if we accidentally invoke undefined behavior then the nasal demons can and sometimes do result.
I have no problem with them changing the code if they want to fix it permanently. Torvalds suggested just equating memcpy() to memmove() and be done with it. No performance loss. No undefined behavior. Everybody is happy. An alternative is to print a warning or two at run-time, noting the risky behavior, but continuing to execute anyway. The worst case is simply breaking it, no notice, no "warning, this is deprecated and will go away or crash in future versions." or anything else.
That I do not consider acceptable, for EXACTLY the same reasons Linux quoted in the great memcpy() debate. Suppose they find a way to detect SOME race conditions. Is just "aborting" OK there? Is it REALLY a race condition (since there is no current method for a compiler to detect it reliably in the first place)? Is it OK to abort for "possible undefined behavior" conditions or must it wait for an actual condition to arise (assuming it could determine this, which it can't.). I see no good reason for aborting on undefined behavior. If they want to get cute, add the test in the PGO code. Then you can get compile-time warnings rather than unexplained execution-time crashes. There are good ways to fix a problem, and bad ways. I suppose if the cops shot every speeder in the head, eventually there would be no speeders. But it does seem to be a bit drastic.