Сбой в коде C++ из-за неопределенного поведения или ошибки компилятора?

я испытываю странные сбои. И мне интересно, ошибка ли это в моем коде или в компиляторе. Когда я скомпилирую следующий код 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

16
задан m3tikn0b 11 May 2012 в 08:52
поделиться