views:

434

answers:

7

I saw some posted code with an out of range error on SO that made me wonder. I would expect a compiler to generate a warning (at the highest level at least) for this code

#pragma warning(push,4)
int main(){
    int x[2];
    x[2]=0;     
    return 0;
}
#pragma warning(pop)

but it does not.

The EDG compiler nicely says:

"sourceFile.cpp", line 3: warning:
          subscript out of range
          x[2]=0;
          ^

Actually EDG says bit more more(all of which are expected)

"sourceFile.cpp", line 1: warning: 
          unrecognized #pragma
  #pragma warning(push,4)
          ^

"sourceFile.cpp", line 4: warning: 
          subscript out of range
      x[2]=0;     
      ^

"sourceFile.cpp", line 3: warning: 
          variable "x" was set but never used
      int x[2];
          ^

"sourceFile.cpp", line 7: warning: 
          unrecognized #pragma
  #pragma warning(pop)

but that's not my question.

I consider this failure to warn a SERIOUS error of omission in VC9,(even more so since an auto variable!!!!). Can anyone give me a serious reason to change my mind?

+8  A: 

The compiler is not required to issue warnings for undefined behaviour (even "serious" ones like this). Many compilers have different sets of behaviour that they tend to check for. I think that if you have VSTS, there is some additional security checks that can be enabled so this might be caught by that. Additionally, the compiler can insert runtime checks that will catch this memory overwrite (probably for debug builds), so you should make sure that you have those enabled.

1800 INFORMATION
Are compilers *required* to warn about anything at all?
Dan Moulding
Darned if I know - in any case the behaviour in the question is undefined, my point being that in the case of undefined behaviour the compiler is allowed to do anything at all (including nothing)
1800 INFORMATION
I realize that it is compiler dependent (I gave the output of the EDG compiler). I don't want a runtime check for something that could have been warned about at compile time. Quite frankly I am very surprised at some of the answers here. They seem to be written by children intent on showing how smart they are.
pgast
It is not compiler dependent, it is undefined behaviour - do you know the difference?
1800 INFORMATION
the fact that the compiler does or does not issue a warning is compiler dependent and that was what we were taking about - not subsequent runtime behavior in a program with the error in question. And my "do you know the difference?" is a bit well....BTW I was not referring to your answer when I wrote "Quite frankly..."
pgast
actually the distinction between compiler dependent and undefined behaviour is well defined in the standard - and it doesn't have anything to do with whether or not certain compilers do one thing while other compilers do another thing. Given that you are asking about the standard behaviour of certain compilers and what they are supposed to do, it is probably a good idea for you to know some of the basics before you get too mired down. To be specific, "undefined behaviour" refers to the allowed behaviour for the compiler, not the the subsequent runtime behaviour for the program
1800 INFORMATION
@Dan Moulding: Compilers are required to give diagnostics for some situations. Errors and warnings are both diagnostics; the difference is whether the compiler decides to still create output.
MSalters
@1800 INFORMATION: It is indeed UB, but it depends on the compiler whether it warns about UB. And if you think it's a good idea for someone to know the basics, why don't you simply explain them? This is what this site is for, after all.
sbi
This is different from C, though. As the code above is likewise C: In C, constraint violations require a diagnostic, whether or not behavior is also explicitly stated as being undefined.
Johannes Schaub - litb
@litb: I assume your comment was a response to mine? I'm not sure what you're arguing for or against. Anyway, while the code might be compilable as C, the tags indicate it's compiled by a C++ compiler. `:)`
sbi
@1800informationRE:"To be specific, "undefined behaviour" refers to the allowed behaviour for the compiler, not the the subsequent runtime behaviour for the program" - in 1.3.12 the phrase used is "translation or program execution"
pgast
+2  A: 

Because, the compiler is not your babysitter.

Justicle
I find this rude an offensive. The fact is that a compiler is there both to generate machine code and to ensure to the best of its ability that it is correct. Perhaps if "the compiler is not your babysitter" you are suggesting that we give up type safety also.
pgast
This is not a helpful answer (and is actually quite rude.) I'm a bit perplexed as to why it's getting voted up.
Falaina
The answer, while it may seem flippant, illustrates the design principles of C. I consider the framing of the question rude, as if the entire C++ compiler community in general (and the VC team in particular) is somehow wrong.
Justicle
Because the question is equally silly and basically a whinning about a particular implementation which we cannot even examine let alone comment on. There is nothing that forces any implementation do static analysis of such an abusable construct as pointers. We do not know if it is even feasible for this one. Also bringing up type safety issue here is totally irrelevant and sound too much like a flamebait.
artificialidiot
Do not bother - it is doubtful that Justicle even bothers to compiles at the highest warning level - after all "the compiler is not your babysitter"
pgast
@Justicle: Your answers are increasingly rude and offensive without any reason. It was a fair question, that is asked by many novices. It deserves a fair answer (and, in fact, it got several). There's no need for your tone.
sbi
@Justicle, i recommend `s,your,our,` to get away with less rudeness xD
Johannes Schaub - litb
I find the opinion that having the compiler make this check is "babysitting" and Justicle's claim that he uses max warnings to be glaringly inconsistent
pgast
My issue was with out the answer was presented. If the answer were of comparable quality to aritifcialidiot's comment above, I don't think there would be a problem. Justcle's answer does little to explain why pgast's question is unreasonable, and is presented in a very rude tone.
Falaina
@litb - agreed - I should have said "Compilers are not our babysitters." and achieved the same effect with less offense. I simply wished answer in the same tone as the question was asked. Apologies to pgast, please note I do think the question is fair, and I haven't voted it down.
Justicle
But it does take time to warning me that all bit operations involve 'conversion of int to bool - performance warning', which isn't even necessarily true
Martin Beckett
+5  A: 

This warning is issued when a static code analysis is performed on the sources. Static code analysis is not a part of the compiler specification, though (at least as far as I know), and is done by a separate tool.

Here's an overview of the C/C++ code analysis. And the list of warnings covered by the tool.

Franci Penov
+17  A: 

Many compilers have options to error out this kind of thing.

But it's quite traditional and even proper for C compilers to let this go by default. There are multiple reasons for this.

  1. Remember that x[i] and i[x] are the same thing in C. You can even do "string"[2] OR you can do 2["string"] and get the same result. Try it. And this is because x[i] is defined as *(x + i) and once C is just doing pointer arithmetic and then derefing the result of the expression it's not in the compiler's domain to decide that it's going to work or not.

  2. Given that pointer arithmetic is legal, lots of fairly-decent-for-their-day design patterns actually depend on technical subscript violations

    struct s {
        ...bunch of stuff...
        int points[1]; // not really [1]
    };
    ...
    struct s *p = malloc(sizeof (struct s) + someNumber * sizeof(int));
    

    There is code like this running today all over the place...    Update: heh, here is an actual example of the struct hack on stackoverflow.

DigitalRoss
Yes I realize this. I did not say that it should be an error just that it should be a warning.
pgast
Cool. But it's still a good question, future visitors will find their way to it.
DigitalRoss
@pgast It might be a matter of the signal-to-noise ratio. I suspect that the legitimate uses are so common (and, unfortunately, basically impossible to distinguish from wrong uses) that if compilers emitted warnings for this kind of stuff, you would see a dozen false positive warnings before you saw a true positive. At that point, it is little better than no warning at all.
Phil
@Phil - I might believe that there are numerous legitimate uses [basically as in 2) above] but I am hard pressed to see one with an auto variable
pgast
+7  A: 

While the example given is pretty simple, to do a good job of static analysis during compilation in general would take considerable code and slow down the compilation (a naive implementation means another pass over the AST).

In a language already often berated for slow compiles.

Letting you be stupid is part and parcel of c++. Compilers that try to save you from yourself are nice, but that is gravy.

FWIW: g++ -Wall also fails to warn.

dmckee
A: 

A couple things that might be worth noting:

  1. Unless you have all optimization turned off, this is going to compile away to nothing. The memory will not be written to at all - you might as well have written:

    #pragma warning(push,4)
    int main(){
        return 0;
    }
    #pragma warning(pop)
    
  2. As mentioned elsewhere, doing analysis like this is hard (as in non-computable-trying-to-solve-the-halting-problem). When doing optimizations, it's OK to only do them in the cases where the analysis is easy. When you're looking for warnings, there is a trade-off between being able to find the easy cases, and letting people get dependent on the warnings. At what point is it ok to stop giving the warnings? Yes the locally declared variable being accessed by a constant offset is trivial - but by virtue of being trivial, it's also less important. What if the access is in a trivially inlined function? Or if the access is in a for-loop with constant bounds? These are both easy enough to look for, but they each represent a whole new set of tests, possible regressions, etc... for very little benefit (if any).

I'm not saying that this warning isn't useful - it's just not as clear-cut as you seem to think it is.

Eclipse
+2  A: 

The reason it doesn't warn about this is that it is very rarely useful. Looking at your code:

int main(){
    int x[2];
    x[2]=0;     
    return 0;
}

We see that the compiler in this case is able to issue a warning, but only because:

  • the array had not yet decayed to a pointer -- in other words, the size information is still available, and
  • you're using a compile-time constant expression to index into the array.

In most real-world code, these two conditions won't hold. The array will almost always be a pointer, in which case the compiler has no size information at all. And equally, you often use a runtime-determined value to index into the array. And again, if you do that, the compiler can't determine if you might go out of bounds.

In other words, while yes, the compiler could issue a warning in this case, and I agree, it might as well, but it would only actually help in very simple toy examples like this one.

If the code had looked like this instead:

void foo(int* x){
    x[2]=0;     
}

or this:

void foo(int i){
    int x[2];
    x[i]=0;
}

the compiler would have been helpless. And those cases are far more common. As has already been mentioned by others, one of the biggest problems with C++ compilers is that they're already slow as hell. Every new warning they have to check for adds more overhead. So is it worth it to add a warning for an error that basically only occurs in little toy examples like this?

As for why you got so bad responses, perhaps the answer is in your question:

I consider this failure to warn a SERIOUS error of omission in VC9,(even more so since an auto variable**!!!!**). Can anyone give me a serious reason to change my mind?

Cut down on the loaded language. Stick to a single exclamation mark. If you sound like you're about to blow a fuse, then people will assume that you are FURIOUS, and then they will tell you that you're overreacting, and that you should just shut up.

jalf