Недопустимая ошибка чтения / записи при совместимости с устаревшим кодом x64 - PullRequest
3 голосов
/ 07 июня 2011

У меня есть следующая функция MyType::Is_Inst (), которая выдает ошибку доступа к недопустимой памяти при возврате в 64-битном режиме, но не в 32-битном:

MyType MyType::Is_Inst () {
    unsigned char Bar=0;    
    MyType Foo={0};    
    return Foo;
    }

Глядя на разборки + пошаговое выполнение программы на линии

mov  dword ptr [rax],ecx

... когда программа в основном пытается разыменовать исходное значение% rdx (с момента первого вызова функции), которое теперь находится в% rax. Тем не менее,% rdx - это просто мусор, оставшийся после предыдущего вызова функции.

В прошлый раз у меня была такая проблема, потому что я пропускал некоторые флаги компиляции или тому подобное. Существуют ли какие-либо настройки, о которых мне следует знать для неуправляемых проектов C ++ x64? Есть ли другие причины, по которым я могу видеть это поведение?

Я могу опубликовать больше разборок, если вам это нужно.


Определение класса для MyType выглядит следующим образом:

class __declspec(dllexport) MyType {
public:
    union {
        struct {
            unsigned int    Id     : 23;
            unsigned int    Flag   : 1;  
            unsigned int    Type   : 4;  
            unsigned int    Unused : 4;  /* 32 bits total */
            };

        unsigned int    All_Bits;          /* Full 32 bits of MyType */
        };

     /* There are some function definitions here, but no other 
        variables, aside from some statically defined ones. */
     };

ОБНОВЛЕНИЕ: Это более лаконичная, оптимизированная версия разборки Is_Inst (), которая показывает проблему. Для краткости я удалил старую версию, которая была здесь раньше.

// MyType MyType::Is_Inst () {
// uchar Bar=0;
// MyType Foo={0};
   mov         dword ptr [rdx],0 /* %rdx is 0x17, from a prev fn call. */ 

// return Foo;
   mov         rax,rdx  
// }
   ret 

Код, вызывающий вызов Is_Inst ():

...
for (Counter=0; Counter<N_Items; Counter++) {
    ...
    myOther32BitType = arrayOfMyOtherTypes [Counter]; /* Debugger shows this is ok. */ 

    if (myOther32BitType.8BitField==UNEQUAL_ENUM_VALUE) {
        /* Some stuff that doesn't happen. */
        }

    /* myOther32BitType.8BitField==0x17, so %rdx gets set to 0x17. */
    else if (strchr((char*)Uchar_Table_Of_Enum_Values, myOther32BitType.8BitField)) continue;

    /* %rdx gets set to 0x17 again. */
    else if (strchr((char*)Other_Uchar_Table_Of_Enum_Values,  myOther32BitType.8BitField)) continue;

    else if ( myOther32BitType.8BitField==EQUAL_ENUM_VALUE) {
        if (myType.Is_Inst ().All_Bits) { /* Is_Inst() called here. */
            return false;
            }
        ...
        }
    ...
    }

Ответы [ 3 ]

1 голос
/ 08 июня 2011

Я отправил сообщение об ошибке в MS здесь: https://connect.microsoft.com/VisualStudio/feedback/details/674672/callee-disassembly-expects-address-which-caller-is-not-providing-in-x64-mode

Еще раз спасибо всем за помощь!

0 голосов
/ 08 июня 2011
else if (strchr((char*)Other_Uchar_Table_Of_Enum_Values,  myOther32BitType.8BitField)) continue;

Это выглядит ужасно неправильно.Вместо того, чтобы прибегать к совершенно ненужному приведению, вы должны использовать std::find.

Фактически весь ваш код выглядит замусоренным небезопасным кодом в стиле C.Где объекты управления памятью?

0 голосов
/ 07 июня 2011

Это похоже на ту же ошибку, с которой Qt люди сталкивались в VS2010. Отчет ссылается на Microsoft Connect здесь . И ошибка должна быть исправлена ​​в SP1 . В SP1 было исправлено множество ошибок по оптимизации, поэтому, возможно, я не связал правильный (обнаружил, что три других просто просеивали ссылки).

...