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: > > > > > > Even if we agree that that particular deviation had become a bad idea > > > to use, reporting it as an error and making compilation fail is harsh, > > > and causes trouble for the users of GCC. > > > For this particular deviation, not reporting it as an error or not > > making compilation fail also causes trouble for the users of GCC. > > Are you and I talking about the same set of cases? Presumably - I mean the cases permitted by -fpermissive as of GCC 14, that were previously permitted by default. > Are you saying it causes trouble _for some programs on some possible > platforms_, or _that it causes trouble for all such programs on > whichever platform that user uses_? The latter. Though, whether the problem manifests noticeably depends on other factors. They're /very/ likely to manifest noticeably on many platforms, however. The examples given before all happen on x86_64 and aarch64 (and presumably also rv64). One of the examples given below manifests on all platforms. > > The users have already changed that code. The vast, vast, majority of > > cases where these diagnostics are emitted are not intentional uses but, > > rather, indicative of a bug. > > I think it would be useful to clarify what "bug" means in that statement. > > Does it mean, "on some possible standard-conforming platform, the > program would execute wrong"? > > Does it mean, "the program will execute wrong on a platform that > user will use in the next year or next decade"? In this particular case, the latter is closer. Again, as an example, it's enough for a pointer to be used as a return value on a 64-bit platforms, which are not at all uncommon, or for a 'long long' to be used as a return value on any platform, for *visible* breakage when such a function is called through an implicit function declaration even in the most forgiving of conditions. Note that this is a lone example in which it is almost guaranteed to manifest as a problem; in practice there are other ways for other bugs to manifest. But, note that even if something does not manifest as, or perhaps even is not at all a bug (e.g. call to an implicitly-declared function whose implicit declaration matches its definition), most GCC users still did not intend it. Very few people intend to rely on implicit function declarations or unprototyped functions, as those mean that the type checker is doing far less work on their project than they'd like it to, and thus they're relying on type checking that isn't happening to keep notify them about incorrect use. However, to broaden this beyond just this one particular change and this one particular example, as I've explained before, programs that make false assumptions aren't only broken on "some possible standard conforming platform", they can - and often will - also break with newer compiler releases, or older compiler releases, or when the user chooses to perform link-time optimization instead of not performing it, or when the user chooses no to perform LTO instead of performing it, or when the user uses -O3 instead of -O2, or if the user uses -O1 instead of -O2, or when the users CPU supports an instruction that the developers' CPU doesn't, or when the users CPU lacks an instruction that the developers' CPU has, or when the stack size used by the user is different to that used by the developer, or when the heap address on the users' end differs to that used by the developer, .... Just because a program happened to work in one configuration (where configuration is understood to mean a total description of the entire system; the particular CPU, compiler, OS, library versions, flags used to build the compiler, OS, libraries, and the final program, ...) does not mean that it will work in any other, even if very similar. The only way to guarantee a program works in all configurations is not to make such false assumptions. And there's no way to "fix" that. How could there be? The compiler can't mind-read to provide guarantees that the developer imagined that have no basis either in the language itself or in the extensions to the language. Please do not imagine such guarantees. Note that this is distinct from implementation-defined behaviour, obviously those can be relied upon *if the implementation guarantees them* even if the base language does not, presuming that you document what implementation is to be used. (IME, though, this is more trouble than it's worth most of the time as it makes it far harder to get programs running on other platforms, but it /is/ a valid thing to do.) Note also that this is not the same as writing portable code. You can write code that will only ever run on one CPU and one libc and one kernel with no other dependencies, and it will still break eventually if it contains such false assumptions. This can be done by, for instance, using inline-asm or some CPU-specific libc extension, while returning a 'long long' from a function called through an implicit function declaration. This is completely unportable, and yet will produce wrong execution. On the other hand, you can write a program for a given Unix-like system which makes no false assumptions and breaks no preconditions the language requires, and it still won't run on e.g. Windows, probably because you included some completely valid, specified, and documented header and called some completely valid, specified, and documented function in the way that is documented from that header, but it only exists for that system, and not for Windows, or even other similar systems. For instance, you could call reallocarray; doing so is completely valid and perfectly fine but that program will no longer be able to run on Windows or even on some Unix-like systems, despite making no false assumptions. But, calling it through a mismatched declaration (e.g. the implicitly generated one) will result in strange bugs even on those systems that provide it. Not violating the rules of the language helps with portability, sure, but it is not the same thing as portability. Foregoing portability does not mean foregoing the rules of the language you're using. Even if I don't particularly care whether or not my programs runs on SPARC, and don't test on it, this does *not* mean that I'm permitted to assume accesses to misaligned pointers are permitted just because 'ld' or 'mov' on the CPUs I /do/ test for permit unaligned accesses. They aren't. If I was to, based on that instruction selection, assume that I can perform unaligned accesses, this may break: a future compiler version may choose an instruction other than 'ld' or 'mov', which does require a higher degree of alignment. And the ensuing breakage is my fault, because I made a false assumption. I already went over why in an earlier reply. -- Arsen Arsenović
signature.asc
(application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE----- iQECBAEWCgCqFiEE/uKz0RP8AKMWLWBhUsKUMB6ixJMFAmqMZZ8bFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGRUUyQjNEMTEzRkMwMEEzMTYyRDYw NjE1MkMyOTQzMDFFQTJDNDkzEBxhcnNlbkBhYXJzZW4ubWUACgkQUsKUMB6ixJPp AAD9FvArfgfiHOEkEmIVb0ZC+L+QDF5Bn/EZTuC2PFaAou0BALDBDsMjNkZGtrOE 99ICj1/z3YP0COrEYpP2U9QckvcA =qI6i -----END PGP SIGNATURE-----