Динамическое выделение памяти в родной dll

У меня есть собственная (неуправляемая) .dll, написанная на С++, которую нужно вызывать из управляемого процесса (программы на С#). При отладке dll проблема, которую я показал, заключается в том, что когда я создаю объект в dll с ключевым словом new, я получаю исключение нарушения доступа к системе. Это проявляется только при вызове dll из управляемого процесса, а не при вызове из другой собственной программы.

Код примерно такой:

// Native.dll file
MyClass myInstance; // global variable (and does need to be so)
__declspec(dllexport) uint8_t _stdcall NativeFunction(){
    myInstance = new MyClass(); // <-- this causes Access Violation Exception
}

и код С#:

using System.Runtime.Interopservices;
// Loading the dll
[DllImport("Native.dll",CallingConvention = CallingConvention.StdCall)]
private extern static byte NativeFunction();

class TestClass{
   byte returnVal = NativeFunction(); //<-- exception in managed context
}

Я знаю, что это как-то связано с тем, что собственный процесс пытается выделить память за пределами разрешенного пространства памяти. Это происходит только тогда, когда память выделяется с помощью new (по крайней мере, в этом проекте), что мне, к сожалению, нужно использовать. Мой вопрос: кто-нибудь знает, почему это вызывает исключение и как его избежать?


person skitiddu    schedule 11.04.2018    source источник


Ответы (1)


new MyClass, скорее всего, вызовет ::operator new, глобального оператора, если только вы не указали MyClass::operator new. И если вы сами не предоставили ::operator new, вы должны получить ::operator new от своего компилятора (скорее всего, Visual Studio).

Эта реализация ::operator new, вероятно, будет перенаправлена ​​на HeapAlloc. И угадайте, что? Это та же самая функция Win32, которую будет вызывать и .Net. Здесь не так много магии; именно так Windows назначает страницы памяти вашему виртуальному адресному пространству. И когда вы используете эти страницы, Windows назначит ОЗУ.

Теперь дело здесь в том, что вам не нужно делать ничего особенного для этого. На самом деле, делая что-то особенное, вы сломаете operator new. И раз ты его сломал, тебе придется это выяснить. Здесь не так много магического кода. Используйте отладочную сборку, чтобы у вас был чистый дамп стека (без встраивания). Вы можете вернуться к HeapAlloc?

Проверьте также содержимое исключения нарушения прав доступа. Код ошибки будет C0000005. Но что это за исключение? Читать или писать? По какому адресу? Код или данные?

person MSalters    schedule 11.04.2018
comment
Таким образом, сообщение Exception thrown at 0x001E15D9 in TheManagedCode.exe: 0xC0000005: Access violation reading location 0x00000004. я не уверен, что полностью понимаю вас здесь; Если я не предоставил свой собственный ::operator new, как его тогда сломать? - person skitiddu; 11.04.2018
comment
@skitiddu: Ну, поскольку вы не предоставили эту информацию заранее, я просто рассмотрел несколько случаев. Итак, проблема здесь заключается в чтении. Очевидно, что это разыменование нулевого указателя, но почему? Следующим битом информации является инструкция, вызвавшая его, в 0x001...... Это, вероятно, в EXE. Почему это там? Статический ЭЛТ? operator new обычно находится в DLL (поскольку вы хотите, чтобы он был общим для всех модулей). - person MSalters; 11.04.2018