я испытываю странные сбои. И мне интересно, ошибка ли это в моем коде или в компиляторе. Когда я скомпилирую следующий код C++ с Microsoft Visual Studio 2010 в качестве оптимизированной версии сборки, он вылетает в отмеченной строке:
struct tup { int x; int y; };
class C
{
public:
struct tup* p;
struct tup* operator--() { return --p; }
struct tup* operator++(int) { return p++; }
virtual void Reset() { p = 0;}
};
int main ()
{
C c;
volatile int x = 0;
struct tup v1;
struct tup v2 = {0, x};
c.p = &v1;
(*(c++)) = v2;
struct tup i = (*(--c)); // crash! (dereferencing a NULL-pointer)
return i.x;
}
Глядя на дизассемблирование, очевидно, что он должен вылететь:
int _tmain(int argc, _TCHAR* argv[])
{
00CE1000 push ebp
00CE1001 mov ebp,esp
00CE1003 sub esp,0Ch
C c;
volatile int x = 0;
00CE1006 xor eax,eax
00CE1008 mov dword ptr [x],eax
struct tup v1;
struct tup v2 = {0, x};
00CE100B mov ecx,dword ptr [x]
c.p = &v1;
(*(c++)) = v2;
00CE100E mov dword ptr [ebp-8],ecx
struct tup i = (*(--c));
00CE1011 mov ecx,dword ptr [x]
00CE1014 mov dword ptr [v1],eax
00CE1017 mov eax,dword ptr [ecx]
00CE1019 mov ecx,dword ptr [ecx+4]
00CE101C mov dword ptr [ebp-8],ecx
return i.x;
}
00CE101F mov esp,ebp
00CE1021 pop ebp
00CE1022 ret
По смещению 00CE1008 пишет 0 в х.
По смещению 00CE100B он считывает x (0) в ecx.
По смещению 00CE1017 он разыменовывает этот 0-указатель.
Я вижу две возможные причины:
Либо есть какой-то тонкий (или не очень тонкий?) случай неопределенного поведения в моем коде. и компилятор «оптимизирует» это неопределенное поведение до сбоя.
или ошибка компилятора
Кто-нибудь знает, в чем может быть проблема?
Спасибо,
Йонас
РЕДАКТИРОВАТЬ: Чтобы ответить на комментарии относительно «указателя на недопустимое местоположение»
Если я изменю v1
на struct tup v1 [10] ;
и установите cp = &v1[0];
, тогда не будет указателя на недопустимое местоположение.Но я все еще могу наблюдать такое же поведение. Дизассемблирование выглядит незначительно по-другому, но сбой по-прежнему происходит, и он по-прежнему вызван загрузкой 0 в ecx и его разыменованием.
РЕДАКТИРОВАТЬ: Заключение
Итак, возможно, это ошибка. Я обнаружил, что сбой исчезает, если я изменю
struct tup* operator--() { return --p; }
на
struct tup* operator--() { --p; return p; }
. Как сообщает нам bames53, сбой не происходит в VS2011, и он делает вывод, что он должен быть исправлен.
Тем не менее, я решил зарегистрировать эту ошибку по двум причинам:
Ошибка может все еще присутствовать в VS2011. Возможно, оптимизатор просто изменился таким образом, что мой код больше не вызывает ошибку. (ошибка кажется очень тонкой, она не возникает, когда я удаляю volative
или virtual void Reset()
)
Я хочу знать, подходит ли мой обходной путь надежный способ исключить сбои, или если изменения кода в других местах могут повторно вызвать ошибку.
Вот ссылка:
https://connect.microsoft.com/VisualStudio/feedback/details/741628/error-in-code-generation-for-x86