9 ms·
That's why you don't enable -Werror in release builds, contrary to received wisdom on the subject. When you compile with -Werror, you surrender control over yo
by quotemstr 9y ago
That's why you don't enable -Werror in release builds, contrary to received wisdom on the subject.
When you compile with -Werror, you surrender control over your build's success to the whims of the same people who think that it's okay that memcpy(0, 0, 0) is undefined behavior. The personal opinions of future compiler authors shouldn't affect whether your program builds successfully. Sometimes warnings are bogus.
Sure, use -Werror in development. But don't make it the default.
- johannes1234321 9y agoThe opinions of (future) compiler authors decides already wether your programm will work in all cases. With those warnings they indicate some of their decisions.
- quotemstr 9y agoFuture compiler authors are at least in theory beholden to current language specifications. If a program does something legal that a compiler author feels is a bad idea, the compiler can whine all it wants, but it still has to compile the program. Compilers drop support for older specifications far less often than they add new warnings.
- AgentME 9y agoIn general yes, but the posts above were talking about a warning about undefined behavior, so the standard says that anything could happen in that case.
- tomsmeding 9y agoThis is especially true for warnings about && and || precedence. When you use those two operators in one expression without parentheses, IIRC both gcc and clang complain, but I once wanted to compile some software that thought it was a good idea to -Werror all the code and don't use parens around &&. Fun times fixing all the zillion makefiles that mentioned Werror. (Yay autoconf?)
- pklausler 9y agoThat's the one warning that I like to disable. I hate having to write superfluous parentheses around conjunctions. I mean, come on. It's just as lame as requiring them around multiplications would be.
- mjevans 9y agoEven if /you/ know the order of operations, making them explicit with the parentheses provides clarity and allows future maintainers to quickly (and correctly) deduce the structure of the logical construct. I generally only leave them out in short simple to follow 'normal math' order of operations.
- quotemstr 9y agoSure. The rule you suggest might be good coding practice --- but people can disagree, and their omitting the extra braces doesn't make the code wrong. An existing correct program shouldn't one day stop building because someone added a warning that enforces your preferred operating precedence marking style.
- zaphar 9y agoThat is because the compiler authors conflated warnings with a linter. Warnings should be used to indicate basically just two things. 1. Dead/Duplicated Code. 2. Probably Broken Code. Anything else is stylistic and the realm of opinion. Even if it's informed opinion enforcing it belongs in a linter.
- quotemstr 9y agoTo be fair, a compiler contains all the infrastructure you'd want in a linter. I don't mind compilers having lint-like warnings: I just want them to very clear about the differences between these warnings and warnings that reflect functional problems with high probability.
- bluGill 9y agoThe C standard is dropping support for things like gets, a compliant modern compiler should fail to build any code that uses that. This is very controversial with compilers - and gets is among the most horrid thing that ever made it into a compiler.
- quotemstr 9y agoPulseEvent and IsBadReadPtr are worse. Windows has some of the very best and the very worst in API design.
- jcelerier 9y ago> The personal opinions of future compiler authors shouldn't affect whether your program builds successfully. So, let's say that you find some 2003 software on some deep corner of SourceForge that you want to use. Would you rather : * Have the build fail because new warnings were introduced ? * Have the build succeed and then get crashes at runtime because the behaviour of the compiler changed anyways and the program was rendered invalid ? I'll personally always want the first one.
- quotemstr 9y agoThere's a name for a kind of change that makes a previously correct program incorrect: "compiler bug".
- jcelerier 9y ago> There's a name for a kind of change that makes a previously correct program incorrect: "compiler bug". No. The only thing that matters is that the language rules are respected. Or maybe you'd want programs that were correct with the first C compilers to still work today ? Because for instance they didn't do type checks at all. `void f(float, float); int x = f;` you say ? no problem! `char c; c[-15];` ? no problem! Everything did compile, sure. Is it the world we want ? Most certainly not.
- colejohnson66 9y agoTrigraphs used to be part of the standard and are now removed. So really old programs that used them now would fail to compile. Granted, that is a bit of a low hanging fruit.
- mrguyorama 9y agothe program wasn't "previously correct", else a new, but still language compliant, compiler would build it just fine
- YSFEJ4SWJUVU6 9y ago
- bennofs 9y agoI agree that using `-Werror` in release builds is a bad idea. But I don't think you need to "not make it the default" for this: just provide an easy way to disable it, and do it automatically for release builds. It should be on by default for any developer.
- slavik81 9y agoI used to have it on by default, but I found it getting in my way while developing. I'd do things like add some temporary debug code, or comment out part of an algorithm and then end up with a bunch of compile errors to fix. The compiler rightly points out that the code is of poor quality, but that's because I'm not done yet. Warnings in that case are still useful. If the project is otherwise warning-free then it's easy enough to spot the new warnings and judge if they represent a real mistake. My preference today is to set -Werror on CI builds. Any code that's final should be warning-free, but it's unnecessarily painful for work-in-progress.
- quotemstr 9y agoIn Java, the compiler complains about unreachable code and aborts. I think that's ridiculous. Sometimes it's useful to create unreachable code during development. int foo = doSomething(); return 0; // Debug XXX DONOTSUBMIT int bar = doSomethingElse(); return foo + bar; It's hilarious, though, that this workaround works: int foo = doSomething(); if (1 > 0) return 0; // Debug XXX DONOTSUBMIT int bar = doSomethingElse(); return foo + bar; Go's mandatory warnings are equally annoying. I'm sick and tired of little rarefied groups of language designers trying to impose their ideas about best practices on the rest of the world.
- anyfoo 9y ago> the same people who think that it's okay that memcpy(0, 0, 0) is undefined behavior. I am curious about this particular example. How does that ever make sense, where do you have that? I'd accept that it would be nice to have memcpy(p1, p2, n) with valid pointers p1 and p2 to still be defined when n=0, because maybe n is variable and might work out to be 0 in some cases, which you then don't need to treat specially. I don't know whether that case is defined or not. But in the case where either p1 or p2 are NULL, the memcpy will be illegal no matter what n is, so if p1 or p2 are variable you always have to check them anyway, and to run into the memcpy(0, 0, 0) case you would actually have to special case n=0 when p1 or p2 were NULL, which makes no sense. Unless 0 is actually a valid address (kernel code with identity mapping at 0, simple platforms), but then NULL becomes a whole different beast.
- quotemstr 9y agoBecause memcpy(x, y, 0) for any x and y is a no-op. Why should we have a special undefined case for x==nullptr || x==nullptr? In general, we shouldn't introduce unnecessary boundary conditions to APIs.
- anyfoo 9y agoBecause not making that case undefined puts additional and completely unnecessary burden on any implementation of memcpy? Now you have defined that memcpy(_, _, 0) is a no-op, so now the implementation has to make sure that it remains a no-op, which, if for instance a particular memcpy needs to perform an operation before the actual copy, may well involve adding conditionals to your implementation. For a case that a program will never sensibly run into (see my previous comment for why).
- quotemstr 9y agoIt's perfectly sensible to run into the case: imagine we're copying from a buffer that's allocated on demand. In the case where we haven't allocated the buffer, we have buf==nullptr and buffsz=0. Why should it be wrong to memcpy(other_buffer, buf, bufsz) without first checking whether bufsz is zero (and thus buf is nullptr)? I don't think your optimization actually exists. In what possible world can we generate better code by assuming that for memcpy(x,y,n), when n==0, x!=nullptr||y!=nullptr? I think that in some cases, the claim that undefined behavior allows for better optimization is bullshit.
- jlg23 9y agoI disagree. Rather write nasty rants in comments that explain compiler-specific workarounds. It should not be too many anyway, if one adheres to KISS. Otherwise you surrender control over the correctness of your program "to the whims of the same people who think that it's okay that memcpy(0, 0, 0) is undefined behavior". More debatable decisions will be made in compiler implementations and I'd rather force the user who compiles the program to understand the implications of warnings by turning them into errors than letting them ignore them (because "it compiled, after all!"). If I was to make the call, I'd make "-Werror" default in all compilers, remove the option and allow to disable it by "--I-really-want-to-ignore-warnings-for-fscks-sake" which when used would sleep(30) after an all-caps nag screen that tells people "don't ever use that option."
- millstone 9y agoWhen I download some random unmaintained tarball from years back, I don't want to have to fight with the compiler. Just build dammit.
- anyfoo 9y ago"When I buy some random unmaintained car from years back, I don't want to have to fight with the transmission fault mode. Just drive dammit."
- throwaway2048 9y agoSoftware doesn't mechanically wear over time, this is an awful analogy.
- AgentME 9y agoIf you build old software that relied on a specific compiler treating undefined behavior in a certain way, then it could.
- anyfoo 9y agoYeah, I admit. A better analogy on my part would have been that you buy a car and it's not street legal anymore, or one that does not work in today's environment anymore. "I don't want to add seat belts, just drive" or "I don't want it to run on unleaded fuel". (Note that I have no idea if there actually were cars that required leaded fuel.) Anyway, I think even more likely than running into new compiler warnings/errors is running into external dependency issues, which require you to touch the software anyway, and, I'd argue, are often much harder to fix than fixing code that triggers warnings.
- adekok 9y agoUsing -Werror in development is annoying too. It works if everyone is running exactly the same OS, header files, and version of the compiler. If not... different developers have different errors. I try to build with all of the warnings turned on, multiple static analysis tools, and with multiple OS / compilers. Yet every time a compiler or OS is upgraded, there's a whole suite of new build warnings.
- bluGill 9y agoHave you tried this lately - in the last 10 years? things used to be bad, but clang and gcc at least have really cleaned up their act, most warning are now zero false positives and so you want to clean everything up. The only time I see the issue you described was when someone upgraded the compiler, and the new warnings were all real bugs. Static analysis tools are a different problem: I find that most of them have so many false positives they are not worth looking at.
- adekok 9y ago> Have you tried this lately - in the last 10 years? I'm wondering what it is about HN that lets people be condescending know-it-alls. If you look, there's only one of me online. I write between 10K and 20K lines of C a year. So yes, I have tried this in the last 10 years.
- quickben 9y agoWhat's warning on one platform is usually error on another. People that decide what memcpy does, have vastly different problems in mind (and hardware realities) from people complaining about it when using it on <random platform>.
- ajdlinux 9y agoThen use -Wno-* to disable specific warnings that are problematic, when they become problematic. That solves 90% of the issues with using -Werror.
- Joky 9y ago> you surrender control over your build's success to the whims of the same people who think that it's okay that memcpy(0, 0, 0) is undefined behavior. You mean the people who write the specs of the language? Well you surrender control to these folks when you decided to pick this language! Otherwise the problem about memcpy of zero-size and nullptr is unfortunate from compiler engineers (at least clang engineers) point of view. The story is that the compiler is optimizing based on programmer annotations: after all if a programmer takes the effort to annotate their APIs, let's benefit from this. However the GNU libc annotated `memcpy` (and others) with this non_null attribute, causing this fragility on invalid (according to the spec) but common code. Opinion of clang authors is somehow "Deleting a null pointer check on p after a memcpy(p, q, 0) call seems extremely user-hostile, and very unlikely to result in a valuable improvement to the program". Clang dev thread: http://lists.llvm.org/pipermail/cfe-dev/2017-January/052066.html http://lists.llvm.org/pipermail/cfe-dev/2017-January/052066.... Note in this thread that clang devs are trying to get the language changed to remove this UB.