Re: Discussion about why GNU/Linux system upgrades cause old programs to break
Arsen Arsenović <[email protected]>
| Newsgroups | gmane.emacs.devel |
|---|---|
| Message-ID | <[email protected]> |
Richard Stallman <[email protected]> writes: > [[[ To any NSA and FBI agents reading my email: please consider ]]] > [[[ whether defending the US Constitution against all enemies, ]]] > [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > > > There are two different classes of users of compilers: program > > authors and program users building the source form. > > > The former is harmed, substantially, by such default laxness, because > > they're enabled to write programs that are slightly wrong. The latter > > receives some slight relief from default backwards compatibility. > > You're arbitrarily defining "wrong" based on official Standard C and > taking that moral stance for granted. But that's not the standard > that I chose for the GNU Project. Our rule is that there is a certain > range of machine behaviors that we try to handle, and we don't need to > go to any lengths to make code work on weird machines outside of that. > > This GNU Project practice is prior to ANSI C (which wasn't finished yet). > I decided we didn't need to try to support all possible machines, > only the ones it was reasonably useful to support. Yes, I'm aware that GNU predates ANSI C. I'm not taking a moral stance here. Like any other program, the compiler exposes some guarantees to its users. These are, usually, called "the interface" of whatever is exposing those guarantees (say, the interface of the C compiler is the language it implements and the semantics it provides). Those guarantees have, for a long time now, been what the C standard (and C++ standard and so on) says. (As a side note, even if it was the case that the toolchain projects adhere 100% strictly to the standards, it would be incorrect to frame this in opposition to what GNU considers correct, because GNU developers play a significant part in the development of these standard) Of course, we also expose some extensions, and support other standard, and delegate some tasks out of the compiler to other components, etc. But, that aside.. Something that I'm considering wrong in the above text is something that fails to adhere to the rules of the interfaces in question, or which rely on assumptions not supported by guarantees of the interfaces in question. For instance, the following code is wrong, because there's no guarantee by any of those, and thus not by the compiler either, that the assumption the developer made (below represented as an assertion) holds: /* Write the 4-byte B to P. */ void write_4b (uint32_t *p, uint32_t b) { *p = b; } ... uint32_t b = /* Given. */; uint64_t q = 0; write_4b ((uint32_t*)&q, b); assert (q == b); We're able to reason what will happen assuming a given system: we may, possibly even correctly, reason that 0) '*p = b' in isolation would compile to something like 'movl %esi, (%rdi)', thus we may reason that the above write_4b 1) has no alignment requirements, 2) is atomic, 3) sets the value of q to b, with the top 32 bits being left as zero. But none of the steps in that reasoning are supported by the interface the compiler defines (in this instance, all of the rules pertaining to the above are part of ISO C). If they were, most compiler transformations would be invalid (how can one transform a program based on the "as-if" rule if even the instruction selection reasoned about in clause 0 is part of what is considered observable behaviour?). Obviously, the above program is rather useless. But such helper functions have been seen before. A correct "write_4b", that writes four bytes to a memory location, would be something like: void write_4b (void *p, char b[4]) { memcpy (p, b, 4); } The above compiles to: write_4b: movl (%rsi), %eax movl %eax, (%rdi) ret This has an extra memory dereference due to the extra pointer argument, but, if put in a header as an inline function, GCC would easily do away with that dereference. The above also, actually, has no alignment requirement, unlike the example of the wrong implementation (but it's still not guaranteed to be atomic), even though the compiler won't use the knowledge of alignment in either example (you can see the difference on, e.g. SPARC, though). Though, I'd note that it is not quite as simple as I've made it out in this illustration. The former write_4b, the one I called wrong, is wrong because of the way it's used. If it was only ever used to assign uint32_t values through a uint32_t pointer, it'd be fine (but quite useless, I'm sure you'd agree). The latter write_4b, which I called correct, can nonetheless be used incorrectly, of course. For instance, by over-running the storage it's being used to write into: char x; write_4b (&x, "foo") In my experience, most breakages that occur on a toolchain update fall into this category. Not all, of course. But most. Even though a given platform doesn't actually manifest a bug, since there's no guarantee of the behavior of the above, the bug may manifest in the future, after a toolchain update, because an unfounded assumption was made. -- Arsen Arsenović
signature.asc
(application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE----- iQECBAEWCgCqFiEE/uKz0RP8AKMWLWBhUsKUMB6ixJMFAmp+QMQbFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGRUUyQjNEMTEzRkMwMEEzMTYyRDYw NjE1MkMyOTQzMDFFQTJDNDkzEBxhcnNlbkBhYXJzZW4ubWUACgkQUsKUMB6ixJOa XAEAhWgCLZChhCKporHM4theGGN5QXuHldSXN0jZDmktk4UBAN7S6QCrwDBeD/KK 04f1ZQp9hb5P4ZYMcMK8DPEzFQYM =FOdg -----END PGP SIGNATURE-----