4 ms·
> The programmer has clearly attempted to set x[0]=0 Then why not just write it like that? This is like deliberately shooting yourself in the foot and complai
by andreyv 9y ago
> The programmer has clearly attempted to set x[0]=0
Then why not just write it like that? This is like deliberately shooting yourself in the foot and complaining that your shotgun works.
- sddfd 9y agoExactly. A compiler cannot guess what a programmer intended, but has to stick to the language semantics. Also, the article goes on to argue that uninitialized memory is used to seed random generators, which is generally undefined behavior. I don't think this should be a valid use-case.
- deleted 9y ago[deleted]
- GedByrne 9y agoSo go use rust and leave C for those who think it should.
- JCzynski 9y agoI will communicate cryptographically with people using C, so no.
- andreareina 9y agoThat business about uninitialized values being used to seed RNGs threw me for a loop as well. I think it's safe to say that x ^= x is equivalent to x = 0 and optimize it that way, just like compilers recognize common idioms for e.g. swapping, counting set bits, etc and emit the correct intrinsic instructions.
- likelynew 9y agoWhile I fully agree with you, but I will still like C to be as self explanatory as possible. C is the closest language for which one doesn't need to know the standard to understand it, at least the standardised C. I think it should be one of the biggest aim of C to let the language as it is(except the standard library). This change creates something that might not be expected by some. If this is replaced by an compilation error, I am okay with it.
- dom0 9y ago> but I will still like C to be as self explanatory as possible. C is not self-explanatory at all and without good knowledge of the standard anyone will write broken code that will fall apart sooner or later. C is not a simple language, nor one with simple semantics. Without knowledge of the standards it is essentially not possible to write portable C code.
- cronjobber 9y ago"Portable" is a red herring. C used to be a great language for writing non-portable code. That's what the optimization hounds are destroying.
- likelynew 9y agoI was thinking about reading the code line by line. Name any other language in which you can do that, without spending at least a week in that. I don't know what is a simple language according to you, but according to me C seems quite a simple language. Not saying it means that a good quality code is easier to write in C.
- dom0 9y agoI can't, but I also think your premise is not correct ("reading the code line by line" "without spending at least a week in that"). A lot of production C code is inscrutable without a good understanding of the language, and to understand many common constructs (e.g. overflow checks) you just have to know it. That trivial code is trivial to understand... well... that's true in most languages, no?
- GedByrne 9y agoThe problem is that the language allows this code and the compiler accepts it. If the code really does make no sense, then why not disallow it or capture it with a compiler warning? Instead the optimizer is to silently remove the code. Isn't it possible that the programmer knows something that the optimizer is unaware of?
- deleted 9y ago[deleted]
- Karellen 9y agoThe standard can't mandate a diagnostic for undefined behaviour, because it's not always possible to determine if behaviour is undefined. (Turing completeness) However, an implementation is allowed to issue any diagnostics it likes, so if you want one for this case, bug your compiler vendor to add one. Or, check the manual - it's possible that your compiler already does issue a diagnostic if you turn the right warnings on.
- xorblurb 9y ago> The standard can't mandate a diagnostic for undefined behaviour, because it's not always possible to determine if behaviour is undefined. Yet that argument is stupid if we are talking about compilers issuing warnings for the UB they "detect", because by definition they have detected them. It might not be possible when it does not work exactly like that in some cases, but at least before removing some code, this is desirable. It might also not be easy given the current internal design of compilers, but then I argue those design should be changed, because it is just too dangerous.
- clarry 9y agoYou are free to pave the way. But pretending that compiler developers are currently just ignoring the issue out of mischief and preference for performance above anything else is disingenous. If the problem were so simple, we'd probably already have a dozen free static analyzers that do a good job, and you'd be happy to use them. The thing is, "detecting" UB in the sense you imply is usually not what happens in the context of said optimizations (that's not to say they won't attempt to do it... ever seen a compiler warn you about use of uninitialized variable?). What compilers do is they assume the program is correct. And following that assumption, they perform an optimization that is only correct for correct programs. That is in fact very simple to do. They do not try to prove or disprove that program actually invokes UB there -- that is impossible in general, and even in the subset of cases where it is possible it could require deep whole-program (including libraries!) analysis that could take massive computational resources. Many people here keep trivializing the problem but I don't think they understand the problem at any depth. And that is why I say you should pave the way, not in a smug "fuck off get off my lawn fix your own problem" sense, but to get people to honestly gain some background in program analysis, read research papers, study existing analyzers, and gain some appreciation for what it takes. It is far, far from trivial. Especially if you can't just take the language and change it to your liking (breaking nearly all existing code) until all the hard stuff is out. And in saying that, I suggest that it is easier to start with a new language (or, at least some existing language other than C) that was designed from ground up with such analysis & correctness provability in mind.
- mobiletelephone 9y agoAgreed. A modern compiler will pick the optimal assembly (most of the time!) That said, I feel like C often lacks the expressiveness to properly define intent and allow the compiler to optimise well.
- srett 9y agoStill, making the compiler do whatever the hell it wants because "hey it's undefined behavior so we have the license to" is just as idiotic. Make the compilation fail and then add a flag to override for those who feel extra smart.
- deleted 9y ago[deleted]
- yorwba 9y agoThe compiler is not doing "whatever the hell it wants". It chooses an interpretation of the undefined behavior and then optimizes based on that. Of course, if the programmer had something else in mind, they will be surprised about the result; but it's their fault for not being precise enough. So why make reads of uninitialized values undefined at all? Consider code like this: uint64_t x; // Will be initialized later /* ... */ if(check_some_condition(y, z)) x = (uint8_t) f(b,d); /* ... */ if(check_some_other_condition(foo)) x = (uint8_t) bar; /* ... */ x &= 0xf; /* ... */ if(x & 0x800) do_stuff(); Now the compiler has no way of knowing whether x will be initialized or not. But if it has been initialized, then it's value must be in 0..255, so the & 0xf can be limited to the lowest byte. But this means that the test for x & 0x800 will always be false, and stuff will never be done, so the compiler can optimize it out, reducing code size and thus cache pressure. If these assumptions don't hold, then some later code may get passed a value for x that has the bit in 0x800 set, and expect do_stuff() to have initialized some data structure, which didn't happen, and the code blows up. But the compiler was just working from what it knew, and under the assumption that the programmer wouldn't depend on completely arbitrary values that happened to be in memory, everything it did was perfectly sensible.
- deleted 9y ago[deleted]
- xorblurb 9y agoThat was just an example but I'm starting to have horror visions: imagine you have a struct with some gaps because of alignment, and you read it as chars (which you are supposed to can and must do to get the representation) after having properly initialized all its fields. You might hit an UB just by doing that, maybe not according to the standard for obscure reasons (I hope so), but the probability you are going to get that one day from a compiler developed by a moron^W zealot UB code deletionist is non-negligible (they do have misqualified some valid constructs as UB in the past...) BTW if my example is actually valid, then that rule of reading uninitialized object being UB is some of the hugest shit, because depending of the type maybe reading an uninitialized byte will be UB, or maybe not, depending of how that byte was in a field of a type or just alignement... In practice, this is even more crazy, because it also depends on which parts of the code your compiler have seen, and it capabilities to break^W understand it, so you might as well considered it has a layer of non-determinism above all that. C/C++ has become too dangerous. Use something safe instead.
- dom0 9y agoThe contents of padding are unspecified after a write; reading it is not UB. Essentially: the padding belongs to the member, and after you initialized the member the padding is initialized as well (you just don't get any guarantee of the value). This is the reason why padding for wire formats has to be made explicit and be explicitly initialized, otherwise the compiler is free to generate code packing bible quotes into the padding.
- xorblurb 9y ago> The contents of padding are unspecified after a write; reading it is not UB. Ok so like I said: "depending of the [effective] type maybe reading an uninitialized byte will be UB, or maybe not, depending of how that byte was in a field of a type or just alignement... " If I understand correctly this is so insane (to treat those that are UB in that context as effectively UB) that I still have no word. I absolutely do not want to use a compiler made by people who consider that that situation is OK or even just tolerable for potential gains, regardless of the speedup you could obtain (even at 1000%, I just don't want it -- the risks are way too high) EDIT: I reread and I think I misunderstood. This is not as bad as I thought, but this is extremely complex and I guess compiler bugs will happen (or have already?) in this area. [ Also what is the relationship with extensions? (like pre-standard or even standard explicit extra alignments...) ]