[英]Code throwing WebException works in .NET 3.5 but not in 4.0
[英]UnmanagedFunctionPointer causes stackoverflow when using .NET 4.0, 3.5 works
我在點擊處理程序中有一個簡單的函數,它有一個 try catch 塊。 如果我在這個 try catch 塊中拋出異常,它會成功捕獲異常。
如果我在拋出異常之前調用非托管 DLL,則異常未處理且未被捕獲。
未管理的 DLL 調用在做什么可能會破壞我的程序異常處理?
如果我在調試模式下運行程序,它會捕獲異常,即使所有異常都未勾選“異常中斷”。 應用程序不會崩潰並按預期運行。
如果我以“不調試啟動”的方式運行程序並在崩潰時點擊調試,我會收到以下錯誤“堆棧 cookie 檢測代碼檢測到基於堆棧的緩沖區溢出”
編輯:看來堆棧溢出破壞了異常處理
我附上了一個產生崩潰的簡化程序。
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);
更新
如果我用以下內容替換對 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 崩潰?
更奇怪的是這段代碼在幾周前似乎可以工作。 主要的變化是 try catch 在另一個線程中,而我沒有使用 lock(syncLock)。 現在一切都在一個線程中,但是在 BackgroundWorker 中運行時也會發生同樣的崩潰。
更新 #2 問題半解決
好的,所以我一一回滾了我的提交,直到它起作用為止。 改變的是我從 .NET 3.5 到 .NET 4.0
無論是否附加調試器,.NET 3.5 都不會崩潰。 如果未附加調試器,.NET 4.0 會崩潰。 為了排除代碼中的錯誤,我只是刪除了日志的 ConcurrentQueue(我使用的唯一 4.0 功能)並將我當前的代碼庫轉換回 3.5,我沒有收到此錯誤。
為了 100% 確定這是 4.0 的問題,我然后將我的代碼庫從 3.5 轉換回 4.0 並將 ConcurrentQueue 排除在外(實際上只是更改了構建選項並進行了重建)並且 StackOverflow 崩潰又回來了。
我更喜歡使用 4.0,任何想法如何調試這個問題?
編輯:.NET 4.6.1 也會崩潰
更新 #3 http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html
顯然 pinvokestackimbalance 在 .NET 3.5 中基本上被忽略了,所以問題仍然存在,它只是不會使我的應用程序崩潰。
將以下代碼添加到 App.Config 會導致 .NET 在轉換回托管代碼時修復堆棧。 一個小的性能損失,但它會解決這個問題。
雖然這確實解決了問題,但我想知道我的 UnmanagedFunctionPointer 有什么問題首先導致了問題。
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
編輯:這個線程不是重復的,另一個被刪除了...
好的,問題是調用約定應該是 StdCall 而不是 Cdecl
這是有道理的,因為通用 J2534 API 文檔指定了以下標題。 雖然我提供的頭文件沒有做這個規范。
extern "C" long WINAPI PassThruConnect
(
unsigned long ProtocolID;
unsigned long Flags
unsigned long *pChannelID
)
WINAPI 也稱為 StdCall,而不是像大多數 C/C++ 庫通常使用的 Cdecl。
.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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.