# Bugs you expected to throw a compiler error ...

This topic is 2434 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I just made a mistake and saw something in C, using Visual Studio 2008 C++ Express, which was so dumb (at least to my mind), that I thought it would throw a compiler error, or at least a warning, but doesn't (at least at the standard error/warning level).

 // set the free block mem to a released value memset( ((u8*)pFree) + sizeof(MemHeapFree), MEMHEAP_RELEASED_MEM, pFree->uSize - sizeof(sizeof(MemHeapFree)) ); 

See it? See the sizeof(sizeof(expression))? I just had a massive WTF moment when I saw that while stepping through the code.

So, this thread is for any other things in C, C++ or any other languages that you think other people would find strange, amusing or unbelievable.

Oh, and for anyone that's interested, the sizeof(sizeof(x)) comes out to 4, which I guess is expected once you know the compiler actually accepts it.

##### Share on other sites
Okay, I understand your point and I see the mistake, but IMO letting the compiler flag this as an error would be stupid.
What if I want to know the size of whatever the type is that sizeof () returns?

That's not a common thing to do, but letting the compiler parse for mistakes like that would be horribly slow - and even then, the compiler shouldn't error on something that's perfectly valid. I could accept a warning though, but it still comes down to the same problem - parsing all sorts of potential mistakes like this would only make the compiler slower.

##### Share on other sites
The compiler can and should only check for lexical, syntactic or semantic errors that cannot be translated. Your example is perfectly valid source code.

I guess what you're looking for is a static code analyzer.
Here's a list of tools that do that, but I'm not sure any of these will the detect the mistake in your example...
http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis

##### Share on other sites
I think you two missed the point of the thread...

##### Share on other sites
Sizeof(sizeof(x)) only evaluates to 4 on a 32-bit system. This looks like it is part of a memory management system and a pointer to the data is stored in a data structure. Doing it this way would ensure there is always enough memory allocated to store the pointer without hard-coding it. Does it make a bit more sense now?

##### Share on other sites
There is nothing wrong in that code.

size_t is defined as result of sizeof operation. While somewhat unusual, it's perfectly legit to query the sizeof(sizeof(x)) to determine its size. While not strictly defined, size_t is commonly size of register on that machine or size of addressable space.

Above code says:

Set pFree-uSize bytes at a specific offset to specific value, but leave last sizeof(size_t) bytes intact. perhaps the last 4 are used for some specific purpose.

In C++, the above code might look like std::fill(pFree.begin() + sizeof(MemFree), pFree.end() - sizeof(FreeContainerType::size_t), X);

Bugs like this are annoying, but causes are quite complex. Pointer arithmetic is idiomatic to C and trying to report every such slightly uncommon use of language features would result in a flood of false positives.

I'm not really sure if a C idiom exists to avoid mistakes like that. Especially since it's really not a mistake.

##### Share on other sites
There is nothing wrong in that code.
The author knows it's valid. It's not wrong, except for the part where it didn't do what the author intended, meaning it caused a bug (and in a memory allocator a bug is quite a wrong thing).
So, this thread is for any other things in C, C++ or any other languages that you think other people would find strange, amusing or unbelievable.
Did you all miss this part? ^^^
Too busy bikeshedding in Parkinson's committee? I heard you like bike sheds (any colour will do)...

##### Share on other sites

[quote name='Antheus' timestamp='1306070656' post='4814217']There is nothing wrong in that code.
The author knows it's valid. It's not wrong, except for the part where it didn't do what the author intended, meaning it caused a bug (and in a memory allocator a bug is quite a wrong thing).
So, this thread is for any other things in C, C++ or any other languages that you think other people would find strange, amusing or unbelievable.
Did you all miss this part? ^^^
Too busy bikeshedding in Parkinson's committee? I heard you like bike sheds (any colour will do)...
[/quote]

Yes yes yes!

Guys, you are great I do appreciate the objective analysis of the code, but yes, I know it is part of a memory management system. In fact is it my own memory management system that I was fixing, in part because of a bug (not the one I posted) that was in that very function call. And I'm not looking for a static code analyzer, although I do appreciate the offer. I also completely understand why that expression returns 4 on a 32-bit system. I'm also not suggesting that this and the other million similar kinds of bugs that people write into their code every day should be picked up by the compiler, and although I immediately wondered how it had gotten past the compiler, after a half second of looking at it, I understood why it had.

As Hodgman pointed out, after the initial "What the heck?" moment, I just found this funny and was looking to add a bit more humor to the forum. So, please, whatever you've got, I'd definitely like to see, in whatever language or form that you feel like sharing it in.

##### Share on other sites
In that case, I consider the functions sprintf, strcpy, strcmp etc without a length parameter to be some of the silliest features of C :-) the fact that nobody considered it to ever be a security problem, and that so many programs use these functions in network code and other security sensitive code without a second thought... Now that is daft indeed :-) (yeah, modern compilers sometimes warn about unsafe functions such as these but jees, it took them how many decades to realise?) Edited by braindigitalis

##### Share on other sites

In that case, I consider the functions sprintf, strcpy, strcmp etc without a length parameter to be some of the silliest features of C :-) the fact that nobody considered it to ever be a security problem, and that so many programs use these functions in network code and other security sensitive code without a second thought... Now that is daft indeed :-) (yeah, modern compilers sometimes warn about unsafe functions such as these but jees, it took them how many decades to realise?)

I agree, that was kinda strange.

Come on guys and gals, surely more people have something they wish to share with the rest of the class?

##### Share on other sites
I'm sorry, when I tried to compile this thread I got an "error C2065: 'humor' : undeclared identifier". :/

##### Share on other sites
#include <iostream> struct Price { double x; explicit Price(double x) : x(x) { } operator double() { return x; } }; Price get_price() { return Price(5.2); } int main() { bool some_condition = false; double price = some_condition ? 0 : get_price(); std::cout << price << '\n'; } 

With g++-2.95.2 you used to get "5.2". Then after g++-3 you would get "5". It turns out "5" is the correct answer according to the standard, but it would have been nice to get a warning about loss of precision. This actually created a problem at work that took a lot of effort to fix.

##### Share on other sites
It turns out "5" is the correct answer according

Huh, I guess I don't see why. Cool example though!

##### Share on other sites

[quote name='alvaro' timestamp='1306167579' post='4814635']It turns out "5" is the correct answer according

Huh, I guess I don't see why. Cool example though!
[/quote]

Covariance and auto type conversion.

0 is integer.
function returns a double.

Ternary operator can only work on same type: int = cond ? int : int, for example, or more generally, T = cond ? T : T. Ternary operator should throw an error for: X = cond ? T : U. Imagine T = string and U = vector<int>. There is no possible conversion and no type that could hold both.

I know that in Java this is an error. It should be in C/C++ as well, but it may go unreported since with primitive types casting and default construction/copy construction converts the types on the fly. Since Price has a () operator defined, the returned Price is evaluated, it returns double, which is cast to int. Or the int is converted to double.

This example points more to dangers of operator().

##### Share on other sites
The bizarre thing about this example is that get_price() used to return a double, and in that case the answer is 5.2, but then someone changed it to return a type that has an implicit conversion to double, and the behavior changed completely.

The standard says that if the two types to the sides of the :' are different, the compiler will try to find both conversions of one type into the other. If only one succeeds, that's what will happen.

In the case of, (bool ? int : double), it is somehow determined that the promotion from int to double is preferable. When you change it to (bool ? int : Price), an int cannot be converted to a Price, but a Price can be converted to an int through double.

One last thing that makes this example horrible is that g++ will warn you that you may lose precision if you convert a double to an int, but in this complicated case it doesn't give you any warnings.

##### Share on other sites

[quote name='mozie' timestamp='1306275681' post='4815338']
[quote name='alvaro' timestamp='1306167579' post='4814635']It turns out "5" is the correct answer according

Huh, I guess I don't see why. Cool example though!
[/quote]

Covariance and auto type conversion.

0 is integer.
function returns a double.

Ternary operator can only work on same type: int = cond ? int : int, for example, or more generally, T = cond ? T : T. Ternary operator should throw an error for: X = cond ? T : U. Imagine T = string and U = vector<int>. There is no possible conversion and no type that could hold both.

I know that in Java this is an error. It should be in C/C++ as well, but it may go unreported since with primitive types casting and default construction/copy construction converts the types on the fly. Since Price has a () operator defined, the returned Price is evaluated, it returns double, which is cast to int. Or the int is converted to double.

This example points more to dangers of operator().
[/quote]

Thanks! So, would changing the 0 to a 0.0 resolve it? Because then it would result in double = (cond) ? double : double.

##### Share on other sites

Thanks! So, would changing the 0 to a 0.0 resolve it? Because then it would result in double = (cond) ? double : double.

Yes, changing the 0 to 0.0 solves the problem. I now always make my constants the type that I intend them to be (0 for int, 0u for unsigned, 0.0 for double, 0.0f for float, T(0) in a template).

##### Share on other sites
Yes, changing the 0 to 0.0 solves the problem. I now always make my constants the type that I intend them to be (0 for int, 0u for unsigned, 0.0 for double, 0.0f for float, T(0) in a template).
I had a similar bug recently with bit-shifting:u64 mask; mask = 1 << 30; assert( mask == 0x40000000 ); mask = 1 << 31; assert( mask == 0x80000000 ); mask = 1 << 32; assert( mask == 0x100000000 );//failThis was failing because the literal '1' is a 32-bit int, so you can't get a 64-bit result from the shift operation. The solution is to use the correct type of literal '1' as above.
The bug snuck in because [font="Courier New"]mask[/font] was originally a [font="Courier New"]u32[/font] and was later upgraded to a [font="Courier New"]u64[/font] without scrutinising all the code that used the variable...

##### Share on other sites
 #include <iostream> class Example { public: Example(int va1ue) : value(value) { } int value; }; int main() { Example e(42); std::cout << "What? " << e.value << '\n'; } 
I had some code similar to above and it drove me demented looking for the problem. Like my example, the type involved was so trivial that I didn't really read it I kept assuming the problem was elsewhere.

##### Share on other sites
It took me a while to see the problem with rip-off's code. I don't know why g++ doesn't complain about use of uninitialized variables unless you compile with -O.

##### Share on other sites
That should also pump out an unused variable warning, though it might require some compiler flag to do so. If you really want to make it a compile error, you could also enable warnings are errors.

Particularly if your compile times are fairly short, it's not a bad idea to turn on all warnings and enable warnings are errors.

##### Share on other sites
Yes, if the compiler gives out a warning, you can't complain because you ignored it. We always compile with warnings as errors at work, and I never ignore warnings even on hobby projects.

##### Share on other sites
I once had an error that I expected the compiler to flag. But didn't.

this was about 10 years ago, and I was programming a "toy OS" (called nachOS)
it was done in C (not C++) so everything was ok, but then random errors would occur, random values sometimes, and other times those values where correct....
it didn't make sense... it took me 3 days to find out the problem, going line by line, debugging every variable etc.

 // we do something here something = somethingelse; more code and more code `

see the error?
obviously // is a c++ thing, so the comments had to be /* we do something here */
I just changed that and the program started to work perfectly. So yeah, don't trust the compiler. just because it said "it's ok, there are no errors here" doesn't mean it's true!

##### Share on other sites
There are several bugs that I was surprised to discover that the compiler doesn't warn about. For example, returning a reference to a local variable.

##### Share on other sites
warning: reference to local variable ‘result’ returned[/quote]