ifsmirnov's blog

By ifsmirnov, 10 years ago, In Russian

Дебагая хеш-таблицу, я вчера наткнулся на очередное забавное проявление оптимизатора g++. Вот минимальный код, на котором я смог его воспроизвести.

#include <iostream>

int main() {
    for (int i = 0; i < 4; ++i) {
        std::cout << i*1000000000 << std::endl;
    }   
}

Казалось бы, вывод предсказуем. Более того, без оптимизации это действительно так. Однако...

ifsmirnov@carbon:./tmp$ g++-4.8 a.cpp -O2 && ./a.out  | head -n 10
0
1000000000
2000000000
-1294967296
-294967296
705032704
1705032704
-1589934592
-589934592
410065408

И так бесконечно долго.

Логическая цепочка оптимизатора понятна: по стандарту переполнение инта при умножении -- это UB, значит, можно делать всё, что угодно. Но во что превратилось условие остановки цикла, я так и не понял.

У меня это воспроизводится на g++-4.8 c -O2 и выше. На 4.4, 4.6 и 4.7, clang-3.4 выводятся четыре числа даже с любыми уровнями оптимизации.

Интересно, что по этому поводу думает MinGW, а также почему все-таки происходит этот эффект.

UPD: если заменить cout на printf, «баг» не вылезает.

UPD2: продолжаем развлекаться. Если вместо вывода делать push_back в вектор, баг вылезает. Если же вместо этого написать свой «вектор», то можно поймать нетривиальный warning.

#include <cstdlib>

struct MyVector {
    int *a;
    int cap;
    int n;
    MyVector() {
        cap = 1;
        n = 0;
        a = (int*)malloc(sizeof(int) * cap);
    }   
    void push_back(int x) {
        if (n == cap) {
            cap *= 2;
            a = (int*)realloc((void*)a, sizeof(int) * cap);
        }   
        a[n++] = x;
    }   
};

int main() {
    MyVector a;
    for (int i = 0; i < 4; ++i) {
        a.push_back(i * 1000000000);
    }   
}

b.cpp: In function ‘int main()’:
b.cpp:24:35: warning: iteration 2u invokes undefined behavior [-Waggressive-loop-optimizations]
         a.push_back(i * 1000000000);
                                   ^
b.cpp:23:5: note: containing loop
     for (int i = 0; i < 4; ++i) {
     ^
Tags ub, c++
  • Vote: I like it
  • +52
  • Vote: I do not like it