Нарушение прав доступа внутри вызова LoadLibrary ()

Я обнаружил нарушение прав доступа при вызове библиотеки DLL внутри LabVIEW. Назовем DLL "extcode.dll". Его кода у меня нет, он от внешнего производителя.

Запустив его в Windbg, он остановился с сообщением:

(724.1200): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll!RtlNewSecurityObjectWithMultipleInheritance+0x12a:

И стек вызовов:

ntdll!RtlNewSecurityObjectWithMultipleInheritance+0x12a
ntdll!MD5Final+0xedfc
ntdll!RtlFindClearBitsAndSet+0xdf4
ntdll!RtlFindClearBitsAndSet+0x3a8
ntdll!RtlFindClearBitsAndSet+0x4b9
ntdll!RtlCreateProcessParametersEx+0x829
ntdll!LdrLoadDll+0x9e
KERNELBASE!LoadLibraryExW+0x19c
KERNELBASE!LoadLibraryExA+0x51
LabVIEW!ChangeVINameWrapper+0x36f5
LabVIEW!ChangeVINameWrapper+0x3970
LabVIEW!ExtFuncDynLibWrapper+0x211

Обратите внимание, что зависимости extcode.dll загружаются до нарушения прав доступа.

Ситуация случайна, но когда это случается, все последующие попытки приводят к ней.

Код представляет собой простую функцию LabVIEW, вызывающую функцию в DLL, а прототип очень простой (int function(void)), поэтому он не может быть неправильной конфигурацией параметров вызова или арифметикой указателя. Я проверил каждую комбинацию соглашений о вызовах и уровней проверки ошибок.

DLL отлично работает при вызове в других средах (.NET и C).

Я обнаружил, что RtlFindClearBitsAndSet связано с манипуляциями с битовыми массивами

О чем это заставляет задуматься? Как вы думаете, проблема в extcode.dll, LabVIEW или Windows?

PS: Я использую 64-разрядную версию LabVIEW 2010, в 64-разрядной версии Windows 7 (а extcode.dll - 64-разрядная версия). Воспроизвести на 32-битной системе мне не удалось.

ИЗМЕНИТЬ 18/11

Я закончил тем, что создал автономный исполняемый файл, который обертывает DLL; LabVIEW общается с ним по каналам. Он работает отлично, но я все еще не понимаю, почему загрузка DLL в LabVIEW может привести к сбою.


person CharlesB    schedule 02.11.2010    source источник


Ответы (5)


Если он работает нормально при вызове из C, вы можете прекратить работу с Windbg, потому что DLL, вероятно, в порядке. Что-то не так с тем, как вызывается DLL, и как только DLL перезаписывает часть памяти LabView, все кончено, хотя может потребоваться 1000 итераций, прежде чем что-то действительно пойдет не так.

Сначала проверьте свои соглашения о вызовах, C или StdCall. Соглашение о вызовах C используется по умолчанию, и StdCall почти наверняка то, что вам нужно. (Проверьте файл заголовка DLL.) LabView 2009, по-видимому, произвел некоторую автоматическую проверку и исправление соглашений о вызовах, но переход на LLVM в LV 2010 сделал это невозможным; теперь это просто танки.

Если после изменения этого параметра он все еще снижается, проверьте свои вызывающие аргументы еще раз. что вы передаете, скаляры или данные указателя? Вы не можете получить доступ к памяти, выделенной DLL из LabView, не выполнив некоторые хитрые действия, хотя вы можете выделить память (то есть массив байтов) в LabView и передать указатель на нее в DLL для изменения.

Кроме того, если вы получаете указатель (например, refnum) от более раннего вызова DLL и возвращаете его, проверьте размер указателя. Функция библиотеки вызовов LabView теперь имеет тип «целочисленный размер указателя», который генерирует тип соответствующего размера в зависимости от того, вызывается ли он в 32-битном или 64-битном LabView. (Это всегда 64 бита в сети, потому что это должно быть определено во время компиляции.) Тот факт, что ваша DLL работает в 32 битах, предполагает, что это возможно.

Также имейте в виду, что структуры C часто выравниваются компилятором (C). Если вы передаете указатель на структуру, состоящую из Uint8 и UInt16, компилятор C выделит для этого 32 бита (или, возможно, даже 64 бита). Вам нужно будет заполнить вашу структуру (кластер) в LabView, чтобы она соответствовала, или написать DLL-оболочку для сборки структуры.

-Роб

person Robert Calhoun    schedule 05.11.2010
comment
Спасибо за ответ: прототип - int func(void), поэтому это не может быть проблема с соглашением о вызовах или указателем аргумента. - person CharlesB; 08.11.2010
comment
Может быть, вам стоит обратиться в службу поддержки NI. Они неплохо помогают с такими вещами. - person Robert Calhoun; 11.11.2010

О нарушении доступа (0xc0000005) также будет сообщено, если на вашем компьютере включена функция DEP (предотвращение выполнения данных) и не одобряется то, что пытается сделать ваш двоичный файл (EXE или DLL). DEP обычно отключен по умолчанию в Windows XP, но активен в Windows Vista / Windows 7.

DEP - это аппаратная мера безопасности, предназначенная для предотвращения выполнения вредоносным кодом некоторых байтов, которые ранее считались «всего лишь некоторыми данными»; У меня было несколько запусков, и все они требовали повторной компиляции проблемных двоичных файлов с последней версией Microsoft Visual Studio; это позволяет вам установить флаг, который определяет, поддерживает ли ваш двоичный файл DEP.

Некоторые полезные ресурсы:

person Edward Dixon    schedule 04.03.2011
comment
Спасибо, Эдвард; Я не могу проверить, была ли это проблема, так как я обошел ее, загрузив DLL в отдельном процессе и выполнив вызовы IPC. - person CharlesB; 04.03.2011

Это сложно диагностировать удаленно, но вот пара идей.

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

Если у вас есть проблема только при использовании 64-битного labview, я сначала предполагаю, что есть проблема с 64-битной версией dll, но если вы уверены, что у вас нет проблем с точно такими же вызовами при использовании dll в других условиях я в тупике. Одна из возможностей заключается в том, что вы используете неправильное соглашение о вызовах (stdcall vs. cdecl) в labview.

Вы пробовали импортировать DLL и заголовок с помощью мастера импорта labview? Это может помочь избежать глупых ошибок с прототипами.

person Marc    schedule 08.11.2010
comment
Нет процедуры инициализации, она может работать с одним вызовом функции. Пробовал мастер импорта labview, другое соглашение о вызовах, безуспешно. Прототип смертельно прост (int func(void)), так что это не проблема с указателем. Я тоже в тупике. - person CharlesB; 18.11.2010

Еще одна вещь, которую стоит попробовать: щелкните правой кнопкой мыши вызов DLL, выберите configure и убедитесь, что вы работаете в потоке пользовательского интерфейса, а не в каком-либо потоке. Иногда это помогает.

person Marc    schedule 18.11.2010

При работе с git и cygwin под NTFS я обнаружил, что иногда исполняемый бит не установлен (или не установлен во время проверки или некоторых файловых операций) - внутри cygwin cd в папку и выполните

chmod a+rwx *.dll

и проверьте, меняет ли это что-то (и проверьте, хотите ли вы этого!). Я нашел этот вопрос при поиске LoadLibrary () с ошибкой GetLastError (), возвращающей 5 (не «0xc0000005», кстати), и решил проблему с помощью этого вызова chmod.

person Heiner    schedule 22.05.2019