Несбалансированные предупреждения в стеке от привязок LLVM - PullRequest
3 голосов
/ 04 марта 2012

После нескольких недель усилий мне удалось написать программы на F #, которые используют LLVM для JIT-компиляции. Однако всякий раз, когда я запускаю свои программы в Visual Studio 2010 с подключенным отладчиком (т.е. нажатием клавиши F5), я получаю следующее предупреждение:

enter image description here

Теперь я получаю это предупреждение для каждого отдельного вызова PInvoke при использовании моего нетбука с Windows 7, но я получаю его только для некоторых вызовов при использовании моего рабочего стола Windows Vista.

Другие люди, сталкивающиеся с этой проблемой, похоже, решили ее, добавив атрибуты к вызовам PInvoke, запрашивающим строки ANSI или CDecl соглашение о вызовах. Я обнаружил, что изменение соглашения о вызовах исправляет предупреждения на моем рабочем столе Windows Vista, но ни одно из доступных соглашений о вызовах (или строк формата ANSI) не исправляет предупреждения на моем нетбуке с Windows 7. Есть идеи как это исправить?

Обратите внимание, что обе машины полностью 32-битные x86.

EDIT

Люди публикуют комментарии с просьбой о репродукции. Самый простой способ воспроизвести эту проблему - установить LLVM и llvm-fs, следуя инструкциям, которые я задокументировал здесь , и запустить любую из приведенных примеров программ. Все они показывают эту проблему на всех вызовах LLVM на моем нетбуке.

В качестве альтернативы следующий код (полученный из llvm-fs) должен повторно воспроизвести проблему, не требуя llvm-fs:

open System.Runtime.InteropServices

[<DllImport("LLVM-3.0.dll",
            EntryPoint="LLVMModuleCreateWithName",
            CharSet=CharSet.Ansi,
            CallingConvention=CallingConvention.Cdecl)>]
extern void *moduleCreateWithNameNative(string ModuleID)

let mdl = moduleCreateWithNameNative "foo"

Обратите внимание, что соответствующие определения в исходном заголовочном файле C:

typedef struct LLVMOpaqueModule *LLVMModuleRef;
...
LLVMModuleRef LLVMModuleCreateWithName(const char *ModuleID);

1 Ответ

4 голосов
/ 04 марта 2012

Вы нацеливаетесь на .NET 4.0 или более раннюю версию?

Причина, по которой я спрашиваю, заключается в том, что для CLR предусмотрена функция безопасности / стабильности, которая выполняет очень строгую проверку подписей Pinvoke; он был примерно с .NET 2.0, но по умолчанию был отключен до .NET 4.0.

Изменение поведения привело к тому, что ряд разработчиков сообщили о той же проблеме, что и вы; их привязки прекрасно работали на .NET 2.0 / 3.5, но начали генерировать ошибки при компиляции для .NET 4.0. На самом деле проблема заключается в том, что в предыдущих версиях .NET допускалось, чтобы слегка ошибочные подписи PInvoke работали без проблем; теперь, когда строгая проверка включена по умолчанию, ошибки начинают обнаруживаться.

Следует также отметить, что даже если вы измените конфигурацию на своей машине, чтобы отключить это поведение в .NET 4.0, Visual Studio все равно будет всегда использовать ее при отладке проекта. Хуже того, строгая проверка по умолчанию включена только в версии x86 .NET 4.0, а не в версии x64, поэтому сборка, которая прекрасно работает на 64-разрядной машине, может произойти сбой на 32-разрядной машине .

MSDN содержит дополнительную информацию о pInvokeStackImbalance MDA и в этом блоге , а также более подробно объясняет, почему проблема возникает в процессе отладки.

РЕДАКТИРОВАТЬ: Я только что заметил, что вы отредактировали свой вопрос, чтобы включить пример кода. Этот вид подтверждает мое подозрение о том, что подпись PInvoke была слегка неправильной. Что произойдет, если вы измените подпись с extern void *moduleCreateWithNameNative(string ModuleID) на extern LLVMModuleRef* moduleCreateWithNameNative(string ModuleID)?

Похоже, что здесь работает ошибка компилятора - F # не должен позволять вам определять метод с именем *moduleCreateWithNameNative. Я предполагаю, что это разрешает (по любой причине), поэтому тип возвращаемой вашей функции компилируется как void - и когда нативный метод пытается вернуть значение (указатель на структуру LLVMModuleRef), CLR получает споткнулся и вылетел.

...