Странная ошибка MSC 8.0: “Значение ESP не было правильно сохранено через вызов функции …”

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

48
задан Cody Gray 30 December 2016 в 13:37
поделиться

10 ответов

При использовании каких-либо функций обратного вызова с Windows API они должны быть объявлены с помощью CALLBACK и/или WINAPI. Это применит соответствующие художественные оформления, чтобы заставить компилятор генерировать код, который чистит стек правильно. Например, на компиляторе Microsoft это добавляет __stdcall.

Windows всегда использовал __stdcall соглашение, когда это приводит к (немного) меньшему коду с очисткой, происходящей в вызванной функции, а не на каждом сайте вызова. Это не совместимо с функциями varargs, хотя (потому что только вызывающая сторона знает, сколько аргументов они продвинули).

0
ответ дан Mike Dimmick 26 November 2019 в 18:44
поделиться

ESP является указателем вершины стека. Таким образом согласно компилятору, Ваш указатель вершины стека становится испорченным. Трудно сказать, как (или если) это могло бы происходить, не видя некоторый код.

, Каков самый маленький сегмент кода, который можно получить для репродуцирования этого?

0
ответ дан Nick 26 November 2019 в 18:44
поделиться

Вы получили бы эту ошибку, если функция вызывается с соглашением о вызовах кроме того, это компилируется в.

Visual Studio использует установку соглашения о вызовах по умолчанию, которой это объявляется в опциях проекта. Проверьте, является ли это значение тем же в orignal настройках проекта и в новых библиотеках. По амбициозному dev, возможно, установил это на _stdcall/pascal в оригинале, так как это уменьшает размер кода по сравнению со значением по умолчанию cdecl. Таким образом, базовый процесс использовал бы эту установку, и новые библиотеки получают значение по умолчанию cdecl, который вызывает проблему

, Так как Вы сказали, что не используете специальных соглашений о вызовах, это, кажется, хорошая вероятность.

Также делают разность на заголовках, чтобы видеть, являются ли объявления / файлы, которые видит процесс, теми же, с которыми компилируются библиотеки.

пикосекунда: То, чтобы заставлять предупреждение уйти является BAAAD., который все еще сохраняет базовая ошибка.

1
ответ дан computinglife 26 November 2019 в 18:44
поделиться

у Вас есть какие-либо typedef'd прототипы функции (например, интервал (*fn) (интервал a, интервал b))

, если Вы dom, которым Вы могли бы быть, поняли прототип превратно.

ESP является ошибкой на вызове функции (можно ли сказать который в отладчике?), который имеет несоответствие в параметрах - т.е. стек, восстановил назад к состоянию, которое он запустил в том, когда Вы вызвали функцию.

можно также получить это при загрузке функций C++, которые должны быть объявлены, экстерн C - C использует cdecl, C++ использует stdcall соглашение о вызовах по умолчанию (IIRC). Поместите некоторые обертки экстерна C вокруг импортированных прототипов функции, и можно зафиксировать его.

, Если можно выполнить его в отладчике, Вы будете видеть функцию immediatey. В противном случае можно установить DrWtsn32 для создания мини-дампа, который можно загрузить в windbg для наблюдения стека вызовов во время ошибки (Вам будут нужны символы или mapfile для наблюдения имен функций хотя).

1
ответ дан gbjbaanb 26 November 2019 в 18:44
поделиться

Вы создаете статичный, освобождает или DLLs? Если DLLs, как определенный экспорт; как библиотеки импорта создаются?

прототипы для функций в освобождении точно то же как объявления функции, где функции определяются?

1
ответ дан Michael Burr 26 November 2019 в 18:44
поделиться

Глушение проверки не является правильным решением. Необходимо выяснить то, что испорчено с соглашениями о вызовах.

существует довольно много способов изменить вызов convetion функции, явно не определяя его. экстерн "C" сделает это, STDMETHODIMP/IFACEMETHODIMP также сделает это, другие макросы могли бы сделать это также.

я верю, если запущено Вашей программе под WinDBG ( http://www.microsoft.com/whdc/devtools/debugging/default.mspx ), время выполнения должно повредиться в точке, где Вы поражаете ту проблему. Можно посмотреть на стек вызовов и фигуру, какая функция имеет проблему, и затем посмотрите на ее определение и объявление, что вызывающая сторона использует.

11
ответ дан Franci Penov 26 November 2019 в 18:44
поделиться

Другой случай, где esp может быть испорчен, с непреднамеренным переполнением буфера, обычно посредством ошибочного использования указателей для работы мимо границы массива. Скажите, что у Вас есть некоторая функция C, которая похожа

int a, b[2];

, Запись в b[3], вероятно, изменится a, и где угодно мимо этого, вероятно, польет из шланга сохраненный esp на стеке.

1
ответ дан Alex M 26 November 2019 в 18:44
поделиться

Я увидел эту ошибку, когда код пытался вызвать функцию для объекта, который не был ожидаемого типа.

Итак, иерархия классов: Родитель с дочерними элементами: Ребенок1 и Ребенок2

Child1* pMyChild = 0;
...
pMyChild = pSomeClass->GetTheObj();// This call actually returned a Child2 object
pMyChild->SomeFunction();          // "...value of ESP..." error occurs here
5
ответ дан 26 November 2019 в 18:44
поделиться

Эта ошибка отладки означает, что регистр указателя стека не возвращается к своему исходному значению после вызова функции, то есть что количество нажатий перед вызовом функции не было выполнено равным числом всплывающих окон после вызова.

Я знаю 2 причины этого (обе с динамически загружаемыми библиотеками). №1 - это то, что VC ++ описывает в сообщении об ошибке, но я не думаю, что это наиболее частая причина ошибки (см. №2).

1) Несоответствующие соглашения о вызовах:

Вызывающий и вызываемый у вас нет должного соглашения о том, кто что будет делать. Например, если вы вызываете функцию DLL, которая называется _stdcall , но по какой-то причине она была объявлена ​​в вашем вызове как _cdecl (по умолчанию в VC ++). Это могло бы случиться, если бы вы вы используете разные языки в разных модулях и т. д.

Вам нужно будет проверить объявление функции-нарушителя и убедиться, что она не объявляется дважды и по-разному.

2) Несовпадающие типы:

Вызывающий и вызываемые объекты не скомпилированы с одинаковыми типами. Например, общий заголовок определяет типы в API и недавно был изменен, и один модуль был перекомпилирован, а другой - нет, т. Е. Некоторые типы могут иметь разный размер в вызывающем и вызываемом.

In В этом случае вызывающий передает аргументы одного размера, но вызываемый (если вы используете _stdcall , где вызываемый объект очищает стек) выдвигает другой размер. Таким образом, ESP не возвращается к правильному значению.

(Конечно, эти аргументы, а также другие аргументы ниже них, могут показаться искаженными в вызываемой функции,

48
ответ дан 26 November 2019 в 18:44
поделиться

Я читал это на другом форуме

У меня была та же проблема, но я просто ИСПРАВИЛ ее. Я получал ту же ошибку из следующего кода:

HMODULE hPowerFunctions = LoadLibrary("Powrprof.dll");
typedef bool (*tSetSuspendStateSig)(BOOL, BOOL, BOOL);

tSetSuspendState SetSuspendState = (tSuspendStateSig)GetProcAddress(hPowerfunctions, "SetSuspendState");

result = SetSuspendState(false, false, false); <---- This line was where the error popped up. 

После некоторого расследования я изменил одну из строк на:

typedef bool (WINAPI*tSetSuspendStateSig)(BOOL, BOOL, BOOL);

, что решило проблему. Если вы посмотрите в заголовочный файл, в котором находится SetSuspendState (powrprof.h, часть SDK), вы увидите, что прототип функции определен как:

BOOLEAN WINAPI SetSuspendState(BOOLEAN, BOOLEAN, BOOLEAN);

Итак, у вас, ребята, возникла аналогичная проблема. Когда вы вызываете заданную функцию из .dll, ее подпись, вероятно, отключена. (В моем случае это было отсутствующее ключевое слово WINAPI).

Надеюсь, что это поможет любому будущему! : -)

Ура.

18
ответ дан 26 November 2019 в 18:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: