從.Net框架Bug的提交到修復代碼成功合並到.NET CoreFX主線


從發現.NET Framework中SmtpClient的Bug並拿出解決方案,然后給微軟開發者社區提交Bug開始,總共耗時一個多月,對Bug修復的代碼最終被采納,現已合並到.NET Core Libraries (CoreFX)主線中。

修復記錄https://github.com/dotnet/corefx/commit/94b1f1eae84fd4823cfa2bbdde6fc87c46b57908

雖然對Bug修復實際生效的代碼只有20個字符,但意義重大,這個Bug不遇上一點事沒有,遇上了不對框架開刀是非常棘手的,而且備受折磨也稍微有點難摸得清頭腦。

相關詳情見我的另外一篇博客《記錄一次.Net框架Bug發現和提交過程:.Net Framework和.Net Core均受影響

問題描述

我們用SmtpClientSendAsyncSendMailAsync異步方法發送郵件,並且要求使用DeliveryFormat = SmtpDeliveryFormat.SevenBit 格式來編碼中文內容,本來預期是郵件內容中帶中文的SubjectAttachments file name 都會進行Base64編碼。

但實際結果是:如果郵件服務器支持SMTPUTF8擴展,那么異步發送SevenBit郵件並不會進行Base64編碼,同步方法沒有此問題。

問題根源

原因是在SmtpClient.SendMailCallback方法中,message.BeginSend allowUnicode參數直接使用的ServerSupportsEai,而不是統一的IsUnicodeSupported()

 private void SendMailCallback(IAsyncResult result)
 { 
    ......
     _message.BeginSend(_writer, DeliveryMethod != SmtpDeliveryMethod.Network, 
         ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState); 
    ......
 } 

ServerSupportsEai改成IsUnicodeSupported()問題解決。就這20個字符的改動~

另外附對現有帶Bug的.Net框架修復方法

比如使用的.NET Framework 4.7.2,純天然原生自帶此Bug,我們可以用我們的代碼修復它。

最開始測試時以為此方法無效,沒想到是Hook錯了地方,換到最深層次調用地方,一抓一個准。

使用DotNetDetour庫對.Net框架內方法進行Hook,找出SmtpClient.ServerSupportsEai最結果最終是從SmtpConnection.ServerSupportsEai得來的,也許是C#編譯后把整個調用過程都優化掉了,變成了取值的地方直接調用的SmtpConnection中的方法,導致Hook前面的方法都是不會被執行,Hook SmtpConnection.ServerSupportsEai一抓一個准。

附上Hook代碼:

public class Hook : IMethodMonitor {
	public bool ServerSupportsEai {
		[Monitor("System.Net.Mail", "SmtpConnection")]
		get {
			Console.WriteLine("Hook");
			return !true?org():false;//什么情況下要Hook? AsyncLocal和CallContext上下文為什么在這里傳不進來?
		}
	}
	[Original]
	public bool org() {
		return false;
	}
}

另外引出了另外一個折磨人Bug,異步環境下,ServerSupportsEai的調用棧中上下文怎么會丟失?難道哪里使用了類似ThreadPool.UnsafeXXX這種效果?我們沒法通過CallContext(AsyncLocal)給Hook代碼傳參數,只能寫死,不管調用方要不要修改返回值,都只能得到修改后的結果,尷尬不尷尬。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM