Errichto's blog

By Errichto, 7 years ago, In English
#include <vector>
int main() {
	std :: vector<int> w;
	for(int x : w);
}

The code above runs forever on my machine, after being compiled with g++ a.cpp (it first prints some warning), the same on ideone: http://ideone.com/5FodQO. Why? EDIT: As yeputons noticed, this bug was already reported by Mike Mirzayanov.

And the following code gives me RTE without any warning if compiled with g++ -O2 a.cpp — is it a compiler bug as well?

#include <bits/stdc++.h>
using namespace std;
struct Big {
	vector<int> w;
	Big(int x) {
		while(x) {
			w.push_back(x % 10);
			x /= 10;
		}
	}
	Big operator - () const {
		return Big(0) - *this;
	}
	int get(int i) const {
		if(i < (int) w.size()) return w[i];
		return 0;
	}
	Big operator - (const Big & other) const {
		Big ans(0);
		ans.w.resize(100, 0); // ans.w.resize(max(w.size(), other.w.size())); // gives RTE too
		puts("a");
		for(int i = 0; i < (int) ans.w.size(); ++i)
			ans.w[i] = get(i) - other.get(i);
			// ans.w[i] = (i < (int) w.size() ? w[i] : 0)
			//	- (i < (int) other.w.size() ? other.w[i] : 0); // gives RTE too
		puts("b");
		return ans;
	}
};
int main() {
	//Big(0) - Big(57); // this line works fine
	-Big(57);
}
Tags c++
  • Vote: I like it
  • +77
  • Vote: I do not like it

»
7 years ago, # |
  Vote: I like it +12 Vote: I do not like it

Looks like compiler's bug. Would you mind sharing your command line and GCC version?

  • »
    »
    7 years ago, # ^ |
    Rev. 3   Vote: I like it 0 Vote: I do not like it

    I've just tried compiling a few versions in various ways. Here is my gcc version:

    gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

    The code above gives me TLE after compiling with gcc -std=c++03 -O2 or g++ -std=c++03 -O2 (Edit: well, the same happens after compiling with g++ without extra flags). In both cases it gives me a warning though:

    x.cpp:4:14: warning: range-based ‘for’ loops only available with -std=c++11 or -std=gnu++11
      for(int x : w);
    

    I also have a longer piece of code that leads to RTE (there were no warnings during the compilation):

    code
    • »
      »
      »
      7 years ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it

      The first one was reported by MikeMirzayanov back in 2015: see bug 68209. There is a more recent similar bug 71052.

      However, the second one is more interesting. I'd highly suggest adding that information to your question because right now your blog post is very far from complete question.

      • »
        »
        »
        »
        7 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Thanks, I've modified the blog.

        • »
          »
          »
          »
          »
          7 years ago, # ^ |
            Vote: I like it 0 Vote: I do not like it

          (it first prints some warning),

          I'd say "prints warning that the code is invalid".

»
7 years ago, # |
  Vote: I like it +5 Vote: I do not like it

Looks like really compiler's bug. In VC++ it works. http://rextester.com/SRIET30307

»
7 years ago, # |
  Vote: I like it +5 Vote: I do not like it

I was able to shorten the latter example even more:

#include <vector>

struct Foo {
  std::vector<int> w;
 
  Foo bar() const {
    Foo ans;
    ans.w.resize(2, 0);
    for (int i = 0; i < (int)ans.w.size(); ++i) {
      ans.w[i] = ((i < (int)w.size()) ? w[i] : 0);
    }
    return ans;
  }
};
int main() {
  Foo().bar();
}

However, I was able to reproduce this bug on the exact same compiler as Errichto has, which is the latest GCC available in Ubuntu 16.04. I think it's an Ubuntu-related bug.

»
7 years ago, # |
Rev. 4   Vote: I like it 0 Vote: I do not like it

Add these lines to the end of the constructor:

if (w.empty())
    w.push_back(0);

Apparently, it's usual Out-Of-Bound access.

  • »
    »
    7 years ago, # ^ |
      Vote: I like it +3 Vote: I do not like it

    I still don't understand why g++ decided to drop size check. But i found another way to avoid crash — just cast i in get method to size_t instead of casting size to int (or just use size_t for indexing and avoid casts all together).

    Standard explicitly says that cast of a value of an unsigned type to a signed type is safe if the value can be represented in the destination type. In this case we can be sure that the condition holds so it must be compiler bug.

»
7 years ago, # |
  Vote: I like it +20 Vote: I do not like it

The first bug happened during the second day of IOI 2016 with the problem messy. The grader contained the range-based for, and the script that all contestants contained the --std=c++11 option in a compile line, so everything almost worked fine for everybody. But those contestants who decided to use some IDE and compile their solution with a grader manually without the --std=c++11 option faced the similar issue and it took us a while to understand what's happening.

  • »
    »
    7 years ago, # ^ |
      Vote: I like it +10 Vote: I do not like it

    I can't believe that it happened to others too:))I thought I'm the only one stupid enough to not be able to get the grader working.