Недавно при портировании нашего приложения с gcc-5.3 на 8.2 мы заметили странное поведение, которое нарушает наше приложение.
Короче говоря, кажется, что gcc-8.2 удалил одну из наших "веток if, которая сравнивает 2 целых числа без знака", даже не выдав предупреждения.
Мы пробовали g ++ 5.3, g ++ 7.4 и g ++ 8.2 сте же параметры компиляции, и только g ++ 8.2 имеет эту проблему.Ниже приведен короткий пример.
#include <iostream>
#include <cstdint>
#include <cstdlib>
#include <cstring>
using namespace std;
struct myunion {
myunion(uint32_t x) {
_data.u32 = x;
}
uint16_t hi() const { return _data.u16[1]; }
uint16_t lo() const { return _data.u16[0]; }
union {
uint16_t u16[2];
uint32_t u32;
} _data;
};
__attribute__((noinline)) void printx1x2(uint32_t x1, uint32_t x2) {
cout << "x1: " << x1 << endl;
cout << "x2: " << x2 << endl;
}
__attribute__((noinline)) int func(uint32_t a, uint32_t b) {
const uint32_t x1 = myunion(a).hi() * myunion(b).lo();
const uint32_t x2 = x1 + myunion(a).lo() * myunion(b).hi();
printx1x2(x1, x2);
int ret = 0;
if ( x2 < x1 ) {
ret = 0x10000;
}
return ret;
}
int main(int argc, char** argv) {
cout << func(4294967295, 4294917296) << endl;
return 0;
}
Приведенный выше код скомпилирован, как показано ниже:
$ g++-7 --version
g++-7 (GCC) 7.4.1 20181207
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++-7 -Wall -std=c++14 -O3 a.cxx -o 7.out
$ ./7.out
x1: 1018151760
x2: 1018020689
65536
$ g++ --version
g++ (GCC) 8.2.1 20181127
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -Wall -std=c++14 -O3 a.cxx -o 8.out
$ ./8.out
x1: 1018151760
x2: 1018020689
0
Я ожидаю, что вывод 7.out
будет правильным.
Это действительно что-то вроде UB (неопределенное поведение) или это может быть ошибка g ++?
ОБНОВЛЕНИЕ
Похоже, удаление UB-доступа с объединением ещеобрабатывает нежелательные результаты:
#include <iostream>
#include <cstdint>
#include <cstdlib>
#include <cstring>
using namespace std;
struct myunion2 {
myunion2(uint32_t x) {
_data = x;
}
uint16_t hi() const { return (uint16_t)((_data & 0xFFFF0000) >> 16); }
uint16_t lo() const { return (uint16_t)((_data & 0xFFFF)); }
uint32_t _data;
};
__attribute__((noinline)) void printx1x2(uint32_t x1, uint32_t x2) {
cout << "x1: " << x1 << endl;
cout << "x2: " << x2 << endl;
}
__attribute__((noinline)) int func(uint32_t a, uint32_t b) {
const uint32_t x1 = myunion2(a).hi() * myunion2(b).lo();
const uint32_t x2 = x1 + myunion2(a).lo() * myunion2(b).hi();
printx1x2(x1, x2);
int ret = 0;
if ( x2 < x1 ) {
ret = 0x10000;
}
return ret;
}
int main(int argc, char** argv) {
cout << func(4294967295, 4294917296) << endl;
return 0;
}
Вывод:
$ g++-7 -Wall -std=c++14 -O3 a.cxx -o 7.out
[2019-03-27 22:48:30][wliu@wliu-arch-vm1 ~/tests]
$ ./7.out
x1: 1018151760
x2: 1018020689
65536
[2019-03-27 22:48:32][wliu@wliu-arch-vm1 ~/tests]
$ g++ -Wall -std=c++14 -O3 a.cxx -o 8.out
[2019-03-27 22:49:11][wliu@wliu-arch-vm1 ~/tests]
$ ./8.out
x1: 1018151760
x2: 1018020689
0