2016-10-17 9 views
2

У меня есть простая функция внутри обработчика кликов, у которого есть блок catch try. Если я сделаю исключение в этом блоке catch catch, он успешно поймает исключение.UnmanagedFunctionPointer вызывает stackoverflow при использовании .NET 4.0, 3.5 works

Если я поместил вызов неуправляемой библиотеки DLL, прежде чем я вычеркнул исключение, исключение будет необработанным и не поймано.

Что такое незанятый вызов DLL, который может нарушить обработку исключений для моих программ?

Если я запустил программу в режиме отладки, она обнаруживает исключение, даже если «исключение для исключения» отключено для всех исключений. Приложение не сбой и работает как ожидалось.

Если я запустить программу как «начать без отладки» и ударили отладки, когда он выходит из строя я получаю следующее сообщение об ошибке «Stack код печенья приборостроения обнаружил стек на основе переполнения буфера»

редактировать: Он появляется переполнение стека прерывает обработку исключений

Я приложил упрощенную программу, которая вызывает сбой.

ISOConnection _comm; //This is instantiated at another time in the same thread 

//C# test function that crashes when run without a debugger attached 
bool DoMagic() 
{ 
    try 
    { 
     //if I uncomment this line the exception becomes unhandled and cannot be caught 
     //_comm.ConnectISO15765(); 

     throw new Exception(); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("Caught exception") 
    } 

//Within ISOConnection class 
public void ConnectISO15765(){ 
    ... 
    lock(syncLock){ 
     uint returnCode = J2534Interface.PassThruConnect((uint)DeviceId, (uint)ProtocolID.ISO15765, (uint)ConnectFlag.NONE, (uint)BaudRate.ISO15765, ref ChannelId); 


//C# UnmanagedFunctionPointer allocation code 
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId); 
public PassThruConnect Connect; 

[DllImport("kernel32.dll")] 
public static extern IntPtr LoadLibrary(string dllToLoad); 

m_pDll = NativeMethods.LoadLibrary(path); 
... 
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "PassThruConnect"); 
if (pAddressOfFunctionToCall != IntPtr.Zero) 
    Connect = (PassThruConnect)Marshal.GetDelegateForFunctionPointer(
     pAddressOfFunctionToCall, 
     typeof(PassThruConnect)); 

//C++ function declaration 
long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long Baudrate, unsigned long *pChannelID); 

UPDATE

Если я заменить вызов на UnmanagedFunctionPointer PassThurConnect с после аварии не происходит

[DllImport("op20pt32.dll", EntryPoint = "PassThruConnect", CallingConvention = CallingConvention.Cdecl)] 
public static extern uint PassThruConnect2(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId); 

Есть ли что-то я не выполняет или я выступаю неправильно при назначении UnmanagedFunctionPointer, который приведет к тому, что отсутствие отладчика приведет к сбою stackoverflow?

Что еще незнакомец этот код появился, чтобы работать несколько недель назад. Основные изменения - это попытка catch в другом потоке, и я не использовал lock (syncLock). Все теперь в одном потоке, но тот же самый сбой произошел и при работе в BackgroundWorker.

UPDATE # 2 ПРОБЛЕМЫ SEMI-решаемые

Ok поэтому я отвалил через мои фиксации один за другим, пока он не работал. Что изменилось, я перешел от .NET 3.5 к .NET 4.0

.NET 3.5 не сбой, независимо от прикрепления отладчика или нет. Ошибка .NET 4.0, если отладчик не подключен. Чтобы исключить ошибку в моем коде, я просто удалил ConcurrentQueue для моего журнала (единственная функция 4.0, которую я использовал) и преобразовал мою текущую базу кода обратно в 3.5, и я не получаю эту ошибку.

Чтобы быть на 100% уверенным, что это проблема с 4.0, я преобразовал мою базу кода обратно в 4.0 из 3.5 и вышел из ConcurrentQueue вне (только что изменил параметры сборки и сделал пересоздание), а сбой StackOverflow вернулся.

Я бы предпочел использовать 4.0, любые идеи по отладке этой проблемы?

Редактировать: .NET 4.6.1 также врезается

UPDATE # 3 http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html

Видимо pinvokestackimbalance в основном игнорируется в .NET 3.5, так что проблема все еще существует, она просто не врезаться мое заявление.

Добавление следующего кода в App.Config заставляет .NET восстанавливать стек при переходе к управляемому коду. Небольшой удар производительности, но он устранит проблему.

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

<configuration> 
    <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/> 

Edit: этот поток не дубликат, а другой удаляется ...

+0

Есть несколько фатальных исключений, которые невозможно поймать с помощью .Net-кода. Я считаю, что один из них. Скорее всего, вы получили неверные обертки для взаимодействия, и стек смещен ... или собственный код просто плох. –

+0

Итак, я добавил Debugger.Launch() непосредственно перед управляемым вызовом и выбрасывает исключение StackOverflow, это, без сомнения, нарушает обработку исключений. Почему это не происходит с отладчиком, подключенным с самого начала? – rolls

+0

Хорошо, если я использую dllimport с тем же прототипом функции, я не получаю stackoverflow. Есть ли что-то еще, что мне нужно делать при использовании неуправляемых указателей? – rolls

ответ

2

Ok поэтому проблема является соглашение о вызове должно быть STDCALL не Cdecl

Это имеет смысл, как в общей документации API J2534 указан следующий заголовок. Хотя заголовочный файл, который я поставил, не выполняет эту спецификацию.

extern "C" long WINAPI PassThruConnect 
(
unsigned long ProtocolID; 
unsigned long Flags 
unsigned long *pChannelID 
) 

Где WINAPI также известен как STDCALL не Cdecl как большинство библиотек C/C++, как правило, используют.

.NET 3.5 допускает неправильное соглашение о вызове и «исправляет» стек. Начиная с версии 4.0 это уже не так, и возникает исключение PinvokeStackImbalance.

Вы можете заставить 4.0 также исправить стек с помощью следующего кода добавлен в ваш App.Config

<configuration> 
    <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/> 

Или вы можете просто исправить соглашение о вызовах, изменив Cdecl к STDCALL:

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID);