Re: Ошибка оптимизациии кода в MSVS 2010
От: Abyx Россия  
Дата: 17.05.11 08:57
Оценка: +4
Здравствуйте, Sunzer, Вы писали:

S>Вот сорец: http://dl.dropbox.com/u/22509984/EpicFail.cpp (4 кб)


приведите *минимальный* код, воспроизводящий ошибку, компилирующийся с опциями компилятора /W4 /WX
In Zen We Trust
Ошибка оптимизациии кода в MSVS 2010
От: Sunzer  
Дата: 17.05.11 08:14
Оценка: :)
Изначальная тема: http://blablabla.xakep.ru/m_2396461/tm.htm

Вот сорец: http://dl.dropbox.com/u/22509984/EpicFail.cpp (4 кб)

#define    INVALID_HANDLE    0xFFFFFFFF
#define RES_HANDLE_BASE    0x80000000

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

struct ResTable
{
 bool Lock;
 bool Align;
 byte InitSize;
 DWORD Size;
 DWORD Offset;
 int MHandle;
} ResTable[100];

DWORD TablePos, ResCount, TableSize, RandSeed = 1;
byte *Table;

unsigned int Random(DWORD seed)
{
 RandSeed = 134775813 * RandSeed + 1;
 return (DWORD)RandSeed * (long long)seed >> 32;
}

DWORD AlignValue(DWORD Value, DWORD Alignment)
{
 return (Value % Alignment != 0) ? Value += Alignment - (Value % Alignment) : Value;
}

void foo(DWORD Value, DWORD Size)
{
 byte Reserved;

 if(TablePos + Size > TableSize) 
 {
    TableSize *= 2;
    Table       = (byte*) realloc(Table, TableSize);
 }
 
 switch(Size)
 {
  case 1: {
   Table[TablePos] = Value;
   TablePos += Size;
   return;
  }
  case 2: {
   *(PWORD) &Table[TablePos] = Value;
   TablePos += Size;
   return;
  }
  case 3: {
   Reserved = Table[TablePos+4];
   *(PDWORD) &Table[TablePos] = Value;
   Table[TablePos+3] = Reserved;
   TablePos += Size;
   return;
  }
  case 4: {
   *(PDWORD) &Table[TablePos] = Value;
   TablePos += Size;
   return;
  }
  default: printf("bad input size!\n"); getchar();  
 }
}

DWORD MemoryAlloc(DWORD Size)
{
 DWORD i;

 /* Сначало пытаемся найти место в свободных ячейках выше, если нет то выделяем новую */
 for(i=0;i<ResCount;i++) if(ResTable[i].Lock == false)
 {
  if(ResTable[i].InitSize + Size <= 4 && Size != 2)
  {
   ResTable[ResCount].Offset    = ResTable[i].Offset + ResTable[i].InitSize;
   ResTable[ResCount].Size        = Size;
   ResTable[ResCount].Lock        = true;
   ResTable[ResCount].MHandle    = i;
   ResTable[ResCount].Align        = false;
   ResTable[i].Align            = false;
   ResTable[i].InitSize            += Size;

   return RES_HANDLE_BASE + ResCount++;
  }
 }

 {
  ResTable[ResCount].Size        = Size;
  ResTable[ResCount].MHandle    = -1;

  ResTable[ResCount].Offset = ~Size;
  switch(Size) {
    case 1:    ResTable[ResCount].Offset  -= 2;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 1;
            break;

    case 2: ResTable[ResCount].Offset  -= 1;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 4;
            break;
   
    case 4: ResTable[ResCount].Offset  += 1;
            ResTable[ResCount].Align    = false;
            ResTable[ResCount].InitSize    = 4;
            break;
   
   default: ResTable[ResCount].Offset  += 1;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 4;
            break;
  }

  for(i=0;i<ResCount;i++) if(ResTable[i].MHandle == -1) ResTable[ResCount].Offset -= AlignValue(ResTable[i].Size, 4);

  return RES_HANDLE_BASE + ResCount++;
 }
 
 return INVALID_HANDLE;
}

DWORD LocalVarAddr(DWORD Handle)
{
 return ResTable[Handle - RES_HANDLE_BASE].Offset;
}

DWORD LocalVarSize(DWORD Handle)
{
 return ResTable[Handle - RES_HANDLE_BASE].Size;
}

void FailFunc(DWORD Handle, BYTE V2)
{
 DWORD Offset, Size;

 if(Handle >= RES_HANDLE_BASE)
 {
    Offset = LocalVarAddr(Handle);
    Size   = LocalVarSize(Handle);

    if(~Offset < 0x80)
    {
        switch(Size)
        {
            case 1: foo(0,3);    break;
            case 2:    foo(0,4);    break;
            case 4:    foo(0,3);    break;
            default:printf("Size = %d\nFail found #1\n", Size); getchar();
        }
        foo(Offset,1);
    }
     else
    {
        switch(Size)
        {
            case 1: foo(0,2);    break;
            case 2: foo(0,3);    break;
            case 4: foo(0,2);    break;
            default:printf("Size = %d\nFail found #2\n", Size); getchar();
        }
        foo(Offset,4);
    }
 }
  else
 {
    printf("Debug test\n");
 }
}

int main(int argc, char *argv[])
{
 RandSeed    = 0xC0DEC0DE;
 TablePos    = 0;
 TableSize    = 0x100000; // 1MB
 Table        = (byte*) calloc(TableSize, 1);
 FailFunc(MemoryAlloc(1), 0);
 return 0;
}


Visual Studio 2010 Express
Флаги компиляции (стандартные, изменены только оптимизация по размеру кода и все):
/Zi /nologo /W3 /WX- /MP /O1 /Oi /Os /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /GF /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Release\EpicFail.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue


Вывод программы:
Size = 1
Fail found #1


дизасм:
[image]http://dl.dropbox.com/u/22509984/epic.PNG[/image]
Re: Ошибка оптимизациии кода в MSVS 2010
От: uzhas Ниоткуда  
Дата: 17.05.11 08:25
Оценка: +1
Здравствуйте, Sunzer, Вы писали:

S>Изначальная тема: http://blablabla.xakep.ru/m_2396461/tm.htm


S>Вот сорец: http://dl.dropbox.com/u/22509984/EpicFail.cpp (4 кб)

а переменную ResCount не следует проинициализировать? да и смелые ResCount++ настораживают. следить за выходами из диапазона надо
Re[2]: Ошибка оптимизациии кода в MSVS 2010
От: Abyx Россия  
Дата: 17.05.11 17:17
Оценка: +1
Здравствуйте, Sunzer, Вы писали:

S>Пожалуйста вот код, который по прежнему работает не правильно при /WX /W4


у меня этот код работает нормально.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
In Zen We Trust
Re: Ошибка оптимизациии кода в MSVS 2010
От: Сергей Мухин Россия  
Дата: 17.05.11 08:47
Оценка:
Здравствуйте, Sunzer, Вы писали:


1. хорошо бы научиться правильно форматировать ccode вместо code
2. отсутствие инициализации вроде как не помеха ошибки
3. всевдо-код смотреть только зрение портить
4. ошибка видмо в этой части. Size и Offset доходят правильными (т.е. все остальное можно выкинуть)


    if(~Offset < 0x80)
    {
        switch(Size)
        {
            case 1: foo(0,3);    break;


который транслируется в

    if(~Offset < 0x80)
01181172 8B CE                mov         ecx,esi  
01181174 F7 D1                not         ecx  
01181176 81 F9 80 00 00 00    cmp         ecx,80h  
    {
        switch(Size)
0118117C 8B C8                mov         ecx,eax  
0118117E 49                   dec         ecx  
0118117F 57                   push        edi  
01181180 73 30                jae         FailFunc+51h (11811B2h)  
01181182 49                   dec         ecx  
01181183 74 1A                je          FailFunc+3Eh (118119Fh)  
01181185 49                   dec         ecx  
01181186 49                   dec         ecx  
01181187 74 1A                je          FailFunc+42h (11811A3h)


такое подозрение, что тут лишний раз генерят dec ecx (первый или второй)

5. было бы хорошо. если бы уменьшили пример и послали в MS.
---
С уважением,
Сергей Мухин
Re: Ошибка оптимизациии кода в MSVS 2010
От: Сергей Мухин Россия  
Дата: 17.05.11 08:52
Оценка:
Здравствуйте, Sunzer, Вы писали:

и еще. когда пишете о возможных ошибках компилятора, указывайте версию полностью. А 2010 этого мало.
я проверял на
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
---
С уважением,
Сергей Мухин
Re: Ошибка оптимизациии кода в MSVS 2010
От: Sunzer  
Дата: 17.05.11 12:58
Оценка:
Я написал минимальный код воспроизводящий ошибку. 4 кб это очень много?

Компилятор самый последний с сайта MS. Express 2010. Опции компиляции выше. Инициализация ResCount не рашеает проблему, к тому же страницы памяти инициализируются нулями.

На старой студии 2008 тоже ошибка проявляется.

10.0.30319.1
Re: Ошибка оптимизациии кода в MSVS 2010
От: Sunzer  
Дата: 17.05.11 13:11
Оценка:
Пожалуйста вот код, который по прежнему работает не правильно при /WX /W4

#define    INVALID_HANDLE    0xFFFFFFFF
#define RES_HANDLE_BASE    0x80000000

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

struct ResTable
{
 bool Lock;
 bool Align;
 byte InitSize;
 DWORD Size;
 DWORD Offset;
 int MHandle;
} ResTable[100];

DWORD TablePos, ResCount, TableSize, RandSeed = 1;
byte *Table;

unsigned int Random(DWORD seed)
{
 RandSeed = 134775813 * RandSeed + 1;
 return (DWORD)RandSeed * (long long)seed >> 32;
}

DWORD AlignValue(DWORD Value, DWORD Alignment)
{
 return (Value % Alignment != 0) ? Value += Alignment - (Value % Alignment) : Value;
}

void foo(DWORD Value, DWORD Size)
{
 byte Reserved;

 if(TablePos + Size > TableSize) 
 {
    TableSize *= 2;
    Table       = (byte*) realloc(Table, TableSize);
 }
 
 switch(Size)
 {
  case 1: {
   Table[TablePos] = (BYTE)Value;
   TablePos += Size;
   return;
  }
  case 2: {
   *(PWORD) &Table[TablePos] = (WORD)Value;
   TablePos += Size;
   return;
  }
  case 3: {
   Reserved = Table[TablePos+4];
   *(PDWORD) &Table[TablePos] = Value;
   Table[TablePos+3] = Reserved;
   TablePos += Size;
   return;
  }
  case 4: {
   *(PDWORD) &Table[TablePos] = Value;
   TablePos += Size;
   return;
  }
  default: printf("bad input size!\n"); getchar();  
 }
}

DWORD MemoryAlloc(DWORD Size)
{
 DWORD i;

 /* Сначало пытаемся найти место в свободных ячейках выше, если нет то выделяем новую */
 for(i=0;i<ResCount;i++) if(ResTable[i].Lock == false)
 {
  if(ResTable[i].InitSize + Size <= 4 && Size != 2)
  {
   ResTable[ResCount].Offset    = ResTable[i].Offset + ResTable[i].InitSize;
   ResTable[ResCount].Size      = Size;
   ResTable[ResCount].Lock      = true;
   ResTable[ResCount].MHandle   = i;
   ResTable[ResCount].Align     = false;
   ResTable[i].Align            = false;
   ResTable[i].InitSize        += (BYTE)Size;

   return RES_HANDLE_BASE + ResCount++;
  }
 }

 {
  ResTable[ResCount].Size        = Size;
  ResTable[ResCount].MHandle    = -1;

  ResTable[ResCount].Offset = ~Size;
  switch(Size) {
    case 1:    ResTable[ResCount].Offset  -= 2;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 1;
            break;

    case 2: ResTable[ResCount].Offset  -= 1;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 4;
            break;
   
    case 4: ResTable[ResCount].Offset  += 1;
            ResTable[ResCount].Align    = false;
            ResTable[ResCount].InitSize    = 4;
            break;
   
   default: ResTable[ResCount].Offset  += 1;
            ResTable[ResCount].Align    = true;
            ResTable[ResCount].InitSize    = 4;
            break;
  }

  for(i=0;i<ResCount;i++) if(ResTable[i].MHandle == -1) ResTable[ResCount].Offset -= AlignValue(ResTable[i].Size, 4);

  return RES_HANDLE_BASE + ResCount++;
 }
}

DWORD LocalVarAddr(DWORD Handle)
{
 return ResTable[Handle - RES_HANDLE_BASE].Offset;
}

DWORD LocalVarSize(DWORD Handle)
{
 return ResTable[Handle - RES_HANDLE_BASE].Size;
}

void FailFunc(DWORD Handle)
{
 DWORD Offset, Size;

 if(Handle >= RES_HANDLE_BASE)
 {
    Offset = LocalVarAddr(Handle);
    Size   = LocalVarSize(Handle);

    if(~Offset < 0x80)
    {
        switch(Size)
        {
            case 1: foo(0,3);    break;
            case 2:    foo(0,4);    break;
            case 4:    foo(0,3);    break;
            default:printf("Size = %d\nFail found #1\n", Size); getchar();
        }
        foo(Offset,1);
    }
     else
    {
        switch(Size)
        {
            case 1: foo(0,2);    break;
            case 2: foo(0,3);    break;
            case 4: foo(0,2);    break;
            default:printf("Size = %d\nFail found #2\n", Size); getchar();
        }
        foo(Offset,4);
    }
 }
  else
 {
    printf("Debug test\n");
 }
}

int main()
{
 RandSeed    = 0xC0DEC0DE;
 TablePos    = 0;
 ResCount    = 0;
 TableSize    = 0x100000; // 1MB
 Table        = (byte*) calloc(TableSize, 1);
 FailFunc(MemoryAlloc(1));
 return 0;
}
Re[3]: Ошибка оптимизациии кода в MSVS 2010
От: Сергей Мухин Россия  
Дата: 17.05.11 17:48
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, Sunzer, Вы писали:


S>>Пожалуйста вот код, который по прежнему работает не правильно при /WX /W4


A>у меня этот код работает нормально.

A>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86

с заявленными опциями?
---
С уважением,
Сергей Мухин
Re[4]: Ошибка оптимизациии кода в MSVS 2010
От: Abyx Россия  
Дата: 17.05.11 18:08
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, Abyx, Вы писали:


A>>Здравствуйте, Sunzer, Вы писали:


S>>>Пожалуйста вот код, который по прежнему работает не правильно при /WX /W4


A>>у меня этот код работает нормально.

A>>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86

СМ>с заявленными опциями?


хм.. действительно, с заявленными опциями выдает ошибку
In Zen We Trust
Re: Ошибка оптимизациии кода в MSVS 2010
От: HolyNick  
Дата: 18.05.11 08:12
Оценка:
У компилятора Visual Studio 2010 под Win 32 ,похоже, есть проблемы с флагом оптимизации \Og. В данном случае он устанавливается флагом \O1 (см. msdn)
Re[2]: Ошибка оптимизациии кода в MSVS 2010
От: Sunzer  
Дата: 19.05.11 13:24
Оценка:
Ну и что делать с багом?
Re[3]: Ошибка оптимизациии кода в MSVS 2010
От: HolyNick  
Дата: 19.05.11 13:35
Оценка:
Если(что не факт, я не разбирался с твоим кодом) в твоем случае проблема с /Og, то следует попробовать его отключить.
Re[3]: Ошибка оптимизациии кода в MSVS 2010
От: Сергей Мухин Россия  
Дата: 19.05.11 21:06
Оценка:
Здравствуйте, Sunzer, Вы писали:

S>Ну и что делать с багом?


шли авторам, что же еще.
а в программе обойди, это не сложно.
---
С уважением,
Сергей Мухин
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.