Ошибка оптимизациии кода в 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]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.